• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************/
2 /*                                                                         */
3 /*  ttpload.c                                                              */
4 /*                                                                         */
5 /*    TrueType-specific tables loader (body).                              */
6 /*                                                                         */
7 /*  Copyright 1996-2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009 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 )
114     {
115       FT_TRACE2(( "glyph count mismatch!  loca: %d, maxp: %d\n",
116                   face->num_locations, 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 = (FT_Long)face->root.num_glyphs << shift;
122 
123         TT_Table  entry = face->dir_tables;
124         TT_Table  limit = entry + face->num_tables;
125 
126         FT_Long   pos  = FT_Stream_Pos( stream );
127         FT_Long   dist = 0x7FFFFFFFL;
128 
129 
130         /* compute the distance to next table in font file */
131         for ( ; entry < limit; entry++ )
132         {
133           FT_Long  diff = entry->Offset - pos;
134 
135 
136           if ( diff > 0 && diff < dist )
137             dist = diff;
138         }
139 
140         if ( new_loca_len <= dist )
141         {
142           face->num_locations = face->root.num_glyphs;
143           table_len           = new_loca_len;
144 
145           FT_TRACE2(( "adjusting num_locations to %d\n",
146                       face->num_locations ));
147         }
148       }
149     }
150 
151     /*
152      * Extract the frame.  We don't need to decompress it since
153      * we are able to parse it directly.
154      */
155     if ( FT_FRAME_EXTRACT( table_len, face->glyph_locations ) )
156       goto Exit;
157 
158     FT_TRACE2(( "loaded\n" ));
159 
160   Exit:
161     return error;
162   }
163 
164 
165   FT_LOCAL_DEF( FT_ULong )
tt_face_get_location(TT_Face face,FT_UInt gindex,FT_UInt * asize)166   tt_face_get_location( TT_Face   face,
167                         FT_UInt   gindex,
168                         FT_UInt  *asize )
169   {
170     FT_ULong  pos1, pos2;
171     FT_Byte*  p;
172     FT_Byte*  p_limit;
173 
174 
175     pos1 = pos2 = 0;
176 
177     if ( gindex < face->num_locations )
178     {
179       if ( face->header.Index_To_Loc_Format != 0 )
180       {
181         p       = face->glyph_locations + gindex * 4;
182         p_limit = face->glyph_locations + face->num_locations * 4;
183 
184         pos1 = FT_NEXT_ULONG( p );
185         pos2 = pos1;
186 
187         if ( p + 4 <= p_limit )
188           pos2 = FT_NEXT_ULONG( p );
189       }
190       else
191       {
192         p       = face->glyph_locations + gindex * 2;
193         p_limit = face->glyph_locations + face->num_locations * 2;
194 
195         pos1 = FT_NEXT_USHORT( p );
196         pos2 = pos1;
197 
198         if ( p + 2 <= p_limit )
199           pos2 = FT_NEXT_USHORT( p );
200 
201         pos1 <<= 1;
202         pos2 <<= 1;
203       }
204     }
205 
206     /* The `loca' table must be ordered; it refers to the length of */
207     /* an entry as the difference between the current and the next  */
208     /* position.  However, there do exist (malformed) fonts which   */
209     /* don't obey this rule, so we are only able to provide an      */
210     /* upper bound for the size.                                    */
211     /*                                                              */
212     /* We get (intentionally) a wrong, non-zero result in case the  */
213     /* `glyf' table is missing.                                     */
214     if ( pos2 >= pos1 )
215       *asize = (FT_UInt)( pos2 - pos1 );
216     else
217       *asize = (FT_UInt)( face->glyf_len - pos1 );
218 
219     return pos1;
220   }
221 
222 
223   FT_LOCAL_DEF( void )
tt_face_done_loca(TT_Face face)224   tt_face_done_loca( TT_Face  face )
225   {
226     FT_Stream  stream = face->root.stream;
227 
228 
229     FT_FRAME_RELEASE( face->glyph_locations );
230     face->num_locations = 0;
231   }
232 
233 
234 
235   /*************************************************************************/
236   /*                                                                       */
237   /* <Function>                                                            */
238   /*    tt_face_load_cvt                                                   */
239   /*                                                                       */
240   /* <Description>                                                         */
241   /*    Load the control value table into a face object.                   */
242   /*                                                                       */
243   /* <InOut>                                                               */
244   /*    face   :: A handle to the target face object.                      */
245   /*                                                                       */
246   /* <Input>                                                               */
247   /*    stream :: A handle to the input stream.                            */
248   /*                                                                       */
249   /* <Return>                                                              */
250   /*    FreeType error code.  0 means success.                             */
251   /*                                                                       */
252   FT_LOCAL_DEF( FT_Error )
tt_face_load_cvt(TT_Face face,FT_Stream stream)253   tt_face_load_cvt( TT_Face    face,
254                     FT_Stream  stream )
255   {
256 #ifdef TT_USE_BYTECODE_INTERPRETER
257 
258     FT_Error   error;
259     FT_Memory  memory = stream->memory;
260     FT_ULong   table_len;
261 
262 
263     FT_TRACE2(( "CVT " ));
264 
265     error = face->goto_table( face, TTAG_cvt, stream, &table_len );
266     if ( error )
267     {
268       FT_TRACE2(( "is missing\n" ));
269 
270       face->cvt_size = 0;
271       face->cvt      = NULL;
272       error          = TT_Err_Ok;
273 
274       goto Exit;
275     }
276 
277     face->cvt_size = table_len / 2;
278 
279     if ( FT_NEW_ARRAY( face->cvt, face->cvt_size ) )
280       goto Exit;
281 
282     if ( FT_FRAME_ENTER( face->cvt_size * 2L ) )
283       goto Exit;
284 
285     {
286       FT_Short*  cur   = face->cvt;
287       FT_Short*  limit = cur + face->cvt_size;
288 
289 
290       for ( ; cur <  limit; cur++ )
291         *cur = FT_GET_SHORT();
292     }
293 
294     FT_FRAME_EXIT();
295     FT_TRACE2(( "loaded\n" ));
296 
297 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
298     if ( face->doblend )
299       error = tt_face_vary_cvt( face, stream );
300 #endif
301 
302   Exit:
303     return error;
304 
305 #else /* !TT_USE_BYTECODE_INTERPRETER */
306 
307     FT_UNUSED( face   );
308     FT_UNUSED( stream );
309 
310     return TT_Err_Ok;
311 
312 #endif
313   }
314 
315 
316   /*************************************************************************/
317   /*                                                                       */
318   /* <Function>                                                            */
319   /*    tt_face_load_fpgm                                                  */
320   /*                                                                       */
321   /* <Description>                                                         */
322   /*    Load the font program.                                             */
323   /*                                                                       */
324   /* <InOut>                                                               */
325   /*    face   :: A handle to the target face object.                      */
326   /*                                                                       */
327   /* <Input>                                                               */
328   /*    stream :: A handle to the input stream.                            */
329   /*                                                                       */
330   /* <Return>                                                              */
331   /*    FreeType error code.  0 means success.                             */
332   /*                                                                       */
333   FT_LOCAL_DEF( FT_Error )
tt_face_load_fpgm(TT_Face face,FT_Stream stream)334   tt_face_load_fpgm( TT_Face    face,
335                      FT_Stream  stream )
336   {
337 #ifdef TT_USE_BYTECODE_INTERPRETER
338 
339     FT_Error  error;
340     FT_ULong  table_len;
341 
342 
343     FT_TRACE2(( "Font program " ));
344 
345     /* The font program is optional */
346     error = face->goto_table( face, TTAG_fpgm, stream, &table_len );
347     if ( error )
348     {
349       face->font_program      = NULL;
350       face->font_program_size = 0;
351       error                   = TT_Err_Ok;
352 
353       FT_TRACE2(( "is missing\n" ));
354     }
355     else
356     {
357       face->font_program_size = table_len;
358       if ( FT_FRAME_EXTRACT( table_len, face->font_program ) )
359         goto Exit;
360 
361       FT_TRACE2(( "loaded, %12d bytes\n", face->font_program_size ));
362     }
363 
364   Exit:
365     return error;
366 
367 #else /* !TT_USE_BYTECODE_INTERPRETER */
368 
369     FT_UNUSED( face   );
370     FT_UNUSED( stream );
371 
372     return TT_Err_Ok;
373 
374 #endif
375   }
376 
377 
378   /*************************************************************************/
379   /*                                                                       */
380   /* <Function>                                                            */
381   /*    tt_face_load_prep                                                  */
382   /*                                                                       */
383   /* <Description>                                                         */
384   /*    Load the cvt program.                                              */
385   /*                                                                       */
386   /* <InOut>                                                               */
387   /*    face   :: A handle to the target face object.                      */
388   /*                                                                       */
389   /* <Input>                                                               */
390   /*    stream :: A handle to the input stream.                            */
391   /*                                                                       */
392   /* <Return>                                                              */
393   /*    FreeType error code.  0 means success.                             */
394   /*                                                                       */
395   FT_LOCAL_DEF( FT_Error )
tt_face_load_prep(TT_Face face,FT_Stream stream)396   tt_face_load_prep( TT_Face    face,
397                      FT_Stream  stream )
398   {
399 #ifdef TT_USE_BYTECODE_INTERPRETER
400 
401     FT_Error  error;
402     FT_ULong  table_len;
403 
404 
405     FT_TRACE2(( "Prep program " ));
406 
407     error = face->goto_table( face, TTAG_prep, stream, &table_len );
408     if ( error )
409     {
410       face->cvt_program      = NULL;
411       face->cvt_program_size = 0;
412       error                  = TT_Err_Ok;
413 
414       FT_TRACE2(( "is missing\n" ));
415     }
416     else
417     {
418       face->cvt_program_size = table_len;
419       if ( FT_FRAME_EXTRACT( table_len, face->cvt_program ) )
420         goto Exit;
421 
422       FT_TRACE2(( "loaded, %12d bytes\n", face->cvt_program_size ));
423     }
424 
425   Exit:
426     return error;
427 
428 #else /* !TT_USE_BYTECODE_INTERPRETER */
429 
430     FT_UNUSED( face   );
431     FT_UNUSED( stream );
432 
433     return TT_Err_Ok;
434 
435 #endif
436   }
437 
438 
439   /*************************************************************************/
440   /*                                                                       */
441   /* <Function>                                                            */
442   /*    tt_face_load_hdmx                                                  */
443   /*                                                                       */
444   /* <Description>                                                         */
445   /*    Load the `hdmx' table into the face object.                        */
446   /*                                                                       */
447   /* <Input>                                                               */
448   /*    face   :: A handle to the target face object.                      */
449   /*                                                                       */
450   /*    stream :: A handle to the input stream.                            */
451   /*                                                                       */
452   /* <Return>                                                              */
453   /*    FreeType error code.  0 means success.                             */
454   /*                                                                       */
455 
456   FT_LOCAL_DEF( FT_Error )
tt_face_load_hdmx(TT_Face face,FT_Stream stream)457   tt_face_load_hdmx( TT_Face    face,
458                      FT_Stream  stream )
459   {
460     FT_Error   error;
461     FT_Memory  memory = stream->memory;
462     FT_UInt    version, nn, num_records;
463     FT_ULong   table_size, record_size;
464     FT_Byte*   p;
465     FT_Byte*   limit;
466 
467 
468     /* this table is optional */
469     error = face->goto_table( face, TTAG_hdmx, stream, &table_size );
470     if ( error || table_size < 8 )
471       return TT_Err_Ok;
472 
473     if ( FT_FRAME_EXTRACT( table_size, face->hdmx_table ) )
474       goto Exit;
475 
476     p     = face->hdmx_table;
477     limit = p + table_size;
478 
479     version     = FT_NEXT_USHORT( p );
480     num_records = FT_NEXT_USHORT( p );
481     record_size = FT_NEXT_ULONG( p );
482 
483     /* The maximum number of bytes in an hdmx device record is the */
484     /* maximum number of glyphs + 2; this is 0xFFFF + 2; this is   */
485     /* the reason why `record_size' is a long (which we read as    */
486     /* unsigned long for convenience).  In practice, two bytes     */
487     /* sufficient to hold the size value.                          */
488     /*                                                             */
489     /* There are at least two fonts, HANNOM-A and HANNOM-B version */
490     /* 2.0 (2005), which get this wrong: The upper two bytes of    */
491     /* the size value are set to 0xFF instead of 0x00.  We catch   */
492     /* and fix this.                                               */
493 
494     if ( record_size >= 0xFFFF0000UL )
495       record_size &= 0xFFFFU;
496 
497     /* The limit for `num_records' is a heuristic value. */
498 
499     if ( version != 0 || num_records > 255 || record_size > 0x10001L )
500     {
501       error = TT_Err_Invalid_File_Format;
502       goto Fail;
503     }
504 
505     if ( FT_NEW_ARRAY( face->hdmx_record_sizes, num_records ) )
506       goto Fail;
507 
508     for ( nn = 0; nn < num_records; nn++ )
509     {
510       if ( p + record_size > limit )
511         break;
512 
513       face->hdmx_record_sizes[nn] = p[0];
514       p                          += record_size;
515     }
516 
517     face->hdmx_record_count = nn;
518     face->hdmx_table_size   = table_size;
519     face->hdmx_record_size  = record_size;
520 
521   Exit:
522     return error;
523 
524   Fail:
525     FT_FRAME_RELEASE( face->hdmx_table );
526     face->hdmx_table_size = 0;
527     goto Exit;
528   }
529 
530 
531   FT_LOCAL_DEF( void )
tt_face_free_hdmx(TT_Face face)532   tt_face_free_hdmx( TT_Face  face )
533   {
534     FT_Stream  stream = face->root.stream;
535     FT_Memory  memory = stream->memory;
536 
537 
538     FT_FREE( face->hdmx_record_sizes );
539     FT_FRAME_RELEASE( face->hdmx_table );
540   }
541 
542 
543   /*************************************************************************/
544   /*                                                                       */
545   /* Return the advance width table for a given pixel size if it is found  */
546   /* in the font's `hdmx' table (if any).                                  */
547   /*                                                                       */
548   FT_LOCAL_DEF( FT_Byte* )
tt_face_get_device_metrics(TT_Face face,FT_UInt ppem,FT_UInt gindex)549   tt_face_get_device_metrics( TT_Face  face,
550                               FT_UInt  ppem,
551                               FT_UInt  gindex )
552   {
553     FT_UInt   nn;
554     FT_Byte*  result      = NULL;
555     FT_ULong  record_size = face->hdmx_record_size;
556     FT_Byte*  record      = face->hdmx_table + 8;
557 
558 
559     for ( nn = 0; nn < face->hdmx_record_count; nn++ )
560       if ( face->hdmx_record_sizes[nn] == ppem )
561       {
562         gindex += 2;
563         if ( gindex < record_size )
564           result = record + nn * record_size + gindex;
565         break;
566       }
567 
568     return result;
569   }
570 
571 
572 /* END */
573