Imported Upstream version 2.13.2
[platform/upstream/freetype2.git] / src / truetype / ttpload.c
1 /****************************************************************************
2  *
3  * ttpload.c
4  *
5  *   TrueType-specific tables loader (body).
6  *
7  * Copyright (C) 1996-2023 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 )
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 )
183   tt_face_get_location( FT_Face    face,   /* TT_Face */
184                         FT_UInt    gindex,
185                         FT_ULong  *asize )
186   {
187     TT_Face   ttface = (TT_Face)face;
188     FT_ULong  pos1, pos2;
189     FT_Byte*  p;
190     FT_Byte*  p_limit;
191
192
193     pos1 = pos2 = 0;
194
195     if ( gindex < ttface->num_locations )
196     {
197       if ( ttface->header.Index_To_Loc_Format != 0 )
198       {
199         p       = ttface->glyph_locations + gindex * 4;
200         p_limit = ttface->glyph_locations + ttface->num_locations * 4;
201
202         pos1 = FT_NEXT_ULONG( p );
203         pos2 = pos1;
204
205         if ( p + 4 <= p_limit )
206           pos2 = FT_NEXT_ULONG( p );
207       }
208       else
209       {
210         p       = ttface->glyph_locations + gindex * 2;
211         p_limit = ttface->glyph_locations + ttface->num_locations * 2;
212
213         pos1 = FT_NEXT_USHORT( p );
214         pos2 = pos1;
215
216         if ( p + 2 <= p_limit )
217           pos2 = FT_NEXT_USHORT( p );
218
219         pos1 <<= 1;
220         pos2 <<= 1;
221       }
222     }
223
224     /* Check broken location data. */
225     if ( pos1 > ttface->glyf_len )
226     {
227       FT_TRACE1(( "tt_face_get_location:"
228                   " too large offset (0x%08lx) found for glyph index %d,\n",
229                   pos1, gindex ));
230       FT_TRACE1(( "                     "
231                   " exceeding the end of `glyf' table (0x%08lx)\n",
232                   ttface->glyf_len ));
233       *asize = 0;
234       return 0;
235     }
236
237     if ( pos2 > ttface->glyf_len )
238     {
239       /* We try to sanitize the last `loca' entry. */
240       if ( gindex == ttface->num_locations - 2 )
241       {
242         FT_TRACE1(( "tt_face_get_location:"
243                     " too large size (%ld bytes) found for glyph index %d,\n",
244                     pos2 - pos1, gindex ));
245         FT_TRACE1(( "                     "
246                     " truncating at the end of `glyf' table to %ld bytes\n",
247                     ttface->glyf_len - pos1 ));
248         pos2 = ttface->glyf_len;
249       }
250       else
251       {
252         FT_TRACE1(( "tt_face_get_location:"
253                     " too large offset (0x%08lx) found for glyph index %d,\n",
254                     pos2, gindex + 1 ));
255         FT_TRACE1(( "                     "
256                     " exceeding the end of `glyf' table (0x%08lx)\n",
257                     ttface->glyf_len ));
258         *asize = 0;
259         return 0;
260       }
261     }
262
263     /* The `loca' table must be ordered; it refers to the length of */
264     /* an entry as the difference between the current and the next  */
265     /* position.  However, there do exist (malformed) fonts which   */
266     /* don't obey this rule, so we are only able to provide an      */
267     /* upper bound for the size.                                    */
268     /*                                                              */
269     /* We get (intentionally) a wrong, non-zero result in case the  */
270     /* `glyf' table is missing.                                     */
271     if ( pos2 >= pos1 )
272       *asize = (FT_ULong)( pos2 - pos1 );
273     else
274       *asize = (FT_ULong)( ttface->glyf_len - pos1 );
275
276     return pos1;
277   }
278
279
280   FT_LOCAL_DEF( void )
281   tt_face_done_loca( TT_Face  face )
282   {
283     FT_Stream  stream = face->root.stream;
284
285
286     FT_FRAME_RELEASE( face->glyph_locations );
287     face->num_locations = 0;
288   }
289
290
291
292   /**************************************************************************
293    *
294    * @Function:
295    *   tt_face_load_cvt
296    *
297    * @Description:
298    *   Load the control value table into a face object.
299    *
300    * @InOut:
301    *   face ::
302    *     A handle to the target face object.
303    *
304    * @Input:
305    *   stream ::
306    *     A handle to the input stream.
307    *
308    * @Return:
309    *   FreeType error code.  0 means success.
310    */
311   FT_LOCAL_DEF( FT_Error )
312   tt_face_load_cvt( TT_Face    face,
313                     FT_Stream  stream )
314   {
315 #ifdef TT_USE_BYTECODE_INTERPRETER
316
317     FT_Error   error;
318     FT_Memory  memory = stream->memory;
319     FT_ULong   table_len;
320
321
322     FT_TRACE2(( "CVT " ));
323
324     error = face->goto_table( face, TTAG_cvt, stream, &table_len );
325     if ( error )
326     {
327       FT_TRACE2(( "is missing\n" ));
328
329       face->cvt_size = 0;
330       face->cvt      = NULL;
331       error          = FT_Err_Ok;
332
333       goto Exit;
334     }
335
336     face->cvt_size = table_len / 2;
337
338     if ( FT_QNEW_ARRAY( face->cvt, face->cvt_size ) )
339       goto Exit;
340
341     if ( FT_FRAME_ENTER( face->cvt_size * 2L ) )
342       goto Exit;
343
344     {
345       FT_Int32*  cur   = face->cvt;
346       FT_Int32*  limit = cur + face->cvt_size;
347
348
349       for ( ; cur < limit; cur++ )
350         *cur = FT_GET_SHORT() * 64;
351     }
352
353     FT_FRAME_EXIT();
354     FT_TRACE2(( "loaded\n" ));
355
356 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
357     if ( face->doblend )
358       error = tt_face_vary_cvt( face, stream );
359 #endif
360
361   Exit:
362     return error;
363
364 #else /* !TT_USE_BYTECODE_INTERPRETER */
365
366     FT_UNUSED( face   );
367     FT_UNUSED( stream );
368
369     return FT_Err_Ok;
370
371 #endif
372   }
373
374
375   /**************************************************************************
376    *
377    * @Function:
378    *   tt_face_load_fpgm
379    *
380    * @Description:
381    *   Load the font program.
382    *
383    * @InOut:
384    *   face ::
385    *     A handle to the target face object.
386    *
387    * @Input:
388    *   stream ::
389    *     A handle to the input stream.
390    *
391    * @Return:
392    *   FreeType error code.  0 means success.
393    */
394   FT_LOCAL_DEF( FT_Error )
395   tt_face_load_fpgm( TT_Face    face,
396                      FT_Stream  stream )
397   {
398 #ifdef TT_USE_BYTECODE_INTERPRETER
399
400     FT_Error  error;
401     FT_ULong  table_len;
402
403
404     FT_TRACE2(( "Font program " ));
405
406     /* The font program is optional */
407     error = face->goto_table( face, TTAG_fpgm, stream, &table_len );
408     if ( error )
409     {
410       face->font_program      = NULL;
411       face->font_program_size = 0;
412       error                   = FT_Err_Ok;
413
414       FT_TRACE2(( "is missing\n" ));
415     }
416     else
417     {
418       face->font_program_size = table_len;
419       if ( FT_FRAME_EXTRACT( table_len, face->font_program ) )
420         goto Exit;
421
422       FT_TRACE2(( "loaded, %12ld bytes\n", face->font_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 FT_Err_Ok;
434
435 #endif
436   }
437
438
439   /**************************************************************************
440    *
441    * @Function:
442    *   tt_face_load_prep
443    *
444    * @Description:
445    *   Load the cvt program.
446    *
447    * @InOut:
448    *   face ::
449    *     A handle to the target face object.
450    *
451    * @Input:
452    *   stream ::
453    *     A handle to the input stream.
454    *
455    * @Return:
456    *   FreeType error code.  0 means success.
457    */
458   FT_LOCAL_DEF( FT_Error )
459   tt_face_load_prep( TT_Face    face,
460                      FT_Stream  stream )
461   {
462 #ifdef TT_USE_BYTECODE_INTERPRETER
463
464     FT_Error  error;
465     FT_ULong  table_len;
466
467
468     FT_TRACE2(( "Prep program " ));
469
470     error = face->goto_table( face, TTAG_prep, stream, &table_len );
471     if ( error )
472     {
473       face->cvt_program      = NULL;
474       face->cvt_program_size = 0;
475       error                  = FT_Err_Ok;
476
477       FT_TRACE2(( "is missing\n" ));
478     }
479     else
480     {
481       face->cvt_program_size = table_len;
482       if ( FT_FRAME_EXTRACT( table_len, face->cvt_program ) )
483         goto Exit;
484
485       FT_TRACE2(( "loaded, %12ld bytes\n", face->cvt_program_size ));
486     }
487
488   Exit:
489     return error;
490
491 #else /* !TT_USE_BYTECODE_INTERPRETER */
492
493     FT_UNUSED( face   );
494     FT_UNUSED( stream );
495
496     return FT_Err_Ok;
497
498 #endif
499   }
500
501
502   FT_COMPARE_DEF( int )
503   compare_ppem( const void*  a,
504                 const void*  b )
505   {
506     return **(FT_Byte**)a - **(FT_Byte**)b;
507   }
508
509
510   /**************************************************************************
511    *
512    * @Function:
513    *   tt_face_load_hdmx
514    *
515    * @Description:
516    *   Load the `hdmx' table into the face object.
517    *
518    * @Input:
519    *   face ::
520    *     A handle to the target face object.
521    *
522    *   stream ::
523    *     A handle to the input stream.
524    *
525    * @Return:
526    *   FreeType error code.  0 means success.
527    */
528
529   FT_LOCAL_DEF( FT_Error )
530   tt_face_load_hdmx( TT_Face    face,
531                      FT_Stream  stream )
532   {
533     FT_Error   error;
534     FT_Memory  memory = stream->memory;
535     FT_UInt    nn, num_records;
536     FT_ULong   table_size, record_size;
537     FT_Byte*   p;
538     FT_Byte*   limit;
539
540
541     /* this table is optional */
542     error = face->goto_table( face, TTAG_hdmx, stream, &table_size );
543     if ( error || table_size < 8 )
544       return FT_Err_Ok;
545
546     if ( FT_FRAME_EXTRACT( table_size, face->hdmx_table ) )
547       goto Exit;
548
549     p     = face->hdmx_table;
550     limit = p + table_size;
551
552     /* Given that `hdmx' tables are losing its importance (for example, */
553     /* variation fonts introduced in OpenType 1.8 must not have this    */
554     /* table) we no longer test for a correct `version' field.          */
555     p          += 2;
556     num_records = FT_NEXT_USHORT( p );
557     record_size = FT_NEXT_ULONG( p );
558
559     /* There are at least two fonts, HANNOM-A and HANNOM-B version */
560     /* 2.0 (2005), which get this wrong: The upper two bytes of    */
561     /* the size value are set to 0xFF instead of 0x00.  We catch   */
562     /* and fix this.                                               */
563
564     if ( record_size >= 0xFFFF0000UL )
565       record_size &= 0xFFFFU;
566
567     FT_TRACE2(( "Hdmx " ));
568
569     /* The limit for `num_records' is a heuristic value. */
570     if ( num_records > 255 || num_records == 0 )
571     {
572       FT_TRACE2(( "with unreasonable %u records rejected\n", num_records ));
573       goto Fail;
574     }
575
576     /* Out-of-spec tables are rejected.  The record size must be */
577     /* equal to the number of glyphs + 2 + 32-bit padding.       */
578     if ( (FT_Long)record_size != ( ( face->root.num_glyphs + 2 + 3 ) & ~3 ) )
579     {
580       FT_TRACE2(( "with record size off by %ld bytes rejected\n",
581                   (FT_Long)record_size -
582                     ( ( face->root.num_glyphs + 2 + 3 ) & ~3 ) ));
583       goto Fail;
584     }
585
586     if ( FT_QNEW_ARRAY( face->hdmx_records, num_records ) )
587       goto Fail;
588
589     for ( nn = 0; nn < num_records; nn++ )
590     {
591       if ( p + record_size > limit )
592         break;
593       face->hdmx_records[nn] = p;
594       p                     += record_size;
595     }
596
597     /* The records must be already sorted by ppem but it does not */
598     /* hurt to make sure so that the binary search works later.   */
599     ft_qsort( face->hdmx_records, nn, sizeof ( FT_Byte* ), compare_ppem );
600
601     face->hdmx_record_count = nn;
602     face->hdmx_table_size   = table_size;
603     face->hdmx_record_size  = record_size;
604
605     FT_TRACE2(( "%ux%lu loaded\n", num_records, record_size ));
606
607   Exit:
608     return error;
609
610   Fail:
611     FT_FRAME_RELEASE( face->hdmx_table );
612     face->hdmx_table_size = 0;
613     goto Exit;
614   }
615
616
617   FT_LOCAL_DEF( void )
618   tt_face_free_hdmx( TT_Face  face )
619   {
620     FT_Stream  stream = face->root.stream;
621     FT_Memory  memory = stream->memory;
622
623
624     FT_FREE( face->hdmx_records );
625     FT_FRAME_RELEASE( face->hdmx_table );
626   }
627
628
629   /**************************************************************************
630    *
631    * Return the advance width table for a given pixel size if it is found
632    * in the font's `hdmx' table (if any).  The records must be sorted for
633    * the binary search to work properly.
634    */
635   FT_LOCAL_DEF( FT_Byte* )
636   tt_face_get_device_metrics( TT_Face  face,
637                               FT_UInt  ppem,
638                               FT_UInt  gindex )
639   {
640     FT_UInt   min    = 0;
641     FT_UInt   max    = face->hdmx_record_count;
642     FT_UInt   mid;
643     FT_Byte*  result = NULL;
644
645
646     while ( min < max )
647     {
648       mid = ( min + max ) >> 1;
649
650       if ( face->hdmx_records[mid][0] > ppem )
651         max = mid;
652       else if ( face->hdmx_records[mid][0] < ppem )
653         min = mid + 1;
654       else
655       {
656         result = face->hdmx_records[mid] + 2 + gindex;
657         break;
658       }
659     }
660
661     return result;
662   }
663
664
665 /* END */