1/****************************************************************************
2 *
3 * ttcolr.c
4 *
5 * TrueType and OpenType colored glyph layer support (body).
6 *
7 * Copyright (C) 2018-2019 by
8 * David Turner, Robert Wilhelm, 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 <ft2build.h>
31#include FT_INTERNAL_DEBUG_H
32#include FT_INTERNAL_STREAM_H
33#include FT_TRUETYPE_TAGS_H
34#include FT_COLOR_H
35
36
37#ifdef TT_CONFIG_OPTION_COLOR_LAYERS
38
39#include "ttcolr.h"
40
41
42 /* NOTE: These are the table sizes calculated through the specs. */
43#define BASE_GLYPH_SIZE 6
44#define LAYER_SIZE 4
45#define COLR_HEADER_SIZE 14
46
47
48 typedef struct BaseGlyphRecord_
49 {
50 FT_UShort gid;
51 FT_UShort first_layer_index;
52 FT_UShort num_layers;
53
54 } BaseGlyphRecord;
55
56
57 typedef struct Colr_
58 {
59 FT_UShort version;
60 FT_UShort num_base_glyphs;
61 FT_UShort num_layers;
62
63 FT_Byte* base_glyphs;
64 FT_Byte* layers;
65
66 /* The memory which backs up the `COLR' table. */
67 void* table;
68 FT_ULong table_size;
69
70 } Colr;
71
72
73 /**************************************************************************
74 *
75 * The macro FT_COMPONENT is used in trace mode. It is an implicit
76 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
77 * messages during execution.
78 */
79#undef FT_COMPONENT
80#define FT_COMPONENT ttcolr
81
82
83 FT_LOCAL_DEF( FT_Error )
84 tt_face_load_colr( TT_Face face,
85 FT_Stream stream )
86 {
87 FT_Error error;
88 FT_Memory memory = face->root.memory;
89
90 FT_Byte* table = NULL;
91 FT_Byte* p = NULL;
92
93 Colr* colr = NULL;
94
95 FT_ULong base_glyph_offset, layer_offset;
96 FT_ULong table_size;
97
98
99 /* `COLR' always needs `CPAL' */
100 if ( !face->cpal )
101 return FT_THROW( Invalid_File_Format );
102
103 error = face->goto_table( face, TTAG_COLR, stream, &table_size );
104 if ( error )
105 goto NoColr;
106
107 if ( table_size < COLR_HEADER_SIZE )
108 goto InvalidTable;
109
110 if ( FT_FRAME_EXTRACT( table_size, table ) )
111 goto NoColr;
112
113 p = table;
114
115 if ( FT_NEW( colr ) )
116 goto NoColr;
117
118 colr->version = FT_NEXT_USHORT( p );
119 if ( colr->version != 0 )
120 goto InvalidTable;
121
122 colr->num_base_glyphs = FT_NEXT_USHORT( p );
123 base_glyph_offset = FT_NEXT_ULONG( p );
124
125 if ( base_glyph_offset >= table_size )
126 goto InvalidTable;
127 if ( colr->num_base_glyphs * BASE_GLYPH_SIZE >
128 table_size - base_glyph_offset )
129 goto InvalidTable;
130
131 layer_offset = FT_NEXT_ULONG( p );
132 colr->num_layers = FT_NEXT_USHORT( p );
133
134 if ( layer_offset >= table_size )
135 goto InvalidTable;
136 if ( colr->num_layers * LAYER_SIZE > table_size - layer_offset )
137 goto InvalidTable;
138
139 colr->base_glyphs = (FT_Byte*)( table + base_glyph_offset );
140 colr->layers = (FT_Byte*)( table + layer_offset );
141 colr->table = table;
142 colr->table_size = table_size;
143
144 face->colr = colr;
145
146 return FT_Err_Ok;
147
148 InvalidTable:
149 error = FT_THROW( Invalid_Table );
150
151 NoColr:
152 FT_FRAME_RELEASE( table );
153 FT_FREE( colr );
154
155 return error;
156 }
157
158
159 FT_LOCAL_DEF( void )
160 tt_face_free_colr( TT_Face face )
161 {
162 FT_Stream stream = face->root.stream;
163 FT_Memory memory = face->root.memory;
164
165 Colr* colr = (Colr*)face->colr;
166
167
168 if ( colr )
169 {
170 FT_FRAME_RELEASE( colr->table );
171 FT_FREE( colr );
172 }
173 }
174
175
176 static FT_Bool
177 find_base_glyph_record( FT_Byte* base_glyph_begin,
178 FT_Int num_base_glyph,
179 FT_UInt glyph_id,
180 BaseGlyphRecord* record )
181 {
182 FT_Int min = 0;
183 FT_Int max = num_base_glyph - 1;
184
185
186 while ( min <= max )
187 {
188 FT_Int mid = min + ( max - min ) / 2;
189 FT_Byte* p = base_glyph_begin + mid * BASE_GLYPH_SIZE;
190
191 FT_UShort gid = FT_NEXT_USHORT( p );
192
193
194 if ( gid < glyph_id )
195 min = mid + 1;
196 else if (gid > glyph_id )
197 max = mid - 1;
198 else
199 {
200 record->gid = gid;
201 record->first_layer_index = FT_NEXT_USHORT( p );
202 record->num_layers = FT_NEXT_USHORT( p );
203
204 return 1;
205 }
206 }
207
208 return 0;
209 }
210
211
212 FT_LOCAL_DEF( FT_Bool )
213 tt_face_get_colr_layer( TT_Face face,
214 FT_UInt base_glyph,
215 FT_UInt *aglyph_index,
216 FT_UInt *acolor_index,
217 FT_LayerIterator* iterator )
218 {
219 Colr* colr = (Colr*)face->colr;
220 BaseGlyphRecord glyph_record;
221
222
223 if ( !colr )
224 return 0;
225
226 if ( !iterator->p )
227 {
228 FT_ULong offset;
229
230
231 /* first call to function */
232 iterator->layer = 0;
233
234 if ( !find_base_glyph_record( colr->base_glyphs,
235 colr->num_base_glyphs,
236 base_glyph,
237 &glyph_record ) )
238 return 0;
239
240 if ( glyph_record.num_layers )
241 iterator->num_layers = glyph_record.num_layers;
242 else
243 return 0;
244
245 offset = LAYER_SIZE * glyph_record.first_layer_index;
246 if ( offset + LAYER_SIZE * glyph_record.num_layers > colr->table_size )
247 return 0;
248
249 iterator->p = colr->layers + offset;
250 }
251
252 if ( iterator->layer >= iterator->num_layers )
253 return 0;
254
255 *aglyph_index = FT_NEXT_USHORT( iterator->p );
256 *acolor_index = FT_NEXT_USHORT( iterator->p );
257
258 if ( *aglyph_index >= (FT_UInt)( FT_FACE( face )->num_glyphs ) ||
259 ( *acolor_index != 0xFFFF &&
260 *acolor_index >= face->palette_data.num_palette_entries ) )
261 return 0;
262
263 iterator->layer++;
264
265 return 1;
266 }
267
268
269 FT_LOCAL_DEF( FT_Error )
270 tt_face_colr_blend_layer( TT_Face face,
271 FT_UInt color_index,
272 FT_GlyphSlot dstSlot,
273 FT_GlyphSlot srcSlot )
274 {
275 FT_Error error;
276
277 FT_UInt x, y;
278 FT_Byte b, g, r, alpha;
279
280 FT_ULong size;
281 FT_Byte* src;
282 FT_Byte* dst;
283
284
285 if ( !dstSlot->bitmap.buffer )
286 {
287 /* Initialize destination of color bitmap */
288 /* with the size of first component. */
289 dstSlot->bitmap_left = srcSlot->bitmap_left;
290 dstSlot->bitmap_top = srcSlot->bitmap_top;
291
292 dstSlot->bitmap.width = srcSlot->bitmap.width;
293 dstSlot->bitmap.rows = srcSlot->bitmap.rows;
294 dstSlot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
295 dstSlot->bitmap.pitch = (int)dstSlot->bitmap.width * 4;
296 dstSlot->bitmap.num_grays = 256;
297
298 size = dstSlot->bitmap.rows * (unsigned int)dstSlot->bitmap.pitch;
299
300 error = ft_glyphslot_alloc_bitmap( dstSlot, size );
301 if ( error )
302 return error;
303
304 FT_MEM_ZERO( dstSlot->bitmap.buffer, size );
305 }
306 else
307 {
308 /* Resize destination if needed such that new component fits. */
309 FT_Int x_min, x_max, y_min, y_max;
310
311
312 x_min = FT_MIN( dstSlot->bitmap_left, srcSlot->bitmap_left );
313 x_max = FT_MAX( dstSlot->bitmap_left + (FT_Int)dstSlot->bitmap.width,
314 srcSlot->bitmap_left + (FT_Int)srcSlot->bitmap.width );
315
316 y_min = FT_MIN( dstSlot->bitmap_top - (FT_Int)dstSlot->bitmap.rows,
317 srcSlot->bitmap_top - (FT_Int)srcSlot->bitmap.rows );
318 y_max = FT_MAX( dstSlot->bitmap_top, srcSlot->bitmap_top );
319
320 if ( x_min != dstSlot->bitmap_left ||
321 x_max != dstSlot->bitmap_left + (FT_Int)dstSlot->bitmap.width ||
322 y_min != dstSlot->bitmap_top - (FT_Int)dstSlot->bitmap.rows ||
323 y_max != dstSlot->bitmap_top )
324 {
325 FT_Memory memory = face->root.memory;
326
327 FT_UInt width = (FT_UInt)( x_max - x_min );
328 FT_UInt rows = (FT_UInt)( y_max - y_min );
329 FT_UInt pitch = width * 4;
330
331 FT_Byte* buf = NULL;
332 FT_Byte* p;
333 FT_Byte* q;
334
335
336 size = rows * pitch;
337 if ( FT_ALLOC( buf, size ) )
338 return error;
339
340 p = dstSlot->bitmap.buffer;
341 q = buf +
342 (int)pitch * ( y_max - dstSlot->bitmap_top ) +
343 4 * ( dstSlot->bitmap_left - x_min );
344
345 for ( y = 0; y < dstSlot->bitmap.rows; y++ )
346 {
347 FT_MEM_COPY( q, p, dstSlot->bitmap.width * 4 );
348
349 p += dstSlot->bitmap.pitch;
350 q += pitch;
351 }
352
353 ft_glyphslot_set_bitmap( dstSlot, buf );
354
355 dstSlot->bitmap_top = y_max;
356 dstSlot->bitmap_left = x_min;
357
358 dstSlot->bitmap.width = width;
359 dstSlot->bitmap.rows = rows;
360 dstSlot->bitmap.pitch = (int)pitch;
361
362 dstSlot->internal->flags |= FT_GLYPH_OWN_BITMAP;
363 dstSlot->format = FT_GLYPH_FORMAT_BITMAP;
364 }
365 }
366
367 if ( color_index == 0xFFFF )
368 {
369 if ( face->have_foreground_color )
370 {
371 b = face->foreground_color.blue;
372 g = face->foreground_color.green;
373 r = face->foreground_color.red;
374 alpha = face->foreground_color.alpha;
375 }
376 else
377 {
378 if ( face->palette_data.palette_flags &&
379 ( face->palette_data.palette_flags[face->palette_index] &
380 FT_PALETTE_FOR_DARK_BACKGROUND ) )
381 {
382 /* white opaque */
383 b = 0xFF;
384 g = 0xFF;
385 r = 0xFF;
386 alpha = 0xFF;
387 }
388 else
389 {
390 /* black opaque */
391 b = 0x00;
392 g = 0x00;
393 r = 0x00;
394 alpha = 0xFF;
395 }
396 }
397 }
398 else
399 {
400 b = face->palette[color_index].blue;
401 g = face->palette[color_index].green;
402 r = face->palette[color_index].red;
403 alpha = face->palette[color_index].alpha;
404 }
405
406 /* XXX Convert if srcSlot.bitmap is not grey? */
407 src = srcSlot->bitmap.buffer;
408 dst = dstSlot->bitmap.buffer +
409 dstSlot->bitmap.pitch * ( dstSlot->bitmap_top - srcSlot->bitmap_top ) +
410 4 * ( srcSlot->bitmap_left - dstSlot->bitmap_left );
411
412 for ( y = 0; y < srcSlot->bitmap.rows; y++ )
413 {
414 for ( x = 0; x < srcSlot->bitmap.width; x++ )
415 {
416 int aa = src[x];
417 int fa = alpha * aa / 255;
418
419 int fb = b * fa / 255;
420 int fg = g * fa / 255;
421 int fr = r * fa / 255;
422
423 int ba2 = 255 - fa;
424
425 int bb = dst[4 * x + 0];
426 int bg = dst[4 * x + 1];
427 int br = dst[4 * x + 2];
428 int ba = dst[4 * x + 3];
429
430
431 dst[4 * x + 0] = (FT_Byte)( bb * ba2 / 255 + fb );
432 dst[4 * x + 1] = (FT_Byte)( bg * ba2 / 255 + fg );
433 dst[4 * x + 2] = (FT_Byte)( br * ba2 / 255 + fr );
434 dst[4 * x + 3] = (FT_Byte)( ba * ba2 / 255 + fa );
435 }
436
437 src += srcSlot->bitmap.pitch;
438 dst += dstSlot->bitmap.pitch;
439 }
440
441 return FT_Err_Ok;
442 }
443
444#else /* !TT_CONFIG_OPTION_COLOR_LAYERS */
445
446 /* ANSI C doesn't like empty source files */
447 typedef int _tt_colr_dummy;
448
449#endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */
450
451/* EOF */
452