1 /* 2 * Copyright © 2018 Ebrahim Byagowi 3 * Copyright © 2020 Google, Inc. 4 * 5 * This is part of HarfBuzz, a text shaping library. 6 * 7 * Permission is hereby granted, without written agreement and without 8 * license or royalty fees, to use, copy, modify, and distribute this 9 * software and its documentation for any purpose, provided that the 10 * above copyright notice and the following two paragraphs appear in 11 * all copies of this software. 12 * 13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 17 * DAMAGE. 18 * 19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 24 * 25 * Google Author(s): Calder Kitagawa 26 */ 27 28 #ifndef HB_OT_COLOR_COLR_TABLE_HH 29 #define HB_OT_COLOR_COLR_TABLE_HH 30 31 #include "hb-open-type.hh" 32 #include "hb-ot-layout-common.hh" 33 34 /* 35 * COLR -- Color 36 * https://docs.microsoft.com/en-us/typography/opentype/spec/colr 37 */ 38 #define HB_OT_TAG_COLR HB_TAG('C','O','L','R') 39 40 41 namespace OT { 42 43 struct LayerRecord 44 { operator hb_ot_color_layer_tOT::LayerRecord45 operator hb_ot_color_layer_t () const { return {glyphId, colorIdx}; } 46 sanitizeOT::LayerRecord47 bool sanitize (hb_sanitize_context_t *c) const 48 { 49 TRACE_SANITIZE (this); 50 return_trace (c->check_struct (this)); 51 } 52 53 public: 54 HBGlyphID glyphId; /* Glyph ID of layer glyph */ 55 Index colorIdx; /* Index value to use with a 56 * selected color palette. 57 * An index value of 0xFFFF 58 * is a special case indicating 59 * that the text foreground 60 * color (defined by a 61 * higher-level client) should 62 * be used and shall not be 63 * treated as actual index 64 * into CPAL ColorRecord array. */ 65 public: 66 DEFINE_SIZE_STATIC (4); 67 }; 68 69 struct BaseGlyphRecord 70 { cmpOT::BaseGlyphRecord71 int cmp (hb_codepoint_t g) const 72 { return g < glyphId ? -1 : g > glyphId ? 1 : 0; } 73 sanitizeOT::BaseGlyphRecord74 bool sanitize (hb_sanitize_context_t *c) const 75 { 76 TRACE_SANITIZE (this); 77 return_trace (likely (c->check_struct (this))); 78 } 79 80 public: 81 HBGlyphID glyphId; /* Glyph ID of reference glyph */ 82 HBUINT16 firstLayerIdx; /* Index (from beginning of 83 * the Layer Records) to the 84 * layer record. There will be 85 * numLayers consecutive entries 86 * for this base glyph. */ 87 HBUINT16 numLayers; /* Number of color layers 88 * associated with this glyph */ 89 public: 90 DEFINE_SIZE_STATIC (6); 91 }; 92 93 template <typename T> 94 struct Variable 95 { sanitizeOT::Variable96 bool sanitize (hb_sanitize_context_t *c) const 97 { 98 TRACE_SANITIZE (this); 99 return_trace (c->check_struct (this)); 100 } 101 102 protected: 103 T value; 104 VarIdx varIdx; 105 public: 106 DEFINE_SIZE_STATIC (4 + T::static_size); 107 }; 108 109 template <typename T> 110 struct NoVariable 111 { sanitizeOT::NoVariable112 bool sanitize (hb_sanitize_context_t *c) const 113 { 114 TRACE_SANITIZE (this); 115 return_trace (c->check_struct (this)); 116 } 117 118 T value; 119 public: 120 DEFINE_SIZE_STATIC (T::static_size); 121 }; 122 123 // Color structures 124 125 template <template<typename> class Var> 126 struct ColorIndex 127 { sanitizeOT::ColorIndex128 bool sanitize (hb_sanitize_context_t *c) const 129 { 130 TRACE_SANITIZE (this); 131 return_trace (c->check_struct (this)); 132 } 133 134 HBUINT16 paletteIndex; 135 Var<F2DOT14> alpha; 136 public: 137 DEFINE_SIZE_STATIC (2 + Var<F2DOT14>::static_size); 138 }; 139 140 template <template<typename> class Var> 141 struct ColorStop 142 { sanitizeOT::ColorStop143 bool sanitize (hb_sanitize_context_t *c) const 144 { 145 TRACE_SANITIZE (this); 146 return_trace (c->check_struct (this)); 147 } 148 149 Var<F2DOT14> stopOffset; 150 ColorIndex<Var> color; 151 public: 152 DEFINE_SIZE_STATIC (Var<F2DOT14>::static_size + ColorIndex<Var>::static_size); 153 }; 154 155 struct Extend : HBUINT8 156 { 157 enum { 158 EXTEND_PAD = 0, 159 EXTEND_REPEAT = 1, 160 EXTEND_REFLECT = 2, 161 }; 162 public: 163 DEFINE_SIZE_STATIC (1); 164 }; 165 166 template <template<typename> class Var> 167 struct ColorLine 168 { sanitizeOT::ColorLine169 bool sanitize (hb_sanitize_context_t *c) const 170 { 171 TRACE_SANITIZE (this); 172 return_trace (c->check_struct (this) && 173 stops.sanitize (c)); 174 } 175 176 Extend extend; 177 Array16Of<ColorStop<Var>> stops; 178 public: 179 DEFINE_SIZE_ARRAY_SIZED (3, stops); 180 }; 181 182 // Composition modes 183 184 // Compositing modes are taken from https://www.w3.org/TR/compositing-1/ 185 // NOTE: a brief audit of major implementations suggests most support most 186 // or all of the specified modes. 187 struct CompositeMode : HBUINT8 188 { 189 enum { 190 // Porter-Duff modes 191 // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators 192 COMPOSITE_CLEAR = 0, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_clear 193 COMPOSITE_SRC = 1, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_src 194 COMPOSITE_DEST = 2, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dst 195 COMPOSITE_SRC_OVER = 3, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcover 196 COMPOSITE_DEST_OVER = 4, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstover 197 COMPOSITE_SRC_IN = 5, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcin 198 COMPOSITE_DEST_IN = 6, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstin 199 COMPOSITE_SRC_OUT = 7, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcout 200 COMPOSITE_DEST_OUT = 8, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstout 201 COMPOSITE_SRC_ATOP = 9, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcatop 202 COMPOSITE_DEST_ATOP = 10, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstatop 203 COMPOSITE_XOR = 11, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_xor 204 COMPOSITE_PLUS = 12, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_plus 205 206 // Blend modes 207 // https://www.w3.org/TR/compositing-1/#blending 208 COMPOSITE_SCREEN = 13, // https://www.w3.org/TR/compositing-1/#blendingscreen 209 COMPOSITE_OVERLAY = 14, // https://www.w3.org/TR/compositing-1/#blendingoverlay 210 COMPOSITE_DARKEN = 15, // https://www.w3.org/TR/compositing-1/#blendingdarken 211 COMPOSITE_LIGHTEN = 16, // https://www.w3.org/TR/compositing-1/#blendinglighten 212 COMPOSITE_COLOR_DODGE = 17, // https://www.w3.org/TR/compositing-1/#blendingcolordodge 213 COMPOSITE_COLOR_BURN = 18, // https://www.w3.org/TR/compositing-1/#blendingcolorburn 214 COMPOSITE_HARD_LIGHT = 19, // https://www.w3.org/TR/compositing-1/#blendinghardlight 215 COMPOSITE_SOFT_LIGHT = 20, // https://www.w3.org/TR/compositing-1/#blendingsoftlight 216 COMPOSITE_DIFFERENCE = 21, // https://www.w3.org/TR/compositing-1/#blendingdifference 217 COMPOSITE_EXCLUSION = 22, // https://www.w3.org/TR/compositing-1/#blendingexclusion 218 COMPOSITE_MULTIPLY = 23, // https://www.w3.org/TR/compositing-1/#blendingmultiply 219 220 // Modes that, uniquely, do not operate on components 221 // https://www.w3.org/TR/compositing-1/#blendingnonseparable 222 COMPOSITE_HSL_HUE = 24, // https://www.w3.org/TR/compositing-1/#blendinghue 223 COMPOSITE_HSL_SATURATION = 25, // https://www.w3.org/TR/compositing-1/#blendingsaturation 224 COMPOSITE_HSL_COLOR = 26, // https://www.w3.org/TR/compositing-1/#blendingcolor 225 COMPOSITE_HSL_LUMINOSITY = 27, // https://www.w3.org/TR/compositing-1/#blendingluminosity 226 }; 227 public: 228 DEFINE_SIZE_STATIC (1); 229 }; 230 231 template <template<typename> class Var> 232 struct Affine2x3 233 { sanitizeOT::Affine2x3234 bool sanitize (hb_sanitize_context_t *c) const 235 { 236 TRACE_SANITIZE (this); 237 return_trace (c->check_struct (this)); 238 } 239 240 Var<HBFixed> xx; 241 Var<HBFixed> yx; 242 Var<HBFixed> xy; 243 Var<HBFixed> yy; 244 Var<HBFixed> dx; 245 Var<HBFixed> dy; 246 public: 247 DEFINE_SIZE_STATIC (6 * Var<HBFixed>::static_size); 248 }; 249 250 struct PaintColrLayers 251 { sanitizeOT::PaintColrLayers252 bool sanitize (hb_sanitize_context_t *c) const 253 { 254 TRACE_SANITIZE (this); 255 return_trace (c->check_struct (this)); 256 } 257 258 HBUINT8 format; /* format = 1 */ 259 HBUINT8 numLayers; 260 HBUINT32 firstLayerIndex; /* index into COLRv1::layersV1 */ 261 public: 262 DEFINE_SIZE_STATIC (6); 263 }; 264 265 template <template<typename> class Var> 266 struct PaintSolid 267 { sanitizeOT::PaintSolid268 bool sanitize (hb_sanitize_context_t *c) const 269 { 270 TRACE_SANITIZE (this); 271 return_trace (c->check_struct (this)); 272 } 273 274 HBUINT8 format; /* format = 2(noVar) or 3(Var)*/ 275 ColorIndex<Var> color; 276 public: 277 DEFINE_SIZE_STATIC (1 + ColorIndex<Var>::static_size); 278 }; 279 280 template <template<typename> class Var> 281 struct PaintLinearGradient 282 { sanitizeOT::PaintLinearGradient283 bool sanitize (hb_sanitize_context_t *c) const 284 { 285 TRACE_SANITIZE (this); 286 return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); 287 } 288 289 HBUINT8 format; /* format = 4(noVar) or 5 (Var) */ 290 Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintLinearGradient 291 * table) to ColorLine subtable. */ 292 Var<FWORD> x0; 293 Var<FWORD> y0; 294 Var<FWORD> x1; 295 Var<FWORD> y1; 296 Var<FWORD> x2; 297 Var<FWORD> y2; 298 public: 299 DEFINE_SIZE_STATIC (4 + 6 * Var<FWORD>::static_size); 300 }; 301 302 template <template<typename> class Var> 303 struct PaintRadialGradient 304 { sanitizeOT::PaintRadialGradient305 bool sanitize (hb_sanitize_context_t *c) const 306 { 307 TRACE_SANITIZE (this); 308 return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); 309 } 310 311 HBUINT8 format; /* format = 6(noVar) or 7 (Var) */ 312 Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintRadialGradient 313 * table) to ColorLine subtable. */ 314 Var<FWORD> x0; 315 Var<FWORD> y0; 316 Var<UFWORD> radius0; 317 Var<FWORD> x1; 318 Var<FWORD> y1; 319 Var<UFWORD> radius1; 320 public: 321 DEFINE_SIZE_STATIC (4 + 6 * Var<FWORD>::static_size); 322 }; 323 324 template <template<typename> class Var> 325 struct PaintSweepGradient 326 { sanitizeOT::PaintSweepGradient327 bool sanitize (hb_sanitize_context_t *c) const 328 { 329 TRACE_SANITIZE (this); 330 return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); 331 } 332 333 HBUINT8 format; /* format = 8(noVar) or 9 (Var) */ 334 Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintSweepGradient 335 * table) to ColorLine subtable. */ 336 Var<FWORD> centerX; 337 Var<FWORD> centerY; 338 Var<HBFixed> startAngle; 339 Var<HBFixed> endAngle; 340 public: 341 DEFINE_SIZE_STATIC (2 * Var<FWORD>::static_size + 2 * Var<HBFixed>::static_size); 342 }; 343 344 struct Paint; 345 // Paint a non-COLR glyph, filled as indicated by paint. 346 struct PaintGlyph 347 { sanitizeOT::PaintGlyph348 bool sanitize (hb_sanitize_context_t *c) const 349 { 350 TRACE_SANITIZE (this); 351 return_trace (c->check_struct (this) && paint.sanitize (c, this)); 352 } 353 354 HBUINT8 format; /* format = 10 */ 355 Offset24To<Paint> paint; /* Offset (from beginning of PaintGlyph table) to Paint subtable. */ 356 HBUINT16 gid; 357 public: 358 DEFINE_SIZE_STATIC (6); 359 }; 360 361 struct PaintColrGlyph 362 { sanitizeOT::PaintColrGlyph363 bool sanitize (hb_sanitize_context_t *c) const 364 { 365 TRACE_SANITIZE (this); 366 return_trace (c->check_struct (this)); 367 } 368 369 HBUINT8 format; /* format = 11 */ 370 HBUINT16 gid; 371 public: 372 DEFINE_SIZE_STATIC (3); 373 }; 374 375 template <template<typename> class Var> 376 struct PaintTransform 377 { sanitizeOT::PaintTransform378 bool sanitize (hb_sanitize_context_t *c) const 379 { 380 TRACE_SANITIZE (this); 381 return_trace (c->check_struct (this) && src.sanitize (c, this)); 382 } 383 384 HBUINT8 format; /* format = 12(noVar) or 13 (Var) */ 385 Offset24To<Paint> src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */ 386 Affine2x3<Var> transform; 387 public: 388 DEFINE_SIZE_STATIC (4 + Affine2x3<Var>::static_size); 389 }; 390 391 template <template<typename> class Var> 392 struct PaintTranslate 393 { sanitizeOT::PaintTranslate394 bool sanitize (hb_sanitize_context_t *c) const 395 { 396 TRACE_SANITIZE (this); 397 return_trace (c->check_struct (this) && src.sanitize (c, this)); 398 } 399 400 HBUINT8 format; /* format = 14(noVar) or 15 (Var) */ 401 Offset24To<Paint> src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */ 402 Var<HBFixed> dx; 403 Var<HBFixed> dy; 404 public: 405 DEFINE_SIZE_STATIC (4 + Var<HBFixed>::static_size); 406 }; 407 408 template <template<typename> class Var> 409 struct PaintRotate 410 { sanitizeOT::PaintRotate411 bool sanitize (hb_sanitize_context_t *c) const 412 { 413 TRACE_SANITIZE (this); 414 return_trace (c->check_struct (this) && src.sanitize (c, this)); 415 } 416 417 HBUINT8 format; /* format = 16 (noVar) or 17(Var) */ 418 Offset24To<Paint> src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */ 419 Var<HBFixed> angle; 420 Var<HBFixed> centerX; 421 Var<HBFixed> centerY; 422 public: 423 DEFINE_SIZE_STATIC (4 + 3 * Var<HBFixed>::static_size); 424 }; 425 426 template <template<typename> class Var> 427 struct PaintSkew 428 { sanitizeOT::PaintSkew429 bool sanitize (hb_sanitize_context_t *c) const 430 { 431 TRACE_SANITIZE (this); 432 return_trace (c->check_struct (this) && src.sanitize (c, this)); 433 } 434 435 HBUINT8 format; /* format = 18(noVar) or 19 (Var) */ 436 Offset24To<Paint> src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */ 437 Var<HBFixed> xSkewAngle; 438 Var<HBFixed> ySkewAngle; 439 Var<HBFixed> centerX; 440 Var<HBFixed> centerY; 441 public: 442 DEFINE_SIZE_STATIC (4 + 4 * Var<HBFixed>::static_size); 443 }; 444 445 struct PaintComposite 446 { sanitizeOT::PaintComposite447 bool sanitize (hb_sanitize_context_t *c) const 448 { 449 TRACE_SANITIZE (this); 450 return_trace (c->check_struct (this) && 451 src.sanitize (c, this) && 452 backdrop.sanitize (c, this)); 453 } 454 455 HBUINT8 format; /* format = 20 */ 456 Offset24To<Paint> src; /* Offset (from beginning of PaintComposite table) to source Paint subtable. */ 457 CompositeMode mode; /* If mode is unrecognized use COMPOSITE_CLEAR */ 458 Offset24To<Paint> backdrop; /* Offset (from beginning of PaintComposite table) to backdrop Paint subtable. */ 459 public: 460 DEFINE_SIZE_STATIC (8); 461 }; 462 463 struct Paint 464 { 465 template <typename context_t, typename ...Ts> dispatchOT::Paint466 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const 467 { 468 TRACE_DISPATCH (this, u.format); 469 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 470 switch (u.format) { 471 case 1: return_trace (c->dispatch (u.paintformat1, hb_forward<Ts> (ds)...)); 472 case 2: return_trace (c->dispatch (u.paintformat2, hb_forward<Ts> (ds)...)); 473 case 3: return_trace (c->dispatch (u.paintformat3, hb_forward<Ts> (ds)...)); 474 case 4: return_trace (c->dispatch (u.paintformat4, hb_forward<Ts> (ds)...)); 475 case 5: return_trace (c->dispatch (u.paintformat5, hb_forward<Ts> (ds)...)); 476 case 6: return_trace (c->dispatch (u.paintformat6, hb_forward<Ts> (ds)...)); 477 case 7: return_trace (c->dispatch (u.paintformat7, hb_forward<Ts> (ds)...)); 478 case 8: return_trace (c->dispatch (u.paintformat8, hb_forward<Ts> (ds)...)); 479 case 9: return_trace (c->dispatch (u.paintformat9, hb_forward<Ts> (ds)...)); 480 case 10: return_trace (c->dispatch (u.paintformat10, hb_forward<Ts> (ds)...)); 481 case 11: return_trace (c->dispatch (u.paintformat11, hb_forward<Ts> (ds)...)); 482 case 12: return_trace (c->dispatch (u.paintformat12, hb_forward<Ts> (ds)...)); 483 case 13: return_trace (c->dispatch (u.paintformat13, hb_forward<Ts> (ds)...)); 484 case 14: return_trace (c->dispatch (u.paintformat14, hb_forward<Ts> (ds)...)); 485 case 15: return_trace (c->dispatch (u.paintformat15, hb_forward<Ts> (ds)...)); 486 case 16: return_trace (c->dispatch (u.paintformat16, hb_forward<Ts> (ds)...)); 487 case 17: return_trace (c->dispatch (u.paintformat17, hb_forward<Ts> (ds)...)); 488 case 18: return_trace (c->dispatch (u.paintformat18, hb_forward<Ts> (ds)...)); 489 case 19: return_trace (c->dispatch (u.paintformat19, hb_forward<Ts> (ds)...)); 490 case 20: return_trace (c->dispatch (u.paintformat20, hb_forward<Ts> (ds)...)); 491 default:return_trace (c->default_return_value ()); 492 } 493 } 494 495 protected: 496 union { 497 HBUINT8 format; 498 PaintColrLayers paintformat1; 499 PaintSolid<NoVariable> paintformat2; 500 PaintSolid<Variable> paintformat3; 501 PaintLinearGradient<NoVariable> paintformat4; 502 PaintLinearGradient<Variable> paintformat5; 503 PaintRadialGradient<NoVariable> paintformat6; 504 PaintRadialGradient<Variable> paintformat7; 505 PaintSweepGradient<NoVariable> paintformat8; 506 PaintSweepGradient<Variable> paintformat9; 507 PaintGlyph paintformat10; 508 PaintColrGlyph paintformat11; 509 PaintTransform<NoVariable> paintformat12; 510 PaintTransform<Variable> paintformat13; 511 PaintTranslate<NoVariable> paintformat14; 512 PaintTranslate<Variable> paintformat15; 513 PaintRotate<NoVariable> paintformat16; 514 PaintRotate<Variable> paintformat17; 515 PaintSkew<NoVariable> paintformat18; 516 PaintSkew<Variable> paintformat19; 517 PaintComposite paintformat20; 518 } u; 519 }; 520 521 struct BaseGlyphV1Record 522 { cmpOT::BaseGlyphV1Record523 int cmp (hb_codepoint_t g) const 524 { return g < glyphId ? -1 : g > glyphId ? 1 : 0; } 525 sanitizeOT::BaseGlyphV1Record526 bool sanitize (hb_sanitize_context_t *c) const 527 { 528 TRACE_SANITIZE (this); 529 return_trace (likely (c->check_struct (this) && paint.sanitize (c, this))); 530 } 531 532 public: 533 HBGlyphID glyphId; /* Glyph ID of reference glyph */ 534 Offset32To<Paint> paint; /* Offset (from beginning of BaseGlyphV1Record) to Paint, 535 * Typically PaintColrLayers */ 536 public: 537 DEFINE_SIZE_STATIC (6); 538 }; 539 540 typedef SortedArray32Of<BaseGlyphV1Record> BaseGlyphV1List; 541 542 struct LayerV1List : Array32OfOffset32To<Paint> 543 { get_paintOT::LayerV1List544 const Paint& get_paint (unsigned i) const 545 { return this+(*this)[i]; } 546 sanitizeOT::LayerV1List547 bool sanitize (hb_sanitize_context_t *c) const 548 { 549 TRACE_SANITIZE (this); 550 return_trace (Array32OfOffset32To<Paint>::sanitize (c, this)); 551 } 552 }; 553 554 struct COLR 555 { 556 static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR; 557 has_dataOT::COLR558 bool has_data () const { return numBaseGlyphs; } 559 get_glyph_layersOT::COLR560 unsigned int get_glyph_layers (hb_codepoint_t glyph, 561 unsigned int start_offset, 562 unsigned int *count, /* IN/OUT. May be NULL. */ 563 hb_ot_color_layer_t *layers /* OUT. May be NULL. */) const 564 { 565 const BaseGlyphRecord &record = (this+baseGlyphsZ).bsearch (numBaseGlyphs, glyph); 566 567 hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers); 568 hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx, 569 record.numLayers); 570 if (count) 571 { 572 + glyph_layers.sub_array (start_offset, count) 573 | hb_sink (hb_array (layers, *count)) 574 ; 575 } 576 return glyph_layers.length; 577 } 578 579 struct accelerator_t 580 { accelerator_tOT::COLR::accelerator_t581 accelerator_t () {} ~accelerator_tOT::COLR::accelerator_t582 ~accelerator_t () { fini (); } 583 initOT::COLR::accelerator_t584 void init (hb_face_t *face) 585 { colr = hb_sanitize_context_t ().reference_table<COLR> (face); } 586 finiOT::COLR::accelerator_t587 void fini () { this->colr.destroy (); } 588 is_validOT::COLR::accelerator_t589 bool is_valid () { return colr.get_blob ()->length; } 590 closure_glyphsOT::COLR::accelerator_t591 void closure_glyphs (hb_codepoint_t glyph, 592 hb_set_t *related_ids /* OUT */) const 593 { colr->closure_glyphs (glyph, related_ids); } 594 595 private: 596 hb_blob_ptr_t<COLR> colr; 597 }; 598 closure_glyphsOT::COLR599 void closure_glyphs (hb_codepoint_t glyph, 600 hb_set_t *related_ids /* OUT */) const 601 { 602 const BaseGlyphRecord *record = get_base_glyph_record (glyph); 603 if (!record) return; 604 605 auto glyph_layers = (this+layersZ).as_array (numLayers).sub_array (record->firstLayerIdx, 606 record->numLayers); 607 if (!glyph_layers.length) return; 608 related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size); 609 } 610 sanitizeOT::COLR611 bool sanitize (hb_sanitize_context_t *c) const 612 { 613 TRACE_SANITIZE (this); 614 return_trace (c->check_struct (this) && 615 (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) && 616 (this+layersZ).sanitize (c, numLayers) && 617 (version == 0 || (version == 1 && 618 baseGlyphsV1List.sanitize (c, this) && 619 layersV1.sanitize (c, this) && 620 varStore.sanitize (c, this)))); 621 } 622 623 template<typename BaseIterator, typename LayerIterator, 624 hb_requires (hb_is_iterator (BaseIterator)), 625 hb_requires (hb_is_iterator (LayerIterator))> serializeOT::COLR626 bool serialize (hb_serialize_context_t *c, 627 unsigned version, 628 BaseIterator base_it, 629 LayerIterator layer_it) 630 { 631 TRACE_SERIALIZE (this); 632 if (unlikely (base_it.len () != layer_it.len ())) 633 return_trace (false); 634 635 if (unlikely (!c->extend_min (this))) return_trace (false); 636 this->version = version; 637 numLayers = 0; 638 numBaseGlyphs = base_it.len (); 639 baseGlyphsZ = COLR::min_size; 640 layersZ = COLR::min_size + numBaseGlyphs * BaseGlyphRecord::min_size; 641 642 for (const hb_item_type<BaseIterator> _ : + base_it.iter ()) 643 { 644 auto* record = c->embed (_); 645 if (unlikely (!record)) return_trace (false); 646 record->firstLayerIdx = numLayers; 647 numLayers += record->numLayers; 648 } 649 650 for (const hb_item_type<LayerIterator>& _ : + layer_it.iter ()) 651 _.as_array ().copy (c); 652 653 return_trace (true); 654 } 655 get_base_glyph_recordOT::COLR656 const BaseGlyphRecord* get_base_glyph_record (hb_codepoint_t gid) const 657 { 658 if ((unsigned int) gid == 0) // Ignore notdef. 659 return nullptr; 660 const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, (unsigned int) gid); 661 if ((record && (hb_codepoint_t) record->glyphId != gid)) 662 record = nullptr; 663 return record; 664 } 665 subsetOT::COLR666 bool subset (hb_subset_context_t *c) const 667 { 668 TRACE_SUBSET (this); 669 670 const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map; 671 672 auto base_it = 673 + hb_range (c->plan->num_output_glyphs ()) 674 | hb_map_retains_sorting ([&](hb_codepoint_t new_gid) 675 { 676 hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid); 677 678 const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid); 679 if (unlikely (!old_record)) 680 return hb_pair_t<bool, BaseGlyphRecord> (false, Null (BaseGlyphRecord)); 681 682 BaseGlyphRecord new_record = {}; 683 new_record.glyphId = new_gid; 684 new_record.numLayers = old_record->numLayers; 685 return hb_pair_t<bool, BaseGlyphRecord> (true, new_record); 686 }) 687 | hb_filter (hb_first) 688 | hb_map_retains_sorting (hb_second) 689 ; 690 691 auto layer_it = 692 + hb_range (c->plan->num_output_glyphs ()) 693 | hb_map (reverse_glyph_map) 694 | hb_map_retains_sorting ([&](hb_codepoint_t old_gid) 695 { 696 const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid); 697 hb_vector_t<LayerRecord> out_layers; 698 699 if (unlikely (!old_record || 700 old_record->firstLayerIdx >= numLayers || 701 old_record->firstLayerIdx + old_record->numLayers > numLayers)) 702 return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers); 703 704 auto layers = (this+layersZ).as_array (numLayers).sub_array (old_record->firstLayerIdx, 705 old_record->numLayers); 706 out_layers.resize (layers.length); 707 for (unsigned int i = 0; i < layers.length; i++) { 708 out_layers[i] = layers[i]; 709 hb_codepoint_t new_gid = 0; 710 if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid))) 711 return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers); 712 out_layers[i].glyphId = new_gid; 713 } 714 715 return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers); 716 }) 717 | hb_filter (hb_first) 718 | hb_map_retains_sorting (hb_second) 719 ; 720 721 if (unlikely (!base_it || !layer_it || base_it.len () != layer_it.len ())) 722 return_trace (false); 723 724 COLR *colr_prime = c->serializer->start_embed<COLR> (); 725 return_trace (colr_prime->serialize (c->serializer, version, base_it, layer_it)); 726 } 727 728 protected: 729 HBUINT16 version; /* Table version number (starts at 0). */ 730 HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records. */ 731 NNOffset32To<SortedUnsizedArrayOf<BaseGlyphRecord>> 732 baseGlyphsZ; /* Offset to Base Glyph records. */ 733 NNOffset32To<UnsizedArrayOf<LayerRecord>> 734 layersZ; /* Offset to Layer Records. */ 735 HBUINT16 numLayers; /* Number of Layer Records. */ 736 // Version-1 additions 737 Offset32To<BaseGlyphV1List> baseGlyphsV1List; 738 Offset32To<LayerV1List> layersV1; 739 Offset32To<VariationStore> varStore; 740 public: 741 DEFINE_SIZE_MIN (14); 742 }; 743 744 } /* namespace OT */ 745 746 747 #endif /* HB_OT_COLOR_COLR_TABLE_HH */ 748