The BIG graph update
[rrdtool.git] / libraries / freetype-2.0.5 / sfobjs.c
1 /***************************************************************************/
2 /*                                                                         */
3 /*  sfobjs.c                                                               */
4 /*                                                                         */
5 /*    SFNT object management (base).                                       */
6 /*                                                                         */
7 /*  Copyright 1996-2001 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 <ft2build.h>
20 #include "sfobjs.h"
21 #include "ttload.h"
22 #include FT_INTERNAL_SFNT_H
23 #include FT_INTERNAL_POSTSCRIPT_NAMES_H
24 #include FT_TRUETYPE_IDS_H
25 #include FT_TRUETYPE_TAGS_H
26
27 #include "sferrors.h"
28
29
30   /*************************************************************************/
31   /*                                                                       */
32   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
33   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
34   /* messages during execution.                                            */
35   /*                                                                       */
36 #undef  FT_COMPONENT
37 #define FT_COMPONENT  trace_sfobjs
38
39
40   /*************************************************************************/
41   /*                                                                       */
42   /* <Function>                                                            */
43   /*    Get_Name                                                           */
44   /*                                                                       */
45   /* <Description>                                                         */
46   /*    Returns a given ENGLISH name record in ASCII.                      */
47   /*                                                                       */
48   /* <Input>                                                               */
49   /*    face   :: A handle to the source face object.                      */
50   /*                                                                       */
51   /*    nameid :: The name id of the name record to return.                */
52   /*                                                                       */
53   /* <Return>                                                              */
54   /*    Character string.  NULL if no name is present.                     */
55   /*                                                                       */
56   static FT_String*
57   Get_Name( TT_Face    face,
58             FT_UShort  nameid )
59   {
60     FT_Memory    memory = face->root.memory;
61     FT_UShort    n;
62     TT_NameRec*  rec;
63     FT_Bool      wide_chars = 1;
64
65
66     rec = face->name_table.names;
67     for ( n = 0; n < face->name_table.numNameRecords; n++, rec++ )
68     {
69       if ( rec->nameID == nameid )
70       {
71         /* found the name -- now create an ASCII string from it */
72         FT_Bool  found = 0;
73
74
75         /* test for Microsoft English language */
76         if ( rec->platformID == TT_PLATFORM_MICROSOFT &&
77              rec->encodingID <= TT_MS_ID_UNICODE_CS   &&
78              ( rec->languageID & 0x3FF ) == 0x009     )
79           found = 1;
80
81         /* test for Apple Unicode encoding */
82         else if ( rec->platformID == TT_PLATFORM_APPLE_UNICODE )
83           found = 1;
84
85         /* test for Apple Roman */
86         else if ( rec->platformID == TT_PLATFORM_MACINTOSH &&
87                   rec->languageID == TT_MAC_ID_ROMAN       )
88         {
89           found      = 1;
90           wide_chars = 0;
91         }
92
93         /* found a Unicode name */
94         if ( found )
95         {
96           FT_String*  string;
97           FT_UInt     len;
98
99
100           if ( wide_chars )
101           {
102             FT_UInt   m;
103
104
105             len = (FT_UInt)rec->stringLength / 2;
106             if ( MEM_Alloc( string, len + 1 ) )
107               return NULL;
108
109             for ( m = 0; m < len; m ++ )
110               string[m] = rec->string[2 * m + 1];
111           }
112           else
113           {
114             len = rec->stringLength;
115             if ( MEM_Alloc( string, len + 1 ) )
116               return NULL;
117
118             MEM_Copy( string, rec->string, len );
119           }
120
121           string[len] = '\0';
122           return string;
123         }
124       }
125     }
126
127     return NULL;
128   }
129
130
131   static FT_Encoding
132   find_encoding( int  platform_id,
133                  int  encoding_id )
134   {
135     typedef struct  TEncoding
136     {
137       int          platform_id;
138       int          encoding_id;
139       FT_Encoding  encoding;
140
141     } TEncoding;
142
143     static
144     const TEncoding  tt_encodings[] =
145     {
146       { TT_PLATFORM_ISO,           -1,                  ft_encoding_unicode },
147
148       { TT_PLATFORM_APPLE_UNICODE, -1,                  ft_encoding_unicode },
149
150       { TT_PLATFORM_MACINTOSH,     TT_MAC_ID_ROMAN,     ft_encoding_apple_roman },
151
152       { TT_PLATFORM_MICROSOFT,     TT_MS_ID_SYMBOL_CS,  ft_encoding_symbol },
153       { TT_PLATFORM_MICROSOFT,     TT_MS_ID_UCS_4,      ft_encoding_unicode },
154       { TT_PLATFORM_MICROSOFT,     TT_MS_ID_UNICODE_CS, ft_encoding_unicode },
155       { TT_PLATFORM_MICROSOFT,     TT_MS_ID_SJIS,       ft_encoding_sjis },
156       { TT_PLATFORM_MICROSOFT,     TT_MS_ID_GB2312,     ft_encoding_gb2312 },
157       { TT_PLATFORM_MICROSOFT,     TT_MS_ID_BIG_5,      ft_encoding_big5 },
158       { TT_PLATFORM_MICROSOFT,     TT_MS_ID_WANSUNG,    ft_encoding_wansung },
159       { TT_PLATFORM_MICROSOFT,     TT_MS_ID_JOHAB,      ft_encoding_johab }
160     };
161
162     const TEncoding  *cur, *limit;
163
164
165     cur   = tt_encodings;
166     limit = cur + sizeof ( tt_encodings ) / sizeof ( tt_encodings[0] );
167
168     for ( ; cur < limit; cur++ )
169     {
170       if ( cur->platform_id == platform_id )
171       {
172         if ( cur->encoding_id == encoding_id ||
173              cur->encoding_id == -1          )
174           return cur->encoding;
175       }
176     }
177
178     return ft_encoding_none;
179   }
180
181
182   FT_LOCAL_DEF FT_Error
183   SFNT_Init_Face( FT_Stream      stream,
184                   TT_Face        face,
185                   FT_Int         face_index,
186                   FT_Int         num_params,
187                   FT_Parameter*  params )
188   {
189     FT_Error            error;
190     FT_Library          library = face->root.driver->root.library;
191     SFNT_Interface*     sfnt;
192     SFNT_Header         sfnt_header;
193
194     /* for now, parameters are unused */
195     FT_UNUSED( num_params );
196     FT_UNUSED( params );
197
198     sfnt = (SFNT_Interface*)face->sfnt;
199     if ( !sfnt )
200     {
201       sfnt = (SFNT_Interface*)FT_Get_Module_Interface( library, "sfnt" );
202       if ( !sfnt )
203       {
204         error = SFNT_Err_Invalid_File_Format;
205         goto Exit;
206       }
207
208       face->sfnt       = sfnt;
209       face->goto_table = sfnt->goto_table;
210     }
211
212     if ( !face->psnames )
213     {
214       face->psnames = (PSNames_Interface*)
215                        FT_Get_Module_Interface( library, "psnames" );
216     }
217
218     /* check that we have a valid TrueType file */
219     error = sfnt->load_sfnt_header( face, stream, face_index, &sfnt_header );
220     if ( error )
221       goto Exit;
222
223     face->format_tag = sfnt_header.format_tag;
224     face->num_tables = sfnt_header.num_tables;
225
226     /* Load font directory */
227     error = sfnt->load_directory( face, stream, &sfnt_header );
228     if ( error )
229       goto Exit;
230
231     face->root.num_faces = face->ttc_header.count;
232     if ( face->root.num_faces < 1 )
233       face->root.num_faces = 1;
234
235   Exit:
236     return error;
237   }
238
239
240 #undef  LOAD_
241 #define LOAD_( x )  ( ( error = sfnt->load_##x( face, stream ) ) \
242                       != SFNT_Err_Ok )
243
244
245   FT_LOCAL_DEF FT_Error
246   SFNT_Load_Face( FT_Stream      stream,
247                   TT_Face        face,
248                   FT_Int         face_index,
249                   FT_Int         num_params,
250                   FT_Parameter*  params )
251   {
252     FT_Error         error;
253     FT_Bool          has_outline;
254     FT_Bool          is_apple_sbit;
255
256     SFNT_Interface*  sfnt = (SFNT_Interface*)face->sfnt;
257
258     FT_UNUSED( face_index );
259     FT_UNUSED( num_params );
260     FT_UNUSED( params );
261
262
263     /* Load tables */
264
265     /* We now support two SFNT-based bitmapped font formats.  They */
266     /* are recognized easily as they do not include a `glyf'       */
267     /* table.                                                      */
268     /*                                                             */
269     /* The first format comes from Apple, and uses a table named   */
270     /* `bhed' instead of `head' to store the font header (using    */
271     /* the same format).  It also doesn't include horizontal and   */
272     /* vertical metrics tables (i.e. `hhea' and `vhea' tables are  */
273     /* missing).                                                   */
274     /*                                                             */
275     /* The other format comes from Microsoft, and is used with     */
276     /* WinCE/PocketPC.  It looks like a standard TTF, except that  */
277     /* it doesn't contain outlines.                                */
278     /*                                                             */
279
280     /* do we have outlines in there? */
281     has_outline   = FT_BOOL( ( TT_LookUp_Table( face, TTAG_glyf ) != 0 ) ||
282                              ( TT_LookUp_Table( face, TTAG_CFF  ) != 0 ) );
283     is_apple_sbit = 0;
284
285 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
286
287     /* if this font doesn't contain outlines, we try to load */
288     /* a `bhed' table                                        */
289     if ( !has_outline )
290       is_apple_sbit = FT_BOOL( !LOAD_( bitmap_header ) );
291
292 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
293
294     /* load the font header (`head' table) if this isn't an Apple */
295     /* sbit font file                                             */
296     if ( !is_apple_sbit && LOAD_( header ) )
297       goto Exit;
298
299     /* load other tables */
300     if ( LOAD_( max_profile ) ||
301          LOAD_( charmaps )    ||
302          LOAD_( names )       ||
303          LOAD_( psnames )     )
304       goto Exit;
305
306     /* do not load the metrics headers and tables if this is an Apple */
307     /* sbit font file                                                 */
308     if ( !is_apple_sbit )
309     {
310       /* load the `hhea' and `hmtx' tables at once */
311       error = sfnt->load_metrics( face, stream, 0 );
312       if ( error )
313         goto Exit;
314
315       /* try to load the `vhea' and `vmtx' tables at once */
316       error = sfnt->load_metrics( face, stream, 1 );
317       if ( error )
318         goto Exit;
319
320       if ( LOAD_( os2 ) )
321         goto Exit;
322     }
323
324     /* the optional tables */
325
326 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
327
328     /* embedded bitmap support. */
329     if ( sfnt->load_sbits && LOAD_( sbits ) )
330     {
331       /* return an error if this font file has no outlines */
332       if ( error == SFNT_Err_Table_Missing && has_outline )
333         error = SFNT_Err_Ok;
334       else
335         goto Exit;
336     }
337 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
338
339     if ( LOAD_( hdmx )    ||
340          LOAD_( gasp )    ||
341          LOAD_( kerning ) ||
342          LOAD_( pclt )    )
343       goto Exit;
344
345 #ifdef TT_CONFIG_OPTION_EXTEND_ENGINE
346     if ( ( error = TT_Extension_Create( face ) ) != SFNT_Err_Ok )
347       goto Exit;
348 #endif
349
350     face->root.family_name = Get_Name( face, TT_NAME_ID_FONT_FAMILY );
351     face->root.style_name  = Get_Name( face, TT_NAME_ID_FONT_SUBFAMILY );
352
353     /* now set up root fields */
354     {
355       FT_Face     root = &face->root;
356       FT_Int      flags = 0;
357       TT_CharMap  charmap;
358       FT_Int      n;
359       FT_Memory   memory;
360
361
362       memory = root->memory;
363
364       /*********************************************************************/
365       /*                                                                   */
366       /* Compute face flags.                                               */
367       /*                                                                   */
368       if ( has_outline == TRUE )
369         flags = FT_FACE_FLAG_SCALABLE;    /* scalable outlines */
370
371       flags |= FT_FACE_FLAG_SFNT      |   /* SFNT file format  */
372                FT_FACE_FLAG_HORIZONTAL;   /* horizontal data   */
373
374 #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES
375       /* might need more polish to detect the presence of a Postscript */
376       /* name table in the font                                        */
377       flags |= FT_FACE_FLAG_GLYPH_NAMES;
378 #endif
379
380       /* fixed width font? */
381       if ( face->postscript.isFixedPitch )
382         flags |= FT_FACE_FLAG_FIXED_WIDTH;
383
384       /* vertical information? */
385       if ( face->vertical_info )
386         flags |= FT_FACE_FLAG_VERTICAL;
387
388       /* kerning available ? */
389       if ( face->kern_pairs )
390         flags |= FT_FACE_FLAG_KERNING;
391
392       root->face_flags = flags;
393
394       /*********************************************************************/
395       /*                                                                   */
396       /* Compute style flags.                                              */
397       /*                                                                   */
398       flags = 0;
399       if ( has_outline == TRUE && face->os2.version != 0xFFFF )
400       {
401         /* we have an OS/2 table; use the `fsSelection' field */
402         if ( face->os2.fsSelection & 1 )
403           flags |= FT_STYLE_FLAG_ITALIC;
404
405         if ( face->os2.fsSelection & 32 )
406           flags |= FT_STYLE_FLAG_BOLD;
407       }
408       else
409       {
410         /* this is an old Mac font, use the header field */
411         if ( face->header.Mac_Style & 1 )
412           flags |= FT_STYLE_FLAG_BOLD;
413
414         if ( face->header.Mac_Style & 2 )
415           flags |= FT_STYLE_FLAG_ITALIC;
416       }
417
418       root->style_flags = flags;
419
420       /*********************************************************************/
421       /*                                                                   */
422       /* Polish the charmaps.                                              */
423       /*                                                                   */
424       /*   Try to set the charmap encoding according to the platform &     */
425       /*   encoding ID of each charmap.                                    */
426       /*                                                                   */
427       charmap            = face->charmaps;
428       root->num_charmaps = face->num_charmaps;
429
430       /* allocate table of pointers */
431       if ( ALLOC_ARRAY( root->charmaps, root->num_charmaps, FT_CharMap ) )
432         goto Exit;
433
434       for ( n = 0; n < root->num_charmaps; n++, charmap++ )
435       {
436         FT_Int  platform = charmap->cmap.platformID;
437         FT_Int  encoding = charmap->cmap.platformEncodingID;
438
439
440         charmap->root.face        = (FT_Face)face;
441         charmap->root.platform_id = (FT_UShort)platform;
442         charmap->root.encoding_id = (FT_UShort)encoding;
443         charmap->root.encoding    = find_encoding( platform, encoding );
444
445         /* now, set root->charmap with a unicode charmap */
446         /* wherever available                            */
447         if ( !root->charmap                                &&
448              charmap->root.encoding == ft_encoding_unicode )
449           root->charmap = (FT_CharMap)charmap;
450
451         root->charmaps[n] = (FT_CharMap)charmap;
452       }
453
454 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
455
456       if ( face->num_sbit_strikes )
457       {
458         root->face_flags |= FT_FACE_FLAG_FIXED_SIZES;
459
460 #if 0
461         /* I don't know criteria whether layout is horizontal or vertical */
462         if ( has_outline.... )
463         {
464           ...
465           root->face_flags |= FT_FACE_FLAG_VERTICAL;
466         }
467 #endif
468         root->num_fixed_sizes = face->num_sbit_strikes;
469
470         if ( ALLOC_ARRAY( root->available_sizes,
471                           face->num_sbit_strikes,
472                           FT_Bitmap_Size ) )
473           goto Exit;
474
475         for ( n = 0 ; n < face->num_sbit_strikes ; n++ )
476         {
477           root->available_sizes[n].width =
478             face->sbit_strikes[n].x_ppem;
479
480           root->available_sizes[n].height =
481             face->sbit_strikes[n].y_ppem;
482         }
483       }
484       else
485
486 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
487
488       {
489         root->num_fixed_sizes = 0;
490         root->available_sizes = 0;
491       }
492
493       /*********************************************************************/
494       /*                                                                   */
495       /*  Set up metrics.                                                  */
496       /*                                                                   */
497       if ( has_outline == TRUE )
498       {
499         /* XXX What about if outline header is missing */
500         /*     (e.g. sfnt wrapped outline)?            */
501         root->bbox.xMin    = face->header.xMin;
502         root->bbox.yMin    = face->header.yMin;
503         root->bbox.xMax    = face->header.xMax;
504         root->bbox.yMax    = face->header.yMax;
505         root->units_per_EM = face->header.Units_Per_EM;
506
507
508         /* XXX: Computing the ascender/descender/height is very different */
509         /*      from what the specification tells you.  Apparently, we    */
510         /*      must be careful because                                   */
511         /*                                                                */
512         /*      - not all fonts have an OS/2 table; in this case, we take */
513         /*        the values in the horizontal header.  However, these    */
514         /*        values very often are not reliable.                     */
515         /*                                                                */
516         /*      - otherwise, the correct typographic values are in the    */
517         /*        sTypoAscender, sTypoDescender & sTypoLineGap fields.    */
518         /*                                                                */
519         /*        However, certains fonts have these fields set to 0.     */
520         /*        Rather, they have usWinAscent & usWinDescent correctly  */
521         /*        set (but with different values).                        */
522         /*                                                                */
523         /*      As an example, Arial Narrow is implemented through four   */
524         /*      files ARIALN.TTF, ARIALNI.TTF, ARIALNB.TTF & ARIALNBI.TTF */
525         /*                                                                */
526         /*      Strangely, all fonts have the same values in their        */
527         /*      sTypoXXX fields, except ARIALNB which sets them to 0.     */
528         /*                                                                */
529         /*      On the other hand, they all have different                */
530         /*      usWinAscent/Descent values -- as a conclusion, the OS/2   */
531         /*      table cannot be used to compute the text height reliably! */
532         /*                                                                */
533
534         /* The ascender/descender/height are computed from the OS/2 table */
535         /* when found.  Otherwise, they're taken from the horizontal      */
536         /* header.                                                        */
537         /*                                                                */
538
539         root->ascender  = face->horizontal.Ascender;
540         root->descender = face->horizontal.Descender;
541
542         root->height    = (FT_Short)( root->ascender - root->descender +
543                                       face->horizontal.Line_Gap );
544
545         /* if the line_gap is 0, we add an extra 15% to the text height --  */
546         /* this computation is based on various versions of Times New Roman */
547         if ( face->horizontal.Line_Gap == 0 )
548           root->height = (FT_Short)( ( root->height * 115 + 50 ) / 100 );
549
550 #if 0
551
552         /* some fonts have the OS/2 "sTypoAscender", "sTypoDescender" & */
553         /* "sTypoLineGap" fields set to 0, like ARIALNB.TTF             */
554         if ( face->os2.version != 0xFFFF && root->ascender )
555         {
556           FT_Int  height;
557
558
559           root->ascender  =  face->os2.sTypoAscender;
560           root->descender = -face->os2.sTypoDescender;
561
562           height = root->ascender + root->descender + face->os2.sTypoLineGap;
563           if ( height > root->height )
564             root->height = height;
565         }
566
567 #endif /* 0 */
568
569         root->max_advance_width   = face->horizontal.advance_Width_Max;
570
571         root->max_advance_height  = (FT_Short)( face->vertical_info
572                                       ? face->vertical.advance_Height_Max
573                                       : root->height );
574
575         root->underline_position  = face->postscript.underlinePosition;
576         root->underline_thickness = face->postscript.underlineThickness;
577
578         /* root->max_points   -- already set up */
579         /* root->max_contours -- already set up */
580       }
581     }
582
583   Exit:
584     return error;
585   }
586
587
588 #undef LOAD_
589
590
591   FT_LOCAL_DEF void
592   SFNT_Done_Face( TT_Face  face )
593   {
594     FT_Memory        memory = face->root.memory;
595     SFNT_Interface*  sfnt   = (SFNT_Interface*)face->sfnt;
596
597
598     if ( sfnt )
599     {
600       /* destroy the postscript names table if it is loaded */
601       if ( sfnt->free_psnames )
602         sfnt->free_psnames( face );
603
604       /* destroy the embedded bitmaps table if it is loaded */
605       if ( sfnt->free_sbits )
606         sfnt->free_sbits( face );
607     }
608
609     /* freeing the kerning table */
610     FREE( face->kern_pairs );
611     face->num_kern_pairs = 0;
612
613     /* freeing the collection table */
614     FREE( face->ttc_header.offsets );
615     face->ttc_header.count = 0;
616
617     /* freeing table directory */
618     FREE( face->dir_tables );
619     face->num_tables = 0;
620
621     /* freeing the character mapping tables */
622     if ( sfnt && sfnt->load_charmaps )
623     {
624       FT_UShort  n;
625
626
627       for ( n = 0; n < face->num_charmaps; n++ )
628         sfnt->free_charmap( face, &face->charmaps[n].cmap );
629     }
630
631     FREE( face->charmaps );
632     face->num_charmaps = 0;
633
634     FREE( face->root.charmaps );
635     face->root.num_charmaps = 0;
636     face->root.charmap      = 0;
637
638     /* freeing the horizontal metrics */
639     FREE( face->horizontal.long_metrics );
640     FREE( face->horizontal.short_metrics );
641
642     /* freeing the vertical ones, if any */
643     if ( face->vertical_info )
644     {
645       FREE( face->vertical.long_metrics  );
646       FREE( face->vertical.short_metrics );
647       face->vertical_info = 0;
648     }
649
650     /* freeing the gasp table */
651     FREE( face->gasp.gaspRanges );
652     face->gasp.numRanges = 0;
653
654     /* freeing the name table */
655     sfnt->free_names( face );
656
657     /* freeing the hdmx table */
658     sfnt->free_hdmx( face );
659
660     /* freeing family and style name */
661     FREE( face->root.family_name );
662     FREE( face->root.style_name );
663
664     /* freeing sbit size table */
665     face->root.num_fixed_sizes = 0;
666     if ( face->root.available_sizes )
667       FREE( face->root.available_sizes );
668
669     face->sfnt = 0;
670   }
671
672
673 /* END */