]> git.saurik.com Git - wxWidgets.git/blame - src/freetype/cff/t2load.c
oops, forgot to fix wxHtmlTag dtor
[wxWidgets.git] / src / freetype / cff / t2load.c
CommitLineData
cabec872
RR
1/***************************************************************************/
2/* */
3/* t2load.c */
4/* */
5/* TrueType glyph data/program tables loader (body). */
6/* */
7/* Copyright 1996-2000 by */
8/* David Turner, Robert Wilhelm, and Werner Lemberg. */
9/* */
10/* This file is part of the FreeType project, and may only be used, */
11/* modified, and distributed under the terms of the FreeType project */
12/* license, LICENSE.TXT. By continuing to use, modify, or distribute */
13/* this file you indicate that you have read the license and */
14/* understand and accept it fully. */
15/* */
16/***************************************************************************/
17
18
19#include <freetype/internal/ftdebug.h>
20#include <freetype/internal/ftobjs.h>
21#include <freetype/internal/ftstream.h>
22#include <freetype/internal/psnames.h>
23
24#include <freetype/internal/t2errors.h>
25#include <freetype/tttags.h>
26
27
28#ifdef FT_FLAT_COMPILE
29
30#include "t2load.h"
31#include "t2parse.h"
32
33#else
34
35#include <cff/t2load.h>
36#include <cff/t2parse.h>
37
38#endif
39
40
41 /*************************************************************************/
42 /* */
43 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */
44 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */
45 /* messages during execution. */
46 /* */
47#undef FT_COMPONENT
48#define FT_COMPONENT trace_t2load
49
50
51 /* read a CFF offset from memory */
52 static
53 FT_ULong t2_get_offset( FT_Byte* p,
54 FT_Byte off_size )
55 {
56 FT_ULong result;
57
58
59 for ( result = 0; off_size > 0; off_size-- )
60 {
61 result <<= 8;
62 result |= *p++;
63 }
64
65 return result;
66 }
67
68
69 static
70 FT_Error t2_new_cff_index( CFF_Index* index,
71 FT_Stream stream,
72 FT_Bool load )
73 {
74 FT_Error error;
75 FT_Memory memory = stream->memory;
76 FT_UShort count;
77
78
79 MEM_Set( index, 0, sizeof ( *index ) );
80
81 index->stream = stream;
82 if ( !READ_UShort( count ) &&
83 count > 0 )
84 {
85 FT_Byte* p;
86 FT_Byte offsize;
87 FT_ULong data_size;
88 FT_ULong* poff;
89
90
91 /* there is at least one element; read the offset size, */
92 /* then access the offset table to compute the index's total size */
93 if ( READ_Byte( offsize ) )
94 goto Exit;
95
96 index->stream = stream;
97 index->count = count;
98 index->off_size = offsize;
99 data_size = (FT_ULong)( count + 1 ) * offsize;
100
101 if ( ALLOC_ARRAY( index->offsets, count + 1, FT_ULong ) ||
102 ACCESS_Frame( data_size ) )
103 goto Exit;
104
105 poff = index->offsets;
106 p = (FT_Byte*)stream->cursor;
107
108 for ( ; (FT_Short)count >= 0; count-- )
109 {
110 poff[0] = t2_get_offset( p, offsize );
111 poff++;
112 p += offsize;
113 }
114
115 FORGET_Frame();
116
117 index->data_offset = FILE_Pos();
118 data_size = poff[-1] - 1;
119
120 if ( load )
121 {
122 /* load the data */
123 if ( EXTRACT_Frame( data_size, index->bytes ) )
124 goto Exit;
125 }
126 else
127 {
128 /* skip the data */
129 (void)FILE_Skip( data_size );
130 }
131 }
132
133 Exit:
134 if ( error )
135 FREE( index->offsets );
136
137 return error;
138 }
139
140
141 static
142 void t2_done_cff_index( CFF_Index* index )
143 {
144 if ( index->stream )
145 {
146 FT_Stream stream = index->stream;
147 FT_Memory memory = stream->memory;
148
149
150 if ( index->bytes )
151 RELEASE_Frame( index->bytes );
152
153 FREE( index->offsets );
154 MEM_Set( index, 0, sizeof ( *index ) );
155 }
156 }
157
158
159 static
160 FT_Error t2_explicit_cff_index( CFF_Index* index,
161 FT_Byte*** table )
162 {
163 FT_Error error = 0;
164 FT_Memory memory = index->stream->memory;
165 FT_UInt n, offset, old_offset;
166 FT_Byte** t;
167
168
169 *table = 0;
170
171 if ( index->count > 0 && !ALLOC_ARRAY( t, index->count + 1, FT_Byte* ) )
172 {
173 old_offset = 1;
174 for ( n = 0; n <= index->count; n++ )
175 {
176 offset = index->offsets[n];
177 if ( !offset )
178 offset = old_offset;
179
180 t[n] = index->bytes + offset - 1;
181
182 old_offset = offset;
183 }
184 *table = t;
185 }
186
187 return error;
188 }
189
190
191 LOCAL_FUNC
192 FT_Error T2_Access_Element( CFF_Index* index,
193 FT_UInt element,
194 FT_Byte** pbytes,
195 FT_ULong* pbyte_len )
196 {
197 FT_Error error = 0;
198
199
200 if ( index && index->count > element )
201 {
202 /* compute start and end offsets */
203 FT_ULong off1, off2;
204
205
206 off1 = index->offsets[element];
207 if ( off1 )
208 {
209 do
210 {
211 element++;
212 off2 = index->offsets[element];
213
214 } while ( off2 == 0 && element < index->count );
215
216 if ( !off2 )
217 off1 = 0;
218 }
219
220 /* access element */
221 if ( off1 )
222 {
223 *pbyte_len = off2 - off1;
224
225 if ( index->bytes )
226 {
227 /* this index was completely loaded in memory, that's easy */
228 *pbytes = index->bytes + off1 - 1;
229 }
230 else
231 {
232 /* this index is still on disk/file, access it through a frame */
233 FT_Stream stream = index->stream;
234
235
236 if ( FILE_Seek( index->data_offset + off1 - 1 ) ||
237 EXTRACT_Frame( off2 - off1, *pbytes ) )
238 goto Exit;
239 }
240 }
241 else
242 {
243 /* empty index element */
244 *pbytes = 0;
245 *pbyte_len = 0;
246 }
247 }
248 else
249 error = T2_Err_Invalid_Argument;
250
251 Exit:
252 return error;
253 }
254
255
256 LOCAL_FUNC
257 void T2_Forget_Element( CFF_Index* index,
258 FT_Byte** pbytes )
259 {
260 if ( index->bytes == 0 )
261 {
262 FT_Stream stream = index->stream;
263
264
265 RELEASE_Frame( *pbytes );
266 }
267 }
268
269
270 LOCAL_FUNC
271 FT_String* T2_Get_Name( CFF_Index* index,
272 FT_UInt element )
273 {
274 FT_Memory memory = index->stream->memory;
275 FT_Byte* bytes;
276 FT_ULong byte_len;
277 FT_Error error;
278 FT_String* name = 0;
279
280
281 error = T2_Access_Element( index, element, &bytes, &byte_len );
282 if ( error )
283 goto Exit;
284
285 if ( !ALLOC( name, byte_len + 1 ) )
286 {
287 MEM_Copy( name, bytes, byte_len );
288 name[byte_len] = 0;
289 }
290 T2_Forget_Element( index, &bytes );
291
292 Exit:
293 return name;
294 }
295
296
297 LOCAL_FUNC
298 FT_String* T2_Get_String( CFF_Index* index,
299 FT_UInt sid,
300 PSNames_Interface* interface )
301 {
302 /* if it is not a standard string, return it */
303 if ( sid > 390 )
304 return T2_Get_Name( index, sid - 390 );
305
306 /* that's a standard string, fetch a copy from the PSName module */
307 {
308 FT_String* name = 0;
309 const char* adobe_name = interface->adobe_std_strings( sid );
310 FT_UInt len;
311
312
313 if ( adobe_name )
314 {
315 FT_Memory memory = index->stream->memory;
316 FT_Error error;
317
318
319 len = (FT_UInt)strlen( adobe_name );
320 if ( !ALLOC( name, len + 1 ) )
321 {
322 MEM_Copy( name, adobe_name, len );
323 name[len] = 0;
324 }
325 }
326
327 return name;
328 }
329 }
330
331
332 /*************************************************************************/
333 /*************************************************************************/
334 /*** ***/
335 /*** FD Select table support ***/
336 /*** ***/
337 /*************************************************************************/
338 /*************************************************************************/
339
340
341 static
342 void CFF_Done_FD_Select( CFF_FD_Select* select,
343 FT_Stream stream )
344 {
345 if ( select->data )
346 RELEASE_Frame( select->data );
347
348 select->data_size = 0;
349 select->format = 0;
350 select->range_count = 0;
351 }
352
353
354 static
355 FT_Error CFF_Load_FD_Select( CFF_FD_Select* select,
356 FT_UInt num_glyphs,
357 FT_Stream stream,
358 FT_ULong offset )
359 {
360 FT_Error error;
361 FT_Byte format;
362 FT_UInt num_ranges;
363
364
365 /* read format */
366 if ( FILE_Seek( offset ) || READ_Byte( format ) )
367 goto Exit;
368
369 select->format = format;
370 select->cache_count = 0; /* clear cache */
371
372 switch ( format )
373 {
374 case 0: /* format 0, that's simple */
375 select->data_size = num_glyphs;
376 goto Load_Data;
377
378 case 3: /* format 3, a tad more complex */
379 if ( READ_UShort( num_ranges ) )
380 goto Exit;
381
382 select->data_size = num_ranges * 3 + 2;
383
384 Load_Data:
385 if ( EXTRACT_Frame( select->data_size, select->data ) )
386 goto Exit;
387 break;
388
389 default: /* hmm... that's wrong */
390 error = T2_Err_Invalid_File_Format;
391 }
392
393 Exit:
394 return error;
395 }
396
397
398 LOCAL_FUNC
399 FT_Byte CFF_Get_FD( CFF_FD_Select* select,
400 FT_UInt glyph_index )
401 {
402 FT_Byte fd = 0;
403
404
405 switch ( select->format )
406 {
407 case 0:
408 fd = select->data[glyph_index];
409 break;
410
411 case 3:
412 /* first, compare to cache */
413 if ( (FT_UInt)(glyph_index-select->cache_first) < select->cache_count )
414 {
415 fd = select->cache_fd;
416 break;
417 }
418
419 /* then, lookup the ranges array */
420 {
421 FT_Byte* p = select->data;
422 FT_Byte* p_limit = p + select->data_size;
423 FT_Byte fd2;
424 FT_UInt first, limit;
425
426
427 first = NEXT_UShort( p );
428 do
429 {
430 if ( glyph_index < first )
431 break;
432
433 fd2 = *p++;
434 limit = NEXT_UShort( p );
435
436 if ( glyph_index < limit )
437 {
438 fd = fd2;
439
440 /* update cache */
441 select->cache_first = first;
442 select->cache_count = limit-first;
443 select->cache_fd = fd2;
444 break;
445 }
446 first = limit;
447
448 } while ( p < p_limit );
449 }
450 break;
451
452 default:
453 ;
454 }
455
456 return fd;
457 }
458
459
460 /*************************************************************************/
461 /*************************************************************************/
462 /*** ***/
463 /*** CFF font support ***/
464 /*** ***/
465 /*************************************************************************/
466 /*************************************************************************/
467
468
469 static
470 FT_Error CFF_Load_SubFont( CFF_SubFont* font,
471 CFF_Index* index,
472 FT_UInt font_index,
473 FT_Stream stream,
474 FT_ULong base_offset )
475 {
476 FT_Error error;
477 T2_Parser parser;
478 FT_Byte* dict;
479 FT_ULong dict_len;
480 CFF_Font_Dict* top = &font->font_dict;
481 CFF_Private* priv = &font->private_dict;
482
483
484 T2_Parser_Init( &parser, T2CODE_TOPDICT, &font->font_dict );
485
486 /* set defaults */
487 MEM_Set( top, 0, sizeof ( *top ) );
488
489 top->underline_position = -100;
490 top->underline_thickness = 50;
491 top->charstring_type = 2;
492 top->font_matrix.xx = 0x10000L;
493 top->font_matrix.yy = 0x10000L;
494 top->cid_count = 8720;
495
496 error = T2_Access_Element( index, font_index, &dict, &dict_len ) ||
497 T2_Parser_Run( &parser, dict, dict + dict_len );
498
499 T2_Forget_Element( index, &dict );
500
501 if ( error )
502 goto Exit;
503
504 /* if it is a CID font, we stop there */
505 if ( top->cid_registry )
506 goto Exit;
507
508 /* parse the private dictionary, if any */
509 if ( top->private_offset && top->private_size )
510 {
511 /* set defaults */
512 MEM_Set( priv, 0, sizeof ( *priv ) );
513
514 priv->blue_shift = 7;
515 priv->blue_fuzz = 1;
516 priv->lenIV = -1;
517 priv->expansion_factor = (FT_Fixed)0.06 * 0x10000L;
518 priv->blue_scale = (FT_Fixed)0.039625 * 0x10000L;
519
520 T2_Parser_Init( &parser, T2CODE_PRIVATE, priv );
521
522 if ( FILE_Seek( base_offset + font->font_dict.private_offset ) ||
523 ACCESS_Frame( font->font_dict.private_size ) )
524 goto Exit;
525
526 error = T2_Parser_Run( &parser,
527 (FT_Byte*)stream->cursor,
528 (FT_Byte*)stream->limit );
529 FORGET_Frame();
530 if ( error )
531 goto Exit;
532 }
533
534 /* read the local subrs, if any */
535 if ( priv->local_subrs_offset )
536 {
537 if ( FILE_Seek( base_offset + top->private_offset +
538 priv->local_subrs_offset ) )
539 goto Exit;
540
541 error = t2_new_cff_index( &font->local_subrs_index, stream, 1 );
542 if ( error )
543 goto Exit;
544
545 font->num_local_subrs = font->local_subrs_index.count;
546 error = t2_explicit_cff_index( &font->local_subrs_index,
547 &font->local_subrs );
548 }
549
550 Exit:
551 return error;
552 }
553
554
555 static
556 void CFF_Done_SubFont( FT_Memory memory,
557 CFF_SubFont* subfont )
558 {
559 if ( subfont )
560 {
561 t2_done_cff_index( &subfont->local_subrs_index );
562 FREE( subfont->local_subrs );
563 }
564 }
565
566
567 LOCAL_FUNC
568 FT_Error T2_Load_CFF_Font( FT_Stream stream,
569 FT_Int face_index,
570 CFF_Font* font )
571 {
572 static const FT_Frame_Field cff_header_fields[] =
573 {
574 FT_FRAME_START( 4 ),
575 FT_FRAME_BYTE( CFF_Font, version_major ),
576 FT_FRAME_BYTE( CFF_Font, version_minor ),
577 FT_FRAME_BYTE( CFF_Font, header_size ),
578 FT_FRAME_BYTE( CFF_Font, absolute_offsize ),
579 FT_FRAME_END
580 };
581
582 FT_Error error;
583 FT_Memory memory = stream->memory;
584 FT_ULong base_offset;
585 CFF_Font_Dict* dict;
586
587
588 MEM_Set( font, 0, sizeof ( *font ) );
589 font->stream = stream;
590 font->memory = memory;
591 dict = &font->top_font.font_dict;
592 base_offset = FILE_Pos();
593
594 /* read CFF font header */
595 if ( READ_Fields( cff_header_fields, font ) )
596 goto Exit;
597
598 /* check format */
599 if ( font->version_major != 1 ||
600 font->header_size < 4 ||
601 font->absolute_offsize > 4 )
602 {
603 FT_TRACE2(( "[not a CFF font header!]\n" ));
604 error = FT_Err_Unknown_File_Format;
605 goto Exit;
606 }
607
608 /* skip the rest of the header */
609 (void)FILE_Skip( font->header_size - 4 );
610
611 /* read the name, top dict, string and global subrs index */
612 error = t2_new_cff_index( &font->name_index, stream, 0 ) ||
613 t2_new_cff_index( &font->font_dict_index, stream, 0 ) ||
614 t2_new_cff_index( &font->string_index, stream, 0 ) ||
615 t2_new_cff_index( &font->global_subrs_index, stream, 1 );
616 if ( error )
617 goto Exit;
618
619 /* well, we don't really forget the `disabled' fonts... */
620 font->num_faces = font->name_index.count;
621 if ( face_index >= (FT_Int)font->num_faces )
622 {
623 FT_ERROR(( "T2_Load_CFF_Font: incorrect face index = %d\n",
624 face_index ));
625 error = T2_Err_Invalid_Argument;
626 }
627
628 /* in case of a font format check, simply exit now */
629 if ( face_index < 0 )
630 goto Exit;
631
632 /* now, parse the top-level font dictionary */
633 error = CFF_Load_SubFont( &font->top_font,
634 &font->font_dict_index,
635 face_index,
636 stream,
637 base_offset );
638 if ( error )
639 goto Exit;
640
641 /* now, check for a CID font */
642 if ( dict->cid_registry )
643 {
644 CFF_Index fd_index;
645 CFF_SubFont* sub;
646 FT_UInt index;
647
648
649 /* this is a CID-keyed font, we must now allocate a table of */
650 /* sub-fonts, then load each of them separately */
651 if ( FILE_Seek( base_offset + dict->cid_fd_array_offset ) )
652 goto Exit;
653
654 error = t2_new_cff_index( &fd_index, stream, 0 );
655 if ( error )
656 goto Exit;
657
658 if ( fd_index.count > CFF_MAX_CID_FONTS )
659 {
660 FT_ERROR(( "T2_Load_CFF_Font: FD array too large in CID font\n" ));
661 goto Fail_CID;
662 }
663
664 /* allocate & read each font dict independently */
665 font->num_subfonts = fd_index.count;
666 if ( ALLOC_ARRAY( sub, fd_index.count, CFF_SubFont ) )
667 goto Fail_CID;
668
669 /* setup pointer table */
670 for ( index = 0; index < fd_index.count; index++ )
671 font->subfonts[index] = sub + index;
672
673 /* now load each sub font independently */
674 for ( index = 0; index < fd_index.count; index++ )
675 {
676 sub = font->subfonts[index];
677 error = CFF_Load_SubFont( sub, &fd_index, index,
678 stream, base_offset );
679 if ( error )
680 goto Fail_CID;
681 }
682
683 /* now load the FD Select array */
684 error = CFF_Load_FD_Select( &font->fd_select,
685 dict->cid_count,
686 stream,
687 base_offset + dict->cid_fd_select_offset );
688
689 Fail_CID:
690 t2_done_cff_index( &fd_index );
691
692 if ( error )
693 goto Exit;
694 }
695 else
696 font->num_subfonts = 0;
697
698 /* read the charstrings index now */
699 if ( dict->charstrings_offset == 0 )
700 {
701 FT_ERROR(( "T2_Load_CFF_Font: no charstrings offset!\n" ));
702 error = FT_Err_Unknown_File_Format;
703 goto Exit;
704 }
705
706 if ( FILE_Seek( base_offset + dict->charstrings_offset ) )
707 goto Exit;
708
709 error = t2_new_cff_index( &font->charstrings_index, stream, 0 );
710 if ( error )
711 goto Exit;
712
713 /* explicit the global subrs */
714 font->num_global_subrs = font->global_subrs_index.count;
715 font->num_glyphs = font->charstrings_index.count;
716
717 error = t2_explicit_cff_index( &font->global_subrs_index,
718 &font->global_subrs ) ;
719
720 if ( error )
721 goto Exit;
722
723 /* get the font name */
724 font->font_name = T2_Get_Name( &font->name_index, face_index );
725
726 Exit:
727 return error;
728 }
729
730
731 LOCAL_FUNC
732 void T2_Done_CFF_Font( CFF_Font* font )
733 {
734 FT_Memory memory = font->memory;
735 FT_UInt index;
736
737
738 t2_done_cff_index( &font->global_subrs_index );
739 t2_done_cff_index( &font->string_index );
740 t2_done_cff_index( &font->font_dict_index );
741 t2_done_cff_index( &font->name_index );
742 t2_done_cff_index( &font->charstrings_index );
743
744 /* release font dictionaries */
745 for ( index = 0; index < font->num_subfonts; index++ )
746 CFF_Done_SubFont( memory, font->subfonts[index] );
747
748 CFF_Done_SubFont( memory, &font->top_font );
749
750 CFF_Done_FD_Select( &font->fd_select, font->stream );
751
752 FREE( font->global_subrs );
753 FREE( font->font_name );
754 }
755
756
757/* END */