1 /**************************************************************************** 2 * 3 * ttcolr.c 4 * 5 * TrueType and OpenType colored glyph layer support (body). 6 * 7 * Copyright 2018 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 trace_ttcolr 81 82 83 FT_LOCAL_DEF( FT_Error ) tt_face_load_colr(TT_Face face,FT_Stream stream)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 ) tt_face_free_colr(TT_Face face)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 find_base_glyph_record(FT_Byte * base_glyph_begin,FT_Int num_base_glyph,FT_UInt glyph_id,BaseGlyphRecord * record)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 ) tt_face_get_colr_layer(TT_Face face,FT_UInt base_glyph,FT_UInt * aglyph_index,FT_UInt * acolor_index,FT_LayerIterator * iterator)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 ) tt_face_colr_blend_layer(TT_Face face,FT_UInt color_index,FT_GlyphSlot dstSlot,FT_GlyphSlot srcSlot)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