• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  *
3  * ttgload.c
4  *
5  *   TrueType Glyph 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 <ft2build.h>
20 #include <freetype/internal/ftdebug.h>
21 #include FT_CONFIG_CONFIG_H
22 #include <freetype/internal/ftcalc.h>
23 #include <freetype/internal/ftstream.h>
24 #include <freetype/internal/sfnt.h>
25 #include <freetype/tttags.h>
26 #include <freetype/ftoutln.h>
27 #include <freetype/ftdriver.h>
28 #include <freetype/ftlist.h>
29 
30 #include "ttgload.h"
31 #include "ttpload.h"
32 
33 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
34 #include "ttgxvar.h"
35 #endif
36 
37 #include "tterrors.h"
38 #include "ttsubpix.h"
39 
40 
41   /**************************************************************************
42    *
43    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
44    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
45    * messages during execution.
46    */
47 #undef  FT_COMPONENT
48 #define FT_COMPONENT  ttgload
49 
50 
51   /**************************************************************************
52    *
53    * Simple glyph flags.
54    */
55 #define ON_CURVE_POINT  0x01  /* same value as FT_CURVE_TAG_ON            */
56 #define X_SHORT_VECTOR  0x02
57 #define Y_SHORT_VECTOR  0x04
58 #define REPEAT_FLAG     0x08
59 #define X_POSITIVE      0x10  /* two meanings depending on X_SHORT_VECTOR */
60 #define SAME_X          0x10
61 #define Y_POSITIVE      0x20  /* two meanings depending on Y_SHORT_VECTOR */
62 #define SAME_Y          0x20
63 #define OVERLAP_SIMPLE  0x40  /* retained as FT_OUTLINE_OVERLAP           */
64 
65 
66   /**************************************************************************
67    *
68    * Composite glyph flags.
69    */
70 #define ARGS_ARE_WORDS             0x0001
71 #define ARGS_ARE_XY_VALUES         0x0002
72 #define ROUND_XY_TO_GRID           0x0004
73 #define WE_HAVE_A_SCALE            0x0008
74 /* reserved                        0x0010 */
75 #define MORE_COMPONENTS            0x0020
76 #define WE_HAVE_AN_XY_SCALE        0x0040
77 #define WE_HAVE_A_2X2              0x0080
78 #define WE_HAVE_INSTR              0x0100
79 #define USE_MY_METRICS             0x0200
80 #define OVERLAP_COMPOUND           0x0400  /* retained as FT_OUTLINE_OVERLAP */
81 #define SCALED_COMPONENT_OFFSET    0x0800
82 #define UNSCALED_COMPONENT_OFFSET  0x1000
83 
84 
85 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
86 #define IS_DEFAULT_INSTANCE( _face )             \
87           ( !( FT_IS_NAMED_INSTANCE( _face ) ||  \
88                FT_IS_VARIATION( _face )      ) )
89 #else
90 #define IS_DEFAULT_INSTANCE( _face )  1
91 #endif
92 
93 
94   /**************************************************************************
95    *
96    * Return the horizontal metrics in font units for a given glyph.
97    */
98   FT_LOCAL_DEF( void )
TT_Get_HMetrics(TT_Face face,FT_UInt idx,FT_Short * lsb,FT_UShort * aw)99   TT_Get_HMetrics( TT_Face     face,
100                    FT_UInt     idx,
101                    FT_Short*   lsb,
102                    FT_UShort*  aw )
103   {
104     ( (SFNT_Service)face->sfnt )->get_metrics( face, 0, idx, lsb, aw );
105 
106     FT_TRACE5(( "  advance width (font units): %d\n", *aw ));
107     FT_TRACE5(( "  left side bearing (font units): %d\n", *lsb ));
108   }
109 
110 
111   /**************************************************************************
112    *
113    * Return the vertical metrics in font units for a given glyph.
114    * See function `tt_loader_set_pp' below for explanations.
115    */
116   FT_LOCAL_DEF( void )
TT_Get_VMetrics(TT_Face face,FT_UInt idx,FT_Pos yMax,FT_Short * tsb,FT_UShort * ah)117   TT_Get_VMetrics( TT_Face     face,
118                    FT_UInt     idx,
119                    FT_Pos      yMax,
120                    FT_Short*   tsb,
121                    FT_UShort*  ah )
122   {
123     if ( face->vertical_info )
124       ( (SFNT_Service)face->sfnt )->get_metrics( face, 1, idx, tsb, ah );
125 
126     else if ( face->os2.version != 0xFFFFU )
127     {
128       *tsb = (FT_Short)( face->os2.sTypoAscender - yMax );
129       *ah  = (FT_UShort)FT_ABS( face->os2.sTypoAscender -
130                                 face->os2.sTypoDescender );
131     }
132 
133     else
134     {
135       *tsb = (FT_Short)( face->horizontal.Ascender - yMax );
136       *ah  = (FT_UShort)FT_ABS( face->horizontal.Ascender -
137                                 face->horizontal.Descender );
138     }
139 
140 #ifdef FT_DEBUG_LEVEL_TRACE
141     if ( !face->vertical_info )
142       FT_TRACE5(( "  [vertical metrics missing, computing values]\n" ));
143 #endif
144 
145     FT_TRACE5(( "  advance height (font units): %d\n", *ah ));
146     FT_TRACE5(( "  top side bearing (font units): %d\n", *tsb ));
147   }
148 
149 
150   static FT_Error
tt_get_metrics(TT_Loader loader,FT_UInt glyph_index)151   tt_get_metrics( TT_Loader  loader,
152                   FT_UInt    glyph_index )
153   {
154     TT_Face    face   = loader->face;
155 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
156     TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( face );
157 #endif
158 
159     FT_Error   error;
160     FT_Stream  stream = loader->stream;
161 
162     FT_Short   left_bearing = 0, top_bearing = 0;
163     FT_UShort  advance_width = 0, advance_height = 0;
164 
165     /* we must preserve the stream position          */
166     /* (which gets altered by the metrics functions) */
167     FT_ULong  pos = FT_STREAM_POS();
168 
169 
170     TT_Get_HMetrics( face, glyph_index,
171                      &left_bearing,
172                      &advance_width );
173     TT_Get_VMetrics( face, glyph_index,
174                      loader->bbox.yMax,
175                      &top_bearing,
176                      &advance_height );
177 
178     if ( FT_STREAM_SEEK( pos ) )
179       return error;
180 
181     loader->left_bearing = left_bearing;
182     loader->advance      = advance_width;
183     loader->top_bearing  = top_bearing;
184     loader->vadvance     = advance_height;
185 
186 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
187     if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 &&
188          loader->exec                                             )
189     {
190       loader->exec->sph_tweak_flags = 0;
191 
192       /* This may not be the right place for this, but it works...  */
193       /* Note that we have to unconditionally load the tweaks since */
194       /* it is possible that glyphs individually switch ClearType's */
195       /* backward compatibility mode on and off.                    */
196       sph_set_tweaks( loader, glyph_index );
197     }
198 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
199 
200 #ifdef FT_CONFIG_OPTION_INCREMENTAL
201     /* With the incremental interface, these values are set by  */
202     /* a call to `tt_get_metrics_incremental'.                  */
203     if ( face->root.internal->incremental_interface == NULL )
204 #endif
205     {
206       if ( !loader->linear_def )
207       {
208         loader->linear_def = 1;
209         loader->linear     = advance_width;
210       }
211     }
212 
213     return FT_Err_Ok;
214   }
215 
216 
217 #ifdef FT_CONFIG_OPTION_INCREMENTAL
218 
219   static void
tt_get_metrics_incremental(TT_Loader loader,FT_UInt glyph_index)220   tt_get_metrics_incremental( TT_Loader  loader,
221                               FT_UInt    glyph_index )
222   {
223     TT_Face  face = loader->face;
224 
225     FT_Short   left_bearing = 0, top_bearing = 0;
226     FT_UShort  advance_width = 0, advance_height = 0;
227 
228 
229     /* If this is an incrementally loaded font check whether there are */
230     /* overriding metrics for this glyph.                              */
231     if ( face->root.internal->incremental_interface                           &&
232          face->root.internal->incremental_interface->funcs->get_glyph_metrics )
233     {
234       FT_Incremental_MetricsRec  incr_metrics;
235       FT_Error                   error;
236 
237 
238       incr_metrics.bearing_x = loader->left_bearing;
239       incr_metrics.bearing_y = 0;
240       incr_metrics.advance   = loader->advance;
241       incr_metrics.advance_v = 0;
242 
243       error = face->root.internal->incremental_interface->funcs->get_glyph_metrics(
244                 face->root.internal->incremental_interface->object,
245                 glyph_index, FALSE, &incr_metrics );
246       if ( error )
247         goto Exit;
248 
249       left_bearing  = (FT_Short)incr_metrics.bearing_x;
250       advance_width = (FT_UShort)incr_metrics.advance;
251 
252 #if 0
253 
254       /* GWW: Do I do the same for vertical metrics? */
255       incr_metrics.bearing_x = 0;
256       incr_metrics.bearing_y = loader->top_bearing;
257       incr_metrics.advance   = loader->vadvance;
258 
259       error = face->root.internal->incremental_interface->funcs->get_glyph_metrics(
260                 face->root.internal->incremental_interface->object,
261                 glyph_index, TRUE, &incr_metrics );
262       if ( error )
263         goto Exit;
264 
265       top_bearing    = (FT_Short)incr_metrics.bearing_y;
266       advance_height = (FT_UShort)incr_metrics.advance;
267 
268 #endif /* 0 */
269 
270       loader->left_bearing = left_bearing;
271       loader->advance      = advance_width;
272       loader->top_bearing  = top_bearing;
273       loader->vadvance     = advance_height;
274 
275       if ( !loader->linear_def )
276       {
277         loader->linear_def = 1;
278         loader->linear     = advance_width;
279       }
280     }
281 
282   Exit:
283     return;
284   }
285 
286 #endif /* FT_CONFIG_OPTION_INCREMENTAL */
287 
288 
289   /**************************************************************************
290    *
291    * The following functions are used by default with TrueType fonts.
292    * However, they can be replaced by alternatives if we need to support
293    * TrueType-compressed formats (like MicroType) in the future.
294    *
295    */
296 
297   FT_CALLBACK_DEF( FT_Error )
TT_Access_Glyph_Frame(TT_Loader loader,FT_UInt glyph_index,FT_ULong offset,FT_UInt byte_count)298   TT_Access_Glyph_Frame( TT_Loader  loader,
299                          FT_UInt    glyph_index,
300                          FT_ULong   offset,
301                          FT_UInt    byte_count )
302   {
303     FT_Error   error;
304     FT_Stream  stream = loader->stream;
305 
306     FT_UNUSED( glyph_index );
307 
308 
309     /* the following line sets the `error' variable through macros! */
310     if ( FT_STREAM_SEEK( offset ) || FT_FRAME_ENTER( byte_count ) )
311       return error;
312 
313     loader->cursor = stream->cursor;
314     loader->limit  = stream->limit;
315 
316     return FT_Err_Ok;
317   }
318 
319 
320   FT_CALLBACK_DEF( void )
TT_Forget_Glyph_Frame(TT_Loader loader)321   TT_Forget_Glyph_Frame( TT_Loader  loader )
322   {
323     FT_Stream  stream = loader->stream;
324 
325 
326     FT_FRAME_EXIT();
327   }
328 
329 
330   FT_CALLBACK_DEF( FT_Error )
TT_Load_Glyph_Header(TT_Loader loader)331   TT_Load_Glyph_Header( TT_Loader  loader )
332   {
333     FT_Byte*  p     = loader->cursor;
334     FT_Byte*  limit = loader->limit;
335 
336 
337     if ( p + 10 > limit )
338       return FT_THROW( Invalid_Outline );
339 
340     loader->n_contours = FT_NEXT_SHORT( p );
341 
342     loader->bbox.xMin = FT_NEXT_SHORT( p );
343     loader->bbox.yMin = FT_NEXT_SHORT( p );
344     loader->bbox.xMax = FT_NEXT_SHORT( p );
345     loader->bbox.yMax = FT_NEXT_SHORT( p );
346 
347     FT_TRACE5(( "  # of contours: %d\n", loader->n_contours ));
348     FT_TRACE5(( "  xMin: %4ld  xMax: %4ld\n", loader->bbox.xMin,
349                                             loader->bbox.xMax ));
350     FT_TRACE5(( "  yMin: %4ld  yMax: %4ld\n", loader->bbox.yMin,
351                                             loader->bbox.yMax ));
352     loader->cursor = p;
353 
354     return FT_Err_Ok;
355   }
356 
357 
358   FT_CALLBACK_DEF( FT_Error )
TT_Load_Simple_Glyph(TT_Loader load)359   TT_Load_Simple_Glyph( TT_Loader  load )
360   {
361     FT_Error        error;
362     FT_Byte*        p          = load->cursor;
363     FT_Byte*        limit      = load->limit;
364     FT_GlyphLoader  gloader    = load->gloader;
365     FT_Int          n_contours = load->n_contours;
366     FT_Outline*     outline;
367     FT_UShort       n_ins;
368     FT_Int          n_points;
369 
370     FT_Byte         *flag, *flag_limit;
371     FT_Byte         c, count;
372     FT_Vector       *vec, *vec_limit;
373     FT_Pos          x, y;
374     FT_Short        *cont, *cont_limit, prev_cont;
375     FT_Int          xy_size = 0;
376 
377 
378     /* check that we can add the contours to the glyph */
379     error = FT_GLYPHLOADER_CHECK_POINTS( gloader, 0, n_contours );
380     if ( error )
381       goto Fail;
382 
383     /* reading the contours' endpoints & number of points */
384     cont       = gloader->current.outline.contours;
385     cont_limit = cont + n_contours;
386 
387     /* check space for contours array + instructions count */
388     if ( n_contours >= 0xFFF || p + ( n_contours + 1 ) * 2 > limit )
389       goto Invalid_Outline;
390 
391     prev_cont = FT_NEXT_SHORT( p );
392 
393     if ( n_contours > 0 )
394       cont[0] = prev_cont;
395 
396     if ( prev_cont < 0 )
397       goto Invalid_Outline;
398 
399     for ( cont++; cont < cont_limit; cont++ )
400     {
401       cont[0] = FT_NEXT_SHORT( p );
402       if ( cont[0] <= prev_cont )
403       {
404         /* unordered contours: this is invalid */
405         goto Invalid_Outline;
406       }
407       prev_cont = cont[0];
408     }
409 
410     n_points = 0;
411     if ( n_contours > 0 )
412     {
413       n_points = cont[-1] + 1;
414       if ( n_points < 0 )
415         goto Invalid_Outline;
416     }
417 
418     FT_TRACE5(( "  # of points: %d\n", n_points ));
419 
420     /* note that we will add four phantom points later */
421     error = FT_GLYPHLOADER_CHECK_POINTS( gloader, n_points + 4, 0 );
422     if ( error )
423       goto Fail;
424 
425     /* reading the bytecode instructions */
426     load->glyph->control_len  = 0;
427     load->glyph->control_data = NULL;
428 
429     if ( p + 2 > limit )
430       goto Invalid_Outline;
431 
432     n_ins = FT_NEXT_USHORT( p );
433 
434     FT_TRACE5(( "  Instructions size: %u\n", n_ins ));
435 
436 #ifdef TT_USE_BYTECODE_INTERPRETER
437 
438     if ( IS_HINTED( load->load_flags ) )
439     {
440       FT_ULong  tmp;
441 
442 
443       /* check instructions size */
444       if ( ( limit - p ) < n_ins )
445       {
446         FT_TRACE1(( "TT_Load_Simple_Glyph: instruction count mismatch\n" ));
447         error = FT_THROW( Too_Many_Hints );
448         goto Fail;
449       }
450 
451       /* we don't trust `maxSizeOfInstructions' in the `maxp' table */
452       /* and thus update the bytecode array size by ourselves       */
453 
454       tmp   = load->exec->glyphSize;
455       error = Update_Max( load->exec->memory,
456                           &tmp,
457                           sizeof ( FT_Byte ),
458                           (void*)&load->exec->glyphIns,
459                           n_ins );
460 
461       load->exec->glyphSize = (FT_UInt)tmp;
462       if ( error )
463         return error;
464 
465       load->glyph->control_len  = n_ins;
466       load->glyph->control_data = load->exec->glyphIns;
467 
468       if ( n_ins )
469         FT_MEM_COPY( load->exec->glyphIns, p, (FT_Long)n_ins );
470     }
471 
472 #endif /* TT_USE_BYTECODE_INTERPRETER */
473 
474     p += n_ins;
475 
476     outline = &gloader->current.outline;
477 
478     /* reading the point tags */
479     flag       = (FT_Byte*)outline->tags;
480     flag_limit = flag + n_points;
481 
482     FT_ASSERT( flag );
483 
484     while ( flag < flag_limit )
485     {
486       if ( p + 1 > limit )
487         goto Invalid_Outline;
488 
489       *flag++ = c = FT_NEXT_BYTE( p );
490       if ( c & REPEAT_FLAG )
491       {
492         if ( p + 1 > limit )
493           goto Invalid_Outline;
494 
495         count = FT_NEXT_BYTE( p );
496         if ( flag + (FT_Int)count > flag_limit )
497           goto Invalid_Outline;
498 
499         for ( ; count > 0; count-- )
500           *flag++ = c;
501       }
502     }
503 
504     /* retain the overlap flag */
505     if ( n_points && outline->tags[0] & OVERLAP_SIMPLE )
506       gloader->base.outline.flags |= FT_OUTLINE_OVERLAP;
507 
508     /* reading the X coordinates */
509 
510     vec       = outline->points;
511     vec_limit = vec + n_points;
512     flag      = (FT_Byte*)outline->tags;
513     x         = 0;
514 
515     if ( p + xy_size > limit )
516       goto Invalid_Outline;
517 
518     for ( ; vec < vec_limit; vec++, flag++ )
519     {
520       FT_Pos   delta = 0;
521       FT_Byte  f     = *flag;
522 
523 
524       if ( f & X_SHORT_VECTOR )
525       {
526         if ( p + 1 > limit )
527           goto Invalid_Outline;
528 
529         delta = (FT_Pos)FT_NEXT_BYTE( p );
530         if ( !( f & X_POSITIVE ) )
531           delta = -delta;
532       }
533       else if ( !( f & SAME_X ) )
534       {
535         if ( p + 2 > limit )
536           goto Invalid_Outline;
537 
538         delta = (FT_Pos)FT_NEXT_SHORT( p );
539       }
540 
541       x     += delta;
542       vec->x = x;
543     }
544 
545     /* reading the Y coordinates */
546 
547     vec       = gloader->current.outline.points;
548     vec_limit = vec + n_points;
549     flag      = (FT_Byte*)outline->tags;
550     y         = 0;
551 
552     for ( ; vec < vec_limit; vec++, flag++ )
553     {
554       FT_Pos   delta = 0;
555       FT_Byte  f     = *flag;
556 
557 
558       if ( f & Y_SHORT_VECTOR )
559       {
560         if ( p + 1 > limit )
561           goto Invalid_Outline;
562 
563         delta = (FT_Pos)FT_NEXT_BYTE( p );
564         if ( !( f & Y_POSITIVE ) )
565           delta = -delta;
566       }
567       else if ( !( f & SAME_Y ) )
568       {
569         if ( p + 2 > limit )
570           goto Invalid_Outline;
571 
572         delta = (FT_Pos)FT_NEXT_SHORT( p );
573       }
574 
575       y     += delta;
576       vec->y = y;
577 
578       /* the cast is for stupid compilers */
579       *flag  = (FT_Byte)( f & ON_CURVE_POINT );
580     }
581 
582     outline->n_points   = (FT_Short)n_points;
583     outline->n_contours = (FT_Short)n_contours;
584 
585     load->cursor = p;
586 
587   Fail:
588     return error;
589 
590   Invalid_Outline:
591     error = FT_THROW( Invalid_Outline );
592     goto Fail;
593   }
594 
595 
596   FT_CALLBACK_DEF( FT_Error )
TT_Load_Composite_Glyph(TT_Loader loader)597   TT_Load_Composite_Glyph( TT_Loader  loader )
598   {
599     FT_Error        error;
600     FT_Byte*        p          = loader->cursor;
601     FT_Byte*        limit      = loader->limit;
602     FT_GlyphLoader  gloader    = loader->gloader;
603     FT_Long         num_glyphs = loader->face->root.num_glyphs;
604     FT_SubGlyph     subglyph;
605     FT_UInt         num_subglyphs;
606 
607 
608     num_subglyphs = 0;
609 
610     do
611     {
612       FT_Fixed  xx, xy, yy, yx;
613       FT_UInt   count;
614 
615 
616       /* check that we can load a new subglyph */
617       error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs + 1 );
618       if ( error )
619         goto Fail;
620 
621       /* check space */
622       if ( p + 4 > limit )
623         goto Invalid_Composite;
624 
625       subglyph = gloader->current.subglyphs + num_subglyphs;
626 
627       subglyph->arg1 = subglyph->arg2 = 0;
628 
629       subglyph->flags = FT_NEXT_USHORT( p );
630       subglyph->index = FT_NEXT_USHORT( p );
631 
632       /* we reject composites that have components */
633       /* with invalid glyph indices                */
634       if ( subglyph->index >= num_glyphs )
635         goto Invalid_Composite;
636 
637       /* check space */
638       count = 2;
639       if ( subglyph->flags & ARGS_ARE_WORDS )
640         count += 2;
641       if ( subglyph->flags & WE_HAVE_A_SCALE )
642         count += 2;
643       else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE )
644         count += 4;
645       else if ( subglyph->flags & WE_HAVE_A_2X2 )
646         count += 8;
647 
648       if ( p + count > limit )
649         goto Invalid_Composite;
650 
651       /* read arguments */
652       if ( subglyph->flags & ARGS_ARE_XY_VALUES )
653       {
654         if ( subglyph->flags & ARGS_ARE_WORDS )
655         {
656           subglyph->arg1 = FT_NEXT_SHORT( p );
657           subglyph->arg2 = FT_NEXT_SHORT( p );
658         }
659         else
660         {
661           subglyph->arg1 = FT_NEXT_CHAR( p );
662           subglyph->arg2 = FT_NEXT_CHAR( p );
663         }
664       }
665       else
666       {
667         if ( subglyph->flags & ARGS_ARE_WORDS )
668         {
669           subglyph->arg1 = (FT_Int)FT_NEXT_USHORT( p );
670           subglyph->arg2 = (FT_Int)FT_NEXT_USHORT( p );
671         }
672         else
673         {
674           subglyph->arg1 = (FT_Int)FT_NEXT_BYTE( p );
675           subglyph->arg2 = (FT_Int)FT_NEXT_BYTE( p );
676         }
677       }
678 
679       /* read transform */
680       xx = yy = 0x10000L;
681       xy = yx = 0;
682 
683       if ( subglyph->flags & WE_HAVE_A_SCALE )
684       {
685         xx = (FT_Fixed)FT_NEXT_SHORT( p ) * 4;
686         yy = xx;
687       }
688       else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE )
689       {
690         xx = (FT_Fixed)FT_NEXT_SHORT( p ) * 4;
691         yy = (FT_Fixed)FT_NEXT_SHORT( p ) * 4;
692       }
693       else if ( subglyph->flags & WE_HAVE_A_2X2 )
694       {
695         xx = (FT_Fixed)FT_NEXT_SHORT( p ) * 4;
696         yx = (FT_Fixed)FT_NEXT_SHORT( p ) * 4;
697         xy = (FT_Fixed)FT_NEXT_SHORT( p ) * 4;
698         yy = (FT_Fixed)FT_NEXT_SHORT( p ) * 4;
699       }
700 
701       subglyph->transform.xx = xx;
702       subglyph->transform.xy = xy;
703       subglyph->transform.yx = yx;
704       subglyph->transform.yy = yy;
705 
706       num_subglyphs++;
707 
708     } while ( subglyph->flags & MORE_COMPONENTS );
709 
710     gloader->current.num_subglyphs = num_subglyphs;
711     FT_TRACE5(( "  %d component%s\n",
712                 num_subglyphs,
713                 num_subglyphs > 1 ? "s" : "" ));
714 
715 #ifdef FT_DEBUG_LEVEL_TRACE
716     {
717       FT_UInt  i;
718 
719 
720       subglyph = gloader->current.subglyphs;
721 
722       for ( i = 0; i < num_subglyphs; i++ )
723       {
724         if ( num_subglyphs > 1 )
725           FT_TRACE7(( "    subglyph %d:\n", i ));
726 
727         FT_TRACE7(( "      glyph index: %d\n", subglyph->index ));
728 
729         if ( subglyph->flags & ARGS_ARE_XY_VALUES )
730           FT_TRACE7(( "      offset: x=%d, y=%d\n",
731                       subglyph->arg1,
732                       subglyph->arg2 ));
733         else
734           FT_TRACE7(( "      matching points: base=%d, component=%d\n",
735                       subglyph->arg1,
736                       subglyph->arg2 ));
737 
738         if ( subglyph->flags & WE_HAVE_A_SCALE )
739           FT_TRACE7(( "      scaling: %f\n",
740                       subglyph->transform.xx / 65536.0 ));
741         else if ( subglyph->flags & WE_HAVE_AN_XY_SCALE )
742           FT_TRACE7(( "      scaling: x=%f, y=%f\n",
743                       subglyph->transform.xx / 65536.0,
744                       subglyph->transform.yy / 65536.0 ));
745         else if ( subglyph->flags & WE_HAVE_A_2X2 )
746         {
747           FT_TRACE7(( "      scaling: xx=%f, yx=%f\n",
748                       subglyph->transform.xx / 65536.0,
749                       subglyph->transform.yx / 65536.0 ));
750           FT_TRACE7(( "               xy=%f, yy=%f\n",
751                       subglyph->transform.xy / 65536.0,
752                       subglyph->transform.yy / 65536.0 ));
753         }
754 
755         subglyph++;
756       }
757     }
758 #endif /* FT_DEBUG_LEVEL_TRACE */
759 
760 #ifdef TT_USE_BYTECODE_INTERPRETER
761 
762     {
763       FT_Stream  stream = loader->stream;
764 
765 
766       /* we must undo the FT_FRAME_ENTER in order to point */
767       /* to the composite instructions, if we find some.   */
768       /* We will process them later.                       */
769       /*                                                   */
770       loader->ins_pos = (FT_ULong)( FT_STREAM_POS() +
771                                     p - limit );
772     }
773 
774 #endif
775 
776     loader->cursor = p;
777 
778   Fail:
779     return error;
780 
781   Invalid_Composite:
782     error = FT_THROW( Invalid_Composite );
783     goto Fail;
784   }
785 
786 
787   FT_LOCAL_DEF( void )
TT_Init_Glyph_Loading(TT_Face face)788   TT_Init_Glyph_Loading( TT_Face  face )
789   {
790     face->access_glyph_frame   = TT_Access_Glyph_Frame;
791     face->read_glyph_header    = TT_Load_Glyph_Header;
792     face->read_simple_glyph    = TT_Load_Simple_Glyph;
793     face->read_composite_glyph = TT_Load_Composite_Glyph;
794     face->forget_glyph_frame   = TT_Forget_Glyph_Frame;
795   }
796 
797 
798   static void
tt_prepare_zone(TT_GlyphZone zone,FT_GlyphLoad load,FT_UInt start_point,FT_UInt start_contour)799   tt_prepare_zone( TT_GlyphZone  zone,
800                    FT_GlyphLoad  load,
801                    FT_UInt       start_point,
802                    FT_UInt       start_contour )
803   {
804     zone->n_points    = (FT_UShort)load->outline.n_points -
805                           (FT_UShort)start_point;
806     zone->n_contours  = load->outline.n_contours -
807                           (FT_Short)start_contour;
808     zone->org         = load->extra_points + start_point;
809     zone->cur         = load->outline.points + start_point;
810     zone->orus        = load->extra_points2 + start_point;
811     zone->tags        = (FT_Byte*)load->outline.tags + start_point;
812     zone->contours    = (FT_UShort*)load->outline.contours + start_contour;
813     zone->first_point = (FT_UShort)start_point;
814   }
815 
816 
817   /**************************************************************************
818    *
819    * @Function:
820    *   TT_Hint_Glyph
821    *
822    * @Description:
823    *   Hint the glyph using the zone prepared by the caller.  Note that
824    *   the zone is supposed to include four phantom points.
825    */
826   static FT_Error
TT_Hint_Glyph(TT_Loader loader,FT_Bool is_composite)827   TT_Hint_Glyph( TT_Loader  loader,
828                  FT_Bool    is_composite )
829   {
830 #if defined TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY || \
831     defined TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
832     TT_Face    face   = loader->face;
833     TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( face );
834 #endif
835 
836     TT_GlyphZone  zone = &loader->zone;
837 
838 #ifdef TT_USE_BYTECODE_INTERPRETER
839     FT_Long       n_ins;
840 #else
841     FT_UNUSED( is_composite );
842 #endif
843 
844 
845 #ifdef TT_USE_BYTECODE_INTERPRETER
846     n_ins = loader->glyph->control_len;
847 
848     /* save original point positions in `org' array */
849     if ( n_ins > 0 )
850       FT_ARRAY_COPY( zone->org, zone->cur, zone->n_points );
851 
852     /* Reset graphics state. */
853     loader->exec->GS = loader->size->GS;
854 
855     /* XXX: UNDOCUMENTED! Hinting instructions of a composite glyph */
856     /*      completely refer to the (already) hinted subglyphs.     */
857     if ( is_composite )
858     {
859       loader->exec->metrics.x_scale = 1 << 16;
860       loader->exec->metrics.y_scale = 1 << 16;
861 
862       FT_ARRAY_COPY( zone->orus, zone->cur, zone->n_points );
863     }
864     else
865     {
866       loader->exec->metrics.x_scale = loader->size->metrics->x_scale;
867       loader->exec->metrics.y_scale = loader->size->metrics->y_scale;
868     }
869 #endif
870 
871     /* round phantom points */
872     zone->cur[zone->n_points - 4].x =
873       FT_PIX_ROUND( zone->cur[zone->n_points - 4].x );
874     zone->cur[zone->n_points - 3].x =
875       FT_PIX_ROUND( zone->cur[zone->n_points - 3].x );
876     zone->cur[zone->n_points - 2].y =
877       FT_PIX_ROUND( zone->cur[zone->n_points - 2].y );
878     zone->cur[zone->n_points - 1].y =
879       FT_PIX_ROUND( zone->cur[zone->n_points - 1].y );
880 
881 #ifdef TT_USE_BYTECODE_INTERPRETER
882 
883     if ( n_ins > 0 )
884     {
885       FT_Error  error;
886 
887       FT_GlyphLoader  gloader         = loader->gloader;
888       FT_Outline      current_outline = gloader->current.outline;
889 
890 
891       TT_Set_CodeRange( loader->exec, tt_coderange_glyph,
892                         loader->exec->glyphIns, n_ins );
893 
894       loader->exec->is_composite = is_composite;
895       loader->exec->pts          = *zone;
896 
897       error = TT_Run_Context( loader->exec );
898       if ( error && loader->exec->pedantic_hinting )
899         return error;
900 
901       /* store drop-out mode in bits 5-7; set bit 2 also as a marker */
902       current_outline.tags[0] |=
903         ( loader->exec->GS.scan_type << 5 ) | FT_CURVE_TAG_HAS_SCANMODE;
904     }
905 
906 #endif
907 
908 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
909     /* Save possibly modified glyph phantom points unless in v40 backward  */
910     /* compatibility mode, where no movement on the x axis means no reason */
911     /* to change bearings or advance widths.                               */
912     if ( !( driver->interpreter_version == TT_INTERPRETER_VERSION_40 &&
913             loader->exec->backward_compatibility ) )
914     {
915 #endif
916       loader->pp1 = zone->cur[zone->n_points - 4];
917       loader->pp2 = zone->cur[zone->n_points - 3];
918       loader->pp3 = zone->cur[zone->n_points - 2];
919       loader->pp4 = zone->cur[zone->n_points - 1];
920 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
921     }
922 #endif
923 
924 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
925     if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
926     {
927       if ( loader->exec->sph_tweak_flags & SPH_TWEAK_DEEMBOLDEN )
928         FT_Outline_EmboldenXY( &loader->gloader->current.outline, -24, 0 );
929 
930       else if ( loader->exec->sph_tweak_flags & SPH_TWEAK_EMBOLDEN )
931         FT_Outline_EmboldenXY( &loader->gloader->current.outline, 24, 0 );
932     }
933 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
934 
935     return FT_Err_Ok;
936   }
937 
938 
939   /**************************************************************************
940    *
941    * @Function:
942    *   TT_Process_Simple_Glyph
943    *
944    * @Description:
945    *   Once a simple glyph has been loaded, it needs to be processed.
946    *   Usually, this means scaling and hinting through bytecode
947    *   interpretation.
948    */
949   static FT_Error
TT_Process_Simple_Glyph(TT_Loader loader)950   TT_Process_Simple_Glyph( TT_Loader  loader )
951   {
952     FT_GlyphLoader  gloader = loader->gloader;
953     FT_Error        error   = FT_Err_Ok;
954     FT_Outline*     outline;
955     FT_Int          n_points;
956 
957 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
958     FT_Memory   memory    = loader->face->root.memory;
959     FT_Vector*  unrounded = NULL;
960 #endif
961 
962 
963     outline  = &gloader->current.outline;
964     n_points = outline->n_points;
965 
966     /* set phantom points */
967 
968     outline->points[n_points    ] = loader->pp1;
969     outline->points[n_points + 1] = loader->pp2;
970     outline->points[n_points + 2] = loader->pp3;
971     outline->points[n_points + 3] = loader->pp4;
972 
973     outline->tags[n_points    ] = 0;
974     outline->tags[n_points + 1] = 0;
975     outline->tags[n_points + 2] = 0;
976     outline->tags[n_points + 3] = 0;
977 
978     n_points += 4;
979 
980 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
981 
982     if ( !IS_DEFAULT_INSTANCE( FT_FACE( loader->face ) ) )
983     {
984       if ( FT_NEW_ARRAY( unrounded, n_points ) )
985         goto Exit;
986 
987       /* Deltas apply to the unscaled data. */
988       error = TT_Vary_Apply_Glyph_Deltas( loader->face,
989                                           loader->glyph_index,
990                                           outline,
991                                           unrounded,
992                                           (FT_UInt)n_points );
993 
994       /* recalculate linear horizontal and vertical advances */
995       /* if we don't have HVAR and VVAR, respectively        */
996 
997       /* XXX: change all FreeType modules to store `linear' and `vadvance' */
998       /*      in 26.6 format before the `base' module scales them to 16.16 */
999       if ( !( loader->face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) )
1000         loader->linear = FT_PIX_ROUND( unrounded[n_points - 3].x -
1001                                        unrounded[n_points - 4].x ) / 64;
1002       if ( !( loader->face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) )
1003         loader->vadvance = FT_PIX_ROUND( unrounded[n_points - 1].x -
1004                                          unrounded[n_points - 2].x ) / 64;
1005 
1006       if ( error )
1007         goto Exit;
1008     }
1009 
1010 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
1011 
1012     if ( IS_HINTED( loader->load_flags ) )
1013     {
1014       tt_prepare_zone( &loader->zone, &gloader->current, 0, 0 );
1015 
1016       FT_ARRAY_COPY( loader->zone.orus, loader->zone.cur,
1017                      loader->zone.n_points + 4 );
1018     }
1019 
1020     {
1021 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
1022       TT_Face    face   = loader->face;
1023       TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( face );
1024 
1025       FT_String*  family         = face->root.family_name;
1026       FT_UInt     ppem           = loader->size->metrics->x_ppem;
1027       FT_String*  style          = face->root.style_name;
1028       FT_UInt     x_scale_factor = 1000;
1029 #endif
1030 
1031       FT_Vector*  vec   = outline->points;
1032       FT_Vector*  limit = outline->points + n_points;
1033 
1034       FT_Fixed  x_scale = 0; /* pacify compiler */
1035       FT_Fixed  y_scale = 0;
1036 
1037       FT_Bool  do_scale = FALSE;
1038 
1039 
1040 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
1041 
1042       if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
1043       {
1044         /* scale, but only if enabled and only if TT hinting is being used */
1045         if ( IS_HINTED( loader->load_flags ) )
1046           x_scale_factor = sph_test_tweak_x_scaling( face,
1047                                                      family,
1048                                                      ppem,
1049                                                      style,
1050                                                      loader->glyph_index );
1051         /* scale the glyph */
1052         if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 ||
1053              x_scale_factor != 1000                         )
1054         {
1055           x_scale = FT_MulDiv( loader->size->metrics->x_scale,
1056                                (FT_Long)x_scale_factor, 1000 );
1057           y_scale = loader->size->metrics->y_scale;
1058 
1059           /* compensate for any scaling by de/emboldening; */
1060           /* the amount was determined via experimentation */
1061           if ( x_scale_factor != 1000 && ppem > 11 )
1062           {
1063 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
1064             FT_Vector*  orig_points = outline->points;
1065 
1066 
1067             if ( !IS_DEFAULT_INSTANCE( FT_FACE( loader->face ) ) )
1068               outline->points = unrounded;
1069 #endif
1070             FT_Outline_EmboldenXY( outline,
1071                                    FT_MulFix( 1280 * ppem,
1072                                               1000 - x_scale_factor ),
1073                                    0 );
1074 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
1075             if ( !IS_DEFAULT_INSTANCE( FT_FACE( loader->face ) ) )
1076               outline->points = orig_points;
1077 #endif
1078           }
1079           do_scale = TRUE;
1080         }
1081       }
1082       else
1083 
1084 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
1085 
1086       {
1087         /* scale the glyph */
1088         if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
1089         {
1090           x_scale = loader->size->metrics->x_scale;
1091           y_scale = loader->size->metrics->y_scale;
1092 
1093           do_scale = TRUE;
1094         }
1095       }
1096 
1097       if ( do_scale )
1098       {
1099 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
1100         if ( !IS_DEFAULT_INSTANCE( FT_FACE( loader->face ) ) )
1101         {
1102           FT_Vector*  u = unrounded;
1103 
1104 
1105           for ( ; vec < limit; vec++, u++ )
1106           {
1107             vec->x = ( FT_MulFix( u->x, x_scale ) + 32 ) >> 6;
1108             vec->y = ( FT_MulFix( u->y, y_scale ) + 32 ) >> 6;
1109           }
1110         }
1111         else
1112 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
1113         {
1114           for ( ; vec < limit; vec++ )
1115           {
1116             vec->x = FT_MulFix( vec->x, x_scale );
1117             vec->y = FT_MulFix( vec->y, y_scale );
1118           }
1119         }
1120       }
1121 
1122 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
1123       /* if we have a HVAR table, `pp1' and/or `pp2' */
1124       /* are already adjusted but unscaled           */
1125       if ( ( loader->face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) &&
1126            IS_HINTED( loader->load_flags )                                 )
1127       {
1128         loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale );
1129         loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale );
1130         /* pp1.y and pp2.y are always zero */
1131       }
1132       else
1133 #endif
1134       {
1135         loader->pp1 = outline->points[n_points - 4];
1136         loader->pp2 = outline->points[n_points - 3];
1137       }
1138 
1139 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
1140       /* if we have a VVAR table, `pp3' and/or `pp4' */
1141       /* are already adjusted but unscaled           */
1142       if ( ( loader->face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) &&
1143            IS_HINTED( loader->load_flags )                                 )
1144       {
1145         loader->pp3.x = FT_MulFix( loader->pp3.x, x_scale );
1146         loader->pp3.y = FT_MulFix( loader->pp3.y, y_scale );
1147         loader->pp4.x = FT_MulFix( loader->pp4.x, x_scale );
1148         loader->pp4.y = FT_MulFix( loader->pp4.y, y_scale );
1149       }
1150       else
1151 #endif
1152       {
1153         loader->pp3 = outline->points[n_points - 2];
1154         loader->pp4 = outline->points[n_points - 1];
1155       }
1156     }
1157 
1158     if ( IS_HINTED( loader->load_flags ) )
1159     {
1160       loader->zone.n_points += 4;
1161 
1162       error = TT_Hint_Glyph( loader, 0 );
1163     }
1164 
1165 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
1166   Exit:
1167     FT_FREE( unrounded );
1168 #endif
1169 
1170     return error;
1171   }
1172 
1173 
1174   /**************************************************************************
1175    *
1176    * @Function:
1177    *   TT_Process_Composite_Component
1178    *
1179    * @Description:
1180    *   Once a composite component has been loaded, it needs to be
1181    *   processed.  Usually, this means transforming and translating.
1182    */
1183   static FT_Error
TT_Process_Composite_Component(TT_Loader loader,FT_SubGlyph subglyph,FT_UInt start_point,FT_UInt num_base_points)1184   TT_Process_Composite_Component( TT_Loader    loader,
1185                                   FT_SubGlyph  subglyph,
1186                                   FT_UInt      start_point,
1187                                   FT_UInt      num_base_points )
1188   {
1189     FT_GlyphLoader  gloader = loader->gloader;
1190     FT_Outline      current;
1191     FT_Bool         have_scale;
1192     FT_Pos          x, y;
1193 
1194 
1195     current.points   = gloader->base.outline.points +
1196                          num_base_points;
1197     current.n_points = gloader->base.outline.n_points -
1198                          (short)num_base_points;
1199 
1200     have_scale = FT_BOOL( subglyph->flags & ( WE_HAVE_A_SCALE     |
1201                                               WE_HAVE_AN_XY_SCALE |
1202                                               WE_HAVE_A_2X2       ) );
1203 
1204     /* perform the transform required for this subglyph */
1205     if ( have_scale )
1206       FT_Outline_Transform( &current, &subglyph->transform );
1207 
1208     /* get offset */
1209     if ( !( subglyph->flags & ARGS_ARE_XY_VALUES ) )
1210     {
1211       FT_UInt     num_points = (FT_UInt)gloader->base.outline.n_points;
1212       FT_UInt     k = (FT_UInt)subglyph->arg1;
1213       FT_UInt     l = (FT_UInt)subglyph->arg2;
1214       FT_Vector*  p1;
1215       FT_Vector*  p2;
1216 
1217 
1218       /* match l-th point of the newly loaded component to the k-th point */
1219       /* of the previously loaded components.                             */
1220 
1221       /* change to the point numbers used by our outline */
1222       k += start_point;
1223       l += num_base_points;
1224       if ( k >= num_base_points ||
1225            l >= num_points      )
1226         return FT_THROW( Invalid_Composite );
1227 
1228       p1 = gloader->base.outline.points + k;
1229       p2 = gloader->base.outline.points + l;
1230 
1231       x = p1->x - p2->x;
1232       y = p1->y - p2->y;
1233     }
1234     else
1235     {
1236       x = subglyph->arg1;
1237       y = subglyph->arg2;
1238 
1239       if ( !x && !y )
1240         return FT_Err_Ok;
1241 
1242       /* Use a default value dependent on                                  */
1243       /* TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED.  This is useful for old */
1244       /* TT fonts which don't set the xxx_COMPONENT_OFFSET bit.            */
1245 
1246       if ( have_scale &&
1247 #ifdef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED
1248            !( subglyph->flags & UNSCALED_COMPONENT_OFFSET ) )
1249 #else
1250             ( subglyph->flags & SCALED_COMPONENT_OFFSET ) )
1251 #endif
1252       {
1253 
1254 #if 0
1255 
1256         /********************************************************************
1257          *
1258          * This algorithm is what Apple documents.  But it doesn't work.
1259          */
1260         int  a = subglyph->transform.xx > 0 ?  subglyph->transform.xx
1261                                             : -subglyph->transform.xx;
1262         int  b = subglyph->transform.yx > 0 ?  subglyph->transform.yx
1263                                             : -subglyph->transform.yx;
1264         int  c = subglyph->transform.xy > 0 ?  subglyph->transform.xy
1265                                             : -subglyph->transform.xy;
1266         int  d = subglyph->transform.yy > 0 ?  subglyph->transform.yy
1267                                             : -subglyph->transform.yy;
1268         int  m = a > b ? a : b;
1269         int  n = c > d ? c : d;
1270 
1271 
1272         if ( a - b <= 33 && a - b >= -33 )
1273           m *= 2;
1274         if ( c - d <= 33 && c - d >= -33 )
1275           n *= 2;
1276         x = FT_MulFix( x, m );
1277         y = FT_MulFix( y, n );
1278 
1279 #else /* 1 */
1280 
1281         /********************************************************************
1282          *
1283          * This algorithm is a guess and works much better than the above.
1284          */
1285         FT_Fixed  mac_xscale = FT_Hypot( subglyph->transform.xx,
1286                                          subglyph->transform.xy );
1287         FT_Fixed  mac_yscale = FT_Hypot( subglyph->transform.yy,
1288                                          subglyph->transform.yx );
1289 
1290 
1291         x = FT_MulFix( x, mac_xscale );
1292         y = FT_MulFix( y, mac_yscale );
1293 
1294 #endif /* 1 */
1295 
1296       }
1297 
1298       if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) )
1299       {
1300         FT_Fixed  x_scale = loader->size->metrics->x_scale;
1301         FT_Fixed  y_scale = loader->size->metrics->y_scale;
1302 
1303 
1304         x = FT_MulFix( x, x_scale );
1305         y = FT_MulFix( y, y_scale );
1306 
1307         if ( subglyph->flags & ROUND_XY_TO_GRID )
1308         {
1309           TT_Face    face   = loader->face;
1310           TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( face );
1311 
1312 
1313           if ( IS_HINTED( loader->load_flags ) )
1314           {
1315             /*
1316              * We round the horizontal offset only if there is hinting along
1317              * the x axis; this corresponds to integer advance width values.
1318              *
1319              * Theoretically, a glyph's bytecode can toggle ClearType's
1320              * `backward compatibility' mode, which would allow modification
1321              * of the advance width.  In reality, however, applications
1322              * neither allow nor expect modified advance widths if subpixel
1323              * rendering is active.
1324              *
1325              */
1326             if ( driver->interpreter_version == TT_INTERPRETER_VERSION_35 )
1327               x = FT_PIX_ROUND( x );
1328 
1329             y = FT_PIX_ROUND( y );
1330           }
1331         }
1332       }
1333     }
1334 
1335     if ( x || y )
1336       FT_Outline_Translate( &current, x, y );
1337 
1338     return FT_Err_Ok;
1339   }
1340 
1341 
1342   /**************************************************************************
1343    *
1344    * @Function:
1345    *   TT_Process_Composite_Glyph
1346    *
1347    * @Description:
1348    *   This is slightly different from TT_Process_Simple_Glyph, in that
1349    *   its sole purpose is to hint the glyph.  Thus this function is
1350    *   only available when bytecode interpreter is enabled.
1351    */
1352   static FT_Error
TT_Process_Composite_Glyph(TT_Loader loader,FT_UInt start_point,FT_UInt start_contour)1353   TT_Process_Composite_Glyph( TT_Loader  loader,
1354                               FT_UInt    start_point,
1355                               FT_UInt    start_contour )
1356   {
1357     FT_Error     error;
1358     FT_Outline*  outline;
1359     FT_UInt      i;
1360 
1361 
1362     outline = &loader->gloader->base.outline;
1363 
1364     /* make room for phantom points */
1365     error = FT_GLYPHLOADER_CHECK_POINTS( loader->gloader,
1366                                          outline->n_points + 4,
1367                                          0 );
1368     if ( error )
1369       return error;
1370 
1371     outline->points[outline->n_points    ] = loader->pp1;
1372     outline->points[outline->n_points + 1] = loader->pp2;
1373     outline->points[outline->n_points + 2] = loader->pp3;
1374     outline->points[outline->n_points + 3] = loader->pp4;
1375 
1376     outline->tags[outline->n_points    ] = 0;
1377     outline->tags[outline->n_points + 1] = 0;
1378     outline->tags[outline->n_points + 2] = 0;
1379     outline->tags[outline->n_points + 3] = 0;
1380 
1381 #ifdef TT_USE_BYTECODE_INTERPRETER
1382 
1383     {
1384       FT_Stream  stream = loader->stream;
1385       FT_UShort  n_ins, max_ins;
1386       FT_ULong   tmp;
1387 
1388 
1389       /* TT_Load_Composite_Glyph only gives us the offset of instructions */
1390       /* so we read them here                                             */
1391       if ( FT_STREAM_SEEK( loader->ins_pos ) ||
1392            FT_READ_USHORT( n_ins )           )
1393         return error;
1394 
1395       FT_TRACE5(( "  Instructions size = %hu\n", n_ins ));
1396 
1397       /* check it */
1398       max_ins = loader->face->max_profile.maxSizeOfInstructions;
1399       if ( n_ins > max_ins )
1400       {
1401         /* don't trust `maxSizeOfInstructions'; */
1402         /* only do a rough safety check         */
1403         if ( n_ins > loader->byte_len )
1404         {
1405           FT_TRACE1(( "TT_Process_Composite_Glyph:"
1406                       " too many instructions (%hu) for glyph with length %u\n",
1407                       n_ins, loader->byte_len ));
1408           return FT_THROW( Too_Many_Hints );
1409         }
1410 
1411         tmp   = loader->exec->glyphSize;
1412         error = Update_Max( loader->exec->memory,
1413                             &tmp,
1414                             sizeof ( FT_Byte ),
1415                             (void*)&loader->exec->glyphIns,
1416                             n_ins );
1417 
1418         loader->exec->glyphSize = (FT_UShort)tmp;
1419         if ( error )
1420           return error;
1421       }
1422       else if ( n_ins == 0 )
1423         return FT_Err_Ok;
1424 
1425       if ( FT_STREAM_READ( loader->exec->glyphIns, n_ins ) )
1426         return error;
1427 
1428       loader->glyph->control_data = loader->exec->glyphIns;
1429       loader->glyph->control_len  = n_ins;
1430     }
1431 
1432 #endif
1433 
1434     tt_prepare_zone( &loader->zone, &loader->gloader->base,
1435                      start_point, start_contour );
1436 
1437     /* Some points are likely touched during execution of  */
1438     /* instructions on components.  So let's untouch them. */
1439     for ( i = 0; i < loader->zone.n_points; i++ )
1440       loader->zone.tags[i] &= ~FT_CURVE_TAG_TOUCH_BOTH;
1441 
1442     loader->zone.n_points += 4;
1443 
1444     return TT_Hint_Glyph( loader, 1 );
1445   }
1446 
1447 
1448   /*
1449    * Calculate the phantom points
1450    *
1451    * Defining the right side bearing (rsb) as
1452    *
1453    *   rsb = aw - (lsb + xmax - xmin)
1454    *
1455    * (with `aw' the advance width, `lsb' the left side bearing, and `xmin'
1456    * and `xmax' the glyph's minimum and maximum x value), the OpenType
1457    * specification defines the initial position of horizontal phantom points
1458    * as
1459    *
1460    *   pp1 = (round(xmin - lsb), 0)      ,
1461    *   pp2 = (round(pp1 + aw), 0)        .
1462    *
1463    * Note that the rounding to the grid (in the device space) is not
1464    * documented currently in the specification.
1465    *
1466    * However, the specification lacks the precise definition of vertical
1467    * phantom points.  Greg Hitchcock provided the following explanation.
1468    *
1469    * - a `vmtx' table is present
1470    *
1471    *   For any glyph, the minimum and maximum y values (`ymin' and `ymax')
1472    *   are given in the `glyf' table, the top side bearing (tsb) and advance
1473    *   height (ah) are given in the `vmtx' table.  The bottom side bearing
1474    *   (bsb) is then calculated as
1475    *
1476    *     bsb = ah - (tsb + ymax - ymin)       ,
1477    *
1478    *   and the initial position of vertical phantom points is
1479    *
1480    *     pp3 = (x, round(ymax + tsb))       ,
1481    *     pp4 = (x, round(pp3 - ah))         .
1482    *
1483    *   See below for value `x'.
1484    *
1485    * - no `vmtx' table in the font
1486    *
1487    *   If there is an `OS/2' table, we set
1488    *
1489    *     DefaultAscender = sTypoAscender       ,
1490    *     DefaultDescender = sTypoDescender     ,
1491    *
1492    *   otherwise we use data from the `hhea' table:
1493    *
1494    *     DefaultAscender = Ascender         ,
1495    *     DefaultDescender = Descender       .
1496    *
1497    *   With these two variables we can now set
1498    *
1499    *     ah = DefaultAscender - sDefaultDescender    ,
1500    *     tsb = DefaultAscender - yMax                ,
1501    *
1502    *   and proceed as if a `vmtx' table was present.
1503    *
1504    * Usually we have
1505    *
1506    *   x = aw / 2      ,                                                (1)
1507    *
1508    * but there is one compatibility case where it can be set to
1509    *
1510    *   x = -DefaultDescender -
1511    *         ((DefaultAscender - DefaultDescender - aw) / 2)     .      (2)
1512    *
1513    * and another one with
1514    *
1515    *   x = 0     .                                                      (3)
1516    *
1517    * In Windows, the history of those values is quite complicated,
1518    * depending on the hinting engine (that is, the graphics framework).
1519    *
1520    *   framework        from                 to       formula
1521    *  ----------------------------------------------------------
1522    *    GDI       Windows 98               current      (1)
1523    *              (Windows 2000 for NT)
1524    *    GDI+      Windows XP               Windows 7    (2)
1525    *    GDI+      Windows 8                current      (3)
1526    *    DWrite    Windows 7                current      (3)
1527    *
1528    * For simplicity, FreeType uses (1) for grayscale subpixel hinting and
1529    * (3) for everything else.
1530    *
1531    */
1532   static void
tt_loader_set_pp(TT_Loader loader)1533   tt_loader_set_pp( TT_Loader  loader )
1534   {
1535     FT_Bool  subpixel_hinting = 0;
1536     FT_Bool  grayscale        = 0;
1537     FT_Bool  use_aw_2         = 0;
1538 
1539 #ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING
1540     TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( loader->face );
1541 #endif
1542 
1543 
1544 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
1545     if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
1546     {
1547       subpixel_hinting = loader->exec ? loader->exec->subpixel_hinting
1548                                       : 0;
1549       grayscale        = loader->exec ? loader->exec->grayscale
1550                                       : 0;
1551     }
1552 #endif
1553 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
1554     if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 )
1555     {
1556       subpixel_hinting = loader->exec ? loader->exec->subpixel_hinting_lean
1557                                       : 0;
1558       grayscale        = loader->exec ? loader->exec->grayscale_cleartype
1559                                       : 0;
1560     }
1561 #endif
1562 
1563     use_aw_2 = FT_BOOL( subpixel_hinting && grayscale );
1564 
1565     loader->pp1.x = loader->bbox.xMin - loader->left_bearing;
1566     loader->pp1.y = 0;
1567     loader->pp2.x = loader->pp1.x + loader->advance;
1568     loader->pp2.y = 0;
1569 
1570     loader->pp3.x = use_aw_2 ? loader->advance / 2 : 0;
1571     loader->pp3.y = loader->bbox.yMax + loader->top_bearing;
1572     loader->pp4.x = use_aw_2 ? loader->advance / 2 : 0;
1573     loader->pp4.y = loader->pp3.y - loader->vadvance;
1574   }
1575 
1576 
1577   /* a utility function to retrieve i-th node from given FT_List */
1578   static FT_ListNode
ft_list_get_node_at(FT_List list,FT_UInt idx)1579   ft_list_get_node_at( FT_List  list,
1580                        FT_UInt  idx )
1581   {
1582     FT_ListNode  cur;
1583 
1584 
1585     if ( !list )
1586       return NULL;
1587 
1588     for ( cur = list->head; cur; cur = cur->next )
1589     {
1590       if ( !idx )
1591         return cur;
1592 
1593       idx--;
1594     }
1595 
1596     return NULL;
1597   }
1598 
1599 
1600   /**************************************************************************
1601    *
1602    * @Function:
1603    *   load_truetype_glyph
1604    *
1605    * @Description:
1606    *   Loads a given truetype glyph.  Handles composites and uses a
1607    *   TT_Loader object.
1608    */
1609   static FT_Error
load_truetype_glyph(TT_Loader loader,FT_UInt glyph_index,FT_UInt recurse_count,FT_Bool header_only)1610   load_truetype_glyph( TT_Loader  loader,
1611                        FT_UInt    glyph_index,
1612                        FT_UInt    recurse_count,
1613                        FT_Bool    header_only )
1614   {
1615     FT_Error        error   = FT_Err_Ok;
1616     FT_Fixed        x_scale, y_scale;
1617     FT_ULong        offset;
1618     TT_Face         face    = loader->face;
1619     FT_GlyphLoader  gloader = loader->gloader;
1620 
1621     FT_Bool  opened_frame = 0;
1622 
1623 #ifdef FT_CONFIG_OPTION_INCREMENTAL
1624     FT_StreamRec    inc_stream;
1625     FT_Data         glyph_data;
1626     FT_Bool         glyph_data_loaded = 0;
1627 #endif
1628 
1629 
1630 #ifdef FT_DEBUG_LEVEL_TRACE
1631     if ( recurse_count )
1632       FT_TRACE5(( "  nesting level: %d\n", recurse_count ));
1633 #endif
1634 
1635     /* some fonts have an incorrect value of `maxComponentDepth' */
1636     if ( recurse_count > face->max_profile.maxComponentDepth )
1637     {
1638       FT_TRACE1(( "load_truetype_glyph: maxComponentDepth set to %d\n",
1639                   recurse_count ));
1640       face->max_profile.maxComponentDepth = (FT_UShort)recurse_count;
1641     }
1642 
1643 #ifndef FT_CONFIG_OPTION_INCREMENTAL
1644     /* check glyph index */
1645     if ( glyph_index >= (FT_UInt)face->root.num_glyphs )
1646     {
1647       error = FT_THROW( Invalid_Glyph_Index );
1648       goto Exit;
1649     }
1650 #endif
1651 
1652     loader->glyph_index = glyph_index;
1653 
1654     if ( loader->load_flags & FT_LOAD_NO_SCALE )
1655     {
1656       x_scale = 0x10000L;
1657       y_scale = 0x10000L;
1658     }
1659     else
1660     {
1661       x_scale = loader->size->metrics->x_scale;
1662       y_scale = loader->size->metrics->y_scale;
1663     }
1664 
1665     /* Set `offset' to the start of the glyph relative to the start of */
1666     /* the `glyf' table, and `byte_len' to the length of the glyph in  */
1667     /* bytes.                                                          */
1668 
1669 #ifdef FT_CONFIG_OPTION_INCREMENTAL
1670 
1671     /* If we are loading glyph data via the incremental interface, set */
1672     /* the loader stream to a memory stream reading the data returned  */
1673     /* by the interface.                                               */
1674     if ( face->root.internal->incremental_interface )
1675     {
1676       error = face->root.internal->incremental_interface->funcs->get_glyph_data(
1677                 face->root.internal->incremental_interface->object,
1678                 glyph_index, &glyph_data );
1679       if ( error )
1680         goto Exit;
1681 
1682       glyph_data_loaded = 1;
1683       offset            = 0;
1684       loader->byte_len  = glyph_data.length;
1685 
1686       FT_ZERO( &inc_stream );
1687       FT_Stream_OpenMemory( &inc_stream,
1688                             glyph_data.pointer,
1689                             glyph_data.length );
1690 
1691       loader->stream = &inc_stream;
1692     }
1693     else
1694 
1695 #endif /* FT_CONFIG_OPTION_INCREMENTAL */
1696 
1697       offset = tt_face_get_location( face, glyph_index, &loader->byte_len );
1698 
1699     if ( loader->byte_len > 0 )
1700     {
1701 #ifdef FT_CONFIG_OPTION_INCREMENTAL
1702       /* for the incremental interface, `glyf_offset' is always zero */
1703       if ( !face->glyf_offset                          &&
1704            !face->root.internal->incremental_interface )
1705 #else
1706       if ( !face->glyf_offset )
1707 #endif /* FT_CONFIG_OPTION_INCREMENTAL */
1708       {
1709         FT_TRACE2(( "no `glyf' table but non-zero `loca' entry\n" ));
1710         error = FT_THROW( Invalid_Table );
1711         goto Exit;
1712       }
1713 
1714       error = face->access_glyph_frame( loader, glyph_index,
1715                                         face->glyf_offset + offset,
1716                                         loader->byte_len );
1717       if ( error )
1718         goto Exit;
1719 
1720       /* read glyph header first */
1721       error = face->read_glyph_header( loader );
1722 
1723       face->forget_glyph_frame( loader );
1724 
1725       if ( error )
1726         goto Exit;
1727     }
1728 
1729     /* a space glyph */
1730     if ( loader->byte_len == 0 || loader->n_contours == 0 )
1731     {
1732       loader->bbox.xMin = 0;
1733       loader->bbox.xMax = 0;
1734       loader->bbox.yMin = 0;
1735       loader->bbox.yMax = 0;
1736     }
1737 
1738     /* the metrics must be computed after loading the glyph header */
1739     /* since we need the glyph's `yMax' value in case the vertical */
1740     /* metrics must be emulated                                    */
1741     error = tt_get_metrics( loader, glyph_index );
1742     if ( error )
1743       goto Exit;
1744 
1745     if ( header_only )
1746       goto Exit;
1747 
1748     if ( loader->byte_len == 0 || loader->n_contours == 0 )
1749     {
1750 #ifdef FT_CONFIG_OPTION_INCREMENTAL
1751       tt_get_metrics_incremental( loader, glyph_index );
1752 #endif
1753       tt_loader_set_pp( loader );
1754 
1755 
1756 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
1757 
1758       if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) ||
1759            FT_IS_VARIATION( FT_FACE( face ) )      )
1760       {
1761         /* a small outline structure with four elements for */
1762         /* communication with `TT_Vary_Apply_Glyph_Deltas'  */
1763         FT_Vector   points[4];
1764         char        tags[4]     = { 1, 1, 1, 1 };
1765         short       contours[4] = { 0, 1, 2, 3 };
1766         FT_Outline  outline;
1767 
1768         /* unrounded values */
1769         FT_Vector  unrounded[4] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
1770 
1771 
1772         points[0].x = loader->pp1.x;
1773         points[0].y = loader->pp1.y;
1774         points[1].x = loader->pp2.x;
1775         points[1].y = loader->pp2.y;
1776 
1777         points[2].x = loader->pp3.x;
1778         points[2].y = loader->pp3.y;
1779         points[3].x = loader->pp4.x;
1780         points[3].y = loader->pp4.y;
1781 
1782         outline.n_points   = 4;
1783         outline.n_contours = 4;
1784         outline.points     = points;
1785         outline.tags       = tags;
1786         outline.contours   = contours;
1787 
1788         /* this must be done before scaling */
1789         error = TT_Vary_Apply_Glyph_Deltas( loader->face,
1790                                             glyph_index,
1791                                             &outline,
1792                                             unrounded,
1793                                             (FT_UInt)outline.n_points );
1794         if ( error )
1795           goto Exit;
1796 
1797         loader->pp1.x = points[0].x;
1798         loader->pp1.y = points[0].y;
1799         loader->pp2.x = points[1].x;
1800         loader->pp2.y = points[1].y;
1801 
1802         loader->pp3.x = points[2].x;
1803         loader->pp3.y = points[2].y;
1804         loader->pp4.x = points[3].x;
1805         loader->pp4.y = points[3].y;
1806 
1807         /* recalculate linear horizontal and vertical advances */
1808         /* if we don't have HVAR and VVAR, respectively        */
1809         if ( !( loader->face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) )
1810           loader->linear = FT_PIX_ROUND( unrounded[1].x -
1811                                          unrounded[0].x ) / 64;
1812         if ( !( loader->face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) )
1813           loader->vadvance = FT_PIX_ROUND( unrounded[3].x -
1814                                            unrounded[2].x ) / 64;
1815       }
1816 
1817 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
1818 
1819       /* scale phantom points, if necessary; */
1820       /* they get rounded in `TT_Hint_Glyph' */
1821       if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
1822       {
1823         loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale );
1824         loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale );
1825         /* pp1.y and pp2.y are always zero */
1826 
1827         loader->pp3.x = FT_MulFix( loader->pp3.x, x_scale );
1828         loader->pp3.y = FT_MulFix( loader->pp3.y, y_scale );
1829         loader->pp4.x = FT_MulFix( loader->pp4.x, x_scale );
1830         loader->pp4.y = FT_MulFix( loader->pp4.y, y_scale );
1831       }
1832 
1833       error = FT_Err_Ok;
1834       goto Exit;
1835     }
1836 
1837 #ifdef FT_CONFIG_OPTION_INCREMENTAL
1838     tt_get_metrics_incremental( loader, glyph_index );
1839 #endif
1840     tt_loader_set_pp( loader );
1841 
1842 
1843     /***********************************************************************/
1844     /***********************************************************************/
1845     /***********************************************************************/
1846 
1847     /* we now open a frame again, right after the glyph header */
1848     /* (which consists of 10 bytes)                            */
1849     error = face->access_glyph_frame( loader, glyph_index,
1850                                       face->glyf_offset + offset + 10,
1851                                       loader->byte_len - 10 );
1852     if ( error )
1853       goto Exit;
1854 
1855     opened_frame = 1;
1856 
1857     /* if it is a simple glyph, load it */
1858 
1859     if ( loader->n_contours > 0 )
1860     {
1861       error = face->read_simple_glyph( loader );
1862       if ( error )
1863         goto Exit;
1864 
1865       /* all data have been read */
1866       face->forget_glyph_frame( loader );
1867       opened_frame = 0;
1868 
1869       error = TT_Process_Simple_Glyph( loader );
1870       if ( error )
1871         goto Exit;
1872 
1873       FT_GlyphLoader_Add( gloader );
1874     }
1875 
1876     /***********************************************************************/
1877     /***********************************************************************/
1878     /***********************************************************************/
1879 
1880     /* otherwise, load a composite! */
1881     else if ( loader->n_contours < 0 )
1882     {
1883       FT_Memory  memory = face->root.memory;
1884 
1885       FT_UInt   start_point;
1886       FT_UInt   start_contour;
1887       FT_ULong  ins_pos;  /* position of composite instructions, if any */
1888 
1889       FT_ListNode  node, node2;
1890 
1891 
1892       /* normalize the `n_contours' value */
1893       loader->n_contours = -1;
1894 
1895       /*
1896        * We store the glyph index directly in the `node->data' pointer,
1897        * following the glib solution (cf. macro `GUINT_TO_POINTER') with a
1898        * double cast to make this portable.  Note, however, that this needs
1899        * pointers with a width of at least 32 bits.
1900        */
1901 
1902       /* clear the nodes filled by sibling chains */
1903       node = ft_list_get_node_at( &loader->composites, recurse_count );
1904       for ( node2 = node; node2; node2 = node2->next )
1905         node2->data = (void*)-1;
1906 
1907       /* check whether we already have a composite glyph with this index */
1908       if ( FT_List_Find( &loader->composites,
1909                          FT_UINT_TO_POINTER( glyph_index ) ) )
1910       {
1911         FT_TRACE1(( "TT_Load_Composite_Glyph:"
1912                     " infinite recursion detected\n" ));
1913         error = FT_THROW( Invalid_Composite );
1914         goto Exit;
1915       }
1916 
1917       else if ( node )
1918         node->data = FT_UINT_TO_POINTER( glyph_index );
1919 
1920       else
1921       {
1922         if ( FT_QNEW( node ) )
1923           goto Exit;
1924         node->data = FT_UINT_TO_POINTER( glyph_index );
1925         FT_List_Add( &loader->composites, node );
1926       }
1927 
1928       start_point   = (FT_UInt)gloader->base.outline.n_points;
1929       start_contour = (FT_UInt)gloader->base.outline.n_contours;
1930 
1931       /* for each subglyph, read composite header */
1932       error = face->read_composite_glyph( loader );
1933       if ( error )
1934         goto Exit;
1935 
1936       /* store the offset of instructions */
1937       ins_pos = loader->ins_pos;
1938 
1939       /* all data we need are read */
1940       face->forget_glyph_frame( loader );
1941       opened_frame = 0;
1942 
1943 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
1944 
1945       if ( FT_IS_NAMED_INSTANCE( FT_FACE( face ) ) ||
1946            FT_IS_VARIATION( FT_FACE( face ) )      )
1947       {
1948         short        i, limit;
1949         FT_SubGlyph  subglyph;
1950 
1951         /* Fix CVE-2025-27363 */
1952         FT_Outline  outline = { 0, 0, NULL, NULL, NULL, 0 };
1953         FT_Vector*  points    = NULL;
1954         char*       tags      = NULL;
1955         short*      contours  = NULL;
1956         FT_Vector*  unrounded = NULL;
1957 
1958 
1959         limit = (short)gloader->current.num_subglyphs;
1960 
1961         /* Fix CVE-2025-27363 */
1962         if ( limit < 0 )
1963         {
1964           error = FT_THROW( Invalid_Argument );
1965           goto Exit;
1966         }
1967 
1968         /* construct an outline structure for              */
1969         /* communication with `TT_Vary_Apply_Glyph_Deltas' */
1970         outline.n_points   = (short)( gloader->current.num_subglyphs + 4 );
1971         outline.n_contours = outline.n_points;
1972 
1973         outline.points   = NULL;
1974         outline.tags     = NULL;
1975         outline.contours = NULL;
1976 
1977         if ( FT_NEW_ARRAY( points, outline.n_points )    ||
1978              FT_NEW_ARRAY( tags, outline.n_points )      ||
1979              FT_NEW_ARRAY( contours, outline.n_points )  ||
1980              FT_NEW_ARRAY( unrounded, outline.n_points ) )
1981           goto Exit1;
1982 
1983         subglyph = gloader->current.subglyphs;
1984 
1985         for ( i = 0; i < limit; i++, subglyph++ )
1986         {
1987           /* applying deltas for anchor points doesn't make sense, */
1988           /* but we don't have to specially check this since       */
1989           /* unused delta values are zero anyways                  */
1990           points[i].x = subglyph->arg1;
1991           points[i].y = subglyph->arg2;
1992           tags[i]     = 1;
1993           contours[i] = i;
1994         }
1995 
1996         points[i].x = loader->pp1.x;
1997         points[i].y = loader->pp1.y;
1998         tags[i]     = 1;
1999         contours[i] = i;
2000 
2001         i++;
2002         points[i].x = loader->pp2.x;
2003         points[i].y = loader->pp2.y;
2004         tags[i]     = 1;
2005         contours[i] = i;
2006 
2007         i++;
2008         points[i].x = loader->pp3.x;
2009         points[i].y = loader->pp3.y;
2010         tags[i]     = 1;
2011         contours[i] = i;
2012 
2013         i++;
2014         points[i].x = loader->pp4.x;
2015         points[i].y = loader->pp4.y;
2016         tags[i]     = 1;
2017         contours[i] = i;
2018 
2019         outline.points   = points;
2020         outline.tags     = tags;
2021         outline.contours = contours;
2022 
2023         /* this call provides additional offsets */
2024         /* for each component's translation      */
2025         if ( FT_SET_ERROR( TT_Vary_Apply_Glyph_Deltas(
2026                              face,
2027                              glyph_index,
2028                              &outline,
2029                              unrounded,
2030                              (FT_UInt)outline.n_points ) ) )
2031           goto Exit1;
2032 
2033         subglyph = gloader->current.subglyphs;
2034 
2035         for ( i = 0; i < limit; i++, subglyph++ )
2036         {
2037           if ( subglyph->flags & ARGS_ARE_XY_VALUES )
2038           {
2039             subglyph->arg1 = (FT_Int16)points[i].x;
2040             subglyph->arg2 = (FT_Int16)points[i].y;
2041           }
2042         }
2043 
2044         loader->pp1.x = points[i + 0].x;
2045         loader->pp1.y = points[i + 0].y;
2046         loader->pp2.x = points[i + 1].x;
2047         loader->pp2.y = points[i + 1].y;
2048 
2049         loader->pp3.x = points[i + 2].x;
2050         loader->pp3.y = points[i + 2].y;
2051         loader->pp4.x = points[i + 3].x;
2052         loader->pp4.y = points[i + 3].y;
2053 
2054         /* recalculate linear horizontal and vertical advances */
2055         /* if we don't have HVAR and VVAR, respectively        */
2056         if ( !( face->variation_support & TT_FACE_FLAG_VAR_HADVANCE ) )
2057           loader->linear =
2058             FT_PIX_ROUND( unrounded[outline.n_points - 3].x -
2059                           unrounded[outline.n_points - 4].x ) / 64;
2060         if ( !( face->variation_support & TT_FACE_FLAG_VAR_VADVANCE ) )
2061           loader->vadvance =
2062             FT_PIX_ROUND( unrounded[outline.n_points - 1].x -
2063                           unrounded[outline.n_points - 2].x ) / 64;
2064 
2065       Exit1:
2066         FT_FREE( outline.points );
2067         FT_FREE( outline.tags );
2068         FT_FREE( outline.contours );
2069         FT_FREE( unrounded );
2070 
2071         if ( error )
2072           goto Exit;
2073       }
2074 
2075 #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
2076 
2077       /* scale phantom points, if necessary; */
2078       /* they get rounded in `TT_Hint_Glyph' */
2079       if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
2080       {
2081         loader->pp1.x = FT_MulFix( loader->pp1.x, x_scale );
2082         loader->pp2.x = FT_MulFix( loader->pp2.x, x_scale );
2083         /* pp1.y and pp2.y are always zero */
2084 
2085         loader->pp3.x = FT_MulFix( loader->pp3.x, x_scale );
2086         loader->pp3.y = FT_MulFix( loader->pp3.y, y_scale );
2087         loader->pp4.x = FT_MulFix( loader->pp4.x, x_scale );
2088         loader->pp4.y = FT_MulFix( loader->pp4.y, y_scale );
2089       }
2090 
2091       /* if the flag FT_LOAD_NO_RECURSE is set, we return the subglyph */
2092       /* `as is' in the glyph slot (the client application will be     */
2093       /* responsible for interpreting these data)...                   */
2094       if ( loader->load_flags & FT_LOAD_NO_RECURSE )
2095       {
2096         FT_GlyphLoader_Add( gloader );
2097         loader->glyph->format = FT_GLYPH_FORMAT_COMPOSITE;
2098 
2099         goto Exit;
2100       }
2101 
2102       /*********************************************************************/
2103       /*********************************************************************/
2104       /*********************************************************************/
2105 
2106       {
2107         FT_UInt      n, num_base_points;
2108         FT_SubGlyph  subglyph       = NULL;
2109 
2110         FT_UInt      num_points     = start_point;
2111         FT_UInt      num_subglyphs  = gloader->current.num_subglyphs;
2112         FT_UInt      num_base_subgs = gloader->base.num_subglyphs;
2113 
2114         FT_Stream    old_stream     = loader->stream;
2115         FT_UInt      old_byte_len   = loader->byte_len;
2116 
2117 
2118         FT_GlyphLoader_Add( gloader );
2119 
2120         /* read each subglyph independently */
2121         for ( n = 0; n < num_subglyphs; n++ )
2122         {
2123           FT_Vector  pp[4];
2124 
2125           FT_Int  linear_hadvance;
2126           FT_Int  linear_vadvance;
2127 
2128 
2129           /* Each time we call `load_truetype_glyph' in this loop, the */
2130           /* value of `gloader.base.subglyphs' can change due to table */
2131           /* reallocations.  We thus need to recompute the subglyph    */
2132           /* pointer on each iteration.                                */
2133           subglyph = gloader->base.subglyphs + num_base_subgs + n;
2134 
2135           pp[0] = loader->pp1;
2136           pp[1] = loader->pp2;
2137           pp[2] = loader->pp3;
2138           pp[3] = loader->pp4;
2139 
2140           linear_hadvance = loader->linear;
2141           linear_vadvance = loader->vadvance;
2142 
2143           num_base_points = (FT_UInt)gloader->base.outline.n_points;
2144 
2145           error = load_truetype_glyph( loader,
2146                                        (FT_UInt)subglyph->index,
2147                                        recurse_count + 1,
2148                                        FALSE );
2149           if ( error )
2150             goto Exit;
2151 
2152           /* restore subglyph pointer */
2153           subglyph = gloader->base.subglyphs + num_base_subgs + n;
2154 
2155           /* restore phantom points if necessary */
2156           if ( !( subglyph->flags & USE_MY_METRICS ) )
2157           {
2158             loader->pp1 = pp[0];
2159             loader->pp2 = pp[1];
2160             loader->pp3 = pp[2];
2161             loader->pp4 = pp[3];
2162 
2163             loader->linear   = linear_hadvance;
2164             loader->vadvance = linear_vadvance;
2165           }
2166 
2167           num_points = (FT_UInt)gloader->base.outline.n_points;
2168 
2169           if ( num_points == num_base_points )
2170             continue;
2171 
2172           /* gloader->base.outline consists of three parts:           */
2173           /*                                                          */
2174           /* 0 ----> start_point ----> num_base_points ----> n_points */
2175           /*    (1)               (2)                   (3)           */
2176           /*                                                          */
2177           /* (1) points that exist from the beginning                 */
2178           /* (2) component points that have been loaded so far        */
2179           /* (3) points of the newly loaded component                 */
2180           error = TT_Process_Composite_Component( loader,
2181                                                   subglyph,
2182                                                   start_point,
2183                                                   num_base_points );
2184           if ( error )
2185             goto Exit;
2186         }
2187 
2188         loader->stream   = old_stream;
2189         loader->byte_len = old_byte_len;
2190 
2191         /* process the glyph */
2192         loader->ins_pos = ins_pos;
2193         if ( IS_HINTED( loader->load_flags ) &&
2194 #ifdef TT_USE_BYTECODE_INTERPRETER
2195              subglyph                        &&
2196              subglyph->flags & WE_HAVE_INSTR &&
2197 #endif
2198              num_points > start_point )
2199         {
2200           error = TT_Process_Composite_Glyph( loader,
2201                                               start_point,
2202                                               start_contour );
2203           if ( error )
2204             goto Exit;
2205         }
2206       }
2207 
2208       /* retain the overlap flag */
2209       if ( gloader->base.num_subglyphs                         &&
2210            gloader->base.subglyphs[0].flags & OVERLAP_COMPOUND )
2211         gloader->base.outline.flags |= FT_OUTLINE_OVERLAP;
2212     }
2213 
2214     /***********************************************************************/
2215     /***********************************************************************/
2216     /***********************************************************************/
2217 
2218   Exit:
2219 
2220     if ( opened_frame )
2221       face->forget_glyph_frame( loader );
2222 
2223 #ifdef FT_CONFIG_OPTION_INCREMENTAL
2224 
2225     if ( glyph_data_loaded )
2226       face->root.internal->incremental_interface->funcs->free_glyph_data(
2227         face->root.internal->incremental_interface->object,
2228         &glyph_data );
2229 
2230 #endif
2231 
2232     return error;
2233   }
2234 
2235 
2236   static FT_Error
compute_glyph_metrics(TT_Loader loader,FT_UInt glyph_index)2237   compute_glyph_metrics( TT_Loader  loader,
2238                          FT_UInt    glyph_index )
2239   {
2240     TT_Face    face   = loader->face;
2241 #if defined TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY || \
2242     defined TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
2243     TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( face );
2244 #endif
2245 
2246     FT_BBox       bbox;
2247     FT_Fixed      y_scale;
2248     TT_GlyphSlot  glyph = loader->glyph;
2249     TT_Size       size  = loader->size;
2250 
2251 
2252     y_scale = 0x10000L;
2253     if ( ( loader->load_flags & FT_LOAD_NO_SCALE ) == 0 )
2254       y_scale = size->metrics->y_scale;
2255 
2256     if ( glyph->format != FT_GLYPH_FORMAT_COMPOSITE )
2257       FT_Outline_Get_CBox( &glyph->outline, &bbox );
2258     else
2259       bbox = loader->bbox;
2260 
2261     /* get the device-independent horizontal advance; it is scaled later */
2262     /* by the base layer.                                                */
2263     glyph->linearHoriAdvance = loader->linear;
2264 
2265     glyph->metrics.horiBearingX = bbox.xMin;
2266     glyph->metrics.horiBearingY = bbox.yMax;
2267     glyph->metrics.horiAdvance  = SUB_LONG(loader->pp2.x, loader->pp1.x);
2268 
2269     /* Adjust advance width to the value contained in the hdmx table   */
2270     /* unless FT_LOAD_COMPUTE_METRICS is set or backward compatibility */
2271     /* mode of the v40 interpreter is active.  See `ttinterp.h' for    */
2272     /* details on backward compatibility mode.                         */
2273     if (
2274 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
2275          !( driver->interpreter_version == TT_INTERPRETER_VERSION_40  &&
2276             ( loader->exec && loader->exec->backward_compatibility  ) ) &&
2277 #endif
2278          !face->postscript.isFixedPitch                                 &&
2279          IS_HINTED( loader->load_flags )                                &&
2280          !( loader->load_flags & FT_LOAD_COMPUTE_METRICS )              )
2281     {
2282       FT_Byte*  widthp;
2283 
2284 
2285       widthp = tt_face_get_device_metrics( face,
2286                                            size->metrics->x_ppem,
2287                                            glyph_index );
2288 
2289 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
2290 
2291       if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
2292       {
2293         FT_Bool  ignore_x_mode;
2294 
2295 
2296         ignore_x_mode = FT_BOOL( FT_LOAD_TARGET_MODE( loader->load_flags ) !=
2297                                  FT_RENDER_MODE_MONO );
2298 
2299         if ( widthp                                                   &&
2300              ( ( ignore_x_mode && loader->exec->compatible_widths ) ||
2301                 !ignore_x_mode                                      ||
2302                 SPH_OPTION_BITMAP_WIDTHS                            ) )
2303           glyph->metrics.horiAdvance = *widthp * 64;
2304       }
2305       else
2306 
2307 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
2308 
2309       {
2310         if ( widthp )
2311           glyph->metrics.horiAdvance = *widthp * 64;
2312       }
2313     }
2314 
2315     /* set glyph dimensions */
2316     glyph->metrics.width  = SUB_LONG( bbox.xMax, bbox.xMin );
2317     glyph->metrics.height = SUB_LONG( bbox.yMax, bbox.yMin );
2318 
2319     /* Now take care of vertical metrics.  In the case where there is */
2320     /* no vertical information within the font (relatively common),   */
2321     /* create some metrics manually                                   */
2322     {
2323       FT_Pos  top;      /* scaled vertical top side bearing  */
2324       FT_Pos  advance;  /* scaled vertical advance height    */
2325 
2326 
2327       /* Get the unscaled top bearing and advance height. */
2328       if ( face->vertical_info                   &&
2329            face->vertical.number_Of_VMetrics > 0 )
2330       {
2331         top = (FT_Short)FT_DivFix( SUB_LONG( loader->pp3.y, bbox.yMax ),
2332                                    y_scale );
2333 
2334         if ( loader->pp3.y <= loader->pp4.y )
2335           advance = 0;
2336         else
2337           advance = (FT_UShort)FT_DivFix( SUB_LONG( loader->pp3.y,
2338                                                     loader->pp4.y ),
2339                                           y_scale );
2340       }
2341       else
2342       {
2343         FT_Pos  height;
2344 
2345 
2346         /* XXX Compute top side bearing and advance height in  */
2347         /*     Get_VMetrics instead of here.                   */
2348 
2349         /* NOTE: The OS/2 values are the only `portable' ones, */
2350         /*       which is why we use them, if there is an OS/2 */
2351         /*       table in the font.  Otherwise, we use the     */
2352         /*       values defined in the horizontal header.      */
2353 
2354         height = (FT_Short)FT_DivFix( SUB_LONG( bbox.yMax,
2355                                                 bbox.yMin ),
2356                                       y_scale );
2357         if ( face->os2.version != 0xFFFFU )
2358           advance = (FT_Pos)( face->os2.sTypoAscender -
2359                               face->os2.sTypoDescender );
2360         else
2361           advance = (FT_Pos)( face->horizontal.Ascender -
2362                               face->horizontal.Descender );
2363 
2364         top = ( advance - height ) / 2;
2365       }
2366 
2367 #ifdef FT_CONFIG_OPTION_INCREMENTAL
2368       {
2369         FT_Incremental_InterfaceRec*  incr;
2370         FT_Incremental_MetricsRec     incr_metrics;
2371         FT_Error                      error;
2372 
2373 
2374         incr = face->root.internal->incremental_interface;
2375 
2376         /* If this is an incrementally loaded font see if there are */
2377         /* overriding metrics for this glyph.                       */
2378         if ( incr && incr->funcs->get_glyph_metrics )
2379         {
2380           incr_metrics.bearing_x = 0;
2381           incr_metrics.bearing_y = top;
2382           incr_metrics.advance   = advance;
2383 
2384           error = incr->funcs->get_glyph_metrics( incr->object,
2385                                                   glyph_index,
2386                                                   TRUE,
2387                                                   &incr_metrics );
2388           if ( error )
2389             return error;
2390 
2391           top     = incr_metrics.bearing_y;
2392           advance = incr_metrics.advance;
2393         }
2394       }
2395 
2396       /* GWW: Do vertical metrics get loaded incrementally too? */
2397 
2398 #endif /* FT_CONFIG_OPTION_INCREMENTAL */
2399 
2400       glyph->linearVertAdvance = advance;
2401 
2402       /* scale the metrics */
2403       if ( !( loader->load_flags & FT_LOAD_NO_SCALE ) )
2404       {
2405         top     = FT_MulFix( top,     y_scale );
2406         advance = FT_MulFix( advance, y_scale );
2407       }
2408 
2409       /* XXX: for now, we have no better algorithm for the lsb, but it */
2410       /*      should work fine.                                        */
2411       /*                                                               */
2412       glyph->metrics.vertBearingX = SUB_LONG( glyph->metrics.horiBearingX,
2413                                               glyph->metrics.horiAdvance / 2 );
2414       glyph->metrics.vertBearingY = top;
2415       glyph->metrics.vertAdvance  = advance;
2416     }
2417 
2418     return FT_Err_Ok;
2419   }
2420 
2421 
2422 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
2423 
2424   static FT_Error
load_sbit_image(TT_Size size,TT_GlyphSlot glyph,FT_UInt glyph_index,FT_Int32 load_flags)2425   load_sbit_image( TT_Size       size,
2426                    TT_GlyphSlot  glyph,
2427                    FT_UInt       glyph_index,
2428                    FT_Int32      load_flags )
2429   {
2430     TT_Face             face;
2431     SFNT_Service        sfnt;
2432     FT_Stream           stream;
2433     FT_Error            error;
2434     TT_SBit_MetricsRec  sbit_metrics;
2435 
2436 
2437     face   = (TT_Face)glyph->face;
2438     sfnt   = (SFNT_Service)face->sfnt;
2439     stream = face->root.stream;
2440 
2441     error = sfnt->load_sbit_image( face,
2442                                    size->strike_index,
2443                                    glyph_index,
2444                                    (FT_UInt)load_flags,
2445                                    stream,
2446                                    &glyph->bitmap,
2447                                    &sbit_metrics );
2448     if ( !error )
2449     {
2450       glyph->outline.n_points   = 0;
2451       glyph->outline.n_contours = 0;
2452 
2453       glyph->metrics.width  = (FT_Pos)sbit_metrics.width  * 64;
2454       glyph->metrics.height = (FT_Pos)sbit_metrics.height * 64;
2455 
2456       glyph->metrics.horiBearingX = (FT_Pos)sbit_metrics.horiBearingX * 64;
2457       glyph->metrics.horiBearingY = (FT_Pos)sbit_metrics.horiBearingY * 64;
2458       glyph->metrics.horiAdvance  = (FT_Pos)sbit_metrics.horiAdvance  * 64;
2459 
2460       glyph->metrics.vertBearingX = (FT_Pos)sbit_metrics.vertBearingX * 64;
2461       glyph->metrics.vertBearingY = (FT_Pos)sbit_metrics.vertBearingY * 64;
2462       glyph->metrics.vertAdvance  = (FT_Pos)sbit_metrics.vertAdvance  * 64;
2463 
2464       glyph->format = FT_GLYPH_FORMAT_BITMAP;
2465 
2466       if ( load_flags & FT_LOAD_VERTICAL_LAYOUT )
2467       {
2468         glyph->bitmap_left = sbit_metrics.vertBearingX;
2469         glyph->bitmap_top  = sbit_metrics.vertBearingY;
2470       }
2471       else
2472       {
2473         glyph->bitmap_left = sbit_metrics.horiBearingX;
2474         glyph->bitmap_top  = sbit_metrics.horiBearingY;
2475       }
2476     }
2477 
2478     return error;
2479   }
2480 
2481 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
2482 
2483 
2484   static FT_Error
tt_loader_init(TT_Loader loader,TT_Size size,TT_GlyphSlot glyph,FT_Int32 load_flags,FT_Bool glyf_table_only)2485   tt_loader_init( TT_Loader     loader,
2486                   TT_Size       size,
2487                   TT_GlyphSlot  glyph,
2488                   FT_Int32      load_flags,
2489                   FT_Bool       glyf_table_only )
2490   {
2491     TT_Face    face;
2492     FT_Stream  stream;
2493 
2494 #ifdef TT_USE_BYTECODE_INTERPRETER
2495     FT_Error   error;
2496     FT_Bool    pedantic = FT_BOOL( load_flags & FT_LOAD_PEDANTIC );
2497 #if defined TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY || \
2498     defined TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
2499     TT_Driver  driver = (TT_Driver)FT_FACE_DRIVER( (TT_Face)glyph->face );
2500 #endif
2501 #endif
2502 
2503 
2504     face   = (TT_Face)glyph->face;
2505     stream = face->root.stream;
2506 
2507     FT_ZERO( loader );
2508 
2509 #ifdef TT_USE_BYTECODE_INTERPRETER
2510 
2511     /* load execution context */
2512     if ( IS_HINTED( load_flags ) && !glyf_table_only )
2513     {
2514       TT_ExecContext  exec;
2515       FT_Bool         grayscale = TRUE;
2516 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
2517       FT_Bool         subpixel_hinting_lean;
2518       FT_Bool         grayscale_cleartype;
2519 #endif
2520 
2521 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
2522       FT_Bool  subpixel_hinting = FALSE;
2523 
2524 #if 0
2525       /* not used yet */
2526       FT_Bool  compatible_widths;
2527       FT_Bool  symmetrical_smoothing;
2528       FT_Bool  bgr;
2529       FT_Bool  vertical_lcd;
2530       FT_Bool  subpixel_positioned;
2531       FT_Bool  gray_cleartype;
2532 #endif
2533 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
2534 
2535       FT_Bool  reexecute = FALSE;
2536 
2537 
2538       if ( size->bytecode_ready < 0 || size->cvt_ready < 0 )
2539       {
2540         error = tt_size_ready_bytecode( size, pedantic );
2541         if ( error )
2542           return error;
2543       }
2544       else if ( size->bytecode_ready )
2545         return size->bytecode_ready;
2546       else if ( size->cvt_ready )
2547         return size->cvt_ready;
2548 
2549       /* query new execution context */
2550       exec = size->context;
2551       if ( !exec )
2552         return FT_THROW( Could_Not_Find_Context );
2553 
2554 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
2555       if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 )
2556       {
2557         subpixel_hinting_lean =
2558           FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
2559                    FT_RENDER_MODE_MONO               );
2560         grayscale_cleartype =
2561           FT_BOOL( subpixel_hinting_lean         &&
2562                    !( ( load_flags         &
2563                         FT_LOAD_TARGET_LCD )   ||
2564                       ( load_flags           &
2565                         FT_LOAD_TARGET_LCD_V ) ) );
2566         exec->vertical_lcd_lean =
2567           FT_BOOL( subpixel_hinting_lean    &&
2568                    ( load_flags           &
2569                      FT_LOAD_TARGET_LCD_V ) );
2570       }
2571       else
2572       {
2573         subpixel_hinting_lean   = FALSE;
2574         grayscale_cleartype     = FALSE;
2575         exec->vertical_lcd_lean = FALSE;
2576       }
2577 #endif
2578 
2579 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
2580 
2581       if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
2582       {
2583         subpixel_hinting = FT_BOOL( ( FT_LOAD_TARGET_MODE( load_flags ) !=
2584                                       FT_RENDER_MODE_MONO               )  &&
2585                                     SPH_OPTION_SET_SUBPIXEL                );
2586 
2587         if ( subpixel_hinting )
2588           grayscale = FALSE;
2589         else if ( SPH_OPTION_SET_GRAYSCALE )
2590         {
2591           grayscale        = TRUE;
2592           subpixel_hinting = FALSE;
2593         }
2594         else
2595           grayscale = FALSE;
2596 
2597         if ( FT_IS_TRICKY( glyph->face ) )
2598           subpixel_hinting = FALSE;
2599 
2600         exec->ignore_x_mode      = subpixel_hinting || grayscale;
2601         exec->rasterizer_version = SPH_OPTION_SET_RASTERIZER_VERSION;
2602         if ( exec->sph_tweak_flags & SPH_TWEAK_RASTERIZER_35 )
2603           exec->rasterizer_version = TT_INTERPRETER_VERSION_35;
2604 
2605 #if 1
2606         exec->compatible_widths     = SPH_OPTION_SET_COMPATIBLE_WIDTHS;
2607         exec->symmetrical_smoothing = TRUE;
2608         exec->bgr                   = FALSE;
2609         exec->vertical_lcd          = FALSE;
2610         exec->subpixel_positioned   = TRUE;
2611         exec->gray_cleartype        = FALSE;
2612 #else /* 0 */
2613         exec->compatible_widths =
2614           FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
2615                    TT_LOAD_COMPATIBLE_WIDTHS );
2616         exec->symmetrical_smoothing =
2617           FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
2618                    TT_LOAD_SYMMETRICAL_SMOOTHING );
2619         exec->bgr =
2620           FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
2621                    TT_LOAD_BGR );
2622         exec->vertical_lcd =
2623           FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
2624                    TT_LOAD_VERTICAL_LCD );
2625         exec->subpixel_positioned =
2626           FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
2627                    TT_LOAD_SUBPIXEL_POSITIONED );
2628         exec->gray_cleartype =
2629           FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
2630                    TT_LOAD_GRAY_CLEARTYPE );
2631 #endif /* 0 */
2632 
2633       }
2634       else
2635 
2636 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
2637 
2638 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
2639       if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 )
2640         grayscale = FT_BOOL( !subpixel_hinting_lean               &&
2641                              FT_LOAD_TARGET_MODE( load_flags ) !=
2642                                FT_RENDER_MODE_MONO                );
2643       else
2644 #endif
2645         grayscale = FT_BOOL( FT_LOAD_TARGET_MODE( load_flags ) !=
2646                                FT_RENDER_MODE_MONO             );
2647 
2648       error = TT_Load_Context( exec, face, size );
2649       if ( error )
2650         return error;
2651 
2652 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
2653 
2654       if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 )
2655       {
2656         /* a change from mono to subpixel rendering (and vice versa) */
2657         /* requires a re-execution of the CVT program                */
2658         if ( subpixel_hinting != exec->subpixel_hinting )
2659         {
2660           FT_TRACE4(( "tt_loader_init: subpixel hinting change,"
2661                       " re-executing `prep' table\n" ));
2662 
2663           exec->subpixel_hinting = subpixel_hinting;
2664           reexecute              = TRUE;
2665         }
2666 
2667         /* a change from mono to grayscale rendering (and vice versa) */
2668         /* requires a re-execution of the CVT program                 */
2669         if ( grayscale != exec->grayscale )
2670         {
2671           FT_TRACE4(( "tt_loader_init: grayscale hinting change,"
2672                       " re-executing `prep' table\n" ));
2673 
2674           exec->grayscale = grayscale;
2675           reexecute       = TRUE;
2676         }
2677       }
2678       else
2679 
2680 #endif /* TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY */
2681 
2682       {
2683 
2684 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL
2685         if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 )
2686         {
2687           /* a change from mono to subpixel rendering (and vice versa) */
2688           /* requires a re-execution of the CVT program                */
2689           if ( subpixel_hinting_lean != exec->subpixel_hinting_lean )
2690           {
2691             FT_TRACE4(( "tt_loader_init: subpixel hinting change,"
2692                         " re-executing `prep' table\n" ));
2693 
2694             exec->subpixel_hinting_lean = subpixel_hinting_lean;
2695             reexecute                   = TRUE;
2696           }
2697 
2698           /* a change from colored to grayscale subpixel rendering (and */
2699           /* vice versa) requires a re-execution of the CVT program     */
2700           if ( grayscale_cleartype != exec->grayscale_cleartype )
2701           {
2702             FT_TRACE4(( "tt_loader_init: grayscale subpixel hinting change,"
2703                         " re-executing `prep' table\n" ));
2704 
2705             exec->grayscale_cleartype = grayscale_cleartype;
2706             reexecute                 = TRUE;
2707           }
2708         }
2709 #endif
2710 
2711         /* a change from mono to grayscale rendering (and vice versa) */
2712         /* requires a re-execution of the CVT program                 */
2713         if ( grayscale != exec->grayscale )
2714         {
2715           FT_TRACE4(( "tt_loader_init: grayscale hinting change,"
2716                       " re-executing `prep' table\n" ));
2717 
2718           exec->grayscale = grayscale;
2719           reexecute       = TRUE;
2720         }
2721       }
2722 
2723       if ( reexecute )
2724       {
2725         error = tt_size_run_prep( size, pedantic );
2726         if ( error )
2727           return error;
2728         error = TT_Load_Context( exec, face, size );
2729         if ( error )
2730           return error;
2731       }
2732 
2733       /* check whether the cvt program has disabled hinting */
2734       if ( exec->GS.instruct_control & 1 )
2735         load_flags |= FT_LOAD_NO_HINTING;
2736 
2737       /* load default graphics state -- if needed */
2738       if ( exec->GS.instruct_control & 2 )
2739         exec->GS = tt_default_graphics_state;
2740 
2741 #ifdef TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY
2742       /* check whether we have a font hinted for ClearType --           */
2743       /* note that this flag can also be modified in a glyph's bytecode */
2744       if ( driver->interpreter_version == TT_INTERPRETER_VERSION_38 &&
2745            exec->GS.instruct_control & 4                            )
2746         exec->ignore_x_mode = 0;
2747 #endif
2748 
2749       exec->pedantic_hinting = FT_BOOL( load_flags & FT_LOAD_PEDANTIC );
2750       loader->exec = exec;
2751       loader->instructions = exec->glyphIns;
2752     }
2753 
2754 #endif /* TT_USE_BYTECODE_INTERPRETER */
2755 
2756     /* get face's glyph loader */
2757     if ( !glyf_table_only )
2758     {
2759       FT_GlyphLoader  gloader = glyph->internal->loader;
2760 
2761 
2762       FT_GlyphLoader_Rewind( gloader );
2763       loader->gloader = gloader;
2764     }
2765 
2766     loader->load_flags = (FT_ULong)load_flags;
2767 
2768     loader->face   = face;
2769     loader->size   = size;
2770     loader->glyph  = (FT_GlyphSlot)glyph;
2771     loader->stream = stream;
2772 
2773     loader->composites.head = NULL;
2774     loader->composites.tail = NULL;
2775 
2776     return FT_Err_Ok;
2777   }
2778 
2779 
2780   static void
tt_loader_done(TT_Loader loader)2781   tt_loader_done( TT_Loader  loader )
2782   {
2783     FT_List_Finalize( &loader->composites,
2784                       NULL,
2785                       loader->face->root.memory,
2786                       NULL );
2787   }
2788 
2789 
2790   /**************************************************************************
2791    *
2792    * @Function:
2793    *   TT_Load_Glyph
2794    *
2795    * @Description:
2796    *   A function used to load a single glyph within a given glyph slot,
2797    *   for a given size.
2798    *
2799    * @Input:
2800    *   glyph ::
2801    *     A handle to a target slot object where the glyph
2802    *     will be loaded.
2803    *
2804    *   size ::
2805    *     A handle to the source face size at which the glyph
2806    *     must be scaled/loaded.
2807    *
2808    *   glyph_index ::
2809    *     The index of the glyph in the font file.
2810    *
2811    *   load_flags ::
2812    *     A flag indicating what to load for this glyph.  The
2813    *     FT_LOAD_XXX constants can be used to control the
2814    *     glyph loading process (e.g., whether the outline
2815    *     should be scaled, whether to load bitmaps or not,
2816    *     whether to hint the outline, etc).
2817    *
2818    * @Return:
2819    *   FreeType error code.  0 means success.
2820    */
2821   FT_LOCAL_DEF( FT_Error )
TT_Load_Glyph(TT_Size size,TT_GlyphSlot glyph,FT_UInt glyph_index,FT_Int32 load_flags)2822   TT_Load_Glyph( TT_Size       size,
2823                  TT_GlyphSlot  glyph,
2824                  FT_UInt       glyph_index,
2825                  FT_Int32      load_flags )
2826   {
2827     FT_Error      error;
2828     TT_LoaderRec  loader;
2829 
2830 
2831     FT_TRACE1(( "TT_Load_Glyph: glyph index %d\n", glyph_index ));
2832 
2833 #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
2834 
2835     /* try to load embedded bitmap (if any) */
2836     if ( size->strike_index != 0xFFFFFFFFUL      &&
2837          ( load_flags & FT_LOAD_NO_BITMAP ) == 0 &&
2838          IS_DEFAULT_INSTANCE( glyph->face )      )
2839     {
2840       FT_Fixed  x_scale = size->root.metrics.x_scale;
2841       FT_Fixed  y_scale = size->root.metrics.y_scale;
2842 
2843 
2844       error = load_sbit_image( size, glyph, glyph_index, load_flags );
2845       if ( FT_ERR_EQ( error, Missing_Bitmap ) )
2846       {
2847         /* the bitmap strike is incomplete and misses the requested glyph; */
2848         /* if we have a bitmap-only font, return an empty glyph            */
2849         if ( !FT_IS_SCALABLE( glyph->face ) )
2850         {
2851           TT_Face  face = (TT_Face)glyph->face;
2852 
2853           FT_Short  left_bearing = 0;
2854           FT_Short  top_bearing  = 0;
2855 
2856           FT_UShort  advance_width  = 0;
2857           FT_UShort  advance_height = 0;
2858 
2859 
2860           /* to return an empty glyph, however, we need metrics data   */
2861           /* from the `hmtx' (or `vmtx') table; the assumption is that */
2862           /* empty glyphs are missing intentionally, representing      */
2863           /* whitespace - not having at least horizontal metrics is    */
2864           /* thus considered an error                                  */
2865           if ( !face->horz_metrics_size )
2866             return error;
2867 
2868           /* we now construct an empty bitmap glyph */
2869           TT_Get_HMetrics( face, glyph_index,
2870                            &left_bearing,
2871                            &advance_width );
2872           TT_Get_VMetrics( face, glyph_index,
2873                            0,
2874                            &top_bearing,
2875                            &advance_height );
2876 
2877           glyph->outline.n_points   = 0;
2878           glyph->outline.n_contours = 0;
2879 
2880           glyph->metrics.width  = 0;
2881           glyph->metrics.height = 0;
2882 
2883           glyph->metrics.horiBearingX = FT_MulFix( left_bearing, x_scale );
2884           glyph->metrics.horiBearingY = 0;
2885           glyph->metrics.horiAdvance  = FT_MulFix( advance_width, x_scale );
2886 
2887           glyph->metrics.vertBearingX = 0;
2888           glyph->metrics.vertBearingY = FT_MulFix( top_bearing, y_scale );
2889           glyph->metrics.vertAdvance  = FT_MulFix( advance_height, y_scale );
2890 
2891           glyph->format            = FT_GLYPH_FORMAT_BITMAP;
2892           glyph->bitmap.pixel_mode = FT_PIXEL_MODE_MONO;
2893 
2894           glyph->bitmap_left = 0;
2895           glyph->bitmap_top  = 0;
2896 
2897           return FT_Err_Ok;
2898         }
2899       }
2900       else if ( error )
2901       {
2902         /* return error if font is not scalable */
2903         if ( !FT_IS_SCALABLE( glyph->face ) )
2904           return error;
2905       }
2906       else
2907       {
2908         if ( FT_IS_SCALABLE( glyph->face ) )
2909         {
2910           /* for the bbox we need the header only */
2911           (void)tt_loader_init( &loader, size, glyph, load_flags, TRUE );
2912           (void)load_truetype_glyph( &loader, glyph_index, 0, TRUE );
2913           tt_loader_done( &loader );
2914           glyph->linearHoriAdvance = loader.linear;
2915           glyph->linearVertAdvance = loader.vadvance;
2916 
2917           /* sanity checks: if `xxxAdvance' in the sbit metric */
2918           /* structure isn't set, use `linearXXXAdvance'      */
2919           if ( !glyph->metrics.horiAdvance && glyph->linearHoriAdvance )
2920             glyph->metrics.horiAdvance = FT_MulFix( glyph->linearHoriAdvance,
2921                                                     x_scale );
2922           if ( !glyph->metrics.vertAdvance && glyph->linearVertAdvance )
2923             glyph->metrics.vertAdvance = FT_MulFix( glyph->linearVertAdvance,
2924                                                     y_scale );
2925         }
2926 
2927         return FT_Err_Ok;
2928       }
2929     }
2930 
2931 #endif /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
2932 
2933     /* if FT_LOAD_NO_SCALE is not set, `ttmetrics' must be valid */
2934     if ( !( load_flags & FT_LOAD_NO_SCALE ) && !size->ttmetrics.valid )
2935     {
2936       error = FT_THROW( Invalid_Size_Handle );
2937       goto Exit;
2938     }
2939 
2940     if ( load_flags & FT_LOAD_SBITS_ONLY )
2941     {
2942       error = FT_THROW( Invalid_Argument );
2943       goto Exit;
2944     }
2945 
2946     error = tt_loader_init( &loader, size, glyph, load_flags, FALSE );
2947     if ( error )
2948       goto Exit;
2949 
2950     glyph->format        = FT_GLYPH_FORMAT_OUTLINE;
2951     glyph->num_subglyphs = 0;
2952     glyph->outline.flags = 0;
2953 
2954     /* main loading loop */
2955     error = load_truetype_glyph( &loader, glyph_index, 0, FALSE );
2956     if ( !error )
2957     {
2958       if ( glyph->format == FT_GLYPH_FORMAT_COMPOSITE )
2959       {
2960         glyph->num_subglyphs = loader.gloader->base.num_subglyphs;
2961         glyph->subglyphs     = loader.gloader->base.subglyphs;
2962       }
2963       else
2964       {
2965         glyph->outline        = loader.gloader->base.outline;
2966         glyph->outline.flags &= ~FT_OUTLINE_SINGLE_PASS;
2967 
2968         /* Translate array so that (0,0) is the glyph's origin.  Note  */
2969         /* that this behaviour is independent on the value of bit 1 of */
2970         /* the `flags' field in the `head' table -- at least major     */
2971         /* applications like Acroread indicate that.                   */
2972         if ( loader.pp1.x )
2973           FT_Outline_Translate( &glyph->outline, -loader.pp1.x, 0 );
2974       }
2975 
2976 #ifdef TT_USE_BYTECODE_INTERPRETER
2977 
2978       if ( IS_HINTED( load_flags ) )
2979       {
2980         if ( loader.exec->GS.scan_control )
2981         {
2982           /* convert scan conversion mode to FT_OUTLINE_XXX flags */
2983           switch ( loader.exec->GS.scan_type )
2984           {
2985           case 0: /* simple drop-outs including stubs */
2986             glyph->outline.flags |= FT_OUTLINE_INCLUDE_STUBS;
2987             break;
2988           case 1: /* simple drop-outs excluding stubs */
2989             /* nothing; it's the default rendering mode */
2990             break;
2991           case 4: /* smart drop-outs including stubs */
2992             glyph->outline.flags |= FT_OUTLINE_SMART_DROPOUTS |
2993                                     FT_OUTLINE_INCLUDE_STUBS;
2994             break;
2995           case 5: /* smart drop-outs excluding stubs  */
2996             glyph->outline.flags |= FT_OUTLINE_SMART_DROPOUTS;
2997             break;
2998 
2999           default: /* no drop-out control */
3000             glyph->outline.flags |= FT_OUTLINE_IGNORE_DROPOUTS;
3001             break;
3002           }
3003         }
3004         else
3005           glyph->outline.flags |= FT_OUTLINE_IGNORE_DROPOUTS;
3006       }
3007 
3008 #endif /* TT_USE_BYTECODE_INTERPRETER */
3009 
3010       error = compute_glyph_metrics( &loader, glyph_index );
3011     }
3012 
3013     /* Set the `high precision' bit flag.                           */
3014     /* This is _critical_ to get correct output for monochrome      */
3015     /* TrueType glyphs at all sizes using the bytecode interpreter. */
3016     /*                                                              */
3017     if ( !( load_flags & FT_LOAD_NO_SCALE ) &&
3018          size->metrics->y_ppem < 24         )
3019       glyph->outline.flags |= FT_OUTLINE_HIGH_PRECISION;
3020 
3021     FT_TRACE1(( "  subglyphs = %u, contours = %hd, points = %hd,"
3022                 " flags = 0x%.3x\n",
3023                 loader.gloader->base.num_subglyphs,
3024                 glyph->outline.n_contours,
3025                 glyph->outline.n_points,
3026                 glyph->outline.flags ));
3027 
3028     tt_loader_done( &loader );
3029 
3030   Exit:
3031 #ifdef FT_DEBUG_LEVEL_TRACE
3032     if ( error )
3033       FT_TRACE1(( "  failed (error code 0x%x)\n",
3034                   error ));
3035 #endif
3036 
3037     return error;
3038   }
3039 
3040 
3041 /* END */
3042