• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************/
2 /*                                                                         */
3 /*  ttpload.c                                                              */
4 /*                                                                         */
5 /*    TrueType-specific tables loader (body).                              */
6 /*                                                                         */
7 /*  Copyright 1996-2002, 2004-2012 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 FT_INTERNAL_DEBUG_H
21 #include FT_INTERNAL_OBJECTS_H
22 #include FT_INTERNAL_STREAM_H
23 #include FT_TRUETYPE_TAGS_H
24 
25 #include "ttpload.h"
26 
27 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
28 #include "ttgxvar.h"
29 #endif
30 
31 #include "tterrors.h"
32 
33 
34   /*************************************************************************/
35   /*                                                                       */
36   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
37   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
38   /* messages during execution.                                            */
39   /*                                                                       */
40 #undef  FT_COMPONENT
41 #define FT_COMPONENT  trace_ttpload
42 
43 
44   /*************************************************************************/
45   /*                                                                       */
46   /* <Function>                                                            */
47   /*    tt_face_load_loca                                                  */
48   /*                                                                       */
49   /* <Description>                                                         */
50   /*    Load the locations table.                                          */
51   /*                                                                       */
52   /* <InOut>                                                               */
53   /*    face   :: A handle to the target face object.                      */
54   /*                                                                       */
55   /* <Input>                                                               */
56   /*    stream :: The input stream.                                        */
57   /*                                                                       */
58   /* <Return>                                                              */
59   /*    FreeType error code.  0 means success.                             */
60   /*                                                                       */
61   FT_LOCAL_DEF( FT_Error )
tt_face_load_loca(TT_Face face,FT_Stream stream)62   tt_face_load_loca( TT_Face    face,
63                      FT_Stream  stream )
64   {
65     FT_Error  error;
66     FT_ULong  table_len;
67     FT_Int    shift;
68 
69 
70     /* we need the size of the `glyf' table for malformed `loca' tables */
71     error = face->goto_table( face, TTAG_glyf, stream, &face->glyf_len );
72 
73     /* it is possible that a font doesn't have a glyf table at all */
74     /* or its size is zero                                         */
75     if ( error == TT_Err_Table_Missing )
76       face->glyf_len = 0;
77     else if ( error )
78       goto Exit;
79 
80     FT_TRACE2(( "Locations " ));
81     error = face->goto_table( face, TTAG_loca, stream, &table_len );
82     if ( error )
83     {
84       error = TT_Err_Locations_Missing;
85       goto Exit;
86     }
87 
88     if ( face->header.Index_To_Loc_Format != 0 )
89     {
90       shift = 2;
91 
92       if ( table_len >= 0x40000L )
93       {
94         FT_TRACE2(( "table too large\n" ));
95         error = TT_Err_Invalid_Table;
96         goto Exit;
97       }
98       face->num_locations = table_len >> shift;
99     }
100     else
101     {
102       shift = 1;
103 
104       if ( table_len >= 0x20000L )
105       {
106         FT_TRACE2(( "table too large\n" ));
107         error = TT_Err_Invalid_Table;
108         goto Exit;
109       }
110       face->num_locations = table_len >> shift;
111     }
112 
113     if ( face->num_locations != (FT_ULong)face->root.num_glyphs + 1 )
114     {
115       FT_TRACE2(( "glyph count mismatch!  loca: %d, maxp: %d\n",
116                   face->num_locations - 1, face->root.num_glyphs ));
117 
118       /* we only handle the case where `maxp' gives a larger value */
119       if ( face->num_locations <= (FT_ULong)face->root.num_glyphs )
120       {
121         FT_Long   new_loca_len =
122                     ( (FT_Long)( face->root.num_glyphs ) + 1 ) << shift;
123 
124         TT_Table  entry = face->dir_tables;
125         TT_Table  limit = entry + face->num_tables;
126 
127         FT_Long   pos  = FT_Stream_Pos( stream );
128         FT_Long   dist = 0x7FFFFFFFL;
129 
130 
131         /* compute the distance to next table in font file */
132         for ( ; entry < limit; entry++ )
133         {
134           FT_Long  diff = entry->Offset - pos;
135 
136 
137           if ( diff > 0 && diff < dist )
138             dist = diff;
139         }
140 
141         if ( entry == limit )
142         {
143           /* `loca' is the last table */
144           dist = stream->size - pos;
145         }
146 
147         if ( new_loca_len <= dist )
148         {
149           face->num_locations = face->root.num_glyphs + 1;
150           table_len           = new_loca_len;
151 
152           FT_TRACE2(( "adjusting num_locations to %d\n",
153                       face->num_locations ));
154         }
155       }
156     }
157 
158     /*
159      * Extract the frame.  We don't need to decompress it since
160      * we are able to parse it directly.
161      */
162     if ( FT_FRAME_EXTRACT( table_len, face->glyph_locations ) )
163       goto Exit;
164 
165     FT_TRACE2(( "loaded\n" ));
166 
167   Exit:
168     return error;
169   }
170 
171 
172   FT_LOCAL_DEF( FT_ULong )
tt_face_get_location(TT_Face face,FT_UInt gindex,FT_UInt * asize)173   tt_face_get_location( TT_Face   face,
174                         FT_UInt   gindex,
175                         FT_UInt  *asize )
176   {
177     FT_ULong  pos1, pos2;
178     FT_Byte*  p;
179     FT_Byte*  p_limit;
180 
181 
182     pos1 = pos2 = 0;
183 
184     if ( gindex < face->num_locations )
185     {
186       if ( face->header.Index_To_Loc_Format != 0 )
187       {
188         p       = face->glyph_locations + gindex * 4;
189         p_limit = face->glyph_locations + face->num_locations * 4;
190 
191         pos1 = FT_NEXT_ULONG( p );
192         pos2 = pos1;
193 
194         if ( p + 4 <= p_limit )
195           pos2 = FT_NEXT_ULONG( p );
196       }
197       else
198       {
199         p       = face->glyph_locations + gindex * 2;
200         p_limit = face->glyph_locations + face->num_locations * 2;
201 
202         pos1 = FT_NEXT_USHORT( p );
203         pos2 = pos1;
204 
205         if ( p + 2 <= p_limit )
206           pos2 = FT_NEXT_USHORT( p );
207 
208         pos1 <<= 1;
209         pos2 <<= 1;
210       }
211     }
212 
213     /* Check broken location data */
214     if ( pos1 > face->glyf_len )
215     {
216       FT_TRACE1(( "tt_face_get_location:"
217                   " too large offset=0x%08lx found for gid=0x%04lx,"
218                   " exceeding the end of glyf table (0x%08lx)\n",
219                   pos1, gindex, face->glyf_len ));
220       *asize = 0;
221       return 0;
222     }
223 
224     if ( pos2 > face->glyf_len )
225     {
226       FT_TRACE1(( "tt_face_get_location:"
227                   " too large offset=0x%08lx found for gid=0x%04lx,"
228                   " truncate at the end of glyf table (0x%08lx)\n",
229                   pos2, gindex + 1, face->glyf_len ));
230       pos2 = face->glyf_len;
231     }
232 
233     /* The `loca' table must be ordered; it refers to the length of */
234     /* an entry as the difference between the current and the next  */
235     /* position.  However, there do exist (malformed) fonts which   */
236     /* don't obey this rule, so we are only able to provide an      */
237     /* upper bound for the size.                                    */
238     /*                                                              */
239     /* We get (intentionally) a wrong, non-zero result in case the  */
240     /* `glyf' table is missing.                                     */
241     if ( pos2 >= pos1 )
242       *asize = (FT_UInt)( pos2 - pos1 );
243     else
244       *asize = (FT_UInt)( face->glyf_len - pos1 );
245 
246     return pos1;
247   }
248 
249 
250   FT_LOCAL_DEF( void )
tt_face_done_loca(TT_Face face)251   tt_face_done_loca( TT_Face  face )
252   {
253     FT_Stream  stream = face->root.stream;
254 
255 
256     FT_FRAME_RELEASE( face->glyph_locations );
257     face->num_locations = 0;
258   }
259 
260 
261 
262   /*************************************************************************/
263   /*                                                                       */
264   /* <Function>                                                            */
265   /*    tt_face_load_cvt                                                   */
266   /*                                                                       */
267   /* <Description>                                                         */
268   /*    Load the control value table into a face object.                   */
269   /*                                                                       */
270   /* <InOut>                                                               */
271   /*    face   :: A handle to the target face object.                      */
272   /*                                                                       */
273   /* <Input>                                                               */
274   /*    stream :: A handle to the input stream.                            */
275   /*                                                                       */
276   /* <Return>                                                              */
277   /*    FreeType error code.  0 means success.                             */
278   /*                                                                       */
279   FT_LOCAL_DEF( FT_Error )
tt_face_load_cvt(TT_Face face,FT_Stream stream)280   tt_face_load_cvt( TT_Face    face,
281                     FT_Stream  stream )
282   {
283 #ifdef TT_USE_BYTECODE_INTERPRETER
284 
285     FT_Error   error;
286     FT_Memory  memory = stream->memory;
287     FT_ULong   table_len;
288 
289 
290     FT_TRACE2(( "CVT " ));
291 
292     error = face->goto_table( face, TTAG_cvt, stream, &table_len );
293     if ( error )
294     {
295       FT_TRACE2(( "is missing\n" ));
296 
297       face->cvt_size = 0;
298       face->cvt      = NULL;
299       error          = TT_Err_Ok;
300 
301       goto Exit;
302     }
303 
304     face->cvt_size = table_len / 2;
305 
306     if ( FT_NEW_ARRAY( face->cvt, face->cvt_size ) )
307       goto Exit;
308 
309     if ( FT_FRAME_ENTER( face->cvt_size * 2L ) )
310       goto Exit;
311 
312     {
313       FT_Short*  cur   = face->cvt;
314       FT_Short*  limit = cur + face->cvt_size;
315 
316 
317       for ( ; cur < limit; cur++ )
318         *cur = FT_GET_SHORT();
319     }
320 
321     FT_FRAME_EXIT();
322     FT_TRACE2(( "loaded\n" ));
323 
324 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
325     if ( face->doblend )
326       error = tt_face_vary_cvt( face, stream );
327 #endif
328 
329   Exit:
330     return error;
331 
332 #else /* !TT_USE_BYTECODE_INTERPRETER */
333 
334     FT_UNUSED( face   );
335     FT_UNUSED( stream );
336 
337     return TT_Err_Ok;
338 
339 #endif
340   }
341 
342 
343   /*************************************************************************/
344   /*                                                                       */
345   /* <Function>                                                            */
346   /*    tt_face_load_fpgm                                                  */
347   /*                                                                       */
348   /* <Description>                                                         */
349   /*    Load the font program.                                             */
350   /*                                                                       */
351   /* <InOut>                                                               */
352   /*    face   :: A handle to the target face object.                      */
353   /*                                                                       */
354   /* <Input>                                                               */
355   /*    stream :: A handle to the input stream.                            */
356   /*                                                                       */
357   /* <Return>                                                              */
358   /*    FreeType error code.  0 means success.                             */
359   /*                                                                       */
360   FT_LOCAL_DEF( FT_Error )
tt_face_load_fpgm(TT_Face face,FT_Stream stream)361   tt_face_load_fpgm( TT_Face    face,
362                      FT_Stream  stream )
363   {
364 #ifdef TT_USE_BYTECODE_INTERPRETER
365 
366     FT_Error  error;
367     FT_ULong  table_len;
368 
369 
370     FT_TRACE2(( "Font program " ));
371 
372     /* The font program is optional */
373     error = face->goto_table( face, TTAG_fpgm, stream, &table_len );
374     if ( error )
375     {
376       face->font_program      = NULL;
377       face->font_program_size = 0;
378       error                   = TT_Err_Ok;
379 
380       FT_TRACE2(( "is missing\n" ));
381     }
382     else
383     {
384       face->font_program_size = table_len;
385       if ( FT_FRAME_EXTRACT( table_len, face->font_program ) )
386         goto Exit;
387 
388       FT_TRACE2(( "loaded, %12d bytes\n", face->font_program_size ));
389     }
390 
391   Exit:
392     return error;
393 
394 #else /* !TT_USE_BYTECODE_INTERPRETER */
395 
396     FT_UNUSED( face   );
397     FT_UNUSED( stream );
398 
399     return TT_Err_Ok;
400 
401 #endif
402   }
403 
404 
405   /*************************************************************************/
406   /*                                                                       */
407   /* <Function>                                                            */
408   /*    tt_face_load_prep                                                  */
409   /*                                                                       */
410   /* <Description>                                                         */
411   /*    Load the cvt program.                                              */
412   /*                                                                       */
413   /* <InOut>                                                               */
414   /*    face   :: A handle to the target face object.                      */
415   /*                                                                       */
416   /* <Input>                                                               */
417   /*    stream :: A handle to the input stream.                            */
418   /*                                                                       */
419   /* <Return>                                                              */
420   /*    FreeType error code.  0 means success.                             */
421   /*                                                                       */
422   FT_LOCAL_DEF( FT_Error )
tt_face_load_prep(TT_Face face,FT_Stream stream)423   tt_face_load_prep( TT_Face    face,
424                      FT_Stream  stream )
425   {
426 #ifdef TT_USE_BYTECODE_INTERPRETER
427 
428     FT_Error  error;
429     FT_ULong  table_len;
430 
431 
432     FT_TRACE2(( "Prep program " ));
433 
434     error = face->goto_table( face, TTAG_prep, stream, &table_len );
435     if ( error )
436     {
437       face->cvt_program      = NULL;
438       face->cvt_program_size = 0;
439       error                  = TT_Err_Ok;
440 
441       FT_TRACE2(( "is missing\n" ));
442     }
443     else
444     {
445       face->cvt_program_size = table_len;
446       if ( FT_FRAME_EXTRACT( table_len, face->cvt_program ) )
447         goto Exit;
448 
449       FT_TRACE2(( "loaded, %12d bytes\n", face->cvt_program_size ));
450     }
451 
452   Exit:
453     return error;
454 
455 #else /* !TT_USE_BYTECODE_INTERPRETER */
456 
457     FT_UNUSED( face   );
458     FT_UNUSED( stream );
459 
460     return TT_Err_Ok;
461 
462 #endif
463   }
464 
465 
466   /*************************************************************************/
467   /*                                                                       */
468   /* <Function>                                                            */
469   /*    tt_face_load_hdmx                                                  */
470   /*                                                                       */
471   /* <Description>                                                         */
472   /*    Load the `hdmx' table into the face object.                        */
473   /*                                                                       */
474   /* <Input>                                                               */
475   /*    face   :: A handle to the target face object.                      */
476   /*                                                                       */
477   /*    stream :: A handle to the input stream.                            */
478   /*                                                                       */
479   /* <Return>                                                              */
480   /*    FreeType error code.  0 means success.                             */
481   /*                                                                       */
482 
483   FT_LOCAL_DEF( FT_Error )
tt_face_load_hdmx(TT_Face face,FT_Stream stream)484   tt_face_load_hdmx( TT_Face    face,
485                      FT_Stream  stream )
486   {
487     FT_Error   error;
488     FT_Memory  memory = stream->memory;
489     FT_UInt    version, nn, num_records;
490     FT_ULong   table_size, record_size;
491     FT_Byte*   p;
492     FT_Byte*   limit;
493 
494 
495     /* this table is optional */
496     error = face->goto_table( face, TTAG_hdmx, stream, &table_size );
497     if ( error || table_size < 8 )
498       return TT_Err_Ok;
499 
500     if ( FT_FRAME_EXTRACT( table_size, face->hdmx_table ) )
501       goto Exit;
502 
503     p     = face->hdmx_table;
504     limit = p + table_size;
505 
506     version     = FT_NEXT_USHORT( p );
507     num_records = FT_NEXT_USHORT( p );
508     record_size = FT_NEXT_ULONG( p );
509 
510     /* The maximum number of bytes in an hdmx device record is the */
511     /* maximum number of glyphs + 2; this is 0xFFFF + 2; this is   */
512     /* the reason why `record_size' is a long (which we read as    */
513     /* unsigned long for convenience).  In practice, two bytes     */
514     /* sufficient to hold the size value.                          */
515     /*                                                             */
516     /* There are at least two fonts, HANNOM-A and HANNOM-B version */
517     /* 2.0 (2005), which get this wrong: The upper two bytes of    */
518     /* the size value are set to 0xFF instead of 0x00.  We catch   */
519     /* and fix this.                                               */
520 
521     if ( record_size >= 0xFFFF0000UL )
522       record_size &= 0xFFFFU;
523 
524     /* The limit for `num_records' is a heuristic value. */
525 
526     if ( version != 0 || num_records > 255 || record_size > 0x10001L )
527     {
528       error = TT_Err_Invalid_File_Format;
529       goto Fail;
530     }
531 
532     if ( FT_NEW_ARRAY( face->hdmx_record_sizes, num_records ) )
533       goto Fail;
534 
535     for ( nn = 0; nn < num_records; nn++ )
536     {
537       if ( p + record_size > limit )
538         break;
539 
540       face->hdmx_record_sizes[nn] = p[0];
541       p                          += record_size;
542     }
543 
544     face->hdmx_record_count = nn;
545     face->hdmx_table_size   = table_size;
546     face->hdmx_record_size  = record_size;
547 
548   Exit:
549     return error;
550 
551   Fail:
552     FT_FRAME_RELEASE( face->hdmx_table );
553     face->hdmx_table_size = 0;
554     goto Exit;
555   }
556 
557 
558   FT_LOCAL_DEF( void )
tt_face_free_hdmx(TT_Face face)559   tt_face_free_hdmx( TT_Face  face )
560   {
561     FT_Stream  stream = face->root.stream;
562     FT_Memory  memory = stream->memory;
563 
564 
565     FT_FREE( face->hdmx_record_sizes );
566     FT_FRAME_RELEASE( face->hdmx_table );
567   }
568 
569 
570   /*************************************************************************/
571   /*                                                                       */
572   /* Return the advance width table for a given pixel size if it is found  */
573   /* in the font's `hdmx' table (if any).                                  */
574   /*                                                                       */
575   FT_LOCAL_DEF( FT_Byte* )
tt_face_get_device_metrics(TT_Face face,FT_UInt ppem,FT_UInt gindex)576   tt_face_get_device_metrics( TT_Face  face,
577                               FT_UInt  ppem,
578                               FT_UInt  gindex )
579   {
580     FT_UInt   nn;
581     FT_Byte*  result      = NULL;
582     FT_ULong  record_size = face->hdmx_record_size;
583     FT_Byte*  record      = face->hdmx_table + 8;
584 
585 
586     for ( nn = 0; nn < face->hdmx_record_count; nn++ )
587       if ( face->hdmx_record_sizes[nn] == ppem )
588       {
589         gindex += 2;
590         if ( gindex < record_size )
591           result = record + nn * record_size + gindex;
592         break;
593       }
594 
595     return result;
596   }
597 
598 
599 /* END */
600