sdk-world v2026.11.05
PS2 SDK - world tier (copyleft-allowed, non-essential packages)
Loading...
Searching...
No Matches
ttcolr.c
1/****************************************************************************
2 *
3 * ttcolr.c
4 *
5 * TrueType and OpenType colored glyph layer support (body).
6 *
7 * Copyright (C) 2018-2025 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
33#include <freetype/tttags.h>
34#include <freetype/ftcolor.h>
36
37#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
39#endif
40
41#ifdef TT_CONFIG_OPTION_COLOR_LAYERS
42
43#include "ttcolr.h"
44
45
46 /* NOTE: These are the table sizes calculated through the specs. */
47#define BASE_GLYPH_SIZE 6U
48#define BASE_GLYPH_PAINT_RECORD_SIZE 6U
49#define LAYER_V1_LIST_PAINT_OFFSET_SIZE 4U
50#define LAYER_V1_LIST_NUM_LAYERS_SIZE 4U
51#define COLOR_STOP_SIZE 6U
52#define VAR_IDX_BASE_SIZE 4U
53#define LAYER_SIZE 4U
54/* https://learn.microsoft.com/typography/opentype/spec/colr#colr-header */
55/* 3 * uint16 + 2 * Offset32 */
56#define COLRV0_HEADER_SIZE 14U
57/* COLRV0_HEADER_SIZE + 5 * Offset32 */
58#define COLRV1_HEADER_SIZE 34U
59
60
61#define ENSURE_READ_BYTES( byte_size ) \
62 if ( p < colr->paints_start_v1 || \
63 p > (FT_Byte*)colr->table + colr->table_size - byte_size ) \
64 return 0
65
66
67 typedef enum FT_PaintFormat_Internal_
68 {
69 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SOLID = 3,
70 FT_COLR_PAINTFORMAT_INTERNAL_VAR_LINEAR_GRADIENT = 5,
71 FT_COLR_PAINTFORMAT_INTERNAL_VAR_RADIAL_GRADIENT = 7,
72 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SWEEP_GRADIENT = 9,
73 FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSFORM = 13,
74 FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSLATE = 15,
75 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE = 17,
76 FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER = 18,
77 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER = 19,
78 FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM = 20,
79 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM = 21,
80 FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER = 22,
81 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER = 23,
82 FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE = 25,
83 FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER = 26,
84 FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER = 27,
85 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW = 29,
86 FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER = 30,
87 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER = 31,
88
89 } FT_PaintFormat_Internal;
90
91
92 typedef struct BaseGlyphRecord_
93 {
94 FT_UShort gid;
95 FT_UShort first_layer_index;
96 FT_UShort num_layers;
97
98 } BaseGlyphRecord;
99
100
101 typedef struct BaseGlyphV1Record_
102 {
103 FT_UShort gid;
104 /* Offset from start of BaseGlyphV1List, i.e., from base_glyphs_v1. */
105 FT_ULong paint_offset;
106
107 } BaseGlyphV1Record;
108
109
110 typedef struct Colr_
111 {
112 FT_UShort version;
113 FT_UShort num_base_glyphs;
114 FT_UShort num_layers;
115
116 FT_Byte* base_glyphs;
117 FT_Byte* layers;
118
119 FT_ULong num_base_glyphs_v1;
120 /* Points at beginning of BaseGlyphV1List. */
121 FT_Byte* base_glyphs_v1;
122
123 FT_ULong num_layers_v1;
124 FT_Byte* layers_v1;
125
126 FT_Byte* clip_list;
127
128 /*
129 * Paint tables start at the minimum of the end of the LayerList and the
130 * end of the BaseGlyphList. Record this location in a field here for
131 * safety checks when accessing paint tables.
132 */
133 FT_Byte* paints_start_v1;
134
135#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
136 /* Item Variation Store for variable 'COLR' v1. */
137 GX_ItemVarStoreRec var_store;
138 GX_DeltaSetIdxMapRec delta_set_idx_map;
139#endif
140
141 /* The memory that backs up the `COLR' table. */
142 void* table;
143 FT_ULong table_size;
144
145 } Colr;
146
147
148 /**************************************************************************
149 *
150 * The macro FT_COMPONENT is used in trace mode. It is an implicit
151 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
152 * messages during execution.
153 */
154#undef FT_COMPONENT
155#define FT_COMPONENT ttcolr
156
157
158 FT_LOCAL_DEF( FT_Error )
159 tt_face_load_colr( TT_Face face,
160 FT_Stream stream )
161 {
162 FT_Error error;
163 FT_Memory memory = face->root.memory;
164
165 FT_Byte* table = NULL;
166 FT_Byte* p = NULL;
167 /* Needed for reading array lengths in referenced tables. */
168 FT_Byte* p1 = NULL;
169
170 Colr* colr = NULL;
171
172 FT_ULong base_glyph_offset, layer_offset;
173 FT_ULong base_glyphs_offset_v1, num_base_glyphs_v1;
174 FT_ULong layer_offset_v1, num_layers_v1, clip_list_offset;
175 FT_ULong table_size;
176#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
177 FT_ULong colr_offset_in_stream;
178#endif
179
180
181 /* `COLR' always needs `CPAL' */
182 if ( !face->cpal )
183 return FT_THROW( Invalid_File_Format );
184
185 error = face->goto_table( face, TTAG_COLR, stream, &table_size );
186 if ( error )
187 goto NoColr;
188
189#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
190 colr_offset_in_stream = FT_STREAM_POS();
191#endif
192
193 if ( table_size < COLRV0_HEADER_SIZE )
194 goto NoColr;
195
196 if ( FT_FRAME_EXTRACT( table_size, table ) )
197 goto NoColr;
198
199 p = table;
200
201 if ( FT_NEW( colr ) )
202 goto NoColr;
203
204 colr->version = FT_NEXT_USHORT( p );
205 if ( colr->version != 0 && colr->version != 1 )
206 goto InvalidTable;
207
208 colr->num_base_glyphs = FT_NEXT_USHORT( p );
209 base_glyph_offset = FT_NEXT_ULONG( p );
210
211 if ( table_size <= base_glyph_offset )
212 goto InvalidTable;
213 if ( ( table_size - base_glyph_offset ) / BASE_GLYPH_SIZE
214 < colr->num_base_glyphs )
215 goto InvalidTable;
216
217 layer_offset = FT_NEXT_ULONG( p );
218 colr->num_layers = FT_NEXT_USHORT( p );
219
220 if ( table_size <= layer_offset )
221 goto InvalidTable;
222 if ( ( table_size - layer_offset ) / LAYER_SIZE
223 < colr->num_layers )
224 goto InvalidTable;
225
226 if ( colr->version == 1 )
227 {
228 if ( table_size < COLRV1_HEADER_SIZE )
229 goto InvalidTable;
230
231 base_glyphs_offset_v1 = FT_NEXT_ULONG( p );
232
233 if ( table_size - 4 <= base_glyphs_offset_v1 )
234 goto InvalidTable;
235
236 p1 = (FT_Byte*)( table + base_glyphs_offset_v1 );
237 num_base_glyphs_v1 = FT_PEEK_ULONG( p1 );
238
239 if ( ( table_size - base_glyphs_offset_v1 ) / BASE_GLYPH_PAINT_RECORD_SIZE
240 < num_base_glyphs_v1 )
241 goto InvalidTable;
242
243 colr->num_base_glyphs_v1 = num_base_glyphs_v1;
244 colr->base_glyphs_v1 = p1;
245
246 layer_offset_v1 = FT_NEXT_ULONG( p );
247
248 if ( table_size <= layer_offset_v1 )
249 goto InvalidTable;
250
251 if ( layer_offset_v1 )
252 {
253 if ( table_size - 4 <= layer_offset_v1 )
254 goto InvalidTable;
255
256 p1 = (FT_Byte*)( table + layer_offset_v1 );
257 num_layers_v1 = FT_PEEK_ULONG( p1 );
258
259 if ( ( table_size - layer_offset_v1 ) / LAYER_V1_LIST_PAINT_OFFSET_SIZE
260 < num_layers_v1 )
261 goto InvalidTable;
262
263 colr->num_layers_v1 = num_layers_v1;
264 colr->layers_v1 = p1;
265
266 colr->paints_start_v1 =
267 FT_MIN( colr->base_glyphs_v1 +
268 colr->num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE,
269 colr->layers_v1 +
270 colr->num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE );
271 }
272 else
273 {
274 colr->num_layers_v1 = 0;
275 colr->layers_v1 = 0;
276 colr->paints_start_v1 =
277 colr->base_glyphs_v1 +
278 colr->num_base_glyphs_v1 * BASE_GLYPH_PAINT_RECORD_SIZE;
279 }
280
281 clip_list_offset = FT_NEXT_ULONG( p );
282
283 if ( table_size <= clip_list_offset )
284 goto InvalidTable;
285
286 if ( clip_list_offset )
287 colr->clip_list = (FT_Byte*)( table + clip_list_offset );
288 else
289 colr->clip_list = 0;
290
291#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
292 colr->var_store.dataCount = 0;
293 colr->var_store.varData = NULL;
294 colr->var_store.axisCount = 0;
295 colr->var_store.regionCount = 0;
296 colr->var_store.varRegionList = 0;
297
298 colr->delta_set_idx_map.mapCount = 0;
299 colr->delta_set_idx_map.outerIndex = NULL;
300 colr->delta_set_idx_map.innerIndex = NULL;
301
302 if ( face->variation_support & TT_FACE_FLAG_VAR_FVAR )
303 {
304 FT_ULong var_idx_map_offset, var_store_offset;
305
306 FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
307
308
309 var_idx_map_offset = FT_NEXT_ULONG( p );
310
311 if ( var_idx_map_offset >= table_size )
312 goto InvalidTable;
313
314 var_store_offset = FT_NEXT_ULONG( p );
315 if ( table_size <= var_store_offset )
316 goto InvalidTable;
317
318 if ( var_store_offset )
319 {
320 /* If variation info has not been initialized yet, try doing so, */
321 /* otherwise loading the variation store will fail as it */
322 /* requires access to `blend` for checking the number of axes. */
323 if ( !face->blend )
324 if ( mm->get_mm_var( FT_FACE( face ), NULL ) )
325 goto InvalidTable;
326
327 /* Try loading `VarIdxMap` and `VarStore`. */
328 error = mm->load_item_var_store(
329 FT_FACE( face ),
330 colr_offset_in_stream + var_store_offset,
331 &colr->var_store );
332 if ( error != FT_Err_Ok )
333 goto InvalidTable;
334 }
335
336 if ( colr->var_store.axisCount && var_idx_map_offset )
337 {
338 error = mm->load_delta_set_idx_map(
339 FT_FACE( face ),
340 colr_offset_in_stream + var_idx_map_offset,
341 &colr->delta_set_idx_map,
342 &colr->var_store,
343 table_size );
344 if ( error != FT_Err_Ok )
345 goto InvalidTable;
346 }
347 }
348#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
349 }
350
351 colr->base_glyphs = (FT_Byte*)( table + base_glyph_offset );
352 colr->layers = (FT_Byte*)( table + layer_offset );
353 colr->table = table;
354 colr->table_size = table_size;
355
356 face->colr = colr;
357
358 return FT_Err_Ok;
359
360 InvalidTable:
361#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
362 {
363 FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
364
365
366 mm->done_delta_set_idx_map( FT_FACE( face ),
367 &colr->delta_set_idx_map );
368 mm->done_item_var_store( FT_FACE( face ),
369 &colr->var_store );
370 }
371#endif
372
373 error = FT_THROW( Invalid_Table );
374
375 NoColr:
376 FT_FRAME_RELEASE( table );
377 FT_FREE( colr );
378
379 return error;
380 }
381
382
383 FT_LOCAL_DEF( void )
384 tt_face_free_colr( TT_Face face )
385 {
386 FT_Stream stream = face->root.stream;
387 FT_Memory memory = face->root.memory;
388
389 Colr* colr = (Colr*)face->colr;
390
391
392 if ( colr )
393 {
394#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
395 {
396 FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
397
398
399 mm->done_delta_set_idx_map( FT_FACE( face ),
400 &colr->delta_set_idx_map );
401 mm->done_item_var_store( FT_FACE( face ),
402 &colr->var_store );
403 }
404#endif
405 FT_FRAME_RELEASE( colr->table );
406 FT_FREE( colr );
407 }
408 }
409
410
411 static FT_Bool
412 find_base_glyph_record( FT_Byte* base_glyph_begin,
413 FT_UInt num_base_glyph,
414 FT_UInt glyph_id,
415 BaseGlyphRecord* record )
416 {
417 FT_UInt min = 0;
418 FT_UInt max = num_base_glyph;
419
420
421 while ( min < max )
422 {
423 FT_UInt mid = min + ( max - min ) / 2;
424 FT_Byte* p = base_glyph_begin + mid * BASE_GLYPH_SIZE;
425
426 FT_UShort gid = FT_NEXT_USHORT( p );
427
428
429 if ( gid < glyph_id )
430 min = mid + 1;
431 else if (gid > glyph_id )
432 max = mid;
433 else
434 {
435 record->gid = gid;
436 record->first_layer_index = FT_NEXT_USHORT( p );
437 record->num_layers = FT_NEXT_USHORT( p );
438
439 return 1;
440 }
441 }
442
443 return 0;
444 }
445
446
447 FT_LOCAL_DEF( FT_Bool )
448 tt_face_get_colr_layer( TT_Face face,
449 FT_UInt base_glyph,
450 FT_UInt *aglyph_index,
451 FT_UInt *acolor_index,
452 FT_LayerIterator* iterator )
453 {
454 Colr* colr = (Colr*)face->colr;
455 BaseGlyphRecord glyph_record;
456
457
458 if ( !colr )
459 return 0;
460
461 if ( !iterator->p )
462 {
463 FT_ULong offset;
464
465
466 /* first call to function */
467 iterator->layer = 0;
468
469 if ( !find_base_glyph_record( colr->base_glyphs,
470 colr->num_base_glyphs,
471 base_glyph,
472 &glyph_record ) )
473 return 0;
474
475 if ( glyph_record.num_layers )
476 iterator->num_layers = glyph_record.num_layers;
477 else
478 return 0;
479
480 offset = LAYER_SIZE * glyph_record.first_layer_index;
481 if ( offset + LAYER_SIZE * glyph_record.num_layers > colr->table_size )
482 return 0;
483
484 iterator->p = colr->layers + offset;
485 }
486
487 if ( iterator->layer >= iterator->num_layers ||
488 iterator->p < colr->layers ||
489 iterator->p >= ( (FT_Byte*)colr->table + colr->table_size ) )
490 return 0;
491
492 *aglyph_index = FT_NEXT_USHORT( iterator->p );
493 *acolor_index = FT_NEXT_USHORT( iterator->p );
494
495 if ( *aglyph_index >= (FT_UInt)( FT_FACE( face )->num_glyphs ) ||
496 ( *acolor_index != 0xFFFF &&
497 *acolor_index >= face->palette_data.num_palette_entries ) )
498 return 0;
499
500 iterator->layer++;
501
502 return 1;
503 }
504
505
506 static FT_Bool
507 read_color_line( Colr* colr,
508 FT_Byte* color_line_p,
509 FT_ColorLine* colorline,
510 FT_Bool read_variable )
511 {
512 FT_Byte* p = color_line_p;
513 FT_PaintExtend paint_extend;
514
515
516 ENSURE_READ_BYTES( 3 );
517
518 paint_extend = (FT_PaintExtend)FT_NEXT_BYTE( p );
519 if ( paint_extend > FT_COLR_PAINT_EXTEND_REFLECT )
520 return 0;
521
522 colorline->extend = paint_extend;
523
524 colorline->color_stop_iterator.num_color_stops = FT_NEXT_USHORT( p );
525 colorline->color_stop_iterator.p = p;
526 colorline->color_stop_iterator.current_color_stop = 0;
527 colorline->color_stop_iterator.read_variable = read_variable;
528
529 return 1;
530 }
531
532
533 /*
534 * Read a paint offset for `FT_Paint*` objects that have them and check
535 * whether it is within reasonable limits within the font and the COLR
536 * table.
537 *
538 * Return 1 on success, 0 on failure.
539 */
540 static FT_Bool
541 get_child_table_pointer ( Colr* colr,
542 FT_Byte* paint_base,
543 FT_Byte** p,
544 FT_Byte** child_table_pointer )
545 {
546 FT_UInt32 paint_offset;
547 FT_Byte* child_table_p;
548
549
550 if ( !child_table_pointer )
551 return 0;
552
553 if ( *p < colr->paints_start_v1 ||
554 *p > (FT_Byte*)colr->table + colr->table_size - 1 - 3 )
555 return 0;
556
557 paint_offset = FT_NEXT_UOFF3( *p );
558 if ( !paint_offset )
559 return 0;
560
561 child_table_p = (FT_Byte*)( paint_base + paint_offset );
562
563 if ( child_table_p < colr->paints_start_v1 ||
564 child_table_p >= ( (FT_Byte*)colr->table + colr->table_size ) )
565 return 0;
566
567 *child_table_pointer = child_table_p;
568 return 1;
569 }
570
571
572#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
573
574 static FT_Bool
575 get_deltas_for_var_index_base ( TT_Face face,
576 Colr* colr,
577 FT_ULong var_index_base,
578 FT_UInt num_deltas,
579 FT_ItemVarDelta* deltas )
580 {
581 FT_UInt outer_index = 0;
582 FT_UInt inner_index = 0;
583 FT_ULong loop_var_index = var_index_base;
584
585 FT_Service_MultiMasters mm = (FT_Service_MultiMasters)face->mm;
586
587 FT_UInt i = 0;
588
589
590 if ( var_index_base == 0xFFFFFFFF )
591 {
592 for ( i = 0; i < num_deltas; ++i )
593 deltas[i] = 0;
594 return 1;
595 }
596
597 for ( i = 0; i < num_deltas; ++i )
598 {
599 loop_var_index = var_index_base + i;
600
601 if ( colr->delta_set_idx_map.innerIndex )
602 {
603 if ( loop_var_index >= colr->delta_set_idx_map.mapCount )
604 loop_var_index = colr->delta_set_idx_map.mapCount - 1;
605
606 outer_index = colr->delta_set_idx_map.outerIndex[loop_var_index];
607 inner_index = colr->delta_set_idx_map.innerIndex[loop_var_index];
608 }
609 else
610 {
611 outer_index = 0;
612 inner_index = loop_var_index;
613 }
614
615 deltas[i] = mm->get_item_delta( FT_FACE( face ), &colr->var_store,
616 outer_index, inner_index );
617 }
618
619 return 1;
620 }
621
622#endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */
623
624
625 static FT_Bool
626 read_paint( TT_Face face,
627 Colr* colr,
628 FT_Byte* p,
629 FT_COLR_Paint* apaint )
630 {
631 FT_Byte* paint_base = p;
632 FT_Byte* child_table_p = NULL;
633 FT_Bool do_read_var = FALSE;
634
635#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
636 FT_ULong var_index_base = 0;
637 /* Longest varIndexBase offset is 5 in the spec. */
638 FT_ItemVarDelta item_deltas[6] = { 0, 0, 0, 0, 0, 0 };
639#else
640 FT_UNUSED( face );
641#endif
642
643
644 if ( !p || !colr || !colr->table )
645 return 0;
646
647 /* The last byte of the 'COLR' table is at 'size-1'; subtract 1 of */
648 /* that to account for the expected format byte we are going to read. */
649 if ( p < colr->paints_start_v1 ||
650 p > (FT_Byte*)colr->table + colr->table_size - 2 )
651 return 0;
652
653 apaint->format = (FT_PaintFormat)FT_NEXT_BYTE( p );
654
655 if ( apaint->format >= FT_COLR_PAINT_FORMAT_MAX )
656 return 0;
657
658 if ( apaint->format == FT_COLR_PAINTFORMAT_COLR_LAYERS )
659 {
660 /* Initialize layer iterator/ */
661 FT_Byte num_layers;
662 FT_UInt32 first_layer_index;
663
664
665 ENSURE_READ_BYTES( 5 );
666 num_layers = FT_NEXT_BYTE( p );
667 if ( num_layers > colr->num_layers_v1 )
668 return 0;
669
670 first_layer_index = FT_NEXT_ULONG( p );
671 if ( first_layer_index + num_layers > colr->num_layers_v1 )
672 return 0;
673
674 apaint->u.colr_layers.layer_iterator.num_layers = num_layers;
675 apaint->u.colr_layers.layer_iterator.layer = 0;
676 /* TODO: Check whether pointer is outside colr? */
677 apaint->u.colr_layers.layer_iterator.p =
678 colr->layers_v1 +
679 LAYER_V1_LIST_NUM_LAYERS_SIZE +
680 LAYER_V1_LIST_PAINT_OFFSET_SIZE * first_layer_index;
681
682 return 1;
683 }
684
685 else if ( apaint->format == FT_COLR_PAINTFORMAT_SOLID ||
686 (FT_PaintFormat_Internal)apaint->format ==
687 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SOLID )
688 {
689 ENSURE_READ_BYTES( 4 );
690 apaint->u.solid.color.palette_index = FT_NEXT_USHORT( p );
691 apaint->u.solid.color.alpha = FT_NEXT_SHORT( p );
692
693#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
694 if ( (FT_PaintFormat_Internal)apaint->format ==
695 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SOLID )
696 {
697 ENSURE_READ_BYTES( 4 );
698 var_index_base = FT_NEXT_ULONG( p );
699
700 if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 1,
701 item_deltas ) )
702 return 0;
703
704 apaint->u.solid.color.alpha += (FT_F2Dot14)item_deltas[0];
705 }
706#endif
707
708 apaint->format = FT_COLR_PAINTFORMAT_SOLID;
709
710 return 1;
711 }
712
713 else if ( apaint->format == FT_COLR_PAINTFORMAT_COLR_GLYPH )
714 {
715 ENSURE_READ_BYTES(2);
716 apaint->u.colr_glyph.glyphID = FT_NEXT_USHORT( p );
717
718 return 1;
719 }
720
721 /*
722 * Grouped below here are all paint formats that have an offset to a
723 * child paint table as the first entry (for example, a color line or a
724 * child paint table). Retrieve that and determine whether that paint
725 * offset is valid first.
726 */
727
728 if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) )
729 return 0;
730
731 if ( apaint->format == FT_COLR_PAINTFORMAT_LINEAR_GRADIENT ||
732 ( do_read_var =
733 ( (FT_PaintFormat_Internal)apaint->format ==
734 FT_COLR_PAINTFORMAT_INTERNAL_VAR_LINEAR_GRADIENT ) ) )
735 {
736 if ( !read_color_line( colr,
737 child_table_p,
738 &apaint->u.linear_gradient.colorline,
739 do_read_var ) )
740 return 0;
741
742 /*
743 * In order to support variations expose these as FT_Fixed 16.16
744 * values so that we can support fractional values after
745 * interpolation.
746 */
747 ENSURE_READ_BYTES( 12 );
748 apaint->u.linear_gradient.p0.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
749 apaint->u.linear_gradient.p0.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
750 apaint->u.linear_gradient.p1.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
751 apaint->u.linear_gradient.p1.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
752 apaint->u.linear_gradient.p2.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
753 apaint->u.linear_gradient.p2.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
754
755#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
756 if ( do_read_var )
757 {
758 ENSURE_READ_BYTES( 4 );
759 var_index_base = FT_NEXT_ULONG ( p );
760
761 if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 6,
762 item_deltas ) )
763 return 0;
764
765 apaint->u.linear_gradient.p0.x += INT_TO_FIXED( item_deltas[0] );
766 apaint->u.linear_gradient.p0.y += INT_TO_FIXED( item_deltas[1] );
767 apaint->u.linear_gradient.p1.x += INT_TO_FIXED( item_deltas[2] );
768 apaint->u.linear_gradient.p1.y += INT_TO_FIXED( item_deltas[3] );
769 apaint->u.linear_gradient.p2.x += INT_TO_FIXED( item_deltas[4] );
770 apaint->u.linear_gradient.p2.y += INT_TO_FIXED( item_deltas[5] );
771 }
772#endif
773
774 apaint->format = FT_COLR_PAINTFORMAT_LINEAR_GRADIENT;
775
776 return 1;
777 }
778
779 else if ( apaint->format == FT_COLR_PAINTFORMAT_RADIAL_GRADIENT ||
780 ( do_read_var =
781 ( (FT_PaintFormat_Internal)apaint->format ==
782 FT_COLR_PAINTFORMAT_INTERNAL_VAR_RADIAL_GRADIENT ) ) )
783 {
784 FT_Pos tmp;
785
786
787 if ( !read_color_line( colr,
788 child_table_p,
789 &apaint->u.radial_gradient.colorline,
790 do_read_var ) )
791 return 0;
792
793
794 /* In the OpenType specification, `r0` and `r1` are defined as */
795 /* `UFWORD`. Since FreeType doesn't have a corresponding 16.16 */
796 /* format we convert to `FWORD` and replace negative values with */
797 /* (32bit) `FT_INT_MAX`. */
798
799 ENSURE_READ_BYTES( 12 );
800
801 apaint->u.radial_gradient.c0.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
802 apaint->u.radial_gradient.c0.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
803
804 tmp = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
805 apaint->u.radial_gradient.r0 = tmp < 0 ? FT_INT_MAX : tmp;
806
807 apaint->u.radial_gradient.c1.x = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
808 apaint->u.radial_gradient.c1.y = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
809
810 tmp = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
811 apaint->u.radial_gradient.r1 = tmp < 0 ? FT_INT_MAX : tmp;
812
813#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
814 if ( do_read_var )
815 {
816 ENSURE_READ_BYTES( 4 );
817 var_index_base = FT_NEXT_ULONG ( p );
818
819 if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 6,
820 item_deltas ) )
821 return 0;
822
823 apaint->u.radial_gradient.c0.x += INT_TO_FIXED( item_deltas[0] );
824 apaint->u.radial_gradient.c0.y += INT_TO_FIXED( item_deltas[1] );
825
826 // TODO: Anything to be done about UFWORD deltas here?
827 apaint->u.radial_gradient.r0 += INT_TO_FIXED( item_deltas[2] );
828
829 apaint->u.radial_gradient.c1.x += INT_TO_FIXED( item_deltas[3] );
830 apaint->u.radial_gradient.c1.y += INT_TO_FIXED( item_deltas[4] );
831
832 apaint->u.radial_gradient.r1 += INT_TO_FIXED( item_deltas[5] );
833 }
834#endif
835
836 apaint->format = FT_COLR_PAINTFORMAT_RADIAL_GRADIENT;
837
838 return 1;
839 }
840
841 else if ( apaint->format == FT_COLR_PAINTFORMAT_SWEEP_GRADIENT ||
842 ( do_read_var =
843 ( (FT_PaintFormat_Internal)apaint->format ==
844 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SWEEP_GRADIENT ) ) )
845 {
846 if ( !read_color_line( colr,
847 child_table_p,
848 &apaint->u.sweep_gradient.colorline,
849 do_read_var) )
850 return 0;
851
852 ENSURE_READ_BYTES( 8 );
853
854 apaint->u.sweep_gradient.center.x =
855 INT_TO_FIXED( FT_NEXT_SHORT( p ) );
856 apaint->u.sweep_gradient.center.y =
857 INT_TO_FIXED( FT_NEXT_SHORT( p ) );
858
859 apaint->u.sweep_gradient.start_angle =
860 F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) );
861 apaint->u.sweep_gradient.end_angle =
862 F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) );
863
864#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
865 if ( do_read_var )
866 {
867 ENSURE_READ_BYTES( 4 );
868 var_index_base = FT_NEXT_ULONG ( p );
869
870 if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 4,
871 item_deltas ) )
872 return 0;
873
874 // TODO: Handle overflow?
875 apaint->u.sweep_gradient.center.x += INT_TO_FIXED( item_deltas[0] );
876 apaint->u.sweep_gradient.center.y += INT_TO_FIXED( item_deltas[1] );
877
878 apaint->u.sweep_gradient.start_angle +=
879 F2DOT14_TO_FIXED( item_deltas[2] );
880 apaint->u.sweep_gradient.end_angle +=
881 F2DOT14_TO_FIXED( item_deltas[3] );
882 }
883#endif
884 apaint->format = FT_COLR_PAINTFORMAT_SWEEP_GRADIENT;
885
886 return 1;
887 }
888
889 if ( apaint->format == FT_COLR_PAINTFORMAT_GLYPH )
890 {
891 ENSURE_READ_BYTES( 2 );
892 apaint->u.glyph.paint.p = child_table_p;
893 apaint->u.glyph.paint.insert_root_transform = 0;
894 apaint->u.glyph.glyphID = FT_NEXT_USHORT( p );
895
896 return 1;
897 }
898
899 else if ( apaint->format == FT_COLR_PAINTFORMAT_TRANSFORM ||
900 (FT_PaintFormat_Internal)apaint->format ==
901 FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSFORM )
902 {
903 apaint->u.transform.paint.p = child_table_p;
904 apaint->u.transform.paint.insert_root_transform = 0;
905
906 if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) )
907 return 0;
908
909 p = child_table_p;
910
911 /*
912 * The following matrix coefficients are encoded as
913 * OpenType 16.16 fixed-point values.
914 */
915 ENSURE_READ_BYTES( 24 );
916 apaint->u.transform.affine.xx = FT_NEXT_LONG( p );
917 apaint->u.transform.affine.yx = FT_NEXT_LONG( p );
918 apaint->u.transform.affine.xy = FT_NEXT_LONG( p );
919 apaint->u.transform.affine.yy = FT_NEXT_LONG( p );
920 apaint->u.transform.affine.dx = FT_NEXT_LONG( p );
921 apaint->u.transform.affine.dy = FT_NEXT_LONG( p );
922
923#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
924 if ( (FT_PaintFormat_Internal)apaint->format ==
925 FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSFORM )
926 {
927 ENSURE_READ_BYTES( 4 );
928 var_index_base = FT_NEXT_ULONG( p );
929
930 if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 6,
931 item_deltas ) )
932 return 0;
933
934 apaint->u.transform.affine.xx += (FT_Fixed)item_deltas[0];
935 apaint->u.transform.affine.yx += (FT_Fixed)item_deltas[1];
936 apaint->u.transform.affine.xy += (FT_Fixed)item_deltas[2];
937 apaint->u.transform.affine.yy += (FT_Fixed)item_deltas[3];
938 apaint->u.transform.affine.dx += (FT_Fixed)item_deltas[4];
939 apaint->u.transform.affine.dy += (FT_Fixed)item_deltas[5];
940 }
941#endif
942
943 apaint->format = FT_COLR_PAINTFORMAT_TRANSFORM;
944
945 return 1;
946 }
947
948 else if ( apaint->format == FT_COLR_PAINTFORMAT_TRANSLATE ||
949 (FT_PaintFormat_Internal)apaint->format ==
950 FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSLATE )
951 {
952 apaint->u.translate.paint.p = child_table_p;
953 apaint->u.translate.paint.insert_root_transform = 0;
954
955 ENSURE_READ_BYTES( 4 );
956 apaint->u.translate.dx = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
957 apaint->u.translate.dy = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
958
959#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
960 if ( (FT_PaintFormat_Internal)apaint->format ==
961 FT_COLR_PAINTFORMAT_INTERNAL_VAR_TRANSLATE )
962 {
963 ENSURE_READ_BYTES( 4 );
964 var_index_base = FT_NEXT_ULONG( p );
965
966 if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 2,
967 item_deltas ) )
968 return 0;
969
970 apaint->u.translate.dx += INT_TO_FIXED( item_deltas[0] );
971 apaint->u.translate.dy += INT_TO_FIXED( item_deltas[1] );
972 }
973#endif
974
975 apaint->format = FT_COLR_PAINTFORMAT_TRANSLATE;
976
977 return 1;
978 }
979
980 else if ( apaint->format >= FT_COLR_PAINTFORMAT_SCALE &&
981 (FT_PaintFormat_Internal)apaint->format <=
982 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER )
983 {
984 apaint->u.scale.paint.p = child_table_p;
985 apaint->u.scale.paint.insert_root_transform = 0;
986
987 /* All scale paints get at least one scale value. */
988 ENSURE_READ_BYTES( 2 );
989 apaint->u.scale.scale_x = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) );
990
991 /* Non-uniform ones read an extra y value. */
992 if ( apaint->format == FT_COLR_PAINTFORMAT_SCALE ||
993 (FT_PaintFormat_Internal)apaint->format ==
994 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE ||
995 (FT_PaintFormat_Internal)apaint->format ==
996 FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER ||
997 (FT_PaintFormat_Internal)apaint->format ==
998 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER )
999 {
1000 ENSURE_READ_BYTES( 2 );
1001 apaint->u.scale.scale_y = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) );
1002 }
1003 else
1004 apaint->u.scale.scale_y = apaint->u.scale.scale_x;
1005
1006 /* Scale paints that have a center read center coordinates, */
1007 /* otherwise the center is (0,0). */
1008 if ( (FT_PaintFormat_Internal)apaint->format ==
1009 FT_COLR_PAINTFORMAT_INTERNAL_SCALE_CENTER ||
1010 (FT_PaintFormat_Internal)apaint->format ==
1011 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER ||
1012 (FT_PaintFormat_Internal)apaint->format ==
1013 FT_COLR_PAINTFORMAT_INTERNAL_SCALE_UNIFORM_CENTER ||
1014 (FT_PaintFormat_Internal)apaint->format ==
1015 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER )
1016 {
1017 ENSURE_READ_BYTES( 4 );
1018 apaint->u.scale.center_x = INT_TO_FIXED( FT_NEXT_SHORT ( p ) );
1019 apaint->u.scale.center_y = INT_TO_FIXED( FT_NEXT_SHORT ( p ) );
1020 }
1021 else
1022 {
1023 apaint->u.scale.center_x = 0;
1024 apaint->u.scale.center_y = 0;
1025 }
1026
1027 /* Base values set, now handle variations. */
1028
1029#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
1030 if ( (FT_PaintFormat_Internal)apaint->format ==
1031 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE ||
1032 (FT_PaintFormat_Internal)apaint->format ==
1033 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER ||
1034 (FT_PaintFormat_Internal)apaint->format ==
1035 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM ||
1036 (FT_PaintFormat_Internal)apaint->format ==
1037 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER )
1038 {
1039 ENSURE_READ_BYTES( 4 );
1040 var_index_base = FT_NEXT_ULONG( p );
1041
1042 if ( (FT_PaintFormat_Internal)apaint->format ==
1043 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE )
1044 {
1045 if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 2,
1046 item_deltas ) )
1047 return 0;
1048
1049 apaint->u.scale.scale_x += F2DOT14_TO_FIXED( item_deltas[0] );
1050 apaint->u.scale.scale_y += F2DOT14_TO_FIXED( item_deltas[1] );
1051 }
1052
1053 if ( (FT_PaintFormat_Internal)apaint->format ==
1054 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_CENTER )
1055 {
1056 if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 4,
1057 item_deltas ) )
1058 return 0;
1059
1060 apaint->u.scale.scale_x += F2DOT14_TO_FIXED( item_deltas[0] );
1061 apaint->u.scale.scale_y += F2DOT14_TO_FIXED( item_deltas[1] );
1062 apaint->u.scale.center_x += INT_TO_FIXED( item_deltas[2] );
1063 apaint->u.scale.center_y += INT_TO_FIXED( item_deltas[3] );
1064 }
1065
1066 if ( (FT_PaintFormat_Internal)apaint->format ==
1067 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM )
1068 {
1069 if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 1,
1070 item_deltas ) )
1071 return 0;
1072
1073 apaint->u.scale.scale_x += F2DOT14_TO_FIXED( item_deltas[0] );
1074 apaint->u.scale.scale_y += F2DOT14_TO_FIXED( item_deltas[0] );
1075 }
1076
1077 if ( (FT_PaintFormat_Internal)apaint->format ==
1078 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SCALE_UNIFORM_CENTER )
1079 {
1080 if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 3,
1081 item_deltas ) )
1082 return 0;
1083
1084 apaint->u.scale.scale_x += F2DOT14_TO_FIXED( item_deltas[0] );
1085 apaint->u.scale.scale_y += F2DOT14_TO_FIXED( item_deltas[0] );
1086 apaint->u.scale.center_x += INT_TO_FIXED( item_deltas[1] );
1087 apaint->u.scale.center_y += INT_TO_FIXED( item_deltas[2] );
1088 }
1089 }
1090#endif
1091
1092 /* FT 'COLR' v1 API output format always returns fully defined */
1093 /* structs; we thus set the format to the public API value. */
1094 apaint->format = FT_COLR_PAINTFORMAT_SCALE;
1095
1096 return 1;
1097 }
1098
1099 else if ( apaint->format == FT_COLR_PAINTFORMAT_ROTATE ||
1100 (FT_PaintFormat_Internal)apaint->format ==
1101 FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER ||
1102 (FT_PaintFormat_Internal)apaint->format ==
1103 FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE ||
1104 (FT_PaintFormat_Internal)apaint->format ==
1105 FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER )
1106 {
1107 apaint->u.rotate.paint.p = child_table_p;
1108 apaint->u.rotate.paint.insert_root_transform = 0;
1109
1110 ENSURE_READ_BYTES( 2 );
1111 apaint->u.rotate.angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) );
1112
1113 if ( (FT_PaintFormat_Internal)apaint->format ==
1114 FT_COLR_PAINTFORMAT_INTERNAL_ROTATE_CENTER ||
1115 (FT_PaintFormat_Internal)apaint->format ==
1116 FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER )
1117 {
1118 ENSURE_READ_BYTES( 4 );
1119 apaint->u.rotate.center_x = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
1120 apaint->u.rotate.center_y = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
1121 }
1122 else
1123 {
1124 apaint->u.rotate.center_x = 0;
1125 apaint->u.rotate.center_y = 0;
1126 }
1127
1128#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
1129 if ( (FT_PaintFormat_Internal)apaint->format ==
1130 FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE ||
1131 (FT_PaintFormat_Internal)apaint->format ==
1132 FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER )
1133 {
1134 FT_UInt num_deltas = 0;
1135
1136
1137 ENSURE_READ_BYTES( 4 );
1138 var_index_base = FT_NEXT_ULONG( p );
1139
1140 if ( (FT_PaintFormat_Internal)apaint->format ==
1141 FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE_CENTER )
1142 num_deltas = 3;
1143 if ( (FT_PaintFormat_Internal)apaint->format ==
1144 FT_COLR_PAINTFORMAT_INTERNAL_VAR_ROTATE )
1145 num_deltas = 1;
1146
1147 if ( num_deltas > 0 )
1148 {
1149 if ( !get_deltas_for_var_index_base( face, colr, var_index_base,
1150 num_deltas, item_deltas ) )
1151 return 0;
1152
1153 apaint->u.rotate.angle += F2DOT14_TO_FIXED( item_deltas[0] );
1154
1155 if ( num_deltas == 3 )
1156 {
1157 apaint->u.rotate.center_x += INT_TO_FIXED( item_deltas[1] );
1158 apaint->u.rotate.center_y += INT_TO_FIXED( item_deltas[2] );
1159 }
1160 }
1161 }
1162#endif
1163
1164 apaint->format = FT_COLR_PAINTFORMAT_ROTATE;
1165
1166
1167 return 1;
1168 }
1169
1170 else if ( apaint->format == FT_COLR_PAINTFORMAT_SKEW ||
1171 (FT_PaintFormat_Internal)apaint->format ==
1172 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW ||
1173 (FT_PaintFormat_Internal)apaint->format ==
1174 FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER ||
1175 (FT_PaintFormat_Internal)apaint->format ==
1176 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER )
1177 {
1178 apaint->u.skew.paint.p = child_table_p;
1179 apaint->u.skew.paint.insert_root_transform = 0;
1180
1181 ENSURE_READ_BYTES( 4 );
1182 apaint->u.skew.x_skew_angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) );
1183 apaint->u.skew.y_skew_angle = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) );
1184
1185 if ( (FT_PaintFormat_Internal)apaint->format ==
1186 FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER ||
1187 (FT_PaintFormat_Internal)apaint->format ==
1188 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER )
1189 {
1190 ENSURE_READ_BYTES( 4 );
1191 apaint->u.skew.center_x = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
1192 apaint->u.skew.center_y = INT_TO_FIXED( FT_NEXT_SHORT( p ) );
1193 }
1194 else
1195 {
1196 apaint->u.skew.center_x = 0;
1197 apaint->u.skew.center_y = 0;
1198 }
1199
1200
1201#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
1202 if ( (FT_PaintFormat_Internal)apaint->format ==
1203 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW ||
1204 (FT_PaintFormat_Internal)apaint->format ==
1205 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER )
1206 {
1207 ENSURE_READ_BYTES( 4 );
1208 var_index_base = FT_NEXT_ULONG( p );
1209
1210 if ( (FT_PaintFormat_Internal)apaint->format ==
1211 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW )
1212 {
1213 if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 2,
1214 item_deltas ) )
1215 return 0;
1216
1217 apaint->u.skew.x_skew_angle += F2DOT14_TO_FIXED( item_deltas[0] );
1218 apaint->u.skew.y_skew_angle += F2DOT14_TO_FIXED( item_deltas[1] );
1219 }
1220
1221 if ( (FT_PaintFormat_Internal)apaint->format ==
1222 FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER )
1223 {
1224 if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 4,
1225 item_deltas ) )
1226 return 0;
1227
1228 apaint->u.skew.x_skew_angle += F2DOT14_TO_FIXED( item_deltas[0] );
1229 apaint->u.skew.y_skew_angle += F2DOT14_TO_FIXED( item_deltas[1] );
1230 apaint->u.skew.center_x += INT_TO_FIXED( item_deltas[2] );
1231 apaint->u.skew.center_y += INT_TO_FIXED( item_deltas[3] );
1232 }
1233 }
1234#endif
1235
1236 apaint->format = FT_COLR_PAINTFORMAT_SKEW;
1237
1238 return 1;
1239 }
1240
1241 else if ( apaint->format == FT_COLR_PAINTFORMAT_COMPOSITE )
1242 {
1243 FT_UInt composite_mode;
1244
1245
1246 apaint->u.composite.source_paint.p = child_table_p;
1247 apaint->u.composite.source_paint.insert_root_transform = 0;
1248
1249 ENSURE_READ_BYTES( 1 );
1250 composite_mode = FT_NEXT_BYTE( p );
1251 if ( composite_mode >= FT_COLR_COMPOSITE_MAX )
1252 return 0;
1253
1254 apaint->u.composite.composite_mode = (FT_Composite_Mode)composite_mode;
1255
1256 if ( !get_child_table_pointer( colr, paint_base, &p, &child_table_p ) )
1257 return 0;
1258
1259 apaint->u.composite.backdrop_paint.p =
1260 child_table_p;
1261 apaint->u.composite.backdrop_paint.insert_root_transform =
1262 0;
1263
1264 return 1;
1265 }
1266
1267 return 0;
1268 }
1269
1270
1271 static FT_Bool
1272 find_base_glyph_v1_record( FT_Byte * base_glyph_begin,
1273 FT_UInt num_base_glyph,
1274 FT_UInt glyph_id,
1275 BaseGlyphV1Record *record )
1276 {
1277 FT_UInt min = 0;
1278 FT_UInt max = num_base_glyph;
1279
1280
1281 while ( min < max )
1282 {
1283 FT_UInt mid = min + ( max - min ) / 2;
1284 FT_UShort gid;
1285
1286 /*
1287 * `base_glyph_begin` is the beginning of `BaseGlyphV1List`;
1288 * skip `numBaseGlyphV1Records` by adding 4 to start binary search
1289 * in the array of `BaseGlyphV1Record`.
1290 */
1291 FT_Byte *p = base_glyph_begin + 4 + mid * BASE_GLYPH_PAINT_RECORD_SIZE;
1292
1293 gid = FT_NEXT_USHORT( p );
1294
1295 if ( gid < glyph_id )
1296 min = mid + 1;
1297 else if (gid > glyph_id )
1298 max = mid;
1299 else
1300 {
1301 record->gid = gid;
1302 record->paint_offset = FT_NEXT_ULONG ( p );
1303 return 1;
1304 }
1305 }
1306
1307 return 0;
1308 }
1309
1310
1311 FT_LOCAL_DEF( FT_Bool )
1312 tt_face_get_colr_glyph_paint( TT_Face face,
1313 FT_UInt base_glyph,
1314 FT_Color_Root_Transform root_transform,
1315 FT_OpaquePaint* opaque_paint )
1316 {
1317 Colr* colr = (Colr*)face->colr;
1318 BaseGlyphV1Record base_glyph_v1_record;
1319 FT_Byte* p;
1320
1321 if ( !colr || !colr->table )
1322 return 0;
1323
1324 if ( colr->version < 1 || !colr->num_base_glyphs_v1 ||
1325 !colr->base_glyphs_v1 )
1326 return 0;
1327
1328 if ( opaque_paint->p )
1329 return 0;
1330
1331 if ( !find_base_glyph_v1_record( colr->base_glyphs_v1,
1332 colr->num_base_glyphs_v1,
1333 base_glyph,
1334 &base_glyph_v1_record ) )
1335 return 0;
1336
1337 if ( !base_glyph_v1_record.paint_offset ||
1338 base_glyph_v1_record.paint_offset > colr->table_size )
1339 return 0;
1340
1341 p = (FT_Byte*)( colr->base_glyphs_v1 +
1342 base_glyph_v1_record.paint_offset );
1343 if ( p >= ( (FT_Byte*)colr->table + colr->table_size ) )
1344 return 0;
1345
1346 opaque_paint->p = p;
1347
1348 if ( root_transform == FT_COLOR_INCLUDE_ROOT_TRANSFORM )
1349 opaque_paint->insert_root_transform = 1;
1350 else
1351 opaque_paint->insert_root_transform = 0;
1352
1353 return 1;
1354 }
1355
1356
1357 FT_LOCAL_DEF( FT_Bool )
1358 tt_face_get_color_glyph_clipbox( TT_Face face,
1359 FT_UInt base_glyph,
1360 FT_ClipBox* clip_box )
1361 {
1362 Colr* colr;
1363
1364 FT_Byte *p, *p1, *clip_base, *limit;
1365
1366 FT_Byte clip_list_format;
1367 FT_ULong num_clip_boxes, i;
1368 FT_UShort gid_start, gid_end;
1369 FT_UInt32 clip_box_offset;
1370 FT_Byte format;
1371
1372 const FT_Byte num_corners = 4;
1373 FT_Vector corners[4];
1374 FT_Byte j;
1375 FT_BBox font_clip_box;
1376
1377
1378 colr = (Colr*)face->colr;
1379 if ( !colr )
1380 return 0;
1381
1382 if ( !colr->clip_list )
1383 return 0;
1384
1385 p = colr->clip_list;
1386
1387 /* Limit points to the first byte after the end of the color table. */
1388 /* Thus, in subsequent limit checks below we need to check whether the */
1389 /* read pointer is strictly greater than a position offset by certain */
1390 /* field sizes to the left of that position. */
1391 limit = (FT_Byte*)colr->table + colr->table_size;
1392
1393 /* Check whether we can extract one `uint8` and one `uint32`. */
1394 if ( p > limit - ( 1 + 4 ) )
1395 return 0;
1396
1397 clip_base = p;
1398 clip_list_format = FT_NEXT_BYTE ( p );
1399
1400 /* Format byte used here to be able to upgrade ClipList for >16bit */
1401 /* glyph ids; for now we can expect it to be 1. */
1402 if ( !( clip_list_format == 1 ) )
1403 return 0;
1404
1405 num_clip_boxes = FT_NEXT_ULONG( p );
1406
1407 /* Check whether we can extract two `uint16` and one `Offset24`, */
1408 /* `num_clip_boxes` times. */
1409 if ( colr->table_size / ( 2 + 2 + 3 ) < num_clip_boxes ||
1410 p > limit - ( 2 + 2 + 3 ) * num_clip_boxes )
1411 return 0;
1412
1413 for ( i = 0; i < num_clip_boxes; ++i )
1414 {
1415 gid_start = FT_NEXT_USHORT( p );
1416 gid_end = FT_NEXT_USHORT( p );
1417 clip_box_offset = FT_NEXT_UOFF3( p );
1418
1419 if ( base_glyph >= gid_start && base_glyph <= gid_end )
1420 {
1421 p1 = (FT_Byte*)( clip_base + clip_box_offset );
1422
1423 /* Check whether we can extract one `uint8`. */
1424 if ( p1 > limit - 1 )
1425 return 0;
1426
1427 format = FT_NEXT_BYTE( p1 );
1428
1429 if ( format > 2 )
1430 return 0;
1431
1432 /* Check whether we can extract four `FWORD`. */
1433 if ( p1 > limit - ( 2 + 2 + 2 + 2 ) )
1434 return 0;
1435
1436 /* `face->root.size->metrics.x_scale` and `y_scale` are factors */
1437 /* that scale a font unit value in integers to a 26.6 fixed value */
1438 /* according to the requested size, see for example */
1439 /* `ft_recompute_scaled_metrics`. */
1440 font_clip_box.xMin = FT_MulFix( FT_NEXT_SHORT( p1 ),
1441 face->root.size->metrics.x_scale );
1442 font_clip_box.yMin = FT_MulFix( FT_NEXT_SHORT( p1 ),
1443 face->root.size->metrics.y_scale );
1444 font_clip_box.xMax = FT_MulFix( FT_NEXT_SHORT( p1 ),
1445 face->root.size->metrics.x_scale );
1446 font_clip_box.yMax = FT_MulFix( FT_NEXT_SHORT( p1 ),
1447 face->root.size->metrics.y_scale );
1448
1449#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
1450 if ( format == 2 )
1451 {
1452 FT_ULong var_index_base = 0;
1453 /* varIndexBase offset for clipbox is 3 at most. */
1454 FT_ItemVarDelta item_deltas[4] = { 0, 0, 0, 0 };
1455
1456
1457 /* Check whether we can extract a 32-bit varIndexBase now. */
1458 if ( p1 > limit - 4 )
1459 return 0;
1460
1461 var_index_base = FT_NEXT_ULONG( p1 );
1462
1463 if ( !get_deltas_for_var_index_base( face, colr, var_index_base, 4,
1464 item_deltas ) )
1465 return 0;
1466
1467 font_clip_box.xMin +=
1468 FT_MulFix( item_deltas[0], face->root.size->metrics.x_scale );
1469 font_clip_box.yMin +=
1470 FT_MulFix( item_deltas[1], face->root.size->metrics.y_scale );
1471 font_clip_box.xMax +=
1472 FT_MulFix( item_deltas[2], face->root.size->metrics.x_scale );
1473 font_clip_box.yMax +=
1474 FT_MulFix( item_deltas[3], face->root.size->metrics.y_scale );
1475 }
1476#endif
1477
1478 /* Make 4 corner points (xMin, yMin), (xMax, yMax) and transform */
1479 /* them. If we we would only transform two corner points and */
1480 /* span a rectangle based on those, the rectangle may become too */
1481 /* small to cover the glyph. */
1482 corners[0].x = font_clip_box.xMin;
1483 corners[1].x = font_clip_box.xMin;
1484 corners[2].x = font_clip_box.xMax;
1485 corners[3].x = font_clip_box.xMax;
1486
1487 corners[0].y = font_clip_box.yMin;
1488 corners[1].y = font_clip_box.yMax;
1489 corners[2].y = font_clip_box.yMax;
1490 corners[3].y = font_clip_box.yMin;
1491
1492 for ( j = 0; j < num_corners; ++j )
1493 {
1494 if ( face->root.internal->transform_flags & 1 )
1495 FT_Vector_Transform( &corners[j],
1496 &face->root.internal->transform_matrix );
1497
1498 if ( face->root.internal->transform_flags & 2 )
1499 {
1500 corners[j].x += face->root.internal->transform_delta.x;
1501 corners[j].y += face->root.internal->transform_delta.y;
1502 }
1503 }
1504
1505 clip_box->bottom_left = corners[0];
1506 clip_box->top_left = corners[1];
1507 clip_box->top_right = corners[2];
1508 clip_box->bottom_right = corners[3];
1509
1510 return 1;
1511 }
1512 }
1513
1514 return 0;
1515 }
1516
1517
1518 FT_LOCAL_DEF( FT_Bool )
1519 tt_face_get_paint_layers( TT_Face face,
1520 FT_LayerIterator* iterator,
1521 FT_OpaquePaint* opaque_paint )
1522 {
1523 FT_Byte* p = NULL;
1524 FT_Byte* p_first_layer = NULL;
1525 FT_Byte* p_paint = NULL;
1526 FT_UInt32 paint_offset;
1527
1528 Colr* colr;
1529
1530
1531 if ( iterator->layer == iterator->num_layers )
1532 return 0;
1533
1534 colr = (Colr*)face->colr;
1535 if ( !colr )
1536 return 0;
1537
1538 /*
1539 * We have an iterator pointing at a paint offset as part of the
1540 * `paintOffset` array in `LayerV1List`.
1541 */
1542 p = iterator->p;
1543
1544 /*
1545 * Do a cursor sanity check of the iterator. Counting backwards from
1546 * where it stands, we need to end up at a position after the beginning
1547 * of the `LayerV1List` table and not after the end of the
1548 * `LayerV1List`.
1549 */
1550 p_first_layer = p -
1551 iterator->layer * LAYER_V1_LIST_PAINT_OFFSET_SIZE -
1552 LAYER_V1_LIST_NUM_LAYERS_SIZE;
1553 if ( p_first_layer < (FT_Byte*)colr->layers_v1 )
1554 return 0;
1555 if ( p_first_layer >= (FT_Byte*)(
1556 colr->layers_v1 + LAYER_V1_LIST_NUM_LAYERS_SIZE +
1557 colr->num_layers_v1 * LAYER_V1_LIST_PAINT_OFFSET_SIZE ) )
1558 return 0;
1559
1560 /*
1561 * Before reading, ensure that `p` is within 'COLR' v1 and we can read a
1562 * 4-byte ULONG.
1563 */
1564 if ( p < colr->layers_v1 ||
1565 p > (FT_Byte*)colr->table + colr->table_size - 4 )
1566 return 0;
1567
1568 paint_offset =
1569 FT_NEXT_ULONG( p );
1570 opaque_paint->insert_root_transform =
1571 0;
1572
1573 p_paint = (FT_Byte*)( colr->layers_v1 + paint_offset );
1574
1575 if ( p_paint < colr->paints_start_v1 ||
1576 p_paint >= ( (FT_Byte*)colr->table + colr->table_size ) )
1577 return 0;
1578
1579 opaque_paint->p = p_paint;
1580
1581 iterator->p = p;
1582
1583 iterator->layer++;
1584
1585 return 1;
1586 }
1587
1588
1589 FT_LOCAL_DEF( FT_Bool )
1590 tt_face_get_colorline_stops( TT_Face face,
1591 FT_ColorStop* color_stop,
1592 FT_ColorStopIterator *iterator )
1593 {
1594 Colr* colr = (Colr*)face->colr;
1595
1596 FT_Byte* p;
1597 FT_ULong var_index_base;
1598 FT_Byte* last_entry_p = NULL;
1599 FT_UInt entry_size = COLOR_STOP_SIZE;
1600
1601
1602 if ( !colr || !colr->table || !iterator )
1603 return 0;
1604
1605 if ( iterator->current_color_stop >= iterator->num_color_stops )
1606 return 0;
1607
1608 if ( iterator->read_variable )
1609 entry_size += VAR_IDX_BASE_SIZE;
1610
1611 /* Calculate the start pointer for the last to-be-read (Var)ColorStop */
1612 /* and check whether we can read a full (Var)ColorStop at that */
1613 /* position by comparing it to the position that is the size of one */
1614 /* (Var)ColorStop before the end of the 'COLR' table. */
1615 last_entry_p =
1616 iterator->p + ( iterator->num_color_stops - 1 -
1617 iterator->current_color_stop ) * entry_size;
1618 if ( iterator->p < colr->paints_start_v1 ||
1619 last_entry_p > (FT_Byte*)colr->table +
1620 colr->table_size - entry_size )
1621 return 0;
1622
1623 /* Iterator points at first `ColorStop` of `ColorLine`. */
1624 p = iterator->p;
1625
1626 color_stop->stop_offset = F2DOT14_TO_FIXED( FT_NEXT_SHORT( p ) );
1627
1628 color_stop->color.palette_index = FT_NEXT_USHORT( p );
1629
1630 color_stop->color.alpha = FT_NEXT_SHORT( p );
1631
1632 if ( iterator->read_variable )
1633 {
1634 /* Pointer p needs to be advanced independently of whether we intend */
1635 /* to take variable deltas into account or not. Otherwise iteration */
1636 /* would fail due to wrong offsets. */
1637 var_index_base = FT_NEXT_ULONG( p );
1638
1639#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT
1640 {
1641 FT_Int item_deltas[2];
1642
1643
1644 if ( !get_deltas_for_var_index_base( face, colr,
1645 var_index_base,
1646 2,
1647 item_deltas ) )
1648 return 0;
1649
1650 color_stop->stop_offset += F2DOT14_TO_FIXED( item_deltas[0] );
1651 color_stop->color.alpha += (FT_F2Dot14)item_deltas[1];
1652 }
1653#else
1654 FT_UNUSED( var_index_base );
1655#endif
1656 }
1657
1658 iterator->p = p;
1659 iterator->current_color_stop++;
1660
1661 return 1;
1662 }
1663
1664
1665 FT_LOCAL_DEF( FT_Bool )
1666 tt_face_get_paint( TT_Face face,
1667 FT_OpaquePaint opaque_paint,
1668 FT_COLR_Paint* paint )
1669 {
1670 Colr* colr = (Colr*)face->colr;
1671 FT_OpaquePaint next_paint;
1672 FT_Matrix ft_root_scale;
1673
1674 if ( !colr || !colr->base_glyphs_v1 || !colr->table )
1675 return 0;
1676
1677 if ( opaque_paint.insert_root_transform )
1678 {
1679 /* 'COLR' v1 glyph information is returned in unscaled coordinates,
1680 * i.e., `FT_Size` is not applied or multiplied into the values. When
1681 * client applications draw color glyphs, they can request to include
1682 * a top-level transform, which includes the active `x_scale` and
1683 * `y_scale` information for scaling the glyph, as well the additional
1684 * transform and translate configured through `FT_Set_Transform`.
1685 * This allows client applications to apply this top-level transform
1686 * to the graphics context first and only once, then have gradient and
1687 * contour scaling applied correctly when performing the additional
1688 * drawing operations for subsequenct paints. Prepare this initial
1689 * transform here.
1690 */
1691 paint->format = FT_COLR_PAINTFORMAT_TRANSFORM;
1692
1693 next_paint.p = opaque_paint.p;
1694 next_paint.insert_root_transform = 0;
1695 paint->u.transform.paint = next_paint;
1696
1697 /* `x_scale` and `y_scale` are in 26.6 format, representing the scale
1698 * factor to get from font units to requested size. However, expected
1699 * return values are in 16.16, so we shift accordingly with rounding.
1700 */
1701 ft_root_scale.xx = ( face->root.size->metrics.x_scale + 32 ) >> 6;
1702 ft_root_scale.xy = 0;
1703 ft_root_scale.yx = 0;
1704 ft_root_scale.yy = ( face->root.size->metrics.y_scale + 32 ) >> 6;
1705
1706 if ( face->root.internal->transform_flags & 1 )
1707 FT_Matrix_Multiply( &face->root.internal->transform_matrix,
1708 &ft_root_scale );
1709
1710 paint->u.transform.affine.xx = ft_root_scale.xx;
1711 paint->u.transform.affine.xy = ft_root_scale.xy;
1712 paint->u.transform.affine.yx = ft_root_scale.yx;
1713 paint->u.transform.affine.yy = ft_root_scale.yy;
1714
1715 /* The translation is specified in 26.6 format and, according to the
1716 * documentation of `FT_Set_Translate`, is performed on the character
1717 * size given in the last call to `FT_Set_Char_Size`. The
1718 * 'PaintTransform' paint table's `FT_Affine23` format expects
1719 * values in 16.16 format, thus we need to shift by 10 bits.
1720 */
1721 if ( face->root.internal->transform_flags & 2 )
1722 {
1723 paint->u.transform.affine.dx =
1724 face->root.internal->transform_delta.x * ( 1 << 10 );
1725 paint->u.transform.affine.dy =
1726 face->root.internal->transform_delta.y * ( 1 << 10 );
1727 }
1728 else
1729 {
1730 paint->u.transform.affine.dx = 0;
1731 paint->u.transform.affine.dy = 0;
1732 }
1733
1734 return 1;
1735 }
1736
1737 return read_paint( face, colr, opaque_paint.p, paint );
1738 }
1739
1740
1741 FT_LOCAL_DEF( FT_Error )
1742 tt_face_colr_blend_layer( TT_Face face,
1743 FT_UInt color_index,
1744 FT_GlyphSlot dstSlot,
1745 FT_GlyphSlot srcSlot )
1746 {
1747 FT_Error error;
1748
1749 FT_UInt x, y;
1750 FT_Byte b, g, r, alpha;
1751
1752 FT_ULong size;
1753 FT_Byte* src;
1754 FT_Byte* dst;
1755
1756
1757 if ( !dstSlot->bitmap.buffer )
1758 {
1759 /* Initialize destination of color bitmap */
1760 /* with the size of first component. */
1761 dstSlot->bitmap_left = srcSlot->bitmap_left;
1762 dstSlot->bitmap_top = srcSlot->bitmap_top;
1763
1764 dstSlot->bitmap.width = srcSlot->bitmap.width;
1765 dstSlot->bitmap.rows = srcSlot->bitmap.rows;
1766 dstSlot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
1767 dstSlot->bitmap.pitch = (int)dstSlot->bitmap.width * 4;
1768 dstSlot->bitmap.num_grays = 256;
1769
1770 size = dstSlot->bitmap.rows * (unsigned int)dstSlot->bitmap.pitch;
1771
1772 error = ft_glyphslot_alloc_bitmap( dstSlot, size );
1773 if ( error )
1774 return error;
1775
1776 FT_MEM_ZERO( dstSlot->bitmap.buffer, size );
1777 }
1778 else
1779 {
1780 /* Resize destination if needed such that new component fits. */
1781 FT_Int x_min, x_max, y_min, y_max;
1782
1783
1784 x_min = FT_MIN( dstSlot->bitmap_left, srcSlot->bitmap_left );
1785 x_max = FT_MAX( dstSlot->bitmap_left + (FT_Int)dstSlot->bitmap.width,
1786 srcSlot->bitmap_left + (FT_Int)srcSlot->bitmap.width );
1787
1788 y_min = FT_MIN( dstSlot->bitmap_top - (FT_Int)dstSlot->bitmap.rows,
1789 srcSlot->bitmap_top - (FT_Int)srcSlot->bitmap.rows );
1790 y_max = FT_MAX( dstSlot->bitmap_top, srcSlot->bitmap_top );
1791
1792 if ( x_min != dstSlot->bitmap_left ||
1793 x_max != dstSlot->bitmap_left + (FT_Int)dstSlot->bitmap.width ||
1794 y_min != dstSlot->bitmap_top - (FT_Int)dstSlot->bitmap.rows ||
1795 y_max != dstSlot->bitmap_top )
1796 {
1797 FT_Memory memory = face->root.memory;
1798
1799 FT_UInt width = (FT_UInt)( x_max - x_min );
1800 FT_UInt rows = (FT_UInt)( y_max - y_min );
1801 FT_UInt pitch = width * 4;
1802
1803 FT_Byte* buf = NULL;
1804 FT_Byte* p;
1805 FT_Byte* q;
1806
1807
1808 size = rows * pitch;
1809 if ( FT_ALLOC( buf, size ) )
1810 return error;
1811
1812 p = dstSlot->bitmap.buffer;
1813 q = buf +
1814 (int)pitch * ( y_max - dstSlot->bitmap_top ) +
1815 4 * ( dstSlot->bitmap_left - x_min );
1816
1817 for ( y = 0; y < dstSlot->bitmap.rows; y++ )
1818 {
1819 FT_MEM_COPY( q, p, dstSlot->bitmap.width * 4 );
1820
1821 p += dstSlot->bitmap.pitch;
1822 q += pitch;
1823 }
1824
1825 ft_glyphslot_set_bitmap( dstSlot, buf );
1826
1827 dstSlot->bitmap_top = y_max;
1828 dstSlot->bitmap_left = x_min;
1829
1830 dstSlot->bitmap.width = width;
1831 dstSlot->bitmap.rows = rows;
1832 dstSlot->bitmap.pitch = (int)pitch;
1833
1834 dstSlot->internal->flags |= FT_GLYPH_OWN_BITMAP;
1835 dstSlot->format = FT_GLYPH_FORMAT_BITMAP;
1836 }
1837 }
1838
1839 if ( color_index == 0xFFFF )
1840 {
1841 if ( face->have_foreground_color )
1842 {
1843 b = face->foreground_color.blue;
1844 g = face->foreground_color.green;
1845 r = face->foreground_color.red;
1846 alpha = face->foreground_color.alpha;
1847 }
1848 else
1849 {
1850 if ( face->palette_data.palette_flags &&
1851 ( face->palette_data.palette_flags[face->palette_index] &
1852 FT_PALETTE_FOR_DARK_BACKGROUND ) )
1853 {
1854 /* white opaque */
1855 b = 0xFF;
1856 g = 0xFF;
1857 r = 0xFF;
1858 alpha = 0xFF;
1859 }
1860 else
1861 {
1862 /* black opaque */
1863 b = 0x00;
1864 g = 0x00;
1865 r = 0x00;
1866 alpha = 0xFF;
1867 }
1868 }
1869 }
1870 else
1871 {
1872 b = face->palette[color_index].blue;
1873 g = face->palette[color_index].green;
1874 r = face->palette[color_index].red;
1875 alpha = face->palette[color_index].alpha;
1876 }
1877
1878 /* XXX Convert if srcSlot.bitmap is not grey? */
1879 src = srcSlot->bitmap.buffer;
1880 dst = dstSlot->bitmap.buffer +
1881 dstSlot->bitmap.pitch * ( dstSlot->bitmap_top - srcSlot->bitmap_top ) +
1882 4 * ( srcSlot->bitmap_left - dstSlot->bitmap_left );
1883
1884 for ( y = 0; y < srcSlot->bitmap.rows; y++ )
1885 {
1886 for ( x = 0; x < srcSlot->bitmap.width; x++ )
1887 {
1888 int aa = src[x];
1889 int fa = alpha * aa / 255;
1890
1891 int fb = b * fa / 255;
1892 int fg = g * fa / 255;
1893 int fr = r * fa / 255;
1894
1895 int ba2 = 255 - fa;
1896
1897 int bb = dst[4 * x + 0];
1898 int bg = dst[4 * x + 1];
1899 int br = dst[4 * x + 2];
1900 int ba = dst[4 * x + 3];
1901
1902
1903 dst[4 * x + 0] = (FT_Byte)( bb * ba2 / 255 + fb );
1904 dst[4 * x + 1] = (FT_Byte)( bg * ba2 / 255 + fg );
1905 dst[4 * x + 2] = (FT_Byte)( br * ba2 / 255 + fr );
1906 dst[4 * x + 3] = (FT_Byte)( ba * ba2 / 255 + fa );
1907 }
1908
1909 src += srcSlot->bitmap.pitch;
1910 dst += dstSlot->bitmap.pitch;
1911 }
1912
1913 return FT_Err_Ok;
1914 }
1915
1916#else /* !TT_CONFIG_OPTION_COLOR_LAYERS */
1917
1918 /* ANSI C doesn't like empty source files */
1919 typedef int tt_colr_dummy_;
1920
1921#endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */
1922
1923/* EOF */