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 #include "hb-ot-var-common.hh" 34 35 /* 36 * COLR -- Color 37 * https://docs.microsoft.com/en-us/typography/opentype/spec/colr 38 */ 39 #define HB_OT_TAG_COLR HB_TAG('C','O','L','R') 40 41 #ifndef HB_COLRV1_MAX_NESTING_LEVEL 42 #define HB_COLRV1_MAX_NESTING_LEVEL 16 43 #endif 44 45 namespace OT { 46 47 struct COLR; 48 struct hb_colrv1_closure_context_t : 49 hb_dispatch_context_t<hb_colrv1_closure_context_t> 50 { 51 template <typename T> dispatchOT::hb_colrv1_closure_context_t52 return_t dispatch (const T &obj) 53 { 54 if (unlikely (nesting_level_left == 0)) 55 return hb_empty_t (); 56 57 if (paint_visited (&obj)) 58 return hb_empty_t (); 59 60 nesting_level_left--; 61 obj.closurev1 (this); 62 nesting_level_left++; 63 return hb_empty_t (); 64 } default_return_valueOT::hb_colrv1_closure_context_t65 static return_t default_return_value () { return hb_empty_t (); } 66 paint_visitedOT::hb_colrv1_closure_context_t67 bool paint_visited (const void *paint) 68 { 69 hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) paint - (uintptr_t) base); 70 if (visited_paint.in_error() || visited_paint.has (delta)) 71 return true; 72 73 visited_paint.add (delta); 74 return false; 75 } 76 get_colr_tableOT::hb_colrv1_closure_context_t77 const COLR* get_colr_table () const 78 { return reinterpret_cast<const COLR *> (base); } 79 add_glyphOT::hb_colrv1_closure_context_t80 void add_glyph (unsigned glyph_id) 81 { glyphs->add (glyph_id); } 82 add_layer_indicesOT::hb_colrv1_closure_context_t83 void add_layer_indices (unsigned first_layer_index, unsigned num_of_layers) 84 { layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1); } 85 add_palette_indexOT::hb_colrv1_closure_context_t86 void add_palette_index (unsigned palette_index) 87 { palette_indices->add (palette_index); } 88 89 public: 90 const void *base; 91 hb_set_t visited_paint; 92 hb_set_t *glyphs; 93 hb_set_t *layer_indices; 94 hb_set_t *palette_indices; 95 unsigned nesting_level_left; 96 hb_colrv1_closure_context_tOT::hb_colrv1_closure_context_t97 hb_colrv1_closure_context_t (const void *base_, 98 hb_set_t *glyphs_, 99 hb_set_t *layer_indices_, 100 hb_set_t *palette_indices_, 101 unsigned nesting_level_left_ = HB_COLRV1_MAX_NESTING_LEVEL) : 102 base (base_), 103 glyphs (glyphs_), 104 layer_indices (layer_indices_), 105 palette_indices (palette_indices_), 106 nesting_level_left (nesting_level_left_) 107 {} 108 }; 109 110 struct LayerRecord 111 { operator hb_ot_color_layer_tOT::LayerRecord112 operator hb_ot_color_layer_t () const { return {glyphId, colorIdx}; } 113 sanitizeOT::LayerRecord114 bool sanitize (hb_sanitize_context_t *c) const 115 { 116 TRACE_SANITIZE (this); 117 return_trace (c->check_struct (this)); 118 } 119 120 public: 121 HBGlyphID16 glyphId; /* Glyph ID of layer glyph */ 122 Index colorIdx; /* Index value to use with a 123 * selected color palette. 124 * An index value of 0xFFFF 125 * is a special case indicating 126 * that the text foreground 127 * color (defined by a 128 * higher-level client) should 129 * be used and shall not be 130 * treated as actual index 131 * into CPAL ColorRecord array. */ 132 public: 133 DEFINE_SIZE_STATIC (4); 134 }; 135 136 struct BaseGlyphRecord 137 { cmpOT::BaseGlyphRecord138 int cmp (hb_codepoint_t g) const 139 { return g < glyphId ? -1 : g > glyphId ? 1 : 0; } 140 sanitizeOT::BaseGlyphRecord141 bool sanitize (hb_sanitize_context_t *c) const 142 { 143 TRACE_SANITIZE (this); 144 return_trace (c->check_struct (this)); 145 } 146 147 public: 148 HBGlyphID16 glyphId; /* Glyph ID of reference glyph */ 149 HBUINT16 firstLayerIdx; /* Index (from beginning of 150 * the Layer Records) to the 151 * layer record. There will be 152 * numLayers consecutive entries 153 * for this base glyph. */ 154 HBUINT16 numLayers; /* Number of color layers 155 * associated with this glyph */ 156 public: 157 DEFINE_SIZE_STATIC (6); 158 }; 159 160 template <typename T> 161 struct Variable 162 { copyOT::Variable163 Variable<T>* copy (hb_serialize_context_t *c) const 164 { 165 TRACE_SERIALIZE (this); 166 return_trace (c->embed (this)); 167 } 168 closurev1OT::Variable169 void closurev1 (hb_colrv1_closure_context_t* c) const 170 { value.closurev1 (c); } 171 subsetOT::Variable172 bool subset (hb_subset_context_t *c) const 173 { 174 TRACE_SUBSET (this); 175 if (!value.subset (c)) return_trace (false); 176 return_trace (c->serializer->embed (varIdxBase)); 177 } 178 sanitizeOT::Variable179 bool sanitize (hb_sanitize_context_t *c) const 180 { 181 TRACE_SANITIZE (this); 182 return_trace (c->check_struct (this) && value.sanitize (c)); 183 } 184 185 protected: 186 T value; 187 public: 188 VarIdx varIdxBase; 189 public: 190 DEFINE_SIZE_STATIC (4 + T::static_size); 191 }; 192 193 template <typename T> 194 struct NoVariable 195 { 196 static constexpr uint32_t varIdxBase = VarIdx::NO_VARIATION; 197 copyOT::NoVariable198 NoVariable<T>* copy (hb_serialize_context_t *c) const 199 { 200 TRACE_SERIALIZE (this); 201 return_trace (c->embed (this)); 202 } 203 closurev1OT::NoVariable204 void closurev1 (hb_colrv1_closure_context_t* c) const 205 { value.closurev1 (c); } 206 subsetOT::NoVariable207 bool subset (hb_subset_context_t *c) const 208 { 209 TRACE_SUBSET (this); 210 return_trace (value.subset (c)); 211 } 212 sanitizeOT::NoVariable213 bool sanitize (hb_sanitize_context_t *c) const 214 { 215 TRACE_SANITIZE (this); 216 return_trace (c->check_struct (this) && value.sanitize (c)); 217 } 218 219 T value; 220 public: 221 DEFINE_SIZE_STATIC (T::static_size); 222 }; 223 224 // Color structures 225 226 struct ColorStop 227 { closurev1OT::ColorStop228 void closurev1 (hb_colrv1_closure_context_t* c) const 229 { c->add_palette_index (paletteIndex); } 230 subsetOT::ColorStop231 bool subset (hb_subset_context_t *c) const 232 { 233 TRACE_SUBSET (this); 234 auto *out = c->serializer->embed (*this); 235 if (unlikely (!out)) return_trace (false); 236 return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex), 237 HB_SERIALIZE_ERROR_INT_OVERFLOW)); 238 } 239 sanitizeOT::ColorStop240 bool sanitize (hb_sanitize_context_t *c) const 241 { 242 TRACE_SANITIZE (this); 243 return_trace (c->check_struct (this)); 244 } 245 246 F2DOT14 stopOffset; 247 HBUINT16 paletteIndex; 248 F2DOT14 alpha; 249 public: 250 DEFINE_SIZE_STATIC (2 + 2 * F2DOT14::static_size); 251 }; 252 253 struct Extend : HBUINT8 254 { 255 enum { 256 EXTEND_PAD = 0, 257 EXTEND_REPEAT = 1, 258 EXTEND_REFLECT = 2, 259 }; 260 public: 261 DEFINE_SIZE_STATIC (1); 262 }; 263 264 template <template<typename> class Var> 265 struct ColorLine 266 { closurev1OT::ColorLine267 void closurev1 (hb_colrv1_closure_context_t* c) const 268 { 269 for (const auto &stop : stops.iter ()) 270 stop.closurev1 (c); 271 } 272 subsetOT::ColorLine273 bool subset (hb_subset_context_t *c) const 274 { 275 TRACE_SUBSET (this); 276 auto *out = c->serializer->start_embed (this); 277 if (unlikely (!out)) return_trace (false); 278 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 279 280 if (!c->serializer->check_assign (out->extend, extend, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); 281 if (!c->serializer->check_assign (out->stops.len, stops.len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)) return_trace (false); 282 283 for (const auto& stop : stops.iter ()) 284 { 285 if (!stop.subset (c)) return_trace (false); 286 } 287 return_trace (true); 288 } 289 sanitizeOT::ColorLine290 bool sanitize (hb_sanitize_context_t *c) const 291 { 292 TRACE_SANITIZE (this); 293 return_trace (c->check_struct (this) && 294 stops.sanitize (c)); 295 } 296 297 Extend extend; 298 Array16Of<Var<ColorStop>> stops; 299 public: 300 DEFINE_SIZE_ARRAY_SIZED (3, stops); 301 }; 302 303 // Composition modes 304 305 // Compositing modes are taken from https://www.w3.org/TR/compositing-1/ 306 // NOTE: a brief audit of major implementations suggests most support most 307 // or all of the specified modes. 308 struct CompositeMode : HBUINT8 309 { 310 enum { 311 // Porter-Duff modes 312 // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators 313 COMPOSITE_CLEAR = 0, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_clear 314 COMPOSITE_SRC = 1, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_src 315 COMPOSITE_DEST = 2, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dst 316 COMPOSITE_SRC_OVER = 3, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcover 317 COMPOSITE_DEST_OVER = 4, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstover 318 COMPOSITE_SRC_IN = 5, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcin 319 COMPOSITE_DEST_IN = 6, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstin 320 COMPOSITE_SRC_OUT = 7, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcout 321 COMPOSITE_DEST_OUT = 8, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstout 322 COMPOSITE_SRC_ATOP = 9, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcatop 323 COMPOSITE_DEST_ATOP = 10, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstatop 324 COMPOSITE_XOR = 11, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_xor 325 COMPOSITE_PLUS = 12, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_plus 326 327 // Blend modes 328 // https://www.w3.org/TR/compositing-1/#blending 329 COMPOSITE_SCREEN = 13, // https://www.w3.org/TR/compositing-1/#blendingscreen 330 COMPOSITE_OVERLAY = 14, // https://www.w3.org/TR/compositing-1/#blendingoverlay 331 COMPOSITE_DARKEN = 15, // https://www.w3.org/TR/compositing-1/#blendingdarken 332 COMPOSITE_LIGHTEN = 16, // https://www.w3.org/TR/compositing-1/#blendinglighten 333 COMPOSITE_COLOR_DODGE = 17, // https://www.w3.org/TR/compositing-1/#blendingcolordodge 334 COMPOSITE_COLOR_BURN = 18, // https://www.w3.org/TR/compositing-1/#blendingcolorburn 335 COMPOSITE_HARD_LIGHT = 19, // https://www.w3.org/TR/compositing-1/#blendinghardlight 336 COMPOSITE_SOFT_LIGHT = 20, // https://www.w3.org/TR/compositing-1/#blendingsoftlight 337 COMPOSITE_DIFFERENCE = 21, // https://www.w3.org/TR/compositing-1/#blendingdifference 338 COMPOSITE_EXCLUSION = 22, // https://www.w3.org/TR/compositing-1/#blendingexclusion 339 COMPOSITE_MULTIPLY = 23, // https://www.w3.org/TR/compositing-1/#blendingmultiply 340 341 // Modes that, uniquely, do not operate on components 342 // https://www.w3.org/TR/compositing-1/#blendingnonseparable 343 COMPOSITE_HSL_HUE = 24, // https://www.w3.org/TR/compositing-1/#blendinghue 344 COMPOSITE_HSL_SATURATION = 25, // https://www.w3.org/TR/compositing-1/#blendingsaturation 345 COMPOSITE_HSL_COLOR = 26, // https://www.w3.org/TR/compositing-1/#blendingcolor 346 COMPOSITE_HSL_LUMINOSITY = 27, // https://www.w3.org/TR/compositing-1/#blendingluminosity 347 }; 348 public: 349 DEFINE_SIZE_STATIC (1); 350 }; 351 352 struct Affine2x3 353 { sanitizeOT::Affine2x3354 bool sanitize (hb_sanitize_context_t *c) const 355 { 356 TRACE_SANITIZE (this); 357 return_trace (c->check_struct (this)); 358 } 359 360 F16DOT16 xx; 361 F16DOT16 yx; 362 F16DOT16 xy; 363 F16DOT16 yy; 364 F16DOT16 dx; 365 F16DOT16 dy; 366 public: 367 DEFINE_SIZE_STATIC (6 * F16DOT16::static_size); 368 }; 369 370 struct PaintColrLayers 371 { 372 void closurev1 (hb_colrv1_closure_context_t* c) const; 373 subsetOT::PaintColrLayers374 bool subset (hb_subset_context_t *c) const 375 { 376 TRACE_SUBSET (this); 377 auto *out = c->serializer->embed (this); 378 if (unlikely (!out)) return_trace (false); 379 return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers->get (firstLayerIndex), 380 HB_SERIALIZE_ERROR_INT_OVERFLOW)); 381 382 return_trace (true); 383 } 384 sanitizeOT::PaintColrLayers385 bool sanitize (hb_sanitize_context_t *c) const 386 { 387 TRACE_SANITIZE (this); 388 return_trace (c->check_struct (this)); 389 } 390 391 HBUINT8 format; /* format = 1 */ 392 HBUINT8 numLayers; 393 HBUINT32 firstLayerIndex; /* index into COLRv1::layerList */ 394 public: 395 DEFINE_SIZE_STATIC (6); 396 }; 397 398 struct PaintSolid 399 { closurev1OT::PaintSolid400 void closurev1 (hb_colrv1_closure_context_t* c) const 401 { c->add_palette_index (paletteIndex); } 402 subsetOT::PaintSolid403 bool subset (hb_subset_context_t *c) const 404 { 405 TRACE_SUBSET (this); 406 auto *out = c->serializer->embed (*this); 407 if (unlikely (!out)) return_trace (false); 408 return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex), 409 HB_SERIALIZE_ERROR_INT_OVERFLOW)); 410 } 411 sanitizeOT::PaintSolid412 bool sanitize (hb_sanitize_context_t *c) const 413 { 414 TRACE_SANITIZE (this); 415 return_trace (c->check_struct (this)); 416 } 417 418 HBUINT8 format; /* format = 2(noVar) or 3(Var)*/ 419 HBUINT16 paletteIndex; 420 F2DOT14 alpha; 421 public: 422 DEFINE_SIZE_STATIC (3 + F2DOT14::static_size); 423 }; 424 425 template <template<typename> class Var> 426 struct PaintLinearGradient 427 { closurev1OT::PaintLinearGradient428 void closurev1 (hb_colrv1_closure_context_t* c) const 429 { (this+colorLine).closurev1 (c); } 430 subsetOT::PaintLinearGradient431 bool subset (hb_subset_context_t *c) const 432 { 433 TRACE_SUBSET (this); 434 auto *out = c->serializer->embed (this); 435 if (unlikely (!out)) return_trace (false); 436 437 return_trace (out->colorLine.serialize_subset (c, colorLine, this)); 438 } 439 sanitizeOT::PaintLinearGradient440 bool sanitize (hb_sanitize_context_t *c) const 441 { 442 TRACE_SANITIZE (this); 443 return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); 444 } 445 446 HBUINT8 format; /* format = 4(noVar) or 5 (Var) */ 447 Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintLinearGradient 448 * table) to ColorLine subtable. */ 449 FWORD x0; 450 FWORD y0; 451 FWORD x1; 452 FWORD y1; 453 FWORD x2; 454 FWORD y2; 455 public: 456 DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size); 457 }; 458 459 template <template<typename> class Var> 460 struct PaintRadialGradient 461 { closurev1OT::PaintRadialGradient462 void closurev1 (hb_colrv1_closure_context_t* c) const 463 { (this+colorLine).closurev1 (c); } 464 subsetOT::PaintRadialGradient465 bool subset (hb_subset_context_t *c) const 466 { 467 TRACE_SUBSET (this); 468 auto *out = c->serializer->embed (this); 469 if (unlikely (!out)) return_trace (false); 470 471 return_trace (out->colorLine.serialize_subset (c, colorLine, this)); 472 } 473 sanitizeOT::PaintRadialGradient474 bool sanitize (hb_sanitize_context_t *c) const 475 { 476 TRACE_SANITIZE (this); 477 return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); 478 } 479 480 HBUINT8 format; /* format = 6(noVar) or 7 (Var) */ 481 Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintRadialGradient 482 * table) to ColorLine subtable. */ 483 FWORD x0; 484 FWORD y0; 485 UFWORD radius0; 486 FWORD x1; 487 FWORD y1; 488 UFWORD radius1; 489 public: 490 DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size); 491 }; 492 493 template <template<typename> class Var> 494 struct PaintSweepGradient 495 { closurev1OT::PaintSweepGradient496 void closurev1 (hb_colrv1_closure_context_t* c) const 497 { (this+colorLine).closurev1 (c); } 498 subsetOT::PaintSweepGradient499 bool subset (hb_subset_context_t *c) const 500 { 501 TRACE_SUBSET (this); 502 auto *out = c->serializer->embed (this); 503 if (unlikely (!out)) return_trace (false); 504 505 return_trace (out->colorLine.serialize_subset (c, colorLine, this)); 506 } 507 sanitizeOT::PaintSweepGradient508 bool sanitize (hb_sanitize_context_t *c) const 509 { 510 TRACE_SANITIZE (this); 511 return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); 512 } 513 514 HBUINT8 format; /* format = 8(noVar) or 9 (Var) */ 515 Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintSweepGradient 516 * table) to ColorLine subtable. */ 517 FWORD centerX; 518 FWORD centerY; 519 F2DOT14 startAngle; 520 F2DOT14 endAngle; 521 public: 522 DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size + 2 * F2DOT14::static_size); 523 }; 524 525 struct Paint; 526 527 // Paint a non-COLR glyph, filled as indicated by paint. 528 struct PaintGlyph 529 { 530 void closurev1 (hb_colrv1_closure_context_t* c) const; 531 subsetOT::PaintGlyph532 bool subset (hb_subset_context_t *c) const 533 { 534 TRACE_SUBSET (this); 535 auto *out = c->serializer->embed (this); 536 if (unlikely (!out)) return_trace (false); 537 538 if (! c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid), 539 HB_SERIALIZE_ERROR_INT_OVERFLOW)) 540 return_trace (false); 541 542 return_trace (out->paint.serialize_subset (c, paint, this)); 543 } 544 sanitizeOT::PaintGlyph545 bool sanitize (hb_sanitize_context_t *c) const 546 { 547 TRACE_SANITIZE (this); 548 return_trace (c->check_struct (this) && paint.sanitize (c, this)); 549 } 550 551 HBUINT8 format; /* format = 10 */ 552 Offset24To<Paint> paint; /* Offset (from beginning of PaintGlyph table) to Paint subtable. */ 553 HBUINT16 gid; 554 public: 555 DEFINE_SIZE_STATIC (6); 556 }; 557 558 struct PaintColrGlyph 559 { 560 void closurev1 (hb_colrv1_closure_context_t* c) const; 561 subsetOT::PaintColrGlyph562 bool subset (hb_subset_context_t *c) const 563 { 564 TRACE_SUBSET (this); 565 auto *out = c->serializer->embed (this); 566 if (unlikely (!out)) return_trace (false); 567 568 return_trace (c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid), 569 HB_SERIALIZE_ERROR_INT_OVERFLOW)); 570 } 571 sanitizeOT::PaintColrGlyph572 bool sanitize (hb_sanitize_context_t *c) const 573 { 574 TRACE_SANITIZE (this); 575 return_trace (c->check_struct (this)); 576 } 577 578 HBUINT8 format; /* format = 11 */ 579 HBUINT16 gid; 580 public: 581 DEFINE_SIZE_STATIC (3); 582 }; 583 584 template <template<typename> class Var> 585 struct PaintTransform 586 { 587 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; 588 subsetOT::PaintTransform589 bool subset (hb_subset_context_t *c) const 590 { 591 TRACE_SUBSET (this); 592 auto *out = c->serializer->embed (this); 593 if (unlikely (!out)) return_trace (false); 594 if (!out->transform.serialize_copy (c->serializer, transform, this)) return_trace (false); 595 return_trace (out->src.serialize_subset (c, src, this)); 596 } 597 sanitizeOT::PaintTransform598 bool sanitize (hb_sanitize_context_t *c) const 599 { 600 TRACE_SANITIZE (this); 601 return_trace (c->check_struct (this) && 602 src.sanitize (c, this) && 603 transform.sanitize (c, this)); 604 } 605 606 HBUINT8 format; /* format = 12(noVar) or 13 (Var) */ 607 Offset24To<Paint> src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */ 608 Offset24To<Var<Affine2x3>> transform; 609 public: 610 DEFINE_SIZE_STATIC (7); 611 }; 612 613 struct PaintTranslate 614 { 615 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; 616 subsetOT::PaintTranslate617 bool subset (hb_subset_context_t *c) const 618 { 619 TRACE_SUBSET (this); 620 auto *out = c->serializer->embed (this); 621 if (unlikely (!out)) return_trace (false); 622 623 return_trace (out->src.serialize_subset (c, src, this)); 624 } 625 sanitizeOT::PaintTranslate626 bool sanitize (hb_sanitize_context_t *c) const 627 { 628 TRACE_SANITIZE (this); 629 return_trace (c->check_struct (this) && src.sanitize (c, this)); 630 } 631 632 HBUINT8 format; /* format = 14(noVar) or 15 (Var) */ 633 Offset24To<Paint> src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */ 634 FWORD dx; 635 FWORD dy; 636 public: 637 DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size); 638 }; 639 640 struct PaintScale 641 { 642 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; 643 subsetOT::PaintScale644 bool subset (hb_subset_context_t *c) const 645 { 646 TRACE_SUBSET (this); 647 auto *out = c->serializer->embed (this); 648 if (unlikely (!out)) return_trace (false); 649 650 return_trace (out->src.serialize_subset (c, src, this)); 651 } 652 sanitizeOT::PaintScale653 bool sanitize (hb_sanitize_context_t *c) const 654 { 655 TRACE_SANITIZE (this); 656 return_trace (c->check_struct (this) && src.sanitize (c, this)); 657 } 658 659 HBUINT8 format; /* format = 16 (noVar) or 17(Var) */ 660 Offset24To<Paint> src; /* Offset (from beginning of PaintScale table) to Paint subtable. */ 661 F2DOT14 scaleX; 662 F2DOT14 scaleY; 663 public: 664 DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size); 665 }; 666 667 struct PaintScaleAroundCenter 668 { 669 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; 670 subsetOT::PaintScaleAroundCenter671 bool subset (hb_subset_context_t *c) const 672 { 673 TRACE_SUBSET (this); 674 auto *out = c->serializer->embed (this); 675 if (unlikely (!out)) return_trace (false); 676 677 return_trace (out->src.serialize_subset (c, src, this)); 678 } 679 sanitizeOT::PaintScaleAroundCenter680 bool sanitize (hb_sanitize_context_t *c) const 681 { 682 TRACE_SANITIZE (this); 683 return_trace (c->check_struct (this) && src.sanitize (c, this)); 684 } 685 686 HBUINT8 format; /* format = 18 (noVar) or 19(Var) */ 687 Offset24To<Paint> src; /* Offset (from beginning of PaintScaleAroundCenter table) to Paint subtable. */ 688 F2DOT14 scaleX; 689 F2DOT14 scaleY; 690 FWORD centerX; 691 FWORD centerY; 692 public: 693 DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size + 2 * FWORD::static_size); 694 }; 695 696 struct PaintScaleUniform 697 { 698 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; 699 subsetOT::PaintScaleUniform700 bool subset (hb_subset_context_t *c) const 701 { 702 TRACE_SUBSET (this); 703 auto *out = c->serializer->embed (this); 704 if (unlikely (!out)) return_trace (false); 705 706 return_trace (out->src.serialize_subset (c, src, this)); 707 } 708 sanitizeOT::PaintScaleUniform709 bool sanitize (hb_sanitize_context_t *c) const 710 { 711 TRACE_SANITIZE (this); 712 return_trace (c->check_struct (this) && src.sanitize (c, this)); 713 } 714 715 HBUINT8 format; /* format = 20 (noVar) or 21(Var) */ 716 Offset24To<Paint> src; /* Offset (from beginning of PaintScaleUniform table) to Paint subtable. */ 717 F2DOT14 scale; 718 public: 719 DEFINE_SIZE_STATIC (4 + F2DOT14::static_size); 720 }; 721 722 struct PaintScaleUniformAroundCenter 723 { 724 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; 725 subsetOT::PaintScaleUniformAroundCenter726 bool subset (hb_subset_context_t *c) const 727 { 728 TRACE_SUBSET (this); 729 auto *out = c->serializer->embed (this); 730 if (unlikely (!out)) return_trace (false); 731 732 return_trace (out->src.serialize_subset (c, src, this)); 733 } 734 sanitizeOT::PaintScaleUniformAroundCenter735 bool sanitize (hb_sanitize_context_t *c) const 736 { 737 TRACE_SANITIZE (this); 738 return_trace (c->check_struct (this) && src.sanitize (c, this)); 739 } 740 741 HBUINT8 format; /* format = 22 (noVar) or 23(Var) */ 742 Offset24To<Paint> src; /* Offset (from beginning of PaintScaleUniformAroundCenter table) to Paint subtable. */ 743 F2DOT14 scale; 744 FWORD centerX; 745 FWORD centerY; 746 public: 747 DEFINE_SIZE_STATIC (4 + F2DOT14::static_size + 2 * FWORD::static_size); 748 }; 749 750 struct PaintRotate 751 { 752 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; 753 subsetOT::PaintRotate754 bool subset (hb_subset_context_t *c) const 755 { 756 TRACE_SUBSET (this); 757 auto *out = c->serializer->embed (this); 758 if (unlikely (!out)) return_trace (false); 759 760 return_trace (out->src.serialize_subset (c, src, this)); 761 } 762 sanitizeOT::PaintRotate763 bool sanitize (hb_sanitize_context_t *c) const 764 { 765 TRACE_SANITIZE (this); 766 return_trace (c->check_struct (this) && src.sanitize (c, this)); 767 } 768 769 HBUINT8 format; /* format = 24 (noVar) or 25(Var) */ 770 Offset24To<Paint> src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */ 771 F2DOT14 angle; 772 public: 773 DEFINE_SIZE_STATIC (4 + F2DOT14::static_size); 774 }; 775 776 struct PaintRotateAroundCenter 777 { 778 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; 779 subsetOT::PaintRotateAroundCenter780 bool subset (hb_subset_context_t *c) const 781 { 782 TRACE_SUBSET (this); 783 auto *out = c->serializer->embed (this); 784 if (unlikely (!out)) return_trace (false); 785 786 return_trace (out->src.serialize_subset (c, src, this)); 787 } 788 sanitizeOT::PaintRotateAroundCenter789 bool sanitize (hb_sanitize_context_t *c) const 790 { 791 TRACE_SANITIZE (this); 792 return_trace (c->check_struct (this) && src.sanitize (c, this)); 793 } 794 795 HBUINT8 format; /* format = 26 (noVar) or 27(Var) */ 796 Offset24To<Paint> src; /* Offset (from beginning of PaintRotateAroundCenter table) to Paint subtable. */ 797 F2DOT14 angle; 798 FWORD centerX; 799 FWORD centerY; 800 public: 801 DEFINE_SIZE_STATIC (4 + F2DOT14::static_size + 2 * FWORD::static_size); 802 }; 803 804 struct PaintSkew 805 { 806 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; 807 subsetOT::PaintSkew808 bool subset (hb_subset_context_t *c) const 809 { 810 TRACE_SUBSET (this); 811 auto *out = c->serializer->embed (this); 812 if (unlikely (!out)) return_trace (false); 813 814 return_trace (out->src.serialize_subset (c, src, this)); 815 } 816 sanitizeOT::PaintSkew817 bool sanitize (hb_sanitize_context_t *c) const 818 { 819 TRACE_SANITIZE (this); 820 return_trace (c->check_struct (this) && src.sanitize (c, this)); 821 } 822 823 HBUINT8 format; /* format = 28(noVar) or 29 (Var) */ 824 Offset24To<Paint> src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */ 825 F2DOT14 xSkewAngle; 826 F2DOT14 ySkewAngle; 827 public: 828 DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size); 829 }; 830 831 struct PaintSkewAroundCenter 832 { 833 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; 834 subsetOT::PaintSkewAroundCenter835 bool subset (hb_subset_context_t *c) const 836 { 837 TRACE_SUBSET (this); 838 auto *out = c->serializer->embed (this); 839 if (unlikely (!out)) return_trace (false); 840 841 return_trace (out->src.serialize_subset (c, src, this)); 842 } 843 sanitizeOT::PaintSkewAroundCenter844 bool sanitize (hb_sanitize_context_t *c) const 845 { 846 TRACE_SANITIZE (this); 847 return_trace (c->check_struct (this) && src.sanitize (c, this)); 848 } 849 850 HBUINT8 format; /* format = 30(noVar) or 31 (Var) */ 851 Offset24To<Paint> src; /* Offset (from beginning of PaintSkewAroundCenter table) to Paint subtable. */ 852 F2DOT14 xSkewAngle; 853 F2DOT14 ySkewAngle; 854 FWORD centerX; 855 FWORD centerY; 856 public: 857 DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size + 2 * FWORD::static_size); 858 }; 859 860 struct PaintComposite 861 { 862 void closurev1 (hb_colrv1_closure_context_t* c) const; 863 subsetOT::PaintComposite864 bool subset (hb_subset_context_t *c) const 865 { 866 TRACE_SUBSET (this); 867 auto *out = c->serializer->embed (this); 868 if (unlikely (!out)) return_trace (false); 869 870 if (!out->src.serialize_subset (c, src, this)) return_trace (false); 871 return_trace (out->backdrop.serialize_subset (c, backdrop, this)); 872 } 873 sanitizeOT::PaintComposite874 bool sanitize (hb_sanitize_context_t *c) const 875 { 876 TRACE_SANITIZE (this); 877 return_trace (c->check_struct (this) && 878 src.sanitize (c, this) && 879 backdrop.sanitize (c, this)); 880 } 881 882 HBUINT8 format; /* format = 32 */ 883 Offset24To<Paint> src; /* Offset (from beginning of PaintComposite table) to source Paint subtable. */ 884 CompositeMode mode; /* If mode is unrecognized use COMPOSITE_CLEAR */ 885 Offset24To<Paint> backdrop; /* Offset (from beginning of PaintComposite table) to backdrop Paint subtable. */ 886 public: 887 DEFINE_SIZE_STATIC (8); 888 }; 889 890 struct ClipBoxData 891 { 892 int xMin, yMin, xMax, yMax; 893 }; 894 895 struct ClipBoxFormat1 896 { sanitizeOT::ClipBoxFormat1897 bool sanitize (hb_sanitize_context_t *c) const 898 { 899 TRACE_SANITIZE (this); 900 return_trace (c->check_struct (this)); 901 } 902 get_clip_boxOT::ClipBoxFormat1903 void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer HB_UNUSED) const 904 { 905 clip_box.xMin = xMin; 906 clip_box.yMin = yMin; 907 clip_box.xMax = xMax; 908 clip_box.yMax = yMax; 909 } 910 911 public: 912 HBUINT8 format; /* format = 1(noVar) or 2(Var)*/ 913 FWORD xMin; 914 FWORD yMin; 915 FWORD xMax; 916 FWORD yMax; 917 public: 918 DEFINE_SIZE_STATIC (1 + 4 * FWORD::static_size); 919 }; 920 921 struct ClipBoxFormat2 : Variable<ClipBoxFormat1> 922 { get_clip_boxOT::ClipBoxFormat2923 void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer) const 924 { 925 value.get_clip_box(clip_box, instancer); 926 if (instancer) 927 { 928 clip_box.xMin += _hb_roundf (instancer (varIdxBase, 0)); 929 clip_box.yMin += _hb_roundf (instancer (varIdxBase, 1)); 930 clip_box.xMax += _hb_roundf (instancer (varIdxBase, 2)); 931 clip_box.yMax += _hb_roundf (instancer (varIdxBase, 3)); 932 } 933 } 934 }; 935 936 struct ClipBox 937 { copyOT::ClipBox938 ClipBox* copy (hb_serialize_context_t *c) const 939 { 940 TRACE_SERIALIZE (this); 941 switch (u.format) { 942 case 1: return_trace (reinterpret_cast<ClipBox *> (c->embed (u.format1))); 943 case 2: return_trace (reinterpret_cast<ClipBox *> (c->embed (u.format2))); 944 default:return_trace (nullptr); 945 } 946 } 947 948 template <typename context_t, typename ...Ts> dispatchOT::ClipBox949 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const 950 { 951 TRACE_DISPATCH (this, u.format); 952 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 953 switch (u.format) { 954 case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); 955 case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...)); 956 default:return_trace (c->default_return_value ()); 957 } 958 } 959 get_extentsOT::ClipBox960 bool get_extents (hb_glyph_extents_t *extents, 961 const VarStoreInstancer &instancer) const 962 { 963 ClipBoxData clip_box; 964 switch (u.format) { 965 case 1: 966 u.format1.get_clip_box (clip_box, instancer); 967 break; 968 case 2: 969 u.format2.get_clip_box (clip_box, instancer); 970 break; 971 default: 972 return false; 973 } 974 975 extents->x_bearing = clip_box.xMin; 976 extents->y_bearing = clip_box.yMax; 977 extents->width = clip_box.xMax - clip_box.xMin; 978 extents->height = clip_box.yMin - clip_box.yMax; 979 return true; 980 } 981 982 protected: 983 union { 984 HBUINT8 format; /* Format identifier */ 985 ClipBoxFormat1 format1; 986 ClipBoxFormat2 format2; 987 } u; 988 }; 989 990 struct ClipRecord 991 { cmpOT::ClipRecord992 int cmp (hb_codepoint_t g) const 993 { return g < startGlyphID ? -1 : g <= endGlyphID ? 0 : +1; } 994 copyOT::ClipRecord995 ClipRecord* copy (hb_serialize_context_t *c, const void *base) const 996 { 997 TRACE_SERIALIZE (this); 998 auto *out = c->embed (this); 999 if (unlikely (!out)) return_trace (nullptr); 1000 if (!out->clipBox.serialize_copy (c, clipBox, base)) return_trace (nullptr); 1001 return_trace (out); 1002 } 1003 sanitizeOT::ClipRecord1004 bool sanitize (hb_sanitize_context_t *c, const void *base) const 1005 { 1006 TRACE_SANITIZE (this); 1007 return_trace (c->check_struct (this) && clipBox.sanitize (c, base)); 1008 } 1009 get_extentsOT::ClipRecord1010 bool get_extents (hb_glyph_extents_t *extents, 1011 const void *base, 1012 const VarStoreInstancer &instancer) const 1013 { 1014 return (base+clipBox).get_extents (extents, instancer); 1015 } 1016 1017 public: 1018 HBUINT16 startGlyphID; // first gid clip applies to 1019 HBUINT16 endGlyphID; // last gid clip applies to, inclusive 1020 Offset24To<ClipBox> clipBox; // Box or VarBox 1021 public: 1022 DEFINE_SIZE_STATIC (7); 1023 }; 1024 DECLARE_NULL_NAMESPACE_BYTES (OT, ClipRecord); 1025 1026 struct ClipList 1027 { serialize_clip_recordsOT::ClipList1028 unsigned serialize_clip_records (hb_serialize_context_t *c, 1029 const hb_set_t& gids, 1030 const hb_map_t& gid_offset_map) const 1031 { 1032 TRACE_SERIALIZE (this); 1033 if (gids.is_empty () || 1034 gid_offset_map.get_population () != gids.get_population ()) 1035 return_trace (0); 1036 1037 unsigned count = 0; 1038 1039 hb_codepoint_t start_gid= gids.get_min (); 1040 hb_codepoint_t prev_gid = start_gid; 1041 1042 unsigned offset = gid_offset_map.get (start_gid); 1043 unsigned prev_offset = offset; 1044 for (const hb_codepoint_t _ : gids.iter ()) 1045 { 1046 if (_ == start_gid) continue; 1047 1048 offset = gid_offset_map.get (_); 1049 if (_ == prev_gid + 1 && offset == prev_offset) 1050 { 1051 prev_gid = _; 1052 continue; 1053 } 1054 1055 ClipRecord record; 1056 record.startGlyphID = start_gid; 1057 record.endGlyphID = prev_gid; 1058 record.clipBox = prev_offset; 1059 1060 if (!c->copy (record, this)) return_trace (0); 1061 count++; 1062 1063 start_gid = _; 1064 prev_gid = _; 1065 prev_offset = offset; 1066 } 1067 1068 //last one 1069 { 1070 ClipRecord record; 1071 record.startGlyphID = start_gid; 1072 record.endGlyphID = prev_gid; 1073 record.clipBox = prev_offset; 1074 if (!c->copy (record, this)) return_trace (0); 1075 count++; 1076 } 1077 return_trace (count); 1078 } 1079 subsetOT::ClipList1080 bool subset (hb_subset_context_t *c) const 1081 { 1082 TRACE_SUBSET (this); 1083 auto *out = c->serializer->start_embed (*this); 1084 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 1085 if (!c->serializer->check_assign (out->format, format, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); 1086 1087 const hb_set_t& glyphset = *c->plan->_glyphset_colred; 1088 const hb_map_t &glyph_map = *c->plan->glyph_map; 1089 1090 hb_map_t new_gid_offset_map; 1091 hb_set_t new_gids; 1092 for (const ClipRecord& record : clips.iter ()) 1093 { 1094 unsigned start_gid = record.startGlyphID; 1095 unsigned end_gid = record.endGlyphID; 1096 for (unsigned gid = start_gid; gid <= end_gid; gid++) 1097 { 1098 if (!glyphset.has (gid) || !glyph_map.has (gid)) continue; 1099 unsigned new_gid = glyph_map.get (gid); 1100 new_gid_offset_map.set (new_gid, record.clipBox); 1101 new_gids.add (new_gid); 1102 } 1103 } 1104 1105 unsigned count = serialize_clip_records (c->serializer, new_gids, new_gid_offset_map); 1106 if (!count) return_trace (false); 1107 return_trace (c->serializer->check_assign (out->clips.len, count, HB_SERIALIZE_ERROR_INT_OVERFLOW)); 1108 } 1109 sanitizeOT::ClipList1110 bool sanitize (hb_sanitize_context_t *c) const 1111 { 1112 TRACE_SANITIZE (this); 1113 // TODO Make a formatted struct! 1114 return_trace (c->check_struct (this) && clips.sanitize (c, this)); 1115 } 1116 1117 bool get_extentsOT::ClipList1118 get_extents (hb_codepoint_t gid, 1119 hb_glyph_extents_t *extents, 1120 const VarStoreInstancer &instancer) const 1121 { 1122 auto *rec = clips.as_array ().bsearch (gid); 1123 if (rec) 1124 { 1125 rec->get_extents (extents, this, instancer); 1126 return true; 1127 } 1128 return false; 1129 } 1130 1131 HBUINT8 format; // Set to 1. 1132 SortedArray32Of<ClipRecord> clips; // Clip records, sorted by startGlyphID 1133 public: 1134 DEFINE_SIZE_ARRAY_SIZED (5, clips); 1135 }; 1136 1137 struct Paint 1138 { 1139 1140 template <typename ...Ts> sanitizeOT::Paint1141 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 1142 { 1143 TRACE_SANITIZE (this); 1144 1145 if (unlikely (!c->check_start_recursion (HB_COLRV1_MAX_NESTING_LEVEL))) 1146 return_trace (c->no_dispatch_return_value ()); 1147 1148 return_trace (c->end_recursion (this->dispatch (c, std::forward<Ts> (ds)...))); 1149 } 1150 1151 template <typename context_t, typename ...Ts> dispatchOT::Paint1152 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const 1153 { 1154 TRACE_DISPATCH (this, u.format); 1155 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 1156 switch (u.format) { 1157 case 1: return_trace (c->dispatch (u.paintformat1, std::forward<Ts> (ds)...)); 1158 case 2: return_trace (c->dispatch (u.paintformat2, std::forward<Ts> (ds)...)); 1159 case 3: return_trace (c->dispatch (u.paintformat3, std::forward<Ts> (ds)...)); 1160 case 4: return_trace (c->dispatch (u.paintformat4, std::forward<Ts> (ds)...)); 1161 case 5: return_trace (c->dispatch (u.paintformat5, std::forward<Ts> (ds)...)); 1162 case 6: return_trace (c->dispatch (u.paintformat6, std::forward<Ts> (ds)...)); 1163 case 7: return_trace (c->dispatch (u.paintformat7, std::forward<Ts> (ds)...)); 1164 case 8: return_trace (c->dispatch (u.paintformat8, std::forward<Ts> (ds)...)); 1165 case 9: return_trace (c->dispatch (u.paintformat9, std::forward<Ts> (ds)...)); 1166 case 10: return_trace (c->dispatch (u.paintformat10, std::forward<Ts> (ds)...)); 1167 case 11: return_trace (c->dispatch (u.paintformat11, std::forward<Ts> (ds)...)); 1168 case 12: return_trace (c->dispatch (u.paintformat12, std::forward<Ts> (ds)...)); 1169 case 13: return_trace (c->dispatch (u.paintformat13, std::forward<Ts> (ds)...)); 1170 case 14: return_trace (c->dispatch (u.paintformat14, std::forward<Ts> (ds)...)); 1171 case 15: return_trace (c->dispatch (u.paintformat15, std::forward<Ts> (ds)...)); 1172 case 16: return_trace (c->dispatch (u.paintformat16, std::forward<Ts> (ds)...)); 1173 case 17: return_trace (c->dispatch (u.paintformat17, std::forward<Ts> (ds)...)); 1174 case 18: return_trace (c->dispatch (u.paintformat18, std::forward<Ts> (ds)...)); 1175 case 19: return_trace (c->dispatch (u.paintformat19, std::forward<Ts> (ds)...)); 1176 case 20: return_trace (c->dispatch (u.paintformat20, std::forward<Ts> (ds)...)); 1177 case 21: return_trace (c->dispatch (u.paintformat21, std::forward<Ts> (ds)...)); 1178 case 22: return_trace (c->dispatch (u.paintformat22, std::forward<Ts> (ds)...)); 1179 case 23: return_trace (c->dispatch (u.paintformat23, std::forward<Ts> (ds)...)); 1180 case 24: return_trace (c->dispatch (u.paintformat24, std::forward<Ts> (ds)...)); 1181 case 25: return_trace (c->dispatch (u.paintformat25, std::forward<Ts> (ds)...)); 1182 case 26: return_trace (c->dispatch (u.paintformat26, std::forward<Ts> (ds)...)); 1183 case 27: return_trace (c->dispatch (u.paintformat27, std::forward<Ts> (ds)...)); 1184 case 28: return_trace (c->dispatch (u.paintformat28, std::forward<Ts> (ds)...)); 1185 case 29: return_trace (c->dispatch (u.paintformat29, std::forward<Ts> (ds)...)); 1186 case 30: return_trace (c->dispatch (u.paintformat30, std::forward<Ts> (ds)...)); 1187 case 31: return_trace (c->dispatch (u.paintformat31, std::forward<Ts> (ds)...)); 1188 case 32: return_trace (c->dispatch (u.paintformat32, std::forward<Ts> (ds)...)); 1189 default:return_trace (c->default_return_value ()); 1190 } 1191 } 1192 1193 protected: 1194 union { 1195 HBUINT8 format; 1196 PaintColrLayers paintformat1; 1197 PaintSolid paintformat2; 1198 Variable<PaintSolid> paintformat3; 1199 PaintLinearGradient<NoVariable> paintformat4; 1200 Variable<PaintLinearGradient<Variable>> paintformat5; 1201 PaintRadialGradient<NoVariable> paintformat6; 1202 Variable<PaintRadialGradient<Variable>> paintformat7; 1203 PaintSweepGradient<NoVariable> paintformat8; 1204 Variable<PaintSweepGradient<Variable>> paintformat9; 1205 PaintGlyph paintformat10; 1206 PaintColrGlyph paintformat11; 1207 PaintTransform<NoVariable> paintformat12; 1208 PaintTransform<Variable> paintformat13; 1209 PaintTranslate paintformat14; 1210 Variable<PaintTranslate> paintformat15; 1211 PaintScale paintformat16; 1212 Variable<PaintScale> paintformat17; 1213 PaintScaleAroundCenter paintformat18; 1214 Variable<PaintScaleAroundCenter> paintformat19; 1215 PaintScaleUniform paintformat20; 1216 Variable<PaintScaleUniform> paintformat21; 1217 PaintScaleUniformAroundCenter paintformat22; 1218 Variable<PaintScaleUniformAroundCenter> paintformat23; 1219 PaintRotate paintformat24; 1220 Variable<PaintRotate> paintformat25; 1221 PaintRotateAroundCenter paintformat26; 1222 Variable<PaintRotateAroundCenter> paintformat27; 1223 PaintSkew paintformat28; 1224 Variable<PaintSkew> paintformat29; 1225 PaintSkewAroundCenter paintformat30; 1226 Variable<PaintSkewAroundCenter> paintformat31; 1227 PaintComposite paintformat32; 1228 } u; 1229 public: 1230 DEFINE_SIZE_MIN (2); 1231 }; 1232 1233 struct BaseGlyphPaintRecord 1234 { cmpOT::BaseGlyphPaintRecord1235 int cmp (hb_codepoint_t g) const 1236 { return g < glyphId ? -1 : g > glyphId ? 1 : 0; } 1237 serializeOT::BaseGlyphPaintRecord1238 bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map, 1239 const void* src_base, hb_subset_context_t *c) const 1240 { 1241 TRACE_SERIALIZE (this); 1242 auto *out = s->embed (this); 1243 if (unlikely (!out)) return_trace (false); 1244 if (!s->check_assign (out->glyphId, glyph_map->get (glyphId), 1245 HB_SERIALIZE_ERROR_INT_OVERFLOW)) 1246 return_trace (false); 1247 1248 return_trace (out->paint.serialize_subset (c, paint, src_base)); 1249 } 1250 sanitizeOT::BaseGlyphPaintRecord1251 bool sanitize (hb_sanitize_context_t *c, const void *base) const 1252 { 1253 TRACE_SANITIZE (this); 1254 return_trace (likely (c->check_struct (this) && paint.sanitize (c, base))); 1255 } 1256 1257 public: 1258 HBGlyphID16 glyphId; /* Glyph ID of reference glyph */ 1259 Offset32To<Paint> paint; /* Offset (from beginning of BaseGlyphPaintRecord array) to Paint, 1260 * Typically PaintColrLayers */ 1261 public: 1262 DEFINE_SIZE_STATIC (6); 1263 }; 1264 1265 struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord> 1266 { subsetOT::BaseGlyphList1267 bool subset (hb_subset_context_t *c) const 1268 { 1269 TRACE_SUBSET (this); 1270 auto *out = c->serializer->start_embed (this); 1271 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 1272 const hb_set_t* glyphset = c->plan->_glyphset_colred; 1273 1274 for (const auto& _ : as_array ()) 1275 { 1276 unsigned gid = _.glyphId; 1277 if (!glyphset->has (gid)) continue; 1278 1279 if (_.serialize (c->serializer, c->plan->glyph_map, this, c)) out->len++; 1280 else return_trace (false); 1281 } 1282 1283 return_trace (out->len != 0); 1284 } 1285 sanitizeOT::BaseGlyphList1286 bool sanitize (hb_sanitize_context_t *c) const 1287 { 1288 TRACE_SANITIZE (this); 1289 return_trace (SortedArray32Of<BaseGlyphPaintRecord>::sanitize (c, this)); 1290 } 1291 }; 1292 1293 struct LayerList : Array32OfOffset32To<Paint> 1294 { get_paintOT::LayerList1295 const Paint& get_paint (unsigned i) const 1296 { return this+(*this)[i]; } 1297 subsetOT::LayerList1298 bool subset (hb_subset_context_t *c) const 1299 { 1300 TRACE_SUBSET (this); 1301 auto *out = c->serializer->start_embed (this); 1302 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 1303 1304 for (const auto& _ : + hb_enumerate (*this) 1305 | hb_filter (c->plan->colrv1_layers, hb_first)) 1306 1307 { 1308 auto *o = out->serialize_append (c->serializer); 1309 if (unlikely (!o) || !o->serialize_subset (c, _.second, this)) 1310 return_trace (false); 1311 } 1312 return_trace (true); 1313 } 1314 sanitizeOT::LayerList1315 bool sanitize (hb_sanitize_context_t *c) const 1316 { 1317 TRACE_SANITIZE (this); 1318 return_trace (Array32OfOffset32To<Paint>::sanitize (c, this)); 1319 } 1320 }; 1321 1322 struct COLR 1323 { 1324 static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR; 1325 has_dataOT::COLR1326 bool has_data () const { return numBaseGlyphs; } 1327 get_glyph_layersOT::COLR1328 unsigned int get_glyph_layers (hb_codepoint_t glyph, 1329 unsigned int start_offset, 1330 unsigned int *count, /* IN/OUT. May be NULL. */ 1331 hb_ot_color_layer_t *layers /* OUT. May be NULL. */) const 1332 { 1333 const BaseGlyphRecord &record = (this+baseGlyphsZ).bsearch (numBaseGlyphs, glyph); 1334 1335 hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers); 1336 hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx, 1337 record.numLayers); 1338 if (count) 1339 { 1340 + glyph_layers.sub_array (start_offset, count) 1341 | hb_sink (hb_array (layers, *count)) 1342 ; 1343 } 1344 return glyph_layers.length; 1345 } 1346 1347 struct accelerator_t 1348 { accelerator_tOT::COLR::accelerator_t1349 accelerator_t (hb_face_t *face) 1350 { colr = hb_sanitize_context_t ().reference_table<COLR> (face); } ~accelerator_tOT::COLR::accelerator_t1351 ~accelerator_t () { this->colr.destroy (); } 1352 is_validOT::COLR::accelerator_t1353 bool is_valid () { return colr.get_blob ()->length; } 1354 closure_glyphsOT::COLR::accelerator_t1355 void closure_glyphs (hb_codepoint_t glyph, 1356 hb_set_t *related_ids /* OUT */) const 1357 { colr->closure_glyphs (glyph, related_ids); } 1358 closure_V0palette_indicesOT::COLR::accelerator_t1359 void closure_V0palette_indices (const hb_set_t *glyphs, 1360 hb_set_t *palettes /* OUT */) const 1361 { colr->closure_V0palette_indices (glyphs, palettes); } 1362 closure_forV1OT::COLR::accelerator_t1363 void closure_forV1 (hb_set_t *glyphset, 1364 hb_set_t *layer_indices, 1365 hb_set_t *palette_indices) const 1366 { colr->closure_forV1 (glyphset, layer_indices, palette_indices); } 1367 1368 private: 1369 hb_blob_ptr_t<COLR> colr; 1370 }; 1371 closure_glyphsOT::COLR1372 void closure_glyphs (hb_codepoint_t glyph, 1373 hb_set_t *related_ids /* OUT */) const 1374 { 1375 const BaseGlyphRecord *record = get_base_glyph_record (glyph); 1376 if (!record) return; 1377 1378 auto glyph_layers = (this+layersZ).as_array (numLayers).sub_array (record->firstLayerIdx, 1379 record->numLayers); 1380 if (!glyph_layers.length) return; 1381 related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size); 1382 } 1383 closure_V0palette_indicesOT::COLR1384 void closure_V0palette_indices (const hb_set_t *glyphs, 1385 hb_set_t *palettes /* OUT */) const 1386 { 1387 if (!numBaseGlyphs || !numLayers) return; 1388 hb_array_t<const BaseGlyphRecord> baseGlyphs = (this+baseGlyphsZ).as_array (numBaseGlyphs); 1389 hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers); 1390 1391 for (const BaseGlyphRecord record : baseGlyphs) 1392 { 1393 if (!glyphs->has (record.glyphId)) continue; 1394 hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx, 1395 record.numLayers); 1396 for (const LayerRecord layer : glyph_layers) 1397 palettes->add (layer.colorIdx); 1398 } 1399 } 1400 closure_forV1OT::COLR1401 void closure_forV1 (hb_set_t *glyphset, 1402 hb_set_t *layer_indices, 1403 hb_set_t *palette_indices) const 1404 { 1405 if (version != 1) return; 1406 hb_set_t visited_glyphs; 1407 1408 hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices); 1409 const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList; 1410 1411 for (const BaseGlyphPaintRecord &baseglyph_paintrecord: baseglyph_paintrecords.iter ()) 1412 { 1413 unsigned gid = baseglyph_paintrecord.glyphId; 1414 if (!glyphset->has (gid)) continue; 1415 1416 const Paint &paint = &baseglyph_paintrecords+baseglyph_paintrecord.paint; 1417 paint.dispatch (&c); 1418 } 1419 hb_set_union (glyphset, &visited_glyphs); 1420 } 1421 get_layerListOT::COLR1422 const LayerList& get_layerList () const 1423 { return (this+layerList); } 1424 get_baseglyphListOT::COLR1425 const BaseGlyphList& get_baseglyphList () const 1426 { return (this+baseGlyphList); } 1427 sanitizeOT::COLR1428 bool sanitize (hb_sanitize_context_t *c) const 1429 { 1430 TRACE_SANITIZE (this); 1431 return_trace (c->check_struct (this) && 1432 (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) && 1433 (this+layersZ).sanitize (c, numLayers) && 1434 (version == 0 || 1435 (version == 1 && 1436 baseGlyphList.sanitize (c, this) && 1437 layerList.sanitize (c, this) && 1438 clipList.sanitize (c, this) && 1439 varIdxMap.sanitize (c, this) && 1440 varStore.sanitize (c, this)))); 1441 } 1442 1443 template<typename BaseIterator, typename LayerIterator, 1444 hb_requires (hb_is_iterator (BaseIterator)), 1445 hb_requires (hb_is_iterator (LayerIterator))> serialize_V0OT::COLR1446 bool serialize_V0 (hb_serialize_context_t *c, 1447 unsigned version, 1448 BaseIterator base_it, 1449 LayerIterator layer_it) 1450 { 1451 TRACE_SERIALIZE (this); 1452 if (unlikely (base_it.len () != layer_it.len ())) 1453 return_trace (false); 1454 1455 this->version = version; 1456 numLayers = 0; 1457 numBaseGlyphs = base_it.len (); 1458 if (numBaseGlyphs == 0) 1459 { 1460 baseGlyphsZ = 0; 1461 layersZ = 0; 1462 return_trace (true); 1463 } 1464 1465 c->push (); 1466 for (const hb_item_type<BaseIterator> _ : + base_it.iter ()) 1467 { 1468 auto* record = c->embed (_); 1469 if (unlikely (!record)) return_trace (false); 1470 record->firstLayerIdx = numLayers; 1471 numLayers += record->numLayers; 1472 } 1473 c->add_link (baseGlyphsZ, c->pop_pack ()); 1474 1475 c->push (); 1476 for (const hb_item_type<LayerIterator>& _ : + layer_it.iter ()) 1477 _.as_array ().copy (c); 1478 1479 c->add_link (layersZ, c->pop_pack ()); 1480 1481 return_trace (true); 1482 } 1483 get_base_glyph_recordOT::COLR1484 const BaseGlyphRecord* get_base_glyph_record (hb_codepoint_t gid) const 1485 { 1486 const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, (unsigned int) gid); 1487 if (record == &Null (BaseGlyphRecord) || 1488 (record && (hb_codepoint_t) record->glyphId != gid)) 1489 record = nullptr; 1490 return record; 1491 } 1492 get_base_glyph_paintrecordOT::COLR1493 const BaseGlyphPaintRecord* get_base_glyph_paintrecord (hb_codepoint_t gid) const 1494 { 1495 const BaseGlyphPaintRecord* record = &(this+baseGlyphList).bsearch ((unsigned) gid); 1496 if ((record && (hb_codepoint_t) record->glyphId != gid)) 1497 record = nullptr; 1498 return record; 1499 } 1500 subsetOT::COLR1501 bool subset (hb_subset_context_t *c) const 1502 { 1503 TRACE_SUBSET (this); 1504 1505 const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map; 1506 const hb_set_t& glyphset = *c->plan->_glyphset_colred; 1507 1508 auto base_it = 1509 + hb_range (c->plan->num_output_glyphs ()) 1510 | hb_filter ([&](hb_codepoint_t new_gid) 1511 { 1512 hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid); 1513 if (glyphset.has (old_gid)) return true; 1514 return false; 1515 }) 1516 | hb_map_retains_sorting ([&](hb_codepoint_t new_gid) 1517 { 1518 hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid); 1519 1520 const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid); 1521 if (unlikely (!old_record)) 1522 return hb_pair_t<bool, BaseGlyphRecord> (false, Null (BaseGlyphRecord)); 1523 BaseGlyphRecord new_record = {}; 1524 new_record.glyphId = new_gid; 1525 new_record.numLayers = old_record->numLayers; 1526 return hb_pair_t<bool, BaseGlyphRecord> (true, new_record); 1527 }) 1528 | hb_filter (hb_first) 1529 | hb_map_retains_sorting (hb_second) 1530 ; 1531 1532 auto layer_it = 1533 + hb_range (c->plan->num_output_glyphs ()) 1534 | hb_map (reverse_glyph_map) 1535 | hb_filter (glyphset) 1536 | hb_map_retains_sorting ([&](hb_codepoint_t old_gid) 1537 { 1538 const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid); 1539 hb_vector_t<LayerRecord> out_layers; 1540 1541 if (unlikely (!old_record || 1542 old_record->firstLayerIdx >= numLayers || 1543 old_record->firstLayerIdx + old_record->numLayers > numLayers)) 1544 return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers); 1545 1546 auto layers = (this+layersZ).as_array (numLayers).sub_array (old_record->firstLayerIdx, 1547 old_record->numLayers); 1548 out_layers.resize (layers.length); 1549 for (unsigned int i = 0; i < layers.length; i++) { 1550 out_layers[i] = layers[i]; 1551 hb_codepoint_t new_gid = 0; 1552 if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid))) 1553 return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers); 1554 out_layers[i].glyphId = new_gid; 1555 out_layers[i].colorIdx = c->plan->colr_palettes->get (layers[i].colorIdx); 1556 } 1557 1558 return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers); 1559 }) 1560 | hb_filter (hb_first) 1561 | hb_map_retains_sorting (hb_second) 1562 ; 1563 1564 if (version == 0 && (!base_it || !layer_it)) 1565 return_trace (false); 1566 1567 COLR *colr_prime = c->serializer->start_embed<COLR> (); 1568 if (unlikely (!c->serializer->extend_min (colr_prime))) return_trace (false); 1569 1570 if (version == 0) 1571 return_trace (colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)); 1572 1573 auto snap = c->serializer->snapshot (); 1574 if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false); 1575 if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this)) 1576 { 1577 if (c->serializer->in_error ()) return_trace (false); 1578 //no more COLRv1 glyphs: downgrade to version 0 1579 c->serializer->revert (snap); 1580 return_trace (colr_prime->serialize_V0 (c->serializer, 0, base_it, layer_it)); 1581 } 1582 1583 if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false); 1584 1585 colr_prime->layerList.serialize_subset (c, layerList, this); 1586 colr_prime->clipList.serialize_subset (c, clipList, this); 1587 colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this); 1588 //TODO: subset varStore once it's implemented in fonttools 1589 return_trace (true); 1590 } 1591 1592 bool get_extentsOT::COLR1593 get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const 1594 { 1595 if (version != 1) 1596 return false; 1597 1598 VarStoreInstancer instancer (this+varStore, 1599 this+varIdxMap, 1600 hb_array (font->coords, font->num_coords)); 1601 1602 if ((this+clipList).get_extents (glyph, 1603 extents, 1604 instancer)) 1605 { 1606 extents->x_bearing = font->em_scale_x (extents->x_bearing); 1607 extents->y_bearing = font->em_scale_x (extents->y_bearing); 1608 extents->width = font->em_scale_x (extents->width); 1609 extents->height = font->em_scale_x (extents->height); 1610 return true; 1611 } 1612 1613 return false; 1614 } 1615 1616 protected: 1617 HBUINT16 version; /* Table version number (starts at 0). */ 1618 HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records. */ 1619 NNOffset32To<SortedUnsizedArrayOf<BaseGlyphRecord>> 1620 baseGlyphsZ; /* Offset to Base Glyph records. */ 1621 NNOffset32To<UnsizedArrayOf<LayerRecord>> 1622 layersZ; /* Offset to Layer Records. */ 1623 HBUINT16 numLayers; /* Number of Layer Records. */ 1624 // Version-1 additions 1625 Offset32To<BaseGlyphList> baseGlyphList; 1626 Offset32To<LayerList> layerList; 1627 Offset32To<ClipList> clipList; // Offset to ClipList table (may be NULL) 1628 Offset32To<DeltaSetIndexMap> varIdxMap; // Offset to DeltaSetIndexMap table (may be NULL) 1629 Offset32To<VariationStore> varStore; 1630 public: 1631 DEFINE_SIZE_MIN (14); 1632 }; 1633 1634 struct COLR_accelerator_t : COLR::accelerator_t { COLR_accelerator_tOT::COLR_accelerator_t1635 COLR_accelerator_t (hb_face_t *face) : COLR::accelerator_t (face) {} 1636 }; 1637 1638 } /* namespace OT */ 1639 1640 1641 #endif /* HB_OT_COLOR_COLR_TABLE_HH */ 1642