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 100 43 #endif 44 45 #ifndef COLRV1_ENABLE_SUBSETTING 46 #define COLRV1_ENABLE_SUBSETTING 1 47 #endif 48 49 namespace OT { 50 51 struct COLR; 52 struct hb_colrv1_closure_context_t : 53 hb_dispatch_context_t<hb_colrv1_closure_context_t> 54 { 55 template <typename T> dispatchOT::hb_colrv1_closure_context_t56 return_t dispatch (const T &obj) 57 { 58 if (unlikely (nesting_level_left == 0)) 59 return hb_empty_t (); 60 61 if (paint_visited (&obj)) 62 return hb_empty_t (); 63 64 nesting_level_left--; 65 obj.closurev1 (this); 66 nesting_level_left++; 67 return hb_empty_t (); 68 } default_return_valueOT::hb_colrv1_closure_context_t69 static return_t default_return_value () { return hb_empty_t (); } 70 paint_visitedOT::hb_colrv1_closure_context_t71 bool paint_visited (const void *paint) 72 { 73 hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) paint - (uintptr_t) base); 74 if (visited_paint.in_error() || visited_paint.has (delta)) 75 return true; 76 77 visited_paint.add (delta); 78 return false; 79 } 80 get_colr_tableOT::hb_colrv1_closure_context_t81 const COLR* get_colr_table () const 82 { return reinterpret_cast<const COLR *> (base); } 83 add_glyphOT::hb_colrv1_closure_context_t84 void add_glyph (unsigned glyph_id) 85 { glyphs->add (glyph_id); } 86 add_layer_indicesOT::hb_colrv1_closure_context_t87 void add_layer_indices (unsigned first_layer_index, unsigned num_of_layers) 88 { layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1); } 89 add_palette_indexOT::hb_colrv1_closure_context_t90 void add_palette_index (unsigned palette_index) 91 { palette_indices->add (palette_index); } 92 93 public: 94 const void *base; 95 hb_set_t visited_paint; 96 hb_set_t *glyphs; 97 hb_set_t *layer_indices; 98 hb_set_t *palette_indices; 99 unsigned nesting_level_left; 100 hb_colrv1_closure_context_tOT::hb_colrv1_closure_context_t101 hb_colrv1_closure_context_t (const void *base_, 102 hb_set_t *glyphs_, 103 hb_set_t *layer_indices_, 104 hb_set_t *palette_indices_, 105 unsigned nesting_level_left_ = HB_COLRV1_MAX_NESTING_LEVEL) : 106 base (base_), 107 glyphs (glyphs_), 108 layer_indices (layer_indices_), 109 palette_indices (palette_indices_), 110 nesting_level_left (nesting_level_left_) 111 {} 112 }; 113 114 struct LayerRecord 115 { operator hb_ot_color_layer_tOT::LayerRecord116 operator hb_ot_color_layer_t () const { return {glyphId, colorIdx}; } 117 sanitizeOT::LayerRecord118 bool sanitize (hb_sanitize_context_t *c) const 119 { 120 TRACE_SANITIZE (this); 121 return_trace (c->check_struct (this)); 122 } 123 124 public: 125 HBGlyphID16 glyphId; /* Glyph ID of layer glyph */ 126 Index colorIdx; /* Index value to use with a 127 * selected color palette. 128 * An index value of 0xFFFF 129 * is a special case indicating 130 * that the text foreground 131 * color (defined by a 132 * higher-level client) should 133 * be used and shall not be 134 * treated as actual index 135 * into CPAL ColorRecord array. */ 136 public: 137 DEFINE_SIZE_STATIC (4); 138 }; 139 140 struct BaseGlyphRecord 141 { cmpOT::BaseGlyphRecord142 int cmp (hb_codepoint_t g) const 143 { return g < glyphId ? -1 : g > glyphId ? 1 : 0; } 144 sanitizeOT::BaseGlyphRecord145 bool sanitize (hb_sanitize_context_t *c) const 146 { 147 TRACE_SANITIZE (this); 148 return_trace (likely (c->check_struct (this))); 149 } 150 151 public: 152 HBGlyphID16 glyphId; /* Glyph ID of reference glyph */ 153 HBUINT16 firstLayerIdx; /* Index (from beginning of 154 * the Layer Records) to the 155 * layer record. There will be 156 * numLayers consecutive entries 157 * for this base glyph. */ 158 HBUINT16 numLayers; /* Number of color layers 159 * associated with this glyph */ 160 public: 161 DEFINE_SIZE_STATIC (6); 162 }; 163 164 template <typename T> 165 struct Variable 166 { copyOT::Variable167 Variable<T>* copy (hb_serialize_context_t *c) const 168 { 169 TRACE_SERIALIZE (this); 170 return_trace (c->embed (this)); 171 } 172 closurev1OT::Variable173 void closurev1 (hb_colrv1_closure_context_t* c) const 174 { value.closurev1 (c); } 175 subsetOT::Variable176 bool subset (hb_subset_context_t *c) const 177 { 178 TRACE_SUBSET (this); 179 if (!value.subset (c)) return_trace (false); 180 return_trace (c->serializer->embed (varIdxBase)); 181 } 182 sanitizeOT::Variable183 bool sanitize (hb_sanitize_context_t *c) const 184 { 185 TRACE_SANITIZE (this); 186 return_trace (c->check_struct (this) && value.sanitize (c)); 187 } 188 189 protected: 190 T value; 191 VarIdx varIdxBase; 192 public: 193 DEFINE_SIZE_STATIC (4 + T::static_size); 194 }; 195 196 template <typename T> 197 struct NoVariable 198 { copyOT::NoVariable199 NoVariable<T>* copy (hb_serialize_context_t *c) const 200 { 201 TRACE_SERIALIZE (this); 202 return_trace (c->embed (this)); 203 } 204 closurev1OT::NoVariable205 void closurev1 (hb_colrv1_closure_context_t* c) const 206 { value.closurev1 (c); } 207 subsetOT::NoVariable208 bool subset (hb_subset_context_t *c) const 209 { 210 TRACE_SUBSET (this); 211 return_trace (value.subset (c)); 212 } 213 sanitizeOT::NoVariable214 bool sanitize (hb_sanitize_context_t *c) const 215 { 216 TRACE_SANITIZE (this); 217 return_trace (c->check_struct (this) && value.sanitize (c)); 218 } 219 220 T value; 221 public: 222 DEFINE_SIZE_STATIC (T::static_size); 223 }; 224 225 // Color structures 226 227 struct ColorStop 228 { closurev1OT::ColorStop229 void closurev1 (hb_colrv1_closure_context_t* c) const 230 { c->add_palette_index (paletteIndex); } 231 subsetOT::ColorStop232 bool subset (hb_subset_context_t *c) const 233 { 234 TRACE_SUBSET (this); 235 auto *out = c->serializer->embed (*this); 236 if (unlikely (!out)) return_trace (false); 237 return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex), 238 HB_SERIALIZE_ERROR_INT_OVERFLOW)); 239 } 240 sanitizeOT::ColorStop241 bool sanitize (hb_sanitize_context_t *c) const 242 { 243 TRACE_SANITIZE (this); 244 return_trace (c->check_struct (this)); 245 } 246 247 F2DOT14 stopOffset; 248 HBUINT16 paletteIndex; 249 F2DOT14 alpha; 250 public: 251 DEFINE_SIZE_STATIC (2 + 2 * F2DOT14::static_size); 252 }; 253 254 struct Extend : HBUINT8 255 { 256 enum { 257 EXTEND_PAD = 0, 258 EXTEND_REPEAT = 1, 259 EXTEND_REFLECT = 2, 260 }; 261 public: 262 DEFINE_SIZE_STATIC (1); 263 }; 264 265 template <template<typename> class Var> 266 struct ColorLine 267 { closurev1OT::ColorLine268 void closurev1 (hb_colrv1_closure_context_t* c) const 269 { 270 for (const auto &stop : stops.iter ()) 271 stop.closurev1 (c); 272 } 273 subsetOT::ColorLine274 bool subset (hb_subset_context_t *c) const 275 { 276 TRACE_SUBSET (this); 277 auto *out = c->serializer->start_embed (this); 278 if (unlikely (!out)) return_trace (false); 279 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 280 281 if (!c->serializer->check_assign (out->extend, extend, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); 282 if (!c->serializer->check_assign (out->stops.len, stops.len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)) return_trace (false); 283 284 for (const auto& stop : stops.iter ()) 285 { 286 if (!stop.subset (c)) return_trace (false); 287 } 288 return_trace (true); 289 } 290 sanitizeOT::ColorLine291 bool sanitize (hb_sanitize_context_t *c) const 292 { 293 TRACE_SANITIZE (this); 294 return_trace (c->check_struct (this) && 295 stops.sanitize (c)); 296 } 297 298 Extend extend; 299 Array16Of<Var<ColorStop>> stops; 300 public: 301 DEFINE_SIZE_ARRAY_SIZED (3, stops); 302 }; 303 304 // Composition modes 305 306 // Compositing modes are taken from https://www.w3.org/TR/compositing-1/ 307 // NOTE: a brief audit of major implementations suggests most support most 308 // or all of the specified modes. 309 struct CompositeMode : HBUINT8 310 { 311 enum { 312 // Porter-Duff modes 313 // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators 314 COMPOSITE_CLEAR = 0, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_clear 315 COMPOSITE_SRC = 1, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_src 316 COMPOSITE_DEST = 2, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dst 317 COMPOSITE_SRC_OVER = 3, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcover 318 COMPOSITE_DEST_OVER = 4, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstover 319 COMPOSITE_SRC_IN = 5, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcin 320 COMPOSITE_DEST_IN = 6, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstin 321 COMPOSITE_SRC_OUT = 7, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcout 322 COMPOSITE_DEST_OUT = 8, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstout 323 COMPOSITE_SRC_ATOP = 9, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcatop 324 COMPOSITE_DEST_ATOP = 10, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstatop 325 COMPOSITE_XOR = 11, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_xor 326 COMPOSITE_PLUS = 12, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_plus 327 328 // Blend modes 329 // https://www.w3.org/TR/compositing-1/#blending 330 COMPOSITE_SCREEN = 13, // https://www.w3.org/TR/compositing-1/#blendingscreen 331 COMPOSITE_OVERLAY = 14, // https://www.w3.org/TR/compositing-1/#blendingoverlay 332 COMPOSITE_DARKEN = 15, // https://www.w3.org/TR/compositing-1/#blendingdarken 333 COMPOSITE_LIGHTEN = 16, // https://www.w3.org/TR/compositing-1/#blendinglighten 334 COMPOSITE_COLOR_DODGE = 17, // https://www.w3.org/TR/compositing-1/#blendingcolordodge 335 COMPOSITE_COLOR_BURN = 18, // https://www.w3.org/TR/compositing-1/#blendingcolorburn 336 COMPOSITE_HARD_LIGHT = 19, // https://www.w3.org/TR/compositing-1/#blendinghardlight 337 COMPOSITE_SOFT_LIGHT = 20, // https://www.w3.org/TR/compositing-1/#blendingsoftlight 338 COMPOSITE_DIFFERENCE = 21, // https://www.w3.org/TR/compositing-1/#blendingdifference 339 COMPOSITE_EXCLUSION = 22, // https://www.w3.org/TR/compositing-1/#blendingexclusion 340 COMPOSITE_MULTIPLY = 23, // https://www.w3.org/TR/compositing-1/#blendingmultiply 341 342 // Modes that, uniquely, do not operate on components 343 // https://www.w3.org/TR/compositing-1/#blendingnonseparable 344 COMPOSITE_HSL_HUE = 24, // https://www.w3.org/TR/compositing-1/#blendinghue 345 COMPOSITE_HSL_SATURATION = 25, // https://www.w3.org/TR/compositing-1/#blendingsaturation 346 COMPOSITE_HSL_COLOR = 26, // https://www.w3.org/TR/compositing-1/#blendingcolor 347 COMPOSITE_HSL_LUMINOSITY = 27, // https://www.w3.org/TR/compositing-1/#blendingluminosity 348 }; 349 public: 350 DEFINE_SIZE_STATIC (1); 351 }; 352 353 struct Affine2x3 354 { sanitizeOT::Affine2x3355 bool sanitize (hb_sanitize_context_t *c) const 356 { 357 TRACE_SANITIZE (this); 358 return_trace (c->check_struct (this)); 359 } 360 361 HBFixed xx; 362 HBFixed yx; 363 HBFixed xy; 364 HBFixed yy; 365 HBFixed dx; 366 HBFixed dy; 367 public: 368 DEFINE_SIZE_STATIC (6 * HBFixed::static_size); 369 }; 370 371 struct PaintColrLayers 372 { 373 void closurev1 (hb_colrv1_closure_context_t* c) const; 374 subsetOT::PaintColrLayers375 bool subset (hb_subset_context_t *c) const 376 { 377 TRACE_SUBSET (this); 378 auto *out = c->serializer->embed (this); 379 if (unlikely (!out)) return_trace (false); 380 return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers->get (firstLayerIndex), 381 HB_SERIALIZE_ERROR_INT_OVERFLOW)); 382 383 return_trace (true); 384 } 385 sanitizeOT::PaintColrLayers386 bool sanitize (hb_sanitize_context_t *c) const 387 { 388 TRACE_SANITIZE (this); 389 return_trace (c->check_struct (this)); 390 } 391 392 HBUINT8 format; /* format = 1 */ 393 HBUINT8 numLayers; 394 HBUINT32 firstLayerIndex; /* index into COLRv1::layerList */ 395 public: 396 DEFINE_SIZE_STATIC (6); 397 }; 398 399 struct PaintSolid 400 { closurev1OT::PaintSolid401 void closurev1 (hb_colrv1_closure_context_t* c) const 402 { c->add_palette_index (paletteIndex); } 403 subsetOT::PaintSolid404 bool subset (hb_subset_context_t *c) const 405 { 406 TRACE_SUBSET (this); 407 auto *out = c->serializer->embed (*this); 408 if (unlikely (!out)) return_trace (false); 409 return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex), 410 HB_SERIALIZE_ERROR_INT_OVERFLOW)); 411 } 412 sanitizeOT::PaintSolid413 bool sanitize (hb_sanitize_context_t *c) const 414 { 415 TRACE_SANITIZE (this); 416 return_trace (c->check_struct (this)); 417 } 418 419 HBUINT8 format; /* format = 2(noVar) or 3(Var)*/ 420 HBUINT16 paletteIndex; 421 F2DOT14 alpha; 422 public: 423 DEFINE_SIZE_STATIC (3 + F2DOT14::static_size); 424 }; 425 426 template <template<typename> class Var> 427 struct PaintLinearGradient 428 { closurev1OT::PaintLinearGradient429 void closurev1 (hb_colrv1_closure_context_t* c) const 430 { (this+colorLine).closurev1 (c); } 431 subsetOT::PaintLinearGradient432 bool subset (hb_subset_context_t *c) const 433 { 434 TRACE_SUBSET (this); 435 auto *out = c->serializer->embed (this); 436 if (unlikely (!out)) return_trace (false); 437 438 return_trace (out->colorLine.serialize_subset (c, colorLine, this)); 439 } 440 sanitizeOT::PaintLinearGradient441 bool sanitize (hb_sanitize_context_t *c) const 442 { 443 TRACE_SANITIZE (this); 444 return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); 445 } 446 447 HBUINT8 format; /* format = 4(noVar) or 5 (Var) */ 448 Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintLinearGradient 449 * table) to ColorLine subtable. */ 450 FWORD x0; 451 FWORD y0; 452 FWORD x1; 453 FWORD y1; 454 FWORD x2; 455 FWORD y2; 456 public: 457 DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size); 458 }; 459 460 template <template<typename> class Var> 461 struct PaintRadialGradient 462 { closurev1OT::PaintRadialGradient463 void closurev1 (hb_colrv1_closure_context_t* c) const 464 { (this+colorLine).closurev1 (c); } 465 subsetOT::PaintRadialGradient466 bool subset (hb_subset_context_t *c) const 467 { 468 TRACE_SUBSET (this); 469 auto *out = c->serializer->embed (this); 470 if (unlikely (!out)) return_trace (false); 471 472 return_trace (out->colorLine.serialize_subset (c, colorLine, this)); 473 } 474 sanitizeOT::PaintRadialGradient475 bool sanitize (hb_sanitize_context_t *c) const 476 { 477 TRACE_SANITIZE (this); 478 return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); 479 } 480 481 HBUINT8 format; /* format = 6(noVar) or 7 (Var) */ 482 Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintRadialGradient 483 * table) to ColorLine subtable. */ 484 FWORD x0; 485 FWORD y0; 486 UFWORD radius0; 487 FWORD x1; 488 FWORD y1; 489 UFWORD radius1; 490 public: 491 DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size); 492 }; 493 494 template <template<typename> class Var> 495 struct PaintSweepGradient 496 { closurev1OT::PaintSweepGradient497 void closurev1 (hb_colrv1_closure_context_t* c) const 498 { (this+colorLine).closurev1 (c); } 499 subsetOT::PaintSweepGradient500 bool subset (hb_subset_context_t *c) const 501 { 502 TRACE_SUBSET (this); 503 auto *out = c->serializer->embed (this); 504 if (unlikely (!out)) return_trace (false); 505 506 return_trace (out->colorLine.serialize_subset (c, colorLine, this)); 507 } 508 sanitizeOT::PaintSweepGradient509 bool sanitize (hb_sanitize_context_t *c) const 510 { 511 TRACE_SANITIZE (this); 512 return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); 513 } 514 515 HBUINT8 format; /* format = 8(noVar) or 9 (Var) */ 516 Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintSweepGradient 517 * table) to ColorLine subtable. */ 518 FWORD centerX; 519 FWORD centerY; 520 F2DOT14 startAngle; 521 F2DOT14 endAngle; 522 public: 523 DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size + 2 * F2DOT14::static_size); 524 }; 525 526 struct Paint; 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 ClipBoxFormat1 891 { sanitizeOT::ClipBoxFormat1892 bool sanitize (hb_sanitize_context_t *c) const 893 { 894 TRACE_SANITIZE (this); 895 return_trace (c->check_struct (this)); 896 } 897 898 public: 899 HBUINT8 format; /* format = 1(noVar) or 2(Var)*/ 900 FWORD xMin; 901 FWORD yMin; 902 FWORD xMax; 903 FWORD yMax; 904 public: 905 DEFINE_SIZE_STATIC (1 + 4 * FWORD::static_size); 906 }; 907 908 struct ClipBoxFormat2 : Variable<ClipBoxFormat1> {}; 909 910 struct ClipBox 911 { copyOT::ClipBox912 ClipBox* copy (hb_serialize_context_t *c) const 913 { 914 TRACE_SERIALIZE (this); 915 switch (u.format) { 916 case 1: return_trace (reinterpret_cast<ClipBox *> (c->embed (u.format1))); 917 case 2: return_trace (reinterpret_cast<ClipBox *> (c->embed (u.format2))); 918 default:return_trace (nullptr); 919 } 920 } 921 922 template <typename context_t, typename ...Ts> dispatchOT::ClipBox923 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const 924 { 925 TRACE_DISPATCH (this, u.format); 926 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 927 switch (u.format) { 928 case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...)); 929 case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...)); 930 default:return_trace (c->default_return_value ()); 931 } 932 } 933 934 protected: 935 union { 936 HBUINT8 format; /* Format identifier */ 937 ClipBoxFormat1 format1; 938 ClipBoxFormat2 format2; 939 } u; 940 }; 941 942 struct ClipRecord 943 { copyOT::ClipRecord944 ClipRecord* copy (hb_serialize_context_t *c, const void *base) const 945 { 946 TRACE_SERIALIZE (this); 947 auto *out = c->embed (this); 948 if (unlikely (!out)) return_trace (nullptr); 949 if (!out->clipBox.serialize_copy (c, clipBox, base)) return_trace (nullptr); 950 return_trace (out); 951 } 952 sanitizeOT::ClipRecord953 bool sanitize (hb_sanitize_context_t *c, const void *base) const 954 { 955 TRACE_SANITIZE (this); 956 return_trace (c->check_struct (this) && clipBox.sanitize (c, base)); 957 } 958 959 public: 960 HBUINT16 startGlyphID; // first gid clip applies to 961 HBUINT16 endGlyphID; // last gid clip applies to, inclusive 962 Offset24To<ClipBox> clipBox; // Box or VarBox 963 public: 964 DEFINE_SIZE_STATIC (7); 965 }; 966 967 struct ClipList 968 { serialize_clip_recordsOT::ClipList969 unsigned serialize_clip_records (hb_serialize_context_t *c, 970 const hb_set_t& gids, 971 const hb_map_t& gid_offset_map) const 972 { 973 TRACE_SERIALIZE (this); 974 if (gids.is_empty () || 975 gid_offset_map.get_population () != gids.get_population ()) 976 return_trace (0); 977 978 unsigned count = 0; 979 980 hb_codepoint_t start_gid= gids.get_min (); 981 hb_codepoint_t prev_gid = start_gid; 982 983 unsigned offset = gid_offset_map.get (start_gid); 984 unsigned prev_offset = offset; 985 for (const hb_codepoint_t _ : gids.iter ()) 986 { 987 if (_ == start_gid) continue; 988 989 offset = gid_offset_map.get (_); 990 if (_ == prev_gid + 1 && offset == prev_offset) 991 { 992 prev_gid = _; 993 continue; 994 } 995 996 ClipRecord record; 997 record.startGlyphID = start_gid; 998 record.endGlyphID = prev_gid; 999 record.clipBox = prev_offset; 1000 1001 if (!c->copy (record, this)) return_trace (0); 1002 count++; 1003 1004 start_gid = _; 1005 prev_gid = _; 1006 prev_offset = offset; 1007 } 1008 1009 //last one 1010 { 1011 ClipRecord record; 1012 record.startGlyphID = start_gid; 1013 record.endGlyphID = prev_gid; 1014 record.clipBox = prev_offset; 1015 if (!c->copy (record, this)) return_trace (0); 1016 count++; 1017 } 1018 return_trace (count); 1019 } 1020 subsetOT::ClipList1021 bool subset (hb_subset_context_t *c) const 1022 { 1023 TRACE_SUBSET (this); 1024 auto *out = c->serializer->start_embed (*this); 1025 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 1026 if (!c->serializer->check_assign (out->format, format, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); 1027 1028 const hb_set_t& glyphset = *c->plan->_glyphset_colred; 1029 const hb_map_t &glyph_map = *c->plan->glyph_map; 1030 1031 hb_map_t new_gid_offset_map; 1032 hb_set_t new_gids; 1033 for (const ClipRecord& record : clips.iter ()) 1034 { 1035 unsigned start_gid = record.startGlyphID; 1036 unsigned end_gid = record.endGlyphID; 1037 for (unsigned gid = start_gid; gid <= end_gid; gid++) 1038 { 1039 if (!glyphset.has (gid) || !glyph_map.has (gid)) continue; 1040 unsigned new_gid = glyph_map.get (gid); 1041 new_gid_offset_map.set (new_gid, record.clipBox); 1042 new_gids.add (new_gid); 1043 } 1044 } 1045 1046 unsigned count = serialize_clip_records (c->serializer, new_gids, new_gid_offset_map); 1047 if (!count) return_trace (false); 1048 return_trace (c->serializer->check_assign (out->clips.len, count, HB_SERIALIZE_ERROR_INT_OVERFLOW)); 1049 } 1050 sanitizeOT::ClipList1051 bool sanitize (hb_sanitize_context_t *c) const 1052 { 1053 TRACE_SANITIZE (this); 1054 return_trace (c->check_struct (this) && clips.sanitize (c, this)); 1055 } 1056 1057 HBUINT8 format; // Set to 1. 1058 Array32Of<ClipRecord> clips; // Clip records, sorted by startGlyphID 1059 public: 1060 DEFINE_SIZE_ARRAY_SIZED (5, clips); 1061 }; 1062 1063 struct Paint 1064 { 1065 1066 template <typename ...Ts> sanitizeOT::Paint1067 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const 1068 { 1069 TRACE_SANITIZE (this); 1070 1071 if (unlikely (!c->check_start_recursion (HB_COLRV1_MAX_NESTING_LEVEL))) 1072 return_trace (c->no_dispatch_return_value ()); 1073 1074 return_trace (c->end_recursion (this->dispatch (c, std::forward<Ts> (ds)...))); 1075 } 1076 1077 template <typename context_t, typename ...Ts> dispatchOT::Paint1078 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const 1079 { 1080 TRACE_DISPATCH (this, u.format); 1081 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 1082 switch (u.format) { 1083 case 1: return_trace (c->dispatch (u.paintformat1, std::forward<Ts> (ds)...)); 1084 case 2: return_trace (c->dispatch (u.paintformat2, std::forward<Ts> (ds)...)); 1085 case 3: return_trace (c->dispatch (u.paintformat3, std::forward<Ts> (ds)...)); 1086 case 4: return_trace (c->dispatch (u.paintformat4, std::forward<Ts> (ds)...)); 1087 case 5: return_trace (c->dispatch (u.paintformat5, std::forward<Ts> (ds)...)); 1088 case 6: return_trace (c->dispatch (u.paintformat6, std::forward<Ts> (ds)...)); 1089 case 7: return_trace (c->dispatch (u.paintformat7, std::forward<Ts> (ds)...)); 1090 case 8: return_trace (c->dispatch (u.paintformat8, std::forward<Ts> (ds)...)); 1091 case 9: return_trace (c->dispatch (u.paintformat9, std::forward<Ts> (ds)...)); 1092 case 10: return_trace (c->dispatch (u.paintformat10, std::forward<Ts> (ds)...)); 1093 case 11: return_trace (c->dispatch (u.paintformat11, std::forward<Ts> (ds)...)); 1094 case 12: return_trace (c->dispatch (u.paintformat12, std::forward<Ts> (ds)...)); 1095 case 13: return_trace (c->dispatch (u.paintformat13, std::forward<Ts> (ds)...)); 1096 case 14: return_trace (c->dispatch (u.paintformat14, std::forward<Ts> (ds)...)); 1097 case 15: return_trace (c->dispatch (u.paintformat15, std::forward<Ts> (ds)...)); 1098 case 16: return_trace (c->dispatch (u.paintformat16, std::forward<Ts> (ds)...)); 1099 case 17: return_trace (c->dispatch (u.paintformat17, std::forward<Ts> (ds)...)); 1100 case 18: return_trace (c->dispatch (u.paintformat18, std::forward<Ts> (ds)...)); 1101 case 19: return_trace (c->dispatch (u.paintformat19, std::forward<Ts> (ds)...)); 1102 case 20: return_trace (c->dispatch (u.paintformat20, std::forward<Ts> (ds)...)); 1103 case 21: return_trace (c->dispatch (u.paintformat21, std::forward<Ts> (ds)...)); 1104 case 22: return_trace (c->dispatch (u.paintformat22, std::forward<Ts> (ds)...)); 1105 case 23: return_trace (c->dispatch (u.paintformat23, std::forward<Ts> (ds)...)); 1106 case 24: return_trace (c->dispatch (u.paintformat24, std::forward<Ts> (ds)...)); 1107 case 25: return_trace (c->dispatch (u.paintformat25, std::forward<Ts> (ds)...)); 1108 case 26: return_trace (c->dispatch (u.paintformat26, std::forward<Ts> (ds)...)); 1109 case 27: return_trace (c->dispatch (u.paintformat27, std::forward<Ts> (ds)...)); 1110 case 28: return_trace (c->dispatch (u.paintformat28, std::forward<Ts> (ds)...)); 1111 case 29: return_trace (c->dispatch (u.paintformat29, std::forward<Ts> (ds)...)); 1112 case 30: return_trace (c->dispatch (u.paintformat30, std::forward<Ts> (ds)...)); 1113 case 31: return_trace (c->dispatch (u.paintformat31, std::forward<Ts> (ds)...)); 1114 case 32: return_trace (c->dispatch (u.paintformat32, std::forward<Ts> (ds)...)); 1115 default:return_trace (c->default_return_value ()); 1116 } 1117 } 1118 1119 protected: 1120 union { 1121 HBUINT8 format; 1122 PaintColrLayers paintformat1; 1123 PaintSolid paintformat2; 1124 Variable<PaintSolid> paintformat3; 1125 PaintLinearGradient<NoVariable> paintformat4; 1126 Variable<PaintLinearGradient<Variable>> paintformat5; 1127 PaintRadialGradient<NoVariable> paintformat6; 1128 Variable<PaintRadialGradient<Variable>> paintformat7; 1129 PaintSweepGradient<NoVariable> paintformat8; 1130 Variable<PaintSweepGradient<Variable>> paintformat9; 1131 PaintGlyph paintformat10; 1132 PaintColrGlyph paintformat11; 1133 PaintTransform<NoVariable> paintformat12; 1134 PaintTransform<Variable> paintformat13; 1135 PaintTranslate paintformat14; 1136 Variable<PaintTranslate> paintformat15; 1137 PaintScale paintformat16; 1138 Variable<PaintScale> paintformat17; 1139 PaintScaleAroundCenter paintformat18; 1140 Variable<PaintScaleAroundCenter> paintformat19; 1141 PaintScaleUniform paintformat20; 1142 Variable<PaintScaleUniform> paintformat21; 1143 PaintScaleUniformAroundCenter paintformat22; 1144 Variable<PaintScaleUniformAroundCenter> paintformat23; 1145 PaintRotate paintformat24; 1146 Variable<PaintRotate> paintformat25; 1147 PaintRotateAroundCenter paintformat26; 1148 Variable<PaintRotateAroundCenter> paintformat27; 1149 PaintSkew paintformat28; 1150 Variable<PaintSkew> paintformat29; 1151 PaintSkewAroundCenter paintformat30; 1152 Variable<PaintSkewAroundCenter> paintformat31; 1153 PaintComposite paintformat32; 1154 } u; 1155 }; 1156 1157 struct BaseGlyphPaintRecord 1158 { cmpOT::BaseGlyphPaintRecord1159 int cmp (hb_codepoint_t g) const 1160 { return g < glyphId ? -1 : g > glyphId ? 1 : 0; } 1161 serializeOT::BaseGlyphPaintRecord1162 bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map, 1163 const void* src_base, hb_subset_context_t *c) const 1164 { 1165 TRACE_SERIALIZE (this); 1166 auto *out = s->embed (this); 1167 if (unlikely (!out)) return_trace (false); 1168 if (!s->check_assign (out->glyphId, glyph_map->get (glyphId), 1169 HB_SERIALIZE_ERROR_INT_OVERFLOW)) 1170 return_trace (false); 1171 1172 return_trace (out->paint.serialize_subset (c, paint, src_base)); 1173 } 1174 sanitizeOT::BaseGlyphPaintRecord1175 bool sanitize (hb_sanitize_context_t *c, const void *base) const 1176 { 1177 TRACE_SANITIZE (this); 1178 return_trace (likely (c->check_struct (this) && paint.sanitize (c, base))); 1179 } 1180 1181 public: 1182 HBGlyphID16 glyphId; /* Glyph ID of reference glyph */ 1183 Offset32To<Paint> paint; /* Offset (from beginning of BaseGlyphPaintRecord array) to Paint, 1184 * Typically PaintColrLayers */ 1185 public: 1186 DEFINE_SIZE_STATIC (6); 1187 }; 1188 1189 struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord> 1190 { subsetOT::BaseGlyphList1191 bool subset (hb_subset_context_t *c) const 1192 { 1193 TRACE_SUBSET (this); 1194 auto *out = c->serializer->start_embed (this); 1195 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 1196 const hb_set_t* glyphset = c->plan->_glyphset_colred; 1197 1198 for (const auto& _ : as_array ()) 1199 { 1200 unsigned gid = _.glyphId; 1201 if (!glyphset->has (gid)) continue; 1202 1203 if (_.serialize (c->serializer, c->plan->glyph_map, this, c)) out->len++; 1204 else return_trace (false); 1205 } 1206 1207 return_trace (out->len != 0); 1208 } 1209 sanitizeOT::BaseGlyphList1210 bool sanitize (hb_sanitize_context_t *c) const 1211 { 1212 TRACE_SANITIZE (this); 1213 return_trace (SortedArray32Of<BaseGlyphPaintRecord>::sanitize (c, this)); 1214 } 1215 }; 1216 1217 struct LayerList : Array32OfOffset32To<Paint> 1218 { get_paintOT::LayerList1219 const Paint& get_paint (unsigned i) const 1220 { return this+(*this)[i]; } 1221 subsetOT::LayerList1222 bool subset (hb_subset_context_t *c) const 1223 { 1224 TRACE_SUBSET (this); 1225 auto *out = c->serializer->start_embed (this); 1226 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 1227 1228 for (const auto& _ : + hb_enumerate (*this) 1229 | hb_filter (c->plan->colrv1_layers, hb_first)) 1230 1231 { 1232 auto *o = out->serialize_append (c->serializer); 1233 if (unlikely (!o) || !o->serialize_subset (c, _.second, this)) 1234 return_trace (false); 1235 } 1236 return_trace (true); 1237 } 1238 sanitizeOT::LayerList1239 bool sanitize (hb_sanitize_context_t *c) const 1240 { 1241 TRACE_SANITIZE (this); 1242 return_trace (Array32OfOffset32To<Paint>::sanitize (c, this)); 1243 } 1244 }; 1245 1246 struct COLR 1247 { 1248 static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR; 1249 has_dataOT::COLR1250 bool has_data () const { return numBaseGlyphs; } 1251 get_glyph_layersOT::COLR1252 unsigned int get_glyph_layers (hb_codepoint_t glyph, 1253 unsigned int start_offset, 1254 unsigned int *count, /* IN/OUT. May be NULL. */ 1255 hb_ot_color_layer_t *layers /* OUT. May be NULL. */) const 1256 { 1257 const BaseGlyphRecord &record = (this+baseGlyphsZ).bsearch (numBaseGlyphs, glyph); 1258 1259 hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers); 1260 hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx, 1261 record.numLayers); 1262 if (count) 1263 { 1264 + glyph_layers.sub_array (start_offset, count) 1265 | hb_sink (hb_array (layers, *count)) 1266 ; 1267 } 1268 return glyph_layers.length; 1269 } 1270 1271 struct accelerator_t 1272 { accelerator_tOT::COLR::accelerator_t1273 accelerator_t (hb_face_t *face) 1274 { colr = hb_sanitize_context_t ().reference_table<COLR> (face); } ~accelerator_tOT::COLR::accelerator_t1275 ~accelerator_t () { this->colr.destroy (); } 1276 is_validOT::COLR::accelerator_t1277 bool is_valid () { return colr.get_blob ()->length; } 1278 closure_glyphsOT::COLR::accelerator_t1279 void closure_glyphs (hb_codepoint_t glyph, 1280 hb_set_t *related_ids /* OUT */) const 1281 { colr->closure_glyphs (glyph, related_ids); } 1282 closure_V0palette_indicesOT::COLR::accelerator_t1283 void closure_V0palette_indices (const hb_set_t *glyphs, 1284 hb_set_t *palettes /* OUT */) const 1285 { colr->closure_V0palette_indices (glyphs, palettes); } 1286 closure_forV1OT::COLR::accelerator_t1287 void closure_forV1 (hb_set_t *glyphset, 1288 hb_set_t *layer_indices, 1289 hb_set_t *palette_indices) const 1290 { colr->closure_forV1 (glyphset, layer_indices, palette_indices); } 1291 1292 private: 1293 hb_blob_ptr_t<COLR> colr; 1294 }; 1295 closure_glyphsOT::COLR1296 void closure_glyphs (hb_codepoint_t glyph, 1297 hb_set_t *related_ids /* OUT */) const 1298 { 1299 const BaseGlyphRecord *record = get_base_glyph_record (glyph); 1300 if (!record) return; 1301 1302 auto glyph_layers = (this+layersZ).as_array (numLayers).sub_array (record->firstLayerIdx, 1303 record->numLayers); 1304 if (!glyph_layers.length) return; 1305 related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size); 1306 } 1307 closure_V0palette_indicesOT::COLR1308 void closure_V0palette_indices (const hb_set_t *glyphs, 1309 hb_set_t *palettes /* OUT */) const 1310 { 1311 if (!numBaseGlyphs || !numLayers) return; 1312 hb_array_t<const BaseGlyphRecord> baseGlyphs = (this+baseGlyphsZ).as_array (numBaseGlyphs); 1313 hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers); 1314 1315 for (const BaseGlyphRecord record : baseGlyphs) 1316 { 1317 if (!glyphs->has (record.glyphId)) continue; 1318 hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx, 1319 record.numLayers); 1320 for (const LayerRecord layer : glyph_layers) 1321 palettes->add (layer.colorIdx); 1322 } 1323 } 1324 closure_forV1OT::COLR1325 void closure_forV1 (hb_set_t *glyphset, 1326 hb_set_t *layer_indices, 1327 hb_set_t *palette_indices) const 1328 { 1329 if (version != 1) return; 1330 hb_set_t visited_glyphs; 1331 1332 hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices); 1333 const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList; 1334 1335 for (const BaseGlyphPaintRecord &baseglyph_paintrecord: baseglyph_paintrecords.iter ()) 1336 { 1337 unsigned gid = baseglyph_paintrecord.glyphId; 1338 if (!glyphset->has (gid)) continue; 1339 1340 const Paint &paint = &baseglyph_paintrecords+baseglyph_paintrecord.paint; 1341 paint.dispatch (&c); 1342 } 1343 hb_set_union (glyphset, &visited_glyphs); 1344 } 1345 get_layerListOT::COLR1346 const LayerList& get_layerList () const 1347 { return (this+layerList); } 1348 get_baseglyphListOT::COLR1349 const BaseGlyphList& get_baseglyphList () const 1350 { return (this+baseGlyphList); } 1351 sanitizeOT::COLR1352 bool sanitize (hb_sanitize_context_t *c) const 1353 { 1354 TRACE_SANITIZE (this); 1355 return_trace (c->check_struct (this) && 1356 (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) && 1357 (this+layersZ).sanitize (c, numLayers) && 1358 (version == 0 || 1359 (COLRV1_ENABLE_SUBSETTING && version == 1 && 1360 baseGlyphList.sanitize (c, this) && 1361 layerList.sanitize (c, this) && 1362 clipList.sanitize (c, this) && 1363 varIdxMap.sanitize (c, this) && 1364 varStore.sanitize (c, this)))); 1365 } 1366 1367 template<typename BaseIterator, typename LayerIterator, 1368 hb_requires (hb_is_iterator (BaseIterator)), 1369 hb_requires (hb_is_iterator (LayerIterator))> serialize_V0OT::COLR1370 bool serialize_V0 (hb_serialize_context_t *c, 1371 unsigned version, 1372 BaseIterator base_it, 1373 LayerIterator layer_it) 1374 { 1375 TRACE_SERIALIZE (this); 1376 if (unlikely (base_it.len () != layer_it.len ())) 1377 return_trace (false); 1378 1379 this->version = version; 1380 numLayers = 0; 1381 numBaseGlyphs = base_it.len (); 1382 if (numBaseGlyphs == 0) 1383 { 1384 baseGlyphsZ = 0; 1385 layersZ = 0; 1386 return_trace (true); 1387 } 1388 1389 c->push (); 1390 for (const hb_item_type<BaseIterator> _ : + base_it.iter ()) 1391 { 1392 auto* record = c->embed (_); 1393 if (unlikely (!record)) return_trace (false); 1394 record->firstLayerIdx = numLayers; 1395 numLayers += record->numLayers; 1396 } 1397 c->add_link (baseGlyphsZ, c->pop_pack ()); 1398 1399 c->push (); 1400 for (const hb_item_type<LayerIterator>& _ : + layer_it.iter ()) 1401 _.as_array ().copy (c); 1402 1403 c->add_link (layersZ, c->pop_pack ()); 1404 1405 return_trace (true); 1406 } 1407 get_base_glyph_recordOT::COLR1408 const BaseGlyphRecord* get_base_glyph_record (hb_codepoint_t gid) const 1409 { 1410 const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, (unsigned int) gid); 1411 if (record == &Null (BaseGlyphRecord) || 1412 (record && (hb_codepoint_t) record->glyphId != gid)) 1413 record = nullptr; 1414 return record; 1415 } 1416 get_base_glyph_paintrecordOT::COLR1417 const BaseGlyphPaintRecord* get_base_glyph_paintrecord (hb_codepoint_t gid) const 1418 { 1419 const BaseGlyphPaintRecord* record = &(this+baseGlyphList).bsearch ((unsigned) gid); 1420 if ((record && (hb_codepoint_t) record->glyphId != gid)) 1421 record = nullptr; 1422 return record; 1423 } 1424 subsetOT::COLR1425 bool subset (hb_subset_context_t *c) const 1426 { 1427 TRACE_SUBSET (this); 1428 1429 const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map; 1430 const hb_set_t& glyphset = *c->plan->_glyphset_colred; 1431 1432 auto base_it = 1433 + hb_range (c->plan->num_output_glyphs ()) 1434 | hb_filter ([&](hb_codepoint_t new_gid) 1435 { 1436 hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid); 1437 if (glyphset.has (old_gid)) return true; 1438 return false; 1439 }) 1440 | hb_map_retains_sorting ([&](hb_codepoint_t new_gid) 1441 { 1442 hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid); 1443 1444 const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid); 1445 if (unlikely (!old_record)) 1446 return hb_pair_t<bool, BaseGlyphRecord> (false, Null (BaseGlyphRecord)); 1447 BaseGlyphRecord new_record = {}; 1448 new_record.glyphId = new_gid; 1449 new_record.numLayers = old_record->numLayers; 1450 return hb_pair_t<bool, BaseGlyphRecord> (true, new_record); 1451 }) 1452 | hb_filter (hb_first) 1453 | hb_map_retains_sorting (hb_second) 1454 ; 1455 1456 auto layer_it = 1457 + hb_range (c->plan->num_output_glyphs ()) 1458 | hb_map (reverse_glyph_map) 1459 | hb_filter (glyphset) 1460 | hb_map_retains_sorting ([&](hb_codepoint_t old_gid) 1461 { 1462 const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid); 1463 hb_vector_t<LayerRecord> out_layers; 1464 1465 if (unlikely (!old_record || 1466 old_record->firstLayerIdx >= numLayers || 1467 old_record->firstLayerIdx + old_record->numLayers > numLayers)) 1468 return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers); 1469 1470 auto layers = (this+layersZ).as_array (numLayers).sub_array (old_record->firstLayerIdx, 1471 old_record->numLayers); 1472 out_layers.resize (layers.length); 1473 for (unsigned int i = 0; i < layers.length; i++) { 1474 out_layers[i] = layers[i]; 1475 hb_codepoint_t new_gid = 0; 1476 if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid))) 1477 return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers); 1478 out_layers[i].glyphId = new_gid; 1479 out_layers[i].colorIdx = c->plan->colr_palettes->get (layers[i].colorIdx); 1480 } 1481 1482 return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers); 1483 }) 1484 | hb_filter (hb_first) 1485 | hb_map_retains_sorting (hb_second) 1486 ; 1487 1488 if (version == 0 && (!base_it || !layer_it)) 1489 return_trace (false); 1490 1491 COLR *colr_prime = c->serializer->start_embed<COLR> (); 1492 if (unlikely (!c->serializer->extend_min (colr_prime))) return_trace (false); 1493 1494 if (version == 0) 1495 return_trace (colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)); 1496 1497 auto snap = c->serializer->snapshot (); 1498 if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false); 1499 if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this)) 1500 { 1501 if (c->serializer->in_error ()) return_trace (false); 1502 //no more COLRv1 glyphs: downgrade to version 0 1503 c->serializer->revert (snap); 1504 return_trace (colr_prime->serialize_V0 (c->serializer, 0, base_it, layer_it)); 1505 } 1506 1507 if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false); 1508 1509 colr_prime->layerList.serialize_subset (c, layerList, this); 1510 colr_prime->clipList.serialize_subset (c, clipList, this); 1511 colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this); 1512 //TODO: subset varStore once it's implemented in fonttools 1513 return_trace (true); 1514 } 1515 1516 protected: 1517 HBUINT16 version; /* Table version number (starts at 0). */ 1518 HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records. */ 1519 NNOffset32To<SortedUnsizedArrayOf<BaseGlyphRecord>> 1520 baseGlyphsZ; /* Offset to Base Glyph records. */ 1521 NNOffset32To<UnsizedArrayOf<LayerRecord>> 1522 layersZ; /* Offset to Layer Records. */ 1523 HBUINT16 numLayers; /* Number of Layer Records. */ 1524 // Version-1 additions 1525 Offset32To<BaseGlyphList> baseGlyphList; 1526 Offset32To<LayerList> layerList; 1527 Offset32To<ClipList> clipList; // Offset to ClipList table (may be NULL) 1528 Offset32To<DeltaSetIndexMap> varIdxMap; // Offset to DeltaSetIndexMap table (may be NULL) 1529 Offset32To<VariationStore> varStore; 1530 public: 1531 DEFINE_SIZE_MIN (14); 1532 }; 1533 1534 struct COLR_accelerator_t : COLR::accelerator_t { COLR_accelerator_tOT::COLR_accelerator_t1535 COLR_accelerator_t (hb_face_t *face) : COLR::accelerator_t (face) {} 1536 }; 1537 1538 } /* namespace OT */ 1539 1540 1541 #endif /* HB_OT_COLOR_COLR_TABLE_HH */ 1542