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