• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  *
3  * ttcolr.c
4  *
5  *   TrueType and OpenType colored glyph layer support (body).
6  *
7  * Copyright (C) 2018-2021 by
8  * David Turner, Robert Wilhelm, Dominik Röttsches, and Werner Lemberg.
9  *
10  * Originally written by Shao Yu Zhang <shaozhang@fb.com>.
11  *
12  * This file is part of the FreeType project, and may only be used,
13  * modified, and distributed under the terms of the FreeType project
14  * license, LICENSE.TXT.  By continuing to use, modify, or distribute
15  * this file you indicate that you have read the license and
16  * understand and accept it fully.
17  *
18  */
19 
20 
21   /**************************************************************************
22    *
23    * `COLR' table specification:
24    *
25    *   https://www.microsoft.com/typography/otspec/colr.htm
26    *
27    */
28 
29 
30 #include <freetype/internal/ftcalc.h>
31 #include <freetype/internal/ftdebug.h>
32 #include <freetype/internal/ftstream.h>
33 #include <freetype/tttags.h>
34 #include <freetype/ftcolor.h>
35 #include <freetype/config/integer-types.h>
36 
37 
38 #ifdef TT_CONFIG_OPTION_COLOR_LAYERS
39 
40 #include "ttcolr.h"
41 
42 
43   /* NOTE: These are the table sizes calculated through the specs. */
44 #define BASE_GLYPH_SIZE                   6U
45 #define BASE_GLYPH_PAINT_RECORD_SIZE      6U
46 #define LAYER_V1_LIST_PAINT_OFFSET_SIZE   4U
47 #define LAYER_V1_LIST_NUM_LAYERS_SIZE     4U
48 #define COLOR_STOP_SIZE                   6U
49 #define LAYER_SIZE                        4U
50 #define COLR_HEADER_SIZE                 14U
51 
52 
53   typedef enum  FT_PaintFormat_Internal_
54   {
55     FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER         = 18,
56     FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM        = 20,
57     FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER = 22,
58     FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER        = 26,
59     FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER          = 30
60 
61   } FT_PaintFormat_Internal;
62 
63 
64   typedef struct  BaseGlyphRecord_
65   {
66     FT_UShort  gid;
67     FT_UShort  first_layer_index;
68     FT_UShort  num_layers;
69 
70   } BaseGlyphRecord;
71 
72 
73   typedef struct  BaseGlyphV1Record_
74   {
75     FT_UShort  gid;
76     /* Offset from start of BaseGlyphV1List, i.e., from base_glyphs_v1. */
77     FT_ULong   paint_offset;
78 
79   } BaseGlyphV1Record;
80 
81 
82   typedef struct  Colr_
83   {
84     FT_UShort  version;
85     FT_UShort  num_base_glyphs;
86     FT_UShort  num_layers;
87 
88     FT_Byte*  base_glyphs;
89     FT_Byte*  layers;
90 
91     FT_ULong  num_base_glyphs_v1;
92     /* Points at beginning of BaseGlyphV1List. */
93     FT_Byte*  base_glyphs_v1;
94 
95     FT_ULong  num_layers_v1;
96     FT_Byte*  layers_v1;
97 
98     FT_Byte*  clip_list;
99 
100     /*
101      * Paint tables start at the minimum of the end of the LayerList and the
102      * end of the BaseGlyphList.  Record this location in a field here for
103      * safety checks when accessing paint tables.
104      */
105     FT_Byte*  paints_start_v1;
106 
107     /* The memory that backs up the `COLR' table. */
108     void*     table;
109     FT_ULong  table_size;
110 
111   } Colr;
112 
113 
114   /**************************************************************************
115    *
116    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
117    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
118    * messages during execution.
119    */
120 #undef  FT_COMPONENT
121 #define FT_COMPONENT  ttcolr
122 
123 
124   FT_LOCAL_DEF( FT_Error )
tt_face_load_colr(TT_Face face,FT_Stream stream)125   tt_face_load_colr( TT_Face    face,
126                      FT_Stream  stream )
127   {
128     FT_Error   error;
129     FT_Memory  memory = face->root.memory;
130 
131     FT_Byte*  table = NULL;
132     FT_Byte*  p     = NULL;
133     /* Needed for reading array lengths in referenced tables. */
134     FT_Byte*  p1    = NULL;
135 
136     Colr*  colr = NULL;
137 
138     FT_ULong  base_glyph_offset, layer_offset;
139     FT_ULong  base_glyphs_offset_v1, num_base_glyphs_v1;
140     FT_ULong  layer_offset_v1, num_layers_v1, clip_list_offset;
141     FT_ULong  table_size;
142 
143 
144     /* `COLR' always needs `CPAL' */
145     if ( !face->cpal )
146       return FT_THROW( Invalid_File_Format );
147 
148     error = face->goto_table( face, TTAG_COLR, stream, &table_size );
149     if ( error )
150       goto NoColr;
151 
152     if ( table_size < COLR_HEADER_SIZE )
153       goto InvalidTable;
154 
155     if ( FT_FRAME_EXTRACT( table_size, table ) )
156       goto NoColr;
157 
158     p = table;
159 
160     if ( FT_NEW( colr ) )
161       goto NoColr;
162 
163     colr->version = FT_NEXT_USHORT( p );
164     if ( colr->version != 0 && colr->version != 1 )
165       goto InvalidTable;
166 
167     colr->num_base_glyphs = FT_NEXT_USHORT( p );
168     base_glyph_offset     = FT_NEXT_ULONG( p );
169 
170     if ( base_glyph_offset >= table_size )
171       goto InvalidTable;
172     if ( colr->num_base_glyphs * BASE_GLYPH_SIZE >
173            table_size - base_glyph_offset )
174       goto InvalidTable;
175 
176     layer_offset     = FT_NEXT_ULONG( p );
177     colr->num_layers = FT_NEXT_USHORT( p );
178 
179     if ( layer_offset >= table_size )
180       goto InvalidTable;
181     if ( colr->num_layers * LAYER_SIZE > table_size - layer_offset )
182       goto InvalidTable;
183 
184     if ( colr->version == 1 )
185     {
186       base_glyphs_offset_v1 = FT_NEXT_ULONG( p );
187 
188       if ( base_glyphs_offset_v1 >= table_size )
189         goto InvalidTable;
190 
191       p1                 = (FT_Byte*)( table + base_glyphs_offset_v1 );
192       num_base_glyphs_v1 = FT_PEEK_ULONG( p1 );
193 
194       if ( num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE >
195              table_size - base_glyphs_offset_v1 )
196         goto InvalidTable;
197 
198       colr->num_base_glyphs_v1 = num_base_glyphs_v1;
199       colr->base_glyphs_v1     = p1;
200 
201       layer_offset_v1 = FT_NEXT_ULONG( p );
202 
203       if ( layer_offset_v1 >= table_size )
204         goto InvalidTable;
205 
206       if ( layer_offset_v1 )
207       {
208         p1            = (FT_Byte*)( table + layer_offset_v1 );
209         num_layers_v1 = FT_PEEK_ULONG( p1 );
210 
211         if ( num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE >
212                table_size - layer_offset_v1 )
213           goto InvalidTable;
214 
215         colr->num_layers_v1 = num_layers_v1;
216         colr->layers_v1     = p1;
217 
218         colr->paints_start_v1 =
219             FT_MIN( colr->base_glyphs_v1 +
220                     colr->num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE,
221                     colr->layers_v1 +
222                     colr->num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE );
223       }
224       else
225       {
226         colr->num_layers_v1   = 0;
227         colr->layers_v1       = 0;
228         colr->paints_start_v1 =
229           colr->base_glyphs_v1 +
230           colr->num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE;
231       }
232 
233       clip_list_offset = FT_NEXT_ULONG( p );
234 
235       if ( clip_list_offset >= table_size )
236         goto InvalidTable;
237 
238       if ( clip_list_offset )
239         colr->clip_list = (FT_Byte*)( table + clip_list_offset );
240       else
241         colr->clip_list = 0;
242     }
243 
244     colr->base_glyphs = (FT_Byte*)( table + base_glyph_offset );
245     colr->layers      = (FT_Byte*)( table + layer_offset      );
246     colr->table       = table;
247     colr->table_size  = table_size;
248 
249     face->colr = colr;
250 
251     return FT_Err_Ok;
252 
253   InvalidTable:
254     error = FT_THROW( Invalid_Table );
255 
256   NoColr:
257     FT_FRAME_RELEASE( table );
258     FT_FREE( colr );
259 
260     return error;
261   }
262 
263 
264   FT_LOCAL_DEF( void )
tt_face_free_colr(TT_Face face)265   tt_face_free_colr( TT_Face  face )
266   {
267     FT_Stream  stream = face->root.stream;
268     FT_Memory  memory = face->root.memory;
269 
270     Colr*  colr = (Colr*)face->colr;
271 
272 
273     if ( colr )
274     {
275       FT_FRAME_RELEASE( colr->table );
276       FT_FREE( colr );
277     }
278   }
279 
280 
281   static FT_Bool
find_base_glyph_record(FT_Byte * base_glyph_begin,FT_UInt num_base_glyph,FT_UInt glyph_id,BaseGlyphRecord * record)282   find_base_glyph_record( FT_Byte*          base_glyph_begin,
283                           FT_UInt           num_base_glyph,
284                           FT_UInt           glyph_id,
285                           BaseGlyphRecord*  record )
286   {
287     FT_UInt  min = 0;
288     FT_UInt  max = num_base_glyph;
289 
290 
291     while ( min < max )
292     {
293       FT_UInt   mid = min + ( max - min ) / 2;
294       FT_Byte*  p   = base_glyph_begin + mid * BASE_GLYPH_SIZE;
295 
296       FT_UShort  gid = FT_NEXT_USHORT( p );
297 
298 
299       if ( gid < glyph_id )
300         min = mid + 1;
301       else if (gid > glyph_id )
302         max = mid;
303       else
304       {
305         record->gid               = gid;
306         record->first_layer_index = FT_NEXT_USHORT( p );
307         record->num_layers        = FT_NEXT_USHORT( p );
308 
309         return 1;
310       }
311     }
312 
313     return 0;
314   }
315 
316 
317   FT_LOCAL_DEF( FT_Bool )
tt_face_get_colr_layer(TT_Face face,FT_UInt base_glyph,FT_UInt * aglyph_index,FT_UInt * acolor_index,FT_LayerIterator * iterator)318   tt_face_get_colr_layer( TT_Face            face,
319                           FT_UInt            base_glyph,
320                           FT_UInt           *aglyph_index,
321                           FT_UInt           *acolor_index,
322                           FT_LayerIterator*  iterator )
323   {
324     Colr*            colr = (Colr*)face->colr;
325     BaseGlyphRecord  glyph_record;
326 
327 
328     if ( !colr )
329       return 0;
330 
331     if ( !iterator->p )
332     {
333       FT_ULong  offset;
334 
335 
336       /* first call to function */
337       iterator->layer = 0;
338 
339       if ( !find_base_glyph_record( colr->base_glyphs,
340                                     colr->num_base_glyphs,
341                                     base_glyph,
342                                     &glyph_record ) )
343         return 0;
344 
345       if ( glyph_record.num_layers )
346         iterator->num_layers = glyph_record.num_layers;
347       else
348         return 0;
349 
350       offset = LAYER_SIZE * glyph_record.first_layer_index;
351       if ( offset + LAYER_SIZE * glyph_record.num_layers > colr->table_size )
352         return 0;
353 
354       iterator->p = colr->layers + offset;
355     }
356 
357     if ( iterator->layer >= iterator->num_layers )
358       return 0;
359 
360     *aglyph_index = FT_NEXT_USHORT( iterator->p );
361     *acolor_index = FT_NEXT_USHORT( iterator->p );
362 
363     if ( *aglyph_index >= (FT_UInt)( FT_FACE( face )->num_glyphs )   ||
364          ( *acolor_index != 0xFFFF                                 &&
365            *acolor_index >= face->palette_data.num_palette_entries ) )
366       return 0;
367 
368     iterator->layer++;
369 
370     return 1;
371   }
372 
373 
374   static FT_Bool
read_color_line(FT_Byte * color_line_p,FT_ColorLine * colorline)375   read_color_line( FT_Byte*      color_line_p,
376                    FT_ColorLine  *colorline )
377   {
378     FT_Byte*        p = color_line_p;
379     FT_PaintExtend  paint_extend;
380 
381 
382     paint_extend = (FT_PaintExtend)FT_NEXT_BYTE( p );
383     if ( paint_extend > FT_COLR_PAINT_EXTEND_REFLECT )
384       return 0;
385 
386     colorline->extend = paint_extend;
387 
388     colorline->color_stop_iterator.num_color_stops    = FT_NEXT_USHORT( p );
389     colorline->color_stop_iterator.p                  = p;
390     colorline->color_stop_iterator.current_color_stop = 0;
391 
392     return 1;
393   }
394 
395 
396   /*
397    * Read a paint offset for `FT_Paint*` objects that have them and check
398    * whether it is within reasonable limits within the font and the COLR
399    * table.
400    *
401    * Return 1 on success, 0 on failure.
402    */
403   static FT_Bool
get_child_table_pointer(Colr * colr,FT_Byte * paint_base,FT_Byte ** p,FT_Byte ** child_table_pointer)404   get_child_table_pointer ( Colr*      colr,
405                             FT_Byte*   paint_base,
406                             FT_Byte**  p,
407                             FT_Byte**  child_table_pointer )
408   {
409     FT_UInt32  paint_offset;
410     FT_Byte*   child_table_p;
411 
412 
413     if ( !child_table_pointer )
414       return 0;
415 
416     paint_offset = FT_NEXT_UOFF3( *p );
417     if ( !paint_offset )
418       return 0;
419 
420     child_table_p = (FT_Byte*)( paint_base + paint_offset );
421 
422     if ( child_table_p < colr->paints_start_v1                         ||
423          child_table_p >= ( (FT_Byte*)colr->table + colr->table_size ) )
424       return 0;
425 
426     *child_table_pointer = child_table_p;
427     return 1;
428   }
429 
430 
431   static FT_Bool
read_paint(Colr * colr,FT_Byte * p,FT_COLR_Paint * apaint)432   read_paint( Colr*           colr,
433               FT_Byte*        p,
434               FT_COLR_Paint*  apaint )
435   {
436     FT_Byte*  paint_base     = p;
437     FT_Byte*  child_table_p  = NULL;
438 
439 
440     if ( !p || !colr || !colr->table )
441       return 0;
442 
443     if ( p < colr->paints_start_v1                         ||
444          p >= ( (FT_Byte*)colr->table + colr->table_size ) )
445       return 0;
446 
447     apaint->format = (FT_PaintFormat)FT_NEXT_BYTE( p );
448 
449     if ( apaint->format >= FT_COLR_PAINT_FORMAT_MAX )
450       return 0;
451 
452     if ( apaint->format == FT_COLR_PAINTFORMAT_COLR_LAYERS )
453     {
454       /* Initialize layer iterator/ */
455       FT_Byte    num_layers;
456       FT_UInt32  first_layer_index;
457 
458 
459       num_layers = FT_NEXT_BYTE( p );
460       if ( num_layers > colr->num_layers_v1 )
461         return 0;
462 
463       first_layer_index = FT_NEXT_ULONG( p );
464       if ( first_layer_index + num_layers > colr->num_layers_v1 )
465         return 0;
466 
467       apaint->u.colr_layers.layer_iterator.num_layers = num_layers;
468       apaint->u.colr_layers.layer_iterator.layer      = 0;
469       /* TODO: Check whether pointer is outside colr? */
470       apaint->u.colr_layers.layer_iterator.p =
471         colr->layers_v1 +
472         LAYER_V1_LIST_NUM_LAYERS_SIZE +
473         LAYER_V1_LIST_PAINT_OFFSET_SIZE * first_layer_index;
474 
475       return 1;
476     }
477 
478     else if ( apaint->format == FT_COLR_PAINTFORMAT_SOLID )
479     {
480       apaint->u.solid.color.palette_index = FT_NEXT_USHORT( p );
481       apaint->u.solid.color.alpha         = FT_NEXT_SHORT( p );
482 
483       return 1;
484     }
485 
486     else if ( apaint->format == FT_COLR_PAINTFORMAT_COLR_GLYPH )
487     {
488       apaint->u.colr_glyph.glyphID = FT_NEXT_USHORT( p );
489 
490       return 1;
491     }
492 
493     /*
494      * Grouped below here are all paint formats that have an offset to a
495      * child paint table as the first entry (for example, a color line or a
496      * child paint table).  Retrieve that and determine whether that paint
497      * offset is valid first.
498      */
499 
500     if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) )
501       return 0;
502 
503     if ( apaint->format == FT_COLR_PAINTFORMAT_LINEAR_GRADIENT )
504     {
505       if ( !read_color_line( child_table_p,
506                              &apaint->u.linear_gradient.colorline ) )
507         return 0;
508 
509       /*
510        * In order to support variations expose these as FT_Fixed 16.16 values so
511        * that we can support fractional values after interpolation.
512        */
513       apaint->u.linear_gradient.p0.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
514       apaint->u.linear_gradient.p0.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
515       apaint->u.linear_gradient.p1.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
516       apaint->u.linear_gradient.p1.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
517       apaint->u.linear_gradient.p2.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
518       apaint->u.linear_gradient.p2.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
519 
520       return 1;
521     }
522 
523     else if ( apaint->format == FT_COLR_PAINTFORMAT_RADIAL_GRADIENT )
524     {
525       if ( !read_color_line( child_table_p,
526                              &apaint->u.radial_gradient.colorline ) )
527         return 0;
528 
529       apaint->u.radial_gradient.c0.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
530       apaint->u.radial_gradient.c0.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
531 
532       apaint->u.radial_gradient.r0 = FT_NEXT_USHORT( p ) << 16;
533 
534       apaint->u.radial_gradient.c1.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
535       apaint->u.radial_gradient.c1.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
536 
537       apaint->u.radial_gradient.r1 = FT_NEXT_USHORT( p ) << 16;
538 
539       return 1;
540     }
541 
542     else if ( apaint->format == FT_COLR_PAINTFORMAT_SWEEP_GRADIENT )
543     {
544       if ( !read_color_line( child_table_p,
545                              &apaint->u.sweep_gradient.colorline ) )
546         return 0;
547 
548       apaint->u.sweep_gradient.center.x =
549           INT_TO_FIXED( FT_NEXT_SHORT( p ) );
550       apaint->u.sweep_gradient.center.y =
551           INT_TO_FIXED( FT_NEXT_SHORT( p ) );
552 
553       apaint->u.sweep_gradient.start_angle =
554           F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) );
555       apaint->u.sweep_gradient.end_angle =
556           F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) );
557 
558       return 1;
559     }
560 
561     if ( apaint->format == FT_COLR_PAINTFORMAT_GLYPH )
562     {
563       apaint->u.glyph.paint.p                     = child_table_p;
564       apaint->u.glyph.paint.insert_root_transform = 0;
565       apaint->u.glyph.glyphID                     = FT_NEXT_USHORT( p );
566 
567       return 1;
568     }
569 
570     else if ( apaint->format == FT_COLR_PAINTFORMAT_TRANSFORM )
571     {
572       apaint->u.transform.paint.p                     = child_table_p;
573       apaint->u.transform.paint.insert_root_transform = 0;
574 
575       if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) )
576          return 0;
577 
578       p = child_table_p;
579 
580       /*
581        * The following matrix coefficients are encoded as
582        * OpenType 16.16 fixed-point values.
583        */
584       apaint->u.transform.affine.xx = FT_NEXT_LONG( p );
585       apaint->u.transform.affine.yx = FT_NEXT_LONG( p );
586       apaint->u.transform.affine.xy = FT_NEXT_LONG( p );
587       apaint->u.transform.affine.yy = FT_NEXT_LONG( p );
588       apaint->u.transform.affine.dx = FT_NEXT_LONG( p );
589       apaint->u.transform.affine.dy = FT_NEXT_LONG( p );
590 
591       return 1;
592     }
593 
594     else if ( apaint->format == FT_COLR_PAINTFORMAT_TRANSLATE )
595     {
596       apaint->u.translate.paint.p                     = child_table_p;
597       apaint->u.translate.paint.insert_root_transform = 0;
598 
599       apaint->u.translate.dx = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
600       apaint->u.translate.dy = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
601 
602       return 1;
603     }
604 
605     else if ( apaint->format ==
606                 FT_COLR_PAINTFORMAT_SCALE                         ||
607               (FT_PaintFormat_Internal)apaint->format ==
608                 FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER         ||
609               (FT_PaintFormat_Internal)apaint->format ==
610                 FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM        ||
611               (FT_PaintFormat_Internal)apaint->format ==
612                 FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER )
613     {
614       apaint->u.scale.paint.p                     = child_table_p;
615       apaint->u.scale.paint.insert_root_transform = 0;
616 
617       /* All scale paints get at least one scale value. */
618       apaint->u.scale.scale_x = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) );
619 
620       /* Non-uniform ones read an extra y value. */
621       if ( apaint->format ==
622              FT_COLR_PAINTFORMAT_SCALE                 ||
623            (FT_PaintFormat_Internal)apaint->format ==
624              FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER )
625         apaint->u.scale.scale_y = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) );
626       else
627         apaint->u.scale.scale_y = apaint->u.scale.scale_x;
628 
629       /* Scale paints that have a center read center coordinates, */
630       /* otherwise the center is (0,0).                           */
631       if ( (FT_PaintFormat_Internal)apaint->format ==
632              FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER         ||
633            (FT_PaintFormat_Internal)apaint->format ==
634              FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER )
635       {
636         apaint->u.scale.center_x = INT_TO_FIXED( FT_NEXT_SHORT ( p ) );
637         apaint->u.scale.center_y = INT_TO_FIXED( FT_NEXT_SHORT ( p ) );
638       }
639       else
640       {
641         apaint->u.scale.center_x = 0;
642         apaint->u.scale.center_y = 0;
643       }
644 
645       /* FT 'COLR' v1 API output format always returns fully defined */
646       /* structs; we thus set the format to the public API value.    */
647       apaint->format = FT_COLR_PAINTFORMAT_SCALE;
648 
649       return 1;
650     }
651 
652     else if ( apaint->format == FT_COLR_PAINTFORMAT_ROTATE ||
653               (FT_PaintFormat_Internal)apaint->format ==
654                 FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER )
655     {
656       apaint->u.rotate.paint.p                     = child_table_p;
657       apaint->u.rotate.paint.insert_root_transform = 0;
658 
659       apaint->u.rotate.angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) );
660 
661       if ( (FT_PaintFormat_Internal)apaint->format ==
662            FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER )
663       {
664         apaint->u.rotate.center_x = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
665         apaint->u.rotate.center_y = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
666       }
667       else
668       {
669         apaint->u.rotate.center_x = 0;
670         apaint->u.rotate.center_y = 0;
671       }
672 
673       apaint->format = FT_COLR_PAINTFORMAT_ROTATE;
674 
675       return 1;
676     }
677 
678     else if ( apaint->format == FT_COLR_PAINTFORMAT_SKEW ||
679               (FT_PaintFormat_Internal)apaint->format ==
680                 FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER )
681     {
682       apaint->u.skew.paint.p                     = child_table_p;
683       apaint->u.skew.paint.insert_root_transform = 0;
684 
685       apaint->u.skew.x_skew_angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) );
686       apaint->u.skew.y_skew_angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) );
687 
688       if ( (FT_PaintFormat_Internal)apaint->format ==
689            FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER )
690       {
691         apaint->u.skew.center_x = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
692         apaint->u.skew.center_y = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
693       }
694       else
695       {
696         apaint->u.skew.center_x = 0;
697         apaint->u.skew.center_y = 0;
698       }
699 
700       apaint->format = FT_COLR_PAINTFORMAT_SKEW;
701 
702       return 1;
703     }
704 
705     else if ( apaint->format == FT_COLR_PAINTFORMAT_COMPOSITE )
706     {
707       FT_UInt  composite_mode;
708 
709 
710       apaint->u.composite.source_paint.p                     = child_table_p;
711       apaint->u.composite.source_paint.insert_root_transform = 0;
712 
713       composite_mode = FT_NEXT_BYTE( p );
714       if ( composite_mode >= FT_COLR_COMPOSITE_MAX )
715         return 0;
716 
717       apaint->u.composite.composite_mode = (FT_Composite_Mode)composite_mode;
718 
719       if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) )
720          return 0;
721 
722       apaint->u.composite.backdrop_paint.p =
723         child_table_p;
724       apaint->u.composite.backdrop_paint.insert_root_transform =
725         0;
726 
727       return 1;
728     }
729 
730     return 0;
731   }
732 
733 
734   static FT_Bool
find_base_glyph_v1_record(FT_Byte * base_glyph_begin,FT_UInt num_base_glyph,FT_UInt glyph_id,BaseGlyphV1Record * record)735   find_base_glyph_v1_record( FT_Byte *           base_glyph_begin,
736                              FT_UInt             num_base_glyph,
737                              FT_UInt             glyph_id,
738                              BaseGlyphV1Record  *record )
739   {
740     FT_UInt  min = 0;
741     FT_UInt  max = num_base_glyph;
742 
743 
744     while ( min < max )
745     {
746       FT_UInt  mid = min + ( max - min ) / 2;
747 
748       /*
749        * `base_glyph_begin` is the beginning of `BaseGlyphV1List`;
750        * skip `numBaseGlyphV1Records` by adding 4 to start binary search
751        * in the array of `BaseGlyphV1Record`.
752        */
753       FT_Byte  *p = base_glyph_begin + 4 + mid * BASE_GLYPH_PAINT_RECORD_SIZE;
754 
755       FT_UShort  gid = FT_NEXT_USHORT( p );
756 
757 
758       if ( gid < glyph_id )
759         min = mid + 1;
760       else if (gid > glyph_id )
761         max = mid;
762       else
763       {
764         record->gid          = gid;
765         record->paint_offset = FT_NEXT_ULONG ( p );
766         return 1;
767       }
768     }
769 
770     return 0;
771   }
772 
773 
774   FT_LOCAL_DEF( FT_Bool )
tt_face_get_colr_glyph_paint(TT_Face face,FT_UInt base_glyph,FT_Color_Root_Transform root_transform,FT_OpaquePaint * opaque_paint)775   tt_face_get_colr_glyph_paint( TT_Face                  face,
776                                 FT_UInt                  base_glyph,
777                                 FT_Color_Root_Transform  root_transform,
778                                 FT_OpaquePaint*          opaque_paint )
779   {
780     Colr*              colr = (Colr*)face->colr;
781     BaseGlyphV1Record  base_glyph_v1_record;
782     FT_Byte*           p;
783 
784     if ( !colr || !colr->table )
785       return 0;
786 
787     if ( colr->version < 1 || !colr->num_base_glyphs_v1 ||
788          !colr->base_glyphs_v1 )
789       return 0;
790 
791     if ( opaque_paint->p )
792       return 0;
793 
794     if ( !find_base_glyph_v1_record( colr->base_glyphs_v1,
795                                      colr->num_base_glyphs_v1,
796                                      base_glyph,
797                                      &base_glyph_v1_record ) )
798       return 0;
799 
800     if ( !base_glyph_v1_record.paint_offset                   ||
801          base_glyph_v1_record.paint_offset > colr->table_size )
802       return 0;
803 
804     p = (FT_Byte*)( colr->base_glyphs_v1 +
805                     base_glyph_v1_record.paint_offset );
806     if ( p >= ( (FT_Byte*)colr->table + colr->table_size ) )
807       return 0;
808 
809     opaque_paint->p = p;
810 
811     if ( root_transform == FT_COLOR_INCLUDE_ROOT_TRANSFORM )
812       opaque_paint->insert_root_transform = 1;
813     else
814       opaque_paint->insert_root_transform = 0;
815 
816     return 1;
817   }
818 
819 
820   FT_LOCAL_DEF( FT_Bool )
tt_face_get_color_glyph_clipbox(TT_Face face,FT_UInt base_glyph,FT_ClipBox * clip_box)821   tt_face_get_color_glyph_clipbox( TT_Face      face,
822                                    FT_UInt      base_glyph,
823                                    FT_ClipBox*  clip_box )
824   {
825     Colr*  colr;
826 
827     FT_Byte  *p, *p1, *clip_base;
828 
829     FT_Byte    clip_list_format;
830     FT_ULong   num_clip_boxes, i;
831     FT_UShort  gid_start, gid_end;
832     FT_UInt32  clip_box_offset;
833     FT_Byte    format;
834 
835     const FT_Byte  num_corners = 4;
836     FT_Vector      corners[4];
837     FT_Byte        j;
838     FT_BBox        font_clip_box;
839 
840 
841     colr = (Colr*)face->colr;
842     if ( !colr )
843       return 0;
844 
845     if ( !colr->clip_list )
846       return 0;
847 
848     p = colr->clip_list;
849 
850     clip_base        = p;
851     clip_list_format = FT_NEXT_BYTE ( p );
852 
853     /* Format byte used here to be able to upgrade ClipList for >16bit */
854     /* glyph ids; for now we can expect it to be 0. */
855     if ( !( clip_list_format == 1 ) )
856       return 0;
857 
858     num_clip_boxes = FT_NEXT_ULONG( p );
859 
860     for ( i = 0; i < num_clip_boxes; ++i )
861     {
862       gid_start       = FT_NEXT_USHORT( p );
863       gid_end         = FT_NEXT_USHORT( p );
864       clip_box_offset = FT_NEXT_UOFF3( p );
865 
866       if ( base_glyph >= gid_start && base_glyph <= gid_end )
867       {
868         p1 = (FT_Byte*)( clip_base + clip_box_offset );
869 
870         if ( p1 >= ( (FT_Byte*)colr->table + colr->table_size ) )
871           return 0;
872 
873         format = FT_NEXT_BYTE( p1 );
874 
875         if ( format > 1 )
876           return 0;
877 
878         /* `face->root.size->metrics.x_scale` and `y_scale` are factors   */
879         /* that scale a font unit value in integers to a 26.6 fixed value */
880         /* according to the requested size, see for example               */
881         /* `ft_recompute_scaled_metrics`.                                 */
882         font_clip_box.xMin = FT_MulFix( FT_NEXT_SHORT( p1 ),
883                                         face->root.size->metrics.x_scale );
884         font_clip_box.yMin = FT_MulFix( FT_NEXT_SHORT( p1 ),
885                                         face->root.size->metrics.x_scale );
886         font_clip_box.xMax = FT_MulFix( FT_NEXT_SHORT( p1 ),
887                                         face->root.size->metrics.x_scale );
888         font_clip_box.yMax = FT_MulFix( FT_NEXT_SHORT( p1 ),
889                                         face->root.size->metrics.x_scale );
890 
891         /* Make 4 corner points (xMin, yMin), (xMax, yMax) and transform */
892         /* them.  If we we would only transform two corner points and    */
893         /* span a rectangle based on those, the rectangle may become too */
894         /* small to cover the glyph.                                     */
895         corners[0].x = font_clip_box.xMin;
896         corners[1].x = font_clip_box.xMin;
897         corners[2].x = font_clip_box.xMax;
898         corners[3].x = font_clip_box.xMax;
899 
900         corners[0].y = font_clip_box.yMin;
901         corners[1].y = font_clip_box.yMax;
902         corners[2].y = font_clip_box.yMax;
903         corners[3].y = font_clip_box.yMin;
904 
905         for ( j = 0; j < num_corners; ++j )
906         {
907           if ( face->root.internal->transform_flags & 1 )
908             FT_Vector_Transform( &corners[j],
909                                  &face->root.internal->transform_matrix );
910 
911           if ( face->root.internal->transform_flags & 2 )
912           {
913             corners[j].x += face->root.internal->transform_delta.x;
914             corners[j].y += face->root.internal->transform_delta.y;
915           }
916         }
917 
918         clip_box->bottom_left  = corners[0];
919         clip_box->top_left     = corners[1];
920         clip_box->top_right    = corners[2];
921         clip_box->bottom_right = corners[3];
922 
923         return 1;
924       }
925     }
926 
927     return 0;
928   }
929 
930 
931   FT_LOCAL_DEF( FT_Bool )
tt_face_get_paint_layers(TT_Face face,FT_LayerIterator * iterator,FT_OpaquePaint * opaque_paint)932   tt_face_get_paint_layers( TT_Face            face,
933                             FT_LayerIterator*  iterator,
934                             FT_OpaquePaint*    opaque_paint )
935   {
936     FT_Byte*   p             = NULL;
937     FT_Byte*   p_first_layer = NULL;
938     FT_Byte*   p_paint       = NULL;
939     FT_UInt32  paint_offset;
940 
941     Colr*  colr;
942 
943 
944     if ( iterator->layer == iterator->num_layers )
945       return 0;
946 
947     colr = (Colr*)face->colr;
948     if ( !colr )
949       return 0;
950 
951     /*
952      * We have an iterator pointing at a paint offset as part of the
953      * `paintOffset` array in `LayerV1List`.
954      */
955     p = iterator->p;
956 
957     /*
958      * First ensure that p is within COLRv1.
959      */
960     if ( p < colr->layers_v1                               ||
961          p >= ( (FT_Byte*)colr->table + colr->table_size ) )
962       return 0;
963 
964     /*
965      * Do a cursor sanity check of the iterator.  Counting backwards from
966      * where it stands, we need to end up at a position after the beginning
967      * of the `LayerV1List` table and not after the end of the
968      * `LayerV1List`.
969      */
970     p_first_layer = p -
971                       iterator->layer * LAYER_V1_LIST_PAINT_OFFSET_SIZE -
972                       LAYER_V1_LIST_NUM_LAYERS_SIZE;
973     if ( p_first_layer < (FT_Byte*)colr->layers_v1 )
974       return 0;
975     if ( p_first_layer >= (FT_Byte*)(
976            colr->layers_v1 + LAYER_V1_LIST_NUM_LAYERS_SIZE +
977            colr->num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE ) )
978       return 0;
979 
980     paint_offset =
981       FT_NEXT_ULONG( p );
982     opaque_paint->insert_root_transform =
983       0;
984 
985     p_paint = (FT_Byte*)( colr->layers_v1 + paint_offset );
986 
987     if ( p_paint < colr->paints_start_v1                         ||
988          p_paint >= ( (FT_Byte*)colr->table + colr->table_size ) )
989       return 0;
990 
991     opaque_paint->p = p_paint;
992 
993     iterator->p = p;
994 
995     iterator->layer++;
996 
997     return 1;
998   }
999 
1000 
1001   FT_LOCAL_DEF( FT_Bool )
tt_face_get_colorline_stops(TT_Face face,FT_ColorStop * color_stop,FT_ColorStopIterator * iterator)1002   tt_face_get_colorline_stops( TT_Face                face,
1003                                FT_ColorStop*          color_stop,
1004                                FT_ColorStopIterator  *iterator )
1005   {
1006     Colr*  colr = (Colr*)face->colr;
1007 
1008     FT_Byte*  p;
1009 
1010 
1011     if ( !colr || !colr->table )
1012       return 0;
1013 
1014     if ( iterator->current_color_stop >= iterator->num_color_stops )
1015       return 0;
1016 
1017     if ( iterator->p +
1018            ( ( iterator->num_color_stops - iterator->current_color_stop ) *
1019              COLOR_STOP_SIZE ) >
1020          ( (FT_Byte *)colr->table + colr->table_size ) )
1021       return 0;
1022 
1023     /* Iterator points at first `ColorStop` of `ColorLine`. */
1024     p = iterator->p;
1025 
1026     color_stop->stop_offset = FT_NEXT_SHORT( p );
1027 
1028     color_stop->color.palette_index = FT_NEXT_USHORT( p );
1029 
1030     color_stop->color.alpha = FT_NEXT_SHORT( p );
1031 
1032     iterator->p = p;
1033     iterator->current_color_stop++;
1034 
1035     return 1;
1036   }
1037 
1038 
1039   FT_LOCAL_DEF( FT_Bool )
tt_face_get_paint(TT_Face face,FT_OpaquePaint opaque_paint,FT_COLR_Paint * paint)1040   tt_face_get_paint( TT_Face         face,
1041                      FT_OpaquePaint  opaque_paint,
1042                      FT_COLR_Paint*  paint )
1043   {
1044     Colr*           colr = (Colr*)face->colr;
1045     FT_OpaquePaint  next_paint;
1046     FT_Matrix       ft_root_scale;
1047 
1048     if ( !colr || !colr->base_glyphs_v1 || !colr->table )
1049       return 0;
1050 
1051     if ( opaque_paint.insert_root_transform )
1052     {
1053       /* 'COLR' v1 glyph information is returned in unscaled coordinates,
1054        * i.e., `FT_Size` is not applied or multiplied into the values.  When
1055        * client applications draw color glyphs, they can request to include
1056        * a top-level transform, which includes the active `x_scale` and
1057        * `y_scale` information for scaling the glyph, as well the additional
1058        * transform and translate configured through `FT_Set_Transform`.
1059        * This allows client applications to apply this top-level transform
1060        * to the graphics context first and only once, then have gradient and
1061        * contour scaling applied correctly when performing the additional
1062        * drawing operations for subsequenct paints.  Prepare this initial
1063        * transform here.
1064        */
1065       paint->format = FT_COLR_PAINTFORMAT_TRANSFORM;
1066 
1067       next_paint.p                     = opaque_paint.p;
1068       next_paint.insert_root_transform = 0;
1069       paint->u.transform.paint         = next_paint;
1070 
1071       /* `x_scale` and `y_scale` are in 26.6 format, representing the scale
1072        * factor to get from font units to requested size.  However, expected
1073        * return values are in 16.16, so we shift accordingly with rounding.
1074        */
1075       ft_root_scale.xx = ( face->root.size->metrics.x_scale + 32 ) >> 6;
1076       ft_root_scale.xy = 0;
1077       ft_root_scale.yx = 0;
1078       ft_root_scale.yy = ( face->root.size->metrics.y_scale + 32 ) >> 6;
1079 
1080       if ( face->root.internal->transform_flags & 1 )
1081         FT_Matrix_Multiply( &face->root.internal->transform_matrix,
1082                             &ft_root_scale );
1083 
1084       paint->u.transform.affine.xx = ft_root_scale.xx;
1085       paint->u.transform.affine.xy = ft_root_scale.xy;
1086       paint->u.transform.affine.yx = ft_root_scale.yx;
1087       paint->u.transform.affine.yy = ft_root_scale.yy;
1088 
1089       /* The translation is specified in 26.6 format and, according to the
1090        * documentation of `FT_Set_Translate`, is performed on the character
1091        * size given in the last call to `FT_Set_Char_Size`.  The
1092        * 'PaintTransform' paint table's `FT_Affine23` format expects
1093        * values in 16.16 format, thus we need to shift by 10 bits.
1094        */
1095       if ( face->root.internal->transform_flags & 2 )
1096       {
1097         paint->u.transform.affine.dx =
1098           face->root.internal->transform_delta.x * ( 1 << 10 );
1099         paint->u.transform.affine.dy =
1100           face->root.internal->transform_delta.y * ( 1 << 10 );
1101       }
1102       else
1103       {
1104         paint->u.transform.affine.dx = 0;
1105         paint->u.transform.affine.dy = 0;
1106       }
1107 
1108       return 1;
1109     }
1110 
1111     return read_paint( colr, opaque_paint.p, paint );
1112   }
1113 
1114 
1115   FT_LOCAL_DEF( FT_Error )
tt_face_colr_blend_layer(TT_Face face,FT_UInt color_index,FT_GlyphSlot dstSlot,FT_GlyphSlot srcSlot)1116   tt_face_colr_blend_layer( TT_Face       face,
1117                             FT_UInt       color_index,
1118                             FT_GlyphSlot  dstSlot,
1119                             FT_GlyphSlot  srcSlot )
1120   {
1121     FT_Error  error;
1122 
1123     FT_UInt  x, y;
1124     FT_Byte  b, g, r, alpha;
1125 
1126     FT_ULong  size;
1127     FT_Byte*  src;
1128     FT_Byte*  dst;
1129 
1130 
1131     if ( !dstSlot->bitmap.buffer )
1132     {
1133       /* Initialize destination of color bitmap */
1134       /* with the size of first component.      */
1135       dstSlot->bitmap_left = srcSlot->bitmap_left;
1136       dstSlot->bitmap_top  = srcSlot->bitmap_top;
1137 
1138       dstSlot->bitmap.width      = srcSlot->bitmap.width;
1139       dstSlot->bitmap.rows       = srcSlot->bitmap.rows;
1140       dstSlot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
1141       dstSlot->bitmap.pitch      = (int)dstSlot->bitmap.width * 4;
1142       dstSlot->bitmap.num_grays  = 256;
1143 
1144       size = dstSlot->bitmap.rows * (unsigned int)dstSlot->bitmap.pitch;
1145 
1146       error = ft_glyphslot_alloc_bitmap( dstSlot, size );
1147       if ( error )
1148         return error;
1149 
1150       FT_MEM_ZERO( dstSlot->bitmap.buffer, size );
1151     }
1152     else
1153     {
1154       /* Resize destination if needed such that new component fits. */
1155       FT_Int  x_min, x_max, y_min, y_max;
1156 
1157 
1158       x_min = FT_MIN( dstSlot->bitmap_left, srcSlot->bitmap_left );
1159       x_max = FT_MAX( dstSlot->bitmap_left + (FT_Int)dstSlot->bitmap.width,
1160                       srcSlot->bitmap_left + (FT_Int)srcSlot->bitmap.width );
1161 
1162       y_min = FT_MIN( dstSlot->bitmap_top - (FT_Int)dstSlot->bitmap.rows,
1163                       srcSlot->bitmap_top - (FT_Int)srcSlot->bitmap.rows );
1164       y_max = FT_MAX( dstSlot->bitmap_top, srcSlot->bitmap_top );
1165 
1166       if ( x_min != dstSlot->bitmap_left                                 ||
1167            x_max != dstSlot->bitmap_left + (FT_Int)dstSlot->bitmap.width ||
1168            y_min != dstSlot->bitmap_top - (FT_Int)dstSlot->bitmap.rows   ||
1169            y_max != dstSlot->bitmap_top                                  )
1170       {
1171         FT_Memory  memory = face->root.memory;
1172 
1173         FT_UInt  width = (FT_UInt)( x_max - x_min );
1174         FT_UInt  rows  = (FT_UInt)( y_max - y_min );
1175         FT_UInt  pitch = width * 4;
1176 
1177         FT_Byte*  buf = NULL;
1178         FT_Byte*  p;
1179         FT_Byte*  q;
1180 
1181 
1182         size  = rows * pitch;
1183         if ( FT_ALLOC( buf, size ) )
1184           return error;
1185 
1186         p = dstSlot->bitmap.buffer;
1187         q = buf +
1188             (int)pitch * ( y_max - dstSlot->bitmap_top ) +
1189             4 * ( dstSlot->bitmap_left - x_min );
1190 
1191         for ( y = 0; y < dstSlot->bitmap.rows; y++ )
1192         {
1193           FT_MEM_COPY( q, p, dstSlot->bitmap.width * 4 );
1194 
1195           p += dstSlot->bitmap.pitch;
1196           q += pitch;
1197         }
1198 
1199         ft_glyphslot_set_bitmap( dstSlot, buf );
1200 
1201         dstSlot->bitmap_top  = y_max;
1202         dstSlot->bitmap_left = x_min;
1203 
1204         dstSlot->bitmap.width = width;
1205         dstSlot->bitmap.rows  = rows;
1206         dstSlot->bitmap.pitch = (int)pitch;
1207 
1208         dstSlot->internal->flags |= FT_GLYPH_OWN_BITMAP;
1209         dstSlot->format           = FT_GLYPH_FORMAT_BITMAP;
1210       }
1211     }
1212 
1213     if ( color_index == 0xFFFF )
1214     {
1215       if ( face->have_foreground_color )
1216       {
1217         b     = face->foreground_color.blue;
1218         g     = face->foreground_color.green;
1219         r     = face->foreground_color.red;
1220         alpha = face->foreground_color.alpha;
1221       }
1222       else
1223       {
1224         if ( face->palette_data.palette_flags                          &&
1225              ( face->palette_data.palette_flags[face->palette_index] &
1226                  FT_PALETTE_FOR_DARK_BACKGROUND                      ) )
1227         {
1228           /* white opaque */
1229           b     = 0xFF;
1230           g     = 0xFF;
1231           r     = 0xFF;
1232           alpha = 0xFF;
1233         }
1234         else
1235         {
1236           /* black opaque */
1237           b     = 0x00;
1238           g     = 0x00;
1239           r     = 0x00;
1240           alpha = 0xFF;
1241         }
1242       }
1243     }
1244     else
1245     {
1246       b     = face->palette[color_index].blue;
1247       g     = face->palette[color_index].green;
1248       r     = face->palette[color_index].red;
1249       alpha = face->palette[color_index].alpha;
1250     }
1251 
1252     /* XXX Convert if srcSlot.bitmap is not grey? */
1253     src = srcSlot->bitmap.buffer;
1254     dst = dstSlot->bitmap.buffer +
1255           dstSlot->bitmap.pitch * ( dstSlot->bitmap_top - srcSlot->bitmap_top ) +
1256           4 * ( srcSlot->bitmap_left - dstSlot->bitmap_left );
1257 
1258     for ( y = 0; y < srcSlot->bitmap.rows; y++ )
1259     {
1260       for ( x = 0; x < srcSlot->bitmap.width; x++ )
1261       {
1262         int  aa = src[x];
1263         int  fa = alpha * aa / 255;
1264 
1265         int  fb = b * fa / 255;
1266         int  fg = g * fa / 255;
1267         int  fr = r * fa / 255;
1268 
1269         int  ba2 = 255 - fa;
1270 
1271         int  bb = dst[4 * x + 0];
1272         int  bg = dst[4 * x + 1];
1273         int  br = dst[4 * x + 2];
1274         int  ba = dst[4 * x + 3];
1275 
1276 
1277         dst[4 * x + 0] = (FT_Byte)( bb * ba2 / 255 + fb );
1278         dst[4 * x + 1] = (FT_Byte)( bg * ba2 / 255 + fg );
1279         dst[4 * x + 2] = (FT_Byte)( br * ba2 / 255 + fr );
1280         dst[4 * x + 3] = (FT_Byte)( ba * ba2 / 255 + fa );
1281       }
1282 
1283       src += srcSlot->bitmap.pitch;
1284       dst += dstSlot->bitmap.pitch;
1285     }
1286 
1287     return FT_Err_Ok;
1288   }
1289 
1290 #else /* !TT_CONFIG_OPTION_COLOR_LAYERS */
1291 
1292   /* ANSI C doesn't like empty source files */
1293   typedef int  _tt_colr_dummy;
1294 
1295 #endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */
1296 
1297 /* EOF */
1298