hb-ft-colr.hh (18916B)
1 /* 2 * Copyright © 2022 Behdad Esfahbod 3 * 4 * This is part of HarfBuzz, a text shaping library. 5 * 6 * Permission is hereby granted, without written agreement and without 7 * license or royalty fees, to use, copy, modify, and distribute this 8 * software and its documentation for any purpose, provided that the 9 * above copyright notice and the following two paragraphs appear in 10 * all copies of this software. 11 * 12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16 * DAMAGE. 17 * 18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23 */ 24 25 #ifndef HB_FT_COLR_HH 26 #define HB_FT_COLR_HH 27 28 #include "hb.hh" 29 30 #include "hb-decycler.hh" 31 #include "hb-paint-bounded.hh" 32 33 #include FT_COLOR_H 34 35 36 static hb_paint_composite_mode_t 37 _hb_ft_paint_composite_mode (FT_Composite_Mode mode) 38 { 39 switch (mode) 40 { 41 case FT_COLR_COMPOSITE_CLEAR: return HB_PAINT_COMPOSITE_MODE_CLEAR; 42 case FT_COLR_COMPOSITE_SRC: return HB_PAINT_COMPOSITE_MODE_SRC; 43 case FT_COLR_COMPOSITE_DEST: return HB_PAINT_COMPOSITE_MODE_DEST; 44 case FT_COLR_COMPOSITE_SRC_OVER: return HB_PAINT_COMPOSITE_MODE_SRC_OVER; 45 case FT_COLR_COMPOSITE_DEST_OVER: return HB_PAINT_COMPOSITE_MODE_DEST_OVER; 46 case FT_COLR_COMPOSITE_SRC_IN: return HB_PAINT_COMPOSITE_MODE_SRC_IN; 47 case FT_COLR_COMPOSITE_DEST_IN: return HB_PAINT_COMPOSITE_MODE_DEST_IN; 48 case FT_COLR_COMPOSITE_SRC_OUT: return HB_PAINT_COMPOSITE_MODE_SRC_OUT; 49 case FT_COLR_COMPOSITE_DEST_OUT: return HB_PAINT_COMPOSITE_MODE_DEST_OUT; 50 case FT_COLR_COMPOSITE_SRC_ATOP: return HB_PAINT_COMPOSITE_MODE_SRC_ATOP; 51 case FT_COLR_COMPOSITE_DEST_ATOP: return HB_PAINT_COMPOSITE_MODE_DEST_ATOP; 52 case FT_COLR_COMPOSITE_XOR: return HB_PAINT_COMPOSITE_MODE_XOR; 53 case FT_COLR_COMPOSITE_PLUS: return HB_PAINT_COMPOSITE_MODE_PLUS; 54 case FT_COLR_COMPOSITE_SCREEN: return HB_PAINT_COMPOSITE_MODE_SCREEN; 55 case FT_COLR_COMPOSITE_OVERLAY: return HB_PAINT_COMPOSITE_MODE_OVERLAY; 56 case FT_COLR_COMPOSITE_DARKEN: return HB_PAINT_COMPOSITE_MODE_DARKEN; 57 case FT_COLR_COMPOSITE_LIGHTEN: return HB_PAINT_COMPOSITE_MODE_LIGHTEN; 58 case FT_COLR_COMPOSITE_COLOR_DODGE: return HB_PAINT_COMPOSITE_MODE_COLOR_DODGE; 59 case FT_COLR_COMPOSITE_COLOR_BURN: return HB_PAINT_COMPOSITE_MODE_COLOR_BURN; 60 case FT_COLR_COMPOSITE_HARD_LIGHT: return HB_PAINT_COMPOSITE_MODE_HARD_LIGHT; 61 case FT_COLR_COMPOSITE_SOFT_LIGHT: return HB_PAINT_COMPOSITE_MODE_SOFT_LIGHT; 62 case FT_COLR_COMPOSITE_DIFFERENCE: return HB_PAINT_COMPOSITE_MODE_DIFFERENCE; 63 case FT_COLR_COMPOSITE_EXCLUSION: return HB_PAINT_COMPOSITE_MODE_EXCLUSION; 64 case FT_COLR_COMPOSITE_MULTIPLY: return HB_PAINT_COMPOSITE_MODE_MULTIPLY; 65 case FT_COLR_COMPOSITE_HSL_HUE: return HB_PAINT_COMPOSITE_MODE_HSL_HUE; 66 case FT_COLR_COMPOSITE_HSL_SATURATION: return HB_PAINT_COMPOSITE_MODE_HSL_SATURATION; 67 case FT_COLR_COMPOSITE_HSL_COLOR: return HB_PAINT_COMPOSITE_MODE_HSL_COLOR; 68 case FT_COLR_COMPOSITE_HSL_LUMINOSITY: return HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY; 69 70 case FT_COLR_COMPOSITE_MAX: HB_FALLTHROUGH; 71 default: return HB_PAINT_COMPOSITE_MODE_CLEAR; 72 } 73 } 74 75 typedef struct hb_ft_paint_context_t hb_ft_paint_context_t; 76 77 static void 78 _hb_ft_paint (hb_ft_paint_context_t *c, 79 FT_OpaquePaint opaque_paint); 80 81 struct hb_ft_paint_context_t 82 { 83 hb_ft_paint_context_t (const hb_ft_font_t *ft_font_, 84 hb_font_t *font_, 85 hb_paint_funcs_t *paint_funcs, void *paint_data, 86 hb_array_t<const FT_Color> palette, 87 unsigned palette_index, 88 hb_color_t foreground) : 89 ft_font (ft_font_), font (font_), 90 funcs (paint_funcs), data (paint_data), 91 palette (palette), palette_index (palette_index), foreground (foreground) 92 { 93 if (font->is_synthetic) 94 { 95 font = hb_font_create_sub_font (font); 96 hb_font_set_synthetic_bold (font, 0, 0, true); 97 hb_font_set_synthetic_slant (font, 0); 98 } 99 else 100 hb_font_reference (font); 101 } 102 103 ~hb_ft_paint_context_t () 104 { 105 hb_font_destroy (font); 106 } 107 108 void recurse (FT_OpaquePaint paint) 109 { 110 if (unlikely (depth_left <= 0 || edge_count <= 0)) return; 111 depth_left--; 112 edge_count--; 113 _hb_ft_paint (this, paint); 114 depth_left++; 115 } 116 117 const hb_ft_font_t *ft_font; 118 hb_font_t *font; 119 hb_paint_funcs_t *funcs; 120 void *data; 121 hb_array_t<const FT_Color> palette; 122 unsigned palette_index; 123 hb_color_t foreground; 124 hb_decycler_t glyphs_decycler; 125 hb_decycler_t layers_decycler; 126 int depth_left = HB_MAX_NESTING_LEVEL; 127 int edge_count = HB_MAX_GRAPH_EDGE_COUNT; 128 }; 129 130 static unsigned 131 _hb_ft_color_line_get_color_stops (hb_color_line_t *color_line, 132 void *color_line_data, 133 unsigned int start, 134 unsigned int *count, 135 hb_color_stop_t *color_stops, 136 void *user_data) 137 { 138 FT_ColorLine *cl = (FT_ColorLine *) color_line_data; 139 hb_ft_paint_context_t *c = (hb_ft_paint_context_t *) user_data; 140 141 if (count) 142 { 143 FT_ColorStop stop; 144 unsigned wrote = 0; 145 FT_ColorStopIterator iter = cl->color_stop_iterator; 146 147 if (start >= cl->color_stop_iterator.num_color_stops) 148 { 149 *count = 0; 150 return cl->color_stop_iterator.num_color_stops; 151 } 152 153 while (cl->color_stop_iterator.current_color_stop < start) 154 FT_Get_Colorline_Stops(c->ft_font->ft_face, 155 &stop, 156 &cl->color_stop_iterator); 157 158 while (count && *count && 159 FT_Get_Colorline_Stops(c->ft_font->ft_face, 160 &stop, 161 &cl->color_stop_iterator)) 162 { 163 // https://github.com/harfbuzz/harfbuzz/issues/4013 164 if (sizeof stop.stop_offset == 2) 165 color_stops->offset = stop.stop_offset / 16384.f; 166 else 167 color_stops->offset = stop.stop_offset / 65536.f; 168 169 color_stops->is_foreground = stop.color.palette_index == 0xFFFF; 170 if (color_stops->is_foreground) 171 color_stops->color = HB_COLOR (hb_color_get_blue (c->foreground), 172 hb_color_get_green (c->foreground), 173 hb_color_get_red (c->foreground), 174 (hb_color_get_alpha (c->foreground) * stop.color.alpha) >> 14); 175 else 176 { 177 hb_color_t color; 178 if (c->funcs->custom_palette_color (c->data, stop.color.palette_index, &color)) 179 { 180 color_stops->color = HB_COLOR (hb_color_get_blue (color), 181 hb_color_get_green (color), 182 hb_color_get_red (color), 183 (hb_color_get_alpha (color) * stop.color.alpha) >> 14); 184 } 185 else if (c->palette) 186 { 187 FT_Color ft_color = c->palette[stop.color.palette_index]; 188 color_stops->color = HB_COLOR (ft_color.blue, 189 ft_color.green, 190 ft_color.red, 191 (ft_color.alpha * stop.color.alpha) >> 14); 192 } 193 else 194 color_stops->color = HB_COLOR (0, 0, 0, 0); 195 } 196 197 color_stops++; 198 wrote++; 199 } 200 201 *count = wrote; 202 203 // reset the iterator for next time 204 cl->color_stop_iterator = iter; 205 } 206 207 return cl->color_stop_iterator.num_color_stops; 208 } 209 210 static hb_paint_extend_t 211 _hb_ft_color_line_get_extend (hb_color_line_t *color_line, 212 void *color_line_data, 213 void *user_data) 214 { 215 FT_ColorLine *c = (FT_ColorLine *) color_line_data; 216 switch (c->extend) 217 { 218 default: 219 case FT_COLR_PAINT_EXTEND_PAD: return HB_PAINT_EXTEND_PAD; 220 case FT_COLR_PAINT_EXTEND_REPEAT: return HB_PAINT_EXTEND_REPEAT; 221 case FT_COLR_PAINT_EXTEND_REFLECT: return HB_PAINT_EXTEND_REFLECT; 222 } 223 } 224 225 void 226 _hb_ft_paint (hb_ft_paint_context_t *c, 227 FT_OpaquePaint opaque_paint) 228 { 229 FT_Face ft_face = c->ft_font->ft_face; 230 FT_COLR_Paint paint; 231 if (!FT_Get_Paint (ft_face, opaque_paint, &paint)) 232 return; 233 234 switch (paint.format) 235 { 236 case FT_COLR_PAINTFORMAT_COLR_LAYERS: 237 { 238 FT_OpaquePaint other_paint = {0}; 239 hb_decycler_node_t node (c->layers_decycler); 240 while (FT_Get_Paint_Layers (ft_face, 241 &paint.u.colr_layers.layer_iterator, 242 &other_paint)) 243 { 244 // FreeType doesn't provide a way to get the layer index, so we use the pointer 245 // for cycle detection. 246 if (unlikely (!node.visit ((uintptr_t) other_paint.p))) 247 continue; 248 249 c->recurse (other_paint); 250 } 251 } 252 break; 253 case FT_COLR_PAINTFORMAT_SOLID: 254 { 255 bool is_foreground = paint.u.solid.color.palette_index == 0xFFFF; 256 hb_color_t color; 257 if (is_foreground) 258 color = HB_COLOR (hb_color_get_blue (c->foreground), 259 hb_color_get_green (c->foreground), 260 hb_color_get_red (c->foreground), 261 (hb_color_get_alpha (c->foreground) * paint.u.solid.color.alpha) >> 14); 262 else 263 { 264 if (c->funcs->custom_palette_color (c->data, paint.u.solid.color.palette_index, &color)) 265 { 266 color = HB_COLOR (hb_color_get_blue (color), 267 hb_color_get_green (color), 268 hb_color_get_red (color), 269 (hb_color_get_alpha (color) * paint.u.solid.color.alpha) >> 14); 270 } 271 else 272 { 273 FT_Color ft_color = c->palette[paint.u.solid.color.palette_index]; 274 color = HB_COLOR (ft_color.blue, 275 ft_color.green, 276 ft_color.red, 277 (ft_color.alpha * paint.u.solid.color.alpha) >> 14); 278 } 279 } 280 c->funcs->color (c->data, is_foreground, color); 281 } 282 break; 283 case FT_COLR_PAINTFORMAT_LINEAR_GRADIENT: 284 { 285 hb_color_line_t cl = { 286 &paint.u.linear_gradient.colorline, 287 _hb_ft_color_line_get_color_stops, c, 288 _hb_ft_color_line_get_extend, nullptr 289 }; 290 291 c->funcs->linear_gradient (c->data, &cl, 292 paint.u.linear_gradient.p0.x / 65536.f, 293 paint.u.linear_gradient.p0.y / 65536.f, 294 paint.u.linear_gradient.p1.x / 65536.f, 295 paint.u.linear_gradient.p1.y / 65536.f, 296 paint.u.linear_gradient.p2.x / 65536.f, 297 paint.u.linear_gradient.p2.y / 65536.f); 298 } 299 break; 300 case FT_COLR_PAINTFORMAT_RADIAL_GRADIENT: 301 { 302 hb_color_line_t cl = { 303 &paint.u.linear_gradient.colorline, 304 _hb_ft_color_line_get_color_stops, c, 305 _hb_ft_color_line_get_extend, nullptr 306 }; 307 308 c->funcs->radial_gradient (c->data, &cl, 309 paint.u.radial_gradient.c0.x / 65536.f, 310 paint.u.radial_gradient.c0.y / 65536.f, 311 paint.u.radial_gradient.r0 / 65536.f, 312 paint.u.radial_gradient.c1.x / 65536.f, 313 paint.u.radial_gradient.c1.y / 65536.f, 314 paint.u.radial_gradient.r1 / 65536.f); 315 } 316 break; 317 case FT_COLR_PAINTFORMAT_SWEEP_GRADIENT: 318 { 319 hb_color_line_t cl = { 320 &paint.u.linear_gradient.colorline, 321 _hb_ft_color_line_get_color_stops, c, 322 _hb_ft_color_line_get_extend, nullptr 323 }; 324 325 c->funcs->sweep_gradient (c->data, &cl, 326 paint.u.sweep_gradient.center.x / 65536.f, 327 paint.u.sweep_gradient.center.y / 65536.f, 328 (paint.u.sweep_gradient.start_angle / 65536.f + 1) * HB_PI, 329 (paint.u.sweep_gradient.end_angle / 65536.f + 1) * HB_PI); 330 } 331 break; 332 case FT_COLR_PAINTFORMAT_GLYPH: 333 { 334 c->funcs->push_inverse_font_transform (c->data, c->font); 335 c->ft_font->lock.unlock (); 336 c->funcs->push_clip_glyph (c->data, paint.u.glyph.glyphID, c->font); 337 c->ft_font->lock.lock (); 338 c->funcs->push_font_transform (c->data, c->font); 339 c->recurse (paint.u.glyph.paint); 340 c->funcs->pop_transform (c->data); 341 c->funcs->pop_clip (c->data); 342 c->funcs->pop_transform (c->data); 343 } 344 break; 345 case FT_COLR_PAINTFORMAT_COLR_GLYPH: 346 { 347 hb_codepoint_t gid = paint.u.colr_glyph.glyphID; 348 349 hb_decycler_node_t node (c->glyphs_decycler); 350 if (unlikely (!node.visit (gid))) 351 return; 352 353 c->funcs->push_inverse_font_transform (c->data, c->font); 354 c->ft_font->lock.unlock (); 355 if (c->funcs->color_glyph (c->data, gid, c->font)) 356 { 357 c->ft_font->lock.lock (); 358 c->funcs->pop_transform (c->data); 359 return; 360 } 361 c->ft_font->lock.lock (); 362 c->funcs->pop_transform (c->data); 363 364 FT_OpaquePaint other_paint = {0}; 365 if (FT_Get_Color_Glyph_Paint (ft_face, gid, 366 FT_COLOR_NO_ROOT_TRANSFORM, 367 &other_paint)) 368 { 369 bool has_clip_box; 370 FT_ClipBox clip_box; 371 has_clip_box = FT_Get_Color_Glyph_ClipBox (ft_face, paint.u.colr_glyph.glyphID, &clip_box); 372 373 if (has_clip_box) 374 { 375 /* The FreeType ClipBox is in scaled coordinates, whereas we need 376 * unscaled clipbox here. Oh well... 377 */ 378 379 float upem = c->font->face->get_upem (); 380 float xscale = upem / (c->font->x_scale ? c->font->x_scale : upem); 381 float yscale = upem / (c->font->y_scale ? c->font->y_scale : upem); 382 383 c->funcs->push_clip_rectangle (c->data, 384 clip_box.bottom_left.x * xscale, 385 clip_box.bottom_left.y * yscale, 386 clip_box.top_right.x * xscale, 387 clip_box.top_right.y * yscale); 388 } 389 390 c->recurse (other_paint); 391 392 if (has_clip_box) 393 c->funcs->pop_clip (c->data); 394 } 395 } 396 break; 397 case FT_COLR_PAINTFORMAT_TRANSFORM: 398 { 399 c->funcs->push_transform (c->data, 400 paint.u.transform.affine.xx / 65536.f, 401 paint.u.transform.affine.yx / 65536.f, 402 paint.u.transform.affine.xy / 65536.f, 403 paint.u.transform.affine.yy / 65536.f, 404 paint.u.transform.affine.dx / 65536.f, 405 paint.u.transform.affine.dy / 65536.f); 406 c->recurse (paint.u.transform.paint); 407 c->funcs->pop_transform (c->data); 408 } 409 break; 410 case FT_COLR_PAINTFORMAT_TRANSLATE: 411 { 412 float dx = paint.u.translate.dx / 65536.f; 413 float dy = paint.u.translate.dy / 65536.f; 414 415 c->funcs->push_translate (c->data, dx, dy); 416 c->recurse (paint.u.translate.paint); 417 c->funcs->pop_transform (c->data); 418 } 419 break; 420 case FT_COLR_PAINTFORMAT_SCALE: 421 { 422 float dx = paint.u.scale.center_x / 65536.f; 423 float dy = paint.u.scale.center_y / 65536.f; 424 float sx = paint.u.scale.scale_x / 65536.f; 425 float sy = paint.u.scale.scale_y / 65536.f; 426 427 c->funcs->push_scale_around_center (c->data, sx, sy, dx, dy); 428 c->recurse (paint.u.scale.paint); 429 c->funcs->pop_transform (c->data); 430 } 431 break; 432 case FT_COLR_PAINTFORMAT_ROTATE: 433 { 434 float dx = paint.u.rotate.center_x / 65536.f; 435 float dy = paint.u.rotate.center_y / 65536.f; 436 float a = paint.u.rotate.angle / 65536.f; 437 438 c->funcs->push_rotate_around_center (c->data, a, dx, dy); 439 c->recurse (paint.u.rotate.paint); 440 c->funcs->pop_transform (c->data); 441 } 442 break; 443 case FT_COLR_PAINTFORMAT_SKEW: 444 { 445 float dx = paint.u.skew.center_x / 65536.f; 446 float dy = paint.u.skew.center_y / 65536.f; 447 float sx = paint.u.skew.x_skew_angle / 65536.f; 448 float sy = paint.u.skew.y_skew_angle / 65536.f; 449 450 c->funcs->push_skew_around_center (c->data, sx, sy, dx, dy); 451 c->recurse (paint.u.skew.paint); 452 c->funcs->pop_transform (c->data); 453 } 454 break; 455 case FT_COLR_PAINTFORMAT_COMPOSITE: 456 { 457 c->funcs->push_group (c->data); 458 c->recurse (paint.u.composite.backdrop_paint); 459 c->funcs->push_group (c->data); 460 c->recurse (paint.u.composite.source_paint); 461 c->funcs->pop_group (c->data, _hb_ft_paint_composite_mode (paint.u.composite.composite_mode)); 462 c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER); 463 } 464 break; 465 466 case FT_COLR_PAINT_FORMAT_MAX: break; 467 default: HB_FALLTHROUGH; 468 case FT_COLR_PAINTFORMAT_UNSUPPORTED: break; 469 } 470 } 471 472 473 static bool 474 hb_ft_paint_glyph_colr (hb_font_t *font, 475 void *font_data, 476 hb_codepoint_t gid, 477 hb_paint_funcs_t *paint_funcs, void *paint_data, 478 unsigned int palette_index, 479 hb_color_t foreground, 480 void *user_data) 481 { 482 const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; 483 FT_Face ft_face = ft_font->ft_face; 484 485 /* Face is locked. */ 486 487 FT_Palette_Data palette_data = {}; 488 FT_Color* palette = NULL; 489 FT_LayerIterator iterator; 490 491 FT_Bool have_layers; 492 FT_UInt layer_glyph_index; 493 FT_UInt layer_color_index; 494 495 (void) FT_Palette_Data_Get(ft_face, &palette_data); 496 (void) FT_Palette_Select(ft_face, palette_index, &palette); 497 if (!palette) 498 { 499 // https://github.com/harfbuzz/harfbuzz/issues/5116 500 (void) FT_Palette_Select(ft_face, 0, &palette); 501 } 502 503 auto palette_array = hb_array ((const FT_Color *) palette, 504 palette ? palette_data.num_palette_entries : 0); 505 506 /* COLRv1 */ 507 FT_OpaquePaint paint = {0}; 508 if (FT_Get_Color_Glyph_Paint (ft_face, gid, 509 FT_COLOR_NO_ROOT_TRANSFORM, 510 &paint)) 511 { 512 hb_ft_paint_context_t c (ft_font, font, 513 paint_funcs, paint_data, 514 palette_array, palette_index, foreground); 515 hb_decycler_node_t node (c.glyphs_decycler); 516 node.visit (gid); 517 518 bool clip = false; 519 bool is_bounded = false; 520 FT_ClipBox clip_box; 521 if (FT_Get_Color_Glyph_ClipBox (ft_face, gid, &clip_box)) 522 { 523 c.funcs->push_clip_rectangle (c.data, 524 clip_box.bottom_left.x, 525 clip_box.bottom_left.y, 526 clip_box.top_right.x, 527 clip_box.top_right.y); 528 clip = true; 529 is_bounded = true; 530 } 531 if (!is_bounded) 532 { 533 auto *bounded_funcs = hb_paint_bounded_get_funcs (); 534 hb_paint_bounded_context_t bounded_data; 535 hb_ft_paint_context_t ce (ft_font, font, 536 bounded_funcs, &bounded_data, 537 palette_array, palette_index, foreground); 538 hb_decycler_node_t node2 (ce.glyphs_decycler); 539 node2.visit (gid); 540 ce.recurse (paint); 541 is_bounded = bounded_data.is_bounded (); 542 } 543 544 c.funcs->push_font_transform (c.data, font); 545 546 if (is_bounded) 547 c.recurse (paint); 548 549 c.funcs->pop_transform (c.data); 550 551 if (clip) 552 c.funcs->pop_clip (c.data); 553 554 return true; 555 } 556 557 /* COLRv0 */ 558 iterator.p = NULL; 559 have_layers = FT_Get_Color_Glyph_Layer(ft_face, 560 gid, 561 &layer_glyph_index, 562 &layer_color_index, 563 &iterator); 564 565 if (palette && have_layers) 566 { 567 do 568 { 569 hb_bool_t is_foreground = true; 570 hb_color_t color = foreground; 571 572 if ( layer_color_index != 0xFFFF ) 573 { 574 FT_Color layer_color = palette[layer_color_index]; 575 color = HB_COLOR (layer_color.blue, 576 layer_color.green, 577 layer_color.red, 578 layer_color.alpha); 579 is_foreground = false; 580 } 581 582 ft_font->lock.unlock (); 583 paint_funcs->push_clip_glyph (paint_data, layer_glyph_index, font); 584 ft_font->lock.lock (); 585 paint_funcs->color (paint_data, is_foreground, color); 586 paint_funcs->pop_clip (paint_data); 587 588 } while (FT_Get_Color_Glyph_Layer(ft_face, 589 gid, 590 &layer_glyph_index, 591 &layer_color_index, 592 &iterator)); 593 return true; 594 } 595 596 return false; 597 } 598 599 600 #endif /* HB_FT_COLR_HH */