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