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