1 /****************************************************************************
5 * TrueType and OpenType colored glyph layer support (body).
7 * Copyright (C) 2018-2020 by
8 * David Turner, Robert Wilhelm, and Werner Lemberg.
10 * Originally written by Shao Yu Zhang <shaozhang@fb.com>.
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.
21 /**************************************************************************
23 * `COLR' table specification:
25 * https://www.microsoft.com/typography/otspec/colr.htm
30 #include <freetype/internal/ftdebug.h>
31 #include <freetype/internal/ftstream.h>
32 #include <freetype/tttags.h>
33 #include <freetype/ftcolor.h>
36 #ifdef TT_CONFIG_OPTION_COLOR_LAYERS
41 /* NOTE: These are the table sizes calculated through the specs. */
42 #define BASE_GLYPH_SIZE 6U
44 #define COLR_HEADER_SIZE 14U
47 typedef struct BaseGlyphRecord_
50 FT_UShort first_layer_index;
59 FT_UShort num_base_glyphs;
65 /* The memory which backs up the `COLR' table. */
72 /**************************************************************************
74 * The macro FT_COMPONENT is used in trace mode. It is an implicit
75 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
76 * messages during execution.
79 #define FT_COMPONENT ttcolr
82 FT_LOCAL_DEF( FT_Error )
83 tt_face_load_colr( TT_Face face,
87 FT_Memory memory = face->root.memory;
89 FT_Byte* table = NULL;
94 FT_ULong base_glyph_offset, layer_offset;
98 /* `COLR' always needs `CPAL' */
100 return FT_THROW( Invalid_File_Format );
102 error = face->goto_table( face, TTAG_COLR, stream, &table_size );
106 if ( table_size < COLR_HEADER_SIZE )
109 if ( FT_FRAME_EXTRACT( table_size, table ) )
114 if ( FT_NEW( colr ) )
117 colr->version = FT_NEXT_USHORT( p );
118 if ( colr->version != 0 )
121 colr->num_base_glyphs = FT_NEXT_USHORT( p );
122 base_glyph_offset = FT_NEXT_ULONG( p );
124 if ( base_glyph_offset >= table_size )
126 if ( colr->num_base_glyphs * BASE_GLYPH_SIZE >
127 table_size - base_glyph_offset )
130 layer_offset = FT_NEXT_ULONG( p );
131 colr->num_layers = FT_NEXT_USHORT( p );
133 if ( layer_offset >= table_size )
135 if ( colr->num_layers * LAYER_SIZE > table_size - layer_offset )
138 colr->base_glyphs = (FT_Byte*)( table + base_glyph_offset );
139 colr->layers = (FT_Byte*)( table + layer_offset );
141 colr->table_size = table_size;
148 error = FT_THROW( Invalid_Table );
151 FT_FRAME_RELEASE( table );
159 tt_face_free_colr( TT_Face face )
161 FT_Stream stream = face->root.stream;
162 FT_Memory memory = face->root.memory;
164 Colr* colr = (Colr*)face->colr;
169 FT_FRAME_RELEASE( colr->table );
176 find_base_glyph_record( FT_Byte* base_glyph_begin,
177 FT_Int num_base_glyph,
179 BaseGlyphRecord* record )
182 FT_Int max = num_base_glyph - 1;
187 FT_Int mid = min + ( max - min ) / 2;
188 FT_Byte* p = base_glyph_begin + mid * BASE_GLYPH_SIZE;
190 FT_UShort gid = FT_NEXT_USHORT( p );
193 if ( gid < glyph_id )
195 else if (gid > glyph_id )
200 record->first_layer_index = FT_NEXT_USHORT( p );
201 record->num_layers = FT_NEXT_USHORT( p );
211 FT_LOCAL_DEF( FT_Bool )
212 tt_face_get_colr_layer( TT_Face face,
214 FT_UInt *aglyph_index,
215 FT_UInt *acolor_index,
216 FT_LayerIterator* iterator )
218 Colr* colr = (Colr*)face->colr;
219 BaseGlyphRecord glyph_record;
230 /* first call to function */
233 if ( !find_base_glyph_record( colr->base_glyphs,
234 colr->num_base_glyphs,
239 if ( glyph_record.num_layers )
240 iterator->num_layers = glyph_record.num_layers;
244 offset = LAYER_SIZE * glyph_record.first_layer_index;
245 if ( offset + LAYER_SIZE * glyph_record.num_layers > colr->table_size )
248 iterator->p = colr->layers + offset;
251 if ( iterator->layer >= iterator->num_layers )
254 *aglyph_index = FT_NEXT_USHORT( iterator->p );
255 *acolor_index = FT_NEXT_USHORT( iterator->p );
257 if ( *aglyph_index >= (FT_UInt)( FT_FACE( face )->num_glyphs ) ||
258 ( *acolor_index != 0xFFFF &&
259 *acolor_index >= face->palette_data.num_palette_entries ) )
268 FT_LOCAL_DEF( FT_Error )
269 tt_face_colr_blend_layer( TT_Face face,
271 FT_GlyphSlot dstSlot,
272 FT_GlyphSlot srcSlot )
277 FT_Byte b, g, r, alpha;
284 if ( !dstSlot->bitmap.buffer )
286 /* Initialize destination of color bitmap */
287 /* with the size of first component. */
288 dstSlot->bitmap_left = srcSlot->bitmap_left;
289 dstSlot->bitmap_top = srcSlot->bitmap_top;
291 dstSlot->bitmap.width = srcSlot->bitmap.width;
292 dstSlot->bitmap.rows = srcSlot->bitmap.rows;
293 dstSlot->bitmap.pixel_mode = FT_PIXEL_MODE_BGRA;
294 dstSlot->bitmap.pitch = (int)dstSlot->bitmap.width * 4;
295 dstSlot->bitmap.num_grays = 256;
297 size = dstSlot->bitmap.rows * (unsigned int)dstSlot->bitmap.pitch;
299 error = ft_glyphslot_alloc_bitmap( dstSlot, size );
303 FT_MEM_ZERO( dstSlot->bitmap.buffer, size );
307 /* Resize destination if needed such that new component fits. */
308 FT_Int x_min, x_max, y_min, y_max;
311 x_min = FT_MIN( dstSlot->bitmap_left, srcSlot->bitmap_left );
312 x_max = FT_MAX( dstSlot->bitmap_left + (FT_Int)dstSlot->bitmap.width,
313 srcSlot->bitmap_left + (FT_Int)srcSlot->bitmap.width );
315 y_min = FT_MIN( dstSlot->bitmap_top - (FT_Int)dstSlot->bitmap.rows,
316 srcSlot->bitmap_top - (FT_Int)srcSlot->bitmap.rows );
317 y_max = FT_MAX( dstSlot->bitmap_top, srcSlot->bitmap_top );
319 if ( x_min != dstSlot->bitmap_left ||
320 x_max != dstSlot->bitmap_left + (FT_Int)dstSlot->bitmap.width ||
321 y_min != dstSlot->bitmap_top - (FT_Int)dstSlot->bitmap.rows ||
322 y_max != dstSlot->bitmap_top )
324 FT_Memory memory = face->root.memory;
326 FT_UInt width = (FT_UInt)( x_max - x_min );
327 FT_UInt rows = (FT_UInt)( y_max - y_min );
328 FT_UInt pitch = width * 4;
336 if ( FT_ALLOC( buf, size ) )
339 p = dstSlot->bitmap.buffer;
341 (int)pitch * ( y_max - dstSlot->bitmap_top ) +
342 4 * ( dstSlot->bitmap_left - x_min );
344 for ( y = 0; y < dstSlot->bitmap.rows; y++ )
346 FT_MEM_COPY( q, p, dstSlot->bitmap.width * 4 );
348 p += dstSlot->bitmap.pitch;
352 ft_glyphslot_set_bitmap( dstSlot, buf );
354 dstSlot->bitmap_top = y_max;
355 dstSlot->bitmap_left = x_min;
357 dstSlot->bitmap.width = width;
358 dstSlot->bitmap.rows = rows;
359 dstSlot->bitmap.pitch = (int)pitch;
361 dstSlot->internal->flags |= FT_GLYPH_OWN_BITMAP;
362 dstSlot->format = FT_GLYPH_FORMAT_BITMAP;
366 if ( color_index == 0xFFFF )
368 if ( face->have_foreground_color )
370 b = face->foreground_color.blue;
371 g = face->foreground_color.green;
372 r = face->foreground_color.red;
373 alpha = face->foreground_color.alpha;
377 if ( face->palette_data.palette_flags &&
378 ( face->palette_data.palette_flags[face->palette_index] &
379 FT_PALETTE_FOR_DARK_BACKGROUND ) )
399 b = face->palette[color_index].blue;
400 g = face->palette[color_index].green;
401 r = face->palette[color_index].red;
402 alpha = face->palette[color_index].alpha;
405 /* XXX Convert if srcSlot.bitmap is not grey? */
406 src = srcSlot->bitmap.buffer;
407 dst = dstSlot->bitmap.buffer +
408 dstSlot->bitmap.pitch * ( dstSlot->bitmap_top - srcSlot->bitmap_top ) +
409 4 * ( srcSlot->bitmap_left - dstSlot->bitmap_left );
411 for ( y = 0; y < srcSlot->bitmap.rows; y++ )
413 for ( x = 0; x < srcSlot->bitmap.width; x++ )
416 int fa = alpha * aa / 255;
418 int fb = b * fa / 255;
419 int fg = g * fa / 255;
420 int fr = r * fa / 255;
424 int bb = dst[4 * x + 0];
425 int bg = dst[4 * x + 1];
426 int br = dst[4 * x + 2];
427 int ba = dst[4 * x + 3];
430 dst[4 * x + 0] = (FT_Byte)( bb * ba2 / 255 + fb );
431 dst[4 * x + 1] = (FT_Byte)( bg * ba2 / 255 + fg );
432 dst[4 * x + 2] = (FT_Byte)( br * ba2 / 255 + fr );
433 dst[4 * x + 3] = (FT_Byte)( ba * ba2 / 255 + fa );
436 src += srcSlot->bitmap.pitch;
437 dst += dstSlot->bitmap.pitch;
443 #else /* !TT_CONFIG_OPTION_COLOR_LAYERS */
445 /* ANSI C doesn't like empty source files */
446 typedef int _tt_colr_dummy;
448 #endif /* !TT_CONFIG_OPTION_COLOR_LAYERS */