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 COLRV1_MAX_NESTING_LEVEL 42 #define 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.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_ = 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; 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 template <typename context_t, typename ...Ts> dispatchOT::Paint1066 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const 1067 { 1068 TRACE_DISPATCH (this, u.format); 1069 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); 1070 switch (u.format) { 1071 case 1: return_trace (c->dispatch (u.paintformat1, std::forward<Ts> (ds)...)); 1072 case 2: return_trace (c->dispatch (u.paintformat2, std::forward<Ts> (ds)...)); 1073 case 3: return_trace (c->dispatch (u.paintformat3, std::forward<Ts> (ds)...)); 1074 case 4: return_trace (c->dispatch (u.paintformat4, std::forward<Ts> (ds)...)); 1075 case 5: return_trace (c->dispatch (u.paintformat5, std::forward<Ts> (ds)...)); 1076 case 6: return_trace (c->dispatch (u.paintformat6, std::forward<Ts> (ds)...)); 1077 case 7: return_trace (c->dispatch (u.paintformat7, std::forward<Ts> (ds)...)); 1078 case 8: return_trace (c->dispatch (u.paintformat8, std::forward<Ts> (ds)...)); 1079 case 9: return_trace (c->dispatch (u.paintformat9, std::forward<Ts> (ds)...)); 1080 case 10: return_trace (c->dispatch (u.paintformat10, std::forward<Ts> (ds)...)); 1081 case 11: return_trace (c->dispatch (u.paintformat11, std::forward<Ts> (ds)...)); 1082 case 12: return_trace (c->dispatch (u.paintformat12, std::forward<Ts> (ds)...)); 1083 case 13: return_trace (c->dispatch (u.paintformat13, std::forward<Ts> (ds)...)); 1084 case 14: return_trace (c->dispatch (u.paintformat14, std::forward<Ts> (ds)...)); 1085 case 15: return_trace (c->dispatch (u.paintformat15, std::forward<Ts> (ds)...)); 1086 case 16: return_trace (c->dispatch (u.paintformat16, std::forward<Ts> (ds)...)); 1087 case 17: return_trace (c->dispatch (u.paintformat17, std::forward<Ts> (ds)...)); 1088 case 18: return_trace (c->dispatch (u.paintformat18, std::forward<Ts> (ds)...)); 1089 case 19: return_trace (c->dispatch (u.paintformat19, std::forward<Ts> (ds)...)); 1090 case 20: return_trace (c->dispatch (u.paintformat20, std::forward<Ts> (ds)...)); 1091 case 21: return_trace (c->dispatch (u.paintformat21, std::forward<Ts> (ds)...)); 1092 case 22: return_trace (c->dispatch (u.paintformat22, std::forward<Ts> (ds)...)); 1093 case 23: return_trace (c->dispatch (u.paintformat23, std::forward<Ts> (ds)...)); 1094 case 24: return_trace (c->dispatch (u.paintformat24, std::forward<Ts> (ds)...)); 1095 case 25: return_trace (c->dispatch (u.paintformat25, std::forward<Ts> (ds)...)); 1096 case 26: return_trace (c->dispatch (u.paintformat26, std::forward<Ts> (ds)...)); 1097 case 27: return_trace (c->dispatch (u.paintformat27, std::forward<Ts> (ds)...)); 1098 case 28: return_trace (c->dispatch (u.paintformat28, std::forward<Ts> (ds)...)); 1099 case 29: return_trace (c->dispatch (u.paintformat29, std::forward<Ts> (ds)...)); 1100 case 30: return_trace (c->dispatch (u.paintformat30, std::forward<Ts> (ds)...)); 1101 case 31: return_trace (c->dispatch (u.paintformat31, std::forward<Ts> (ds)...)); 1102 case 32: return_trace (c->dispatch (u.paintformat32, std::forward<Ts> (ds)...)); 1103 default:return_trace (c->default_return_value ()); 1104 } 1105 } 1106 1107 protected: 1108 union { 1109 HBUINT8 format; 1110 PaintColrLayers paintformat1; 1111 PaintSolid paintformat2; 1112 Variable<PaintSolid> paintformat3; 1113 PaintLinearGradient<NoVariable> paintformat4; 1114 Variable<PaintLinearGradient<Variable>> paintformat5; 1115 PaintRadialGradient<NoVariable> paintformat6; 1116 Variable<PaintRadialGradient<Variable>> paintformat7; 1117 PaintSweepGradient<NoVariable> paintformat8; 1118 Variable<PaintSweepGradient<Variable>> paintformat9; 1119 PaintGlyph paintformat10; 1120 PaintColrGlyph paintformat11; 1121 PaintTransform<NoVariable> paintformat12; 1122 PaintTransform<Variable> paintformat13; 1123 PaintTranslate paintformat14; 1124 Variable<PaintTranslate> paintformat15; 1125 PaintScale paintformat16; 1126 Variable<PaintScale> paintformat17; 1127 PaintScaleAroundCenter paintformat18; 1128 Variable<PaintScaleAroundCenter> paintformat19; 1129 PaintScaleUniform paintformat20; 1130 Variable<PaintScaleUniform> paintformat21; 1131 PaintScaleUniformAroundCenter paintformat22; 1132 Variable<PaintScaleUniformAroundCenter> paintformat23; 1133 PaintRotate paintformat24; 1134 Variable<PaintRotate> paintformat25; 1135 PaintRotateAroundCenter paintformat26; 1136 Variable<PaintRotateAroundCenter> paintformat27; 1137 PaintSkew paintformat28; 1138 Variable<PaintSkew> paintformat29; 1139 PaintSkewAroundCenter paintformat30; 1140 Variable<PaintSkewAroundCenter> paintformat31; 1141 PaintComposite paintformat32; 1142 } u; 1143 }; 1144 1145 struct BaseGlyphPaintRecord 1146 { cmpOT::BaseGlyphPaintRecord1147 int cmp (hb_codepoint_t g) const 1148 { return g < glyphId ? -1 : g > glyphId ? 1 : 0; } 1149 serializeOT::BaseGlyphPaintRecord1150 bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map, 1151 const void* src_base, hb_subset_context_t *c) const 1152 { 1153 TRACE_SERIALIZE (this); 1154 auto *out = s->embed (this); 1155 if (unlikely (!out)) return_trace (false); 1156 if (!s->check_assign (out->glyphId, glyph_map->get (glyphId), 1157 HB_SERIALIZE_ERROR_INT_OVERFLOW)) 1158 return_trace (false); 1159 1160 return_trace (out->paint.serialize_subset (c, paint, src_base)); 1161 } 1162 sanitizeOT::BaseGlyphPaintRecord1163 bool sanitize (hb_sanitize_context_t *c, const void *base) const 1164 { 1165 TRACE_SANITIZE (this); 1166 return_trace (likely (c->check_struct (this) && paint.sanitize (c, base))); 1167 } 1168 1169 public: 1170 HBGlyphID16 glyphId; /* Glyph ID of reference glyph */ 1171 Offset32To<Paint> paint; /* Offset (from beginning of BaseGlyphPaintRecord array) to Paint, 1172 * Typically PaintColrLayers */ 1173 public: 1174 DEFINE_SIZE_STATIC (6); 1175 }; 1176 1177 struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord> 1178 { subsetOT::BaseGlyphList1179 bool subset (hb_subset_context_t *c) const 1180 { 1181 TRACE_SUBSET (this); 1182 auto *out = c->serializer->start_embed (this); 1183 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 1184 const hb_set_t* glyphset = c->plan->_glyphset; 1185 1186 for (const auto& _ : as_array ()) 1187 { 1188 unsigned gid = _.glyphId; 1189 if (!glyphset->has (gid)) continue; 1190 1191 if (_.serialize (c->serializer, c->plan->glyph_map, this, c)) out->len++; 1192 else return_trace (false); 1193 } 1194 1195 return_trace (out->len != 0); 1196 } 1197 sanitizeOT::BaseGlyphList1198 bool sanitize (hb_sanitize_context_t *c) const 1199 { 1200 TRACE_SANITIZE (this); 1201 return_trace (SortedArray32Of<BaseGlyphPaintRecord>::sanitize (c, this)); 1202 } 1203 }; 1204 1205 struct LayerList : Array32OfOffset32To<Paint> 1206 { get_paintOT::LayerList1207 const Paint& get_paint (unsigned i) const 1208 { return this+(*this)[i]; } 1209 subsetOT::LayerList1210 bool subset (hb_subset_context_t *c) const 1211 { 1212 TRACE_SUBSET (this); 1213 auto *out = c->serializer->start_embed (this); 1214 if (unlikely (!c->serializer->extend_min (out))) return_trace (false); 1215 1216 for (const auto& _ : + hb_enumerate (*this) 1217 | hb_filter (c->plan->colrv1_layers, hb_first)) 1218 1219 { 1220 auto *o = out->serialize_append (c->serializer); 1221 if (unlikely (!o) || !o->serialize_subset (c, _.second, this)) 1222 return_trace (false); 1223 } 1224 return_trace (true); 1225 } 1226 sanitizeOT::LayerList1227 bool sanitize (hb_sanitize_context_t *c) const 1228 { 1229 TRACE_SANITIZE (this); 1230 return_trace (Array32OfOffset32To<Paint>::sanitize (c, this)); 1231 } 1232 }; 1233 1234 struct COLR 1235 { 1236 static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR; 1237 has_dataOT::COLR1238 bool has_data () const { return numBaseGlyphs; } 1239 get_glyph_layersOT::COLR1240 unsigned int get_glyph_layers (hb_codepoint_t glyph, 1241 unsigned int start_offset, 1242 unsigned int *count, /* IN/OUT. May be NULL. */ 1243 hb_ot_color_layer_t *layers /* OUT. May be NULL. */) const 1244 { 1245 const BaseGlyphRecord &record = (this+baseGlyphsZ).bsearch (numBaseGlyphs, glyph); 1246 1247 hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers); 1248 hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx, 1249 record.numLayers); 1250 if (count) 1251 { 1252 + glyph_layers.sub_array (start_offset, count) 1253 | hb_sink (hb_array (layers, *count)) 1254 ; 1255 } 1256 return glyph_layers.length; 1257 } 1258 1259 struct accelerator_t 1260 { accelerator_tOT::COLR::accelerator_t1261 accelerator_t () {} ~accelerator_tOT::COLR::accelerator_t1262 ~accelerator_t () { fini (); } 1263 initOT::COLR::accelerator_t1264 void init (hb_face_t *face) 1265 { colr = hb_sanitize_context_t ().reference_table<COLR> (face); } 1266 finiOT::COLR::accelerator_t1267 void fini () { this->colr.destroy (); } 1268 is_validOT::COLR::accelerator_t1269 bool is_valid () { return colr.get_blob ()->length; } 1270 closure_glyphsOT::COLR::accelerator_t1271 void closure_glyphs (hb_codepoint_t glyph, 1272 hb_set_t *related_ids /* OUT */) const 1273 { colr->closure_glyphs (glyph, related_ids); } 1274 closure_V0palette_indicesOT::COLR::accelerator_t1275 void closure_V0palette_indices (const hb_set_t *glyphs, 1276 hb_set_t *palettes /* OUT */) const 1277 { colr->closure_V0palette_indices (glyphs, palettes); } 1278 closure_forV1OT::COLR::accelerator_t1279 void closure_forV1 (hb_set_t *glyphset, 1280 hb_set_t *layer_indices, 1281 hb_set_t *palette_indices) const 1282 { colr->closure_forV1 (glyphset, layer_indices, palette_indices); } 1283 1284 private: 1285 hb_blob_ptr_t<COLR> colr; 1286 }; 1287 closure_glyphsOT::COLR1288 void closure_glyphs (hb_codepoint_t glyph, 1289 hb_set_t *related_ids /* OUT */) const 1290 { 1291 const BaseGlyphRecord *record = get_base_glyph_record (glyph); 1292 if (!record) return; 1293 1294 auto glyph_layers = (this+layersZ).as_array (numLayers).sub_array (record->firstLayerIdx, 1295 record->numLayers); 1296 if (!glyph_layers.length) return; 1297 related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size); 1298 } 1299 closure_V0palette_indicesOT::COLR1300 void closure_V0palette_indices (const hb_set_t *glyphs, 1301 hb_set_t *palettes /* OUT */) const 1302 { 1303 if (!numBaseGlyphs || !numLayers) return; 1304 hb_array_t<const BaseGlyphRecord> baseGlyphs = (this+baseGlyphsZ).as_array (numBaseGlyphs); 1305 hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers); 1306 1307 for (const BaseGlyphRecord record : baseGlyphs) 1308 { 1309 if (!glyphs->has (record.glyphId)) continue; 1310 hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx, 1311 record.numLayers); 1312 for (const LayerRecord layer : glyph_layers) 1313 palettes->add (layer.colorIdx); 1314 } 1315 } 1316 closure_forV1OT::COLR1317 void closure_forV1 (hb_set_t *glyphset, 1318 hb_set_t *layer_indices, 1319 hb_set_t *palette_indices) const 1320 { 1321 if (version != 1) return; 1322 hb_set_t visited_glyphs; 1323 1324 hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices); 1325 const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList; 1326 1327 for (const BaseGlyphPaintRecord &baseglyph_paintrecord: baseglyph_paintrecords.iter ()) 1328 { 1329 unsigned gid = baseglyph_paintrecord.glyphId; 1330 if (!glyphset->has (gid)) continue; 1331 1332 const Paint &paint = &baseglyph_paintrecords+baseglyph_paintrecord.paint; 1333 paint.dispatch (&c); 1334 } 1335 hb_set_union (glyphset, &visited_glyphs); 1336 } 1337 get_layerListOT::COLR1338 const LayerList& get_layerList () const 1339 { return (this+layerList); } 1340 get_baseglyphListOT::COLR1341 const BaseGlyphList& get_baseglyphList () const 1342 { return (this+baseGlyphList); } 1343 sanitizeOT::COLR1344 bool sanitize (hb_sanitize_context_t *c) const 1345 { 1346 TRACE_SANITIZE (this); 1347 return_trace (c->check_struct (this) && 1348 (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) && 1349 (this+layersZ).sanitize (c, numLayers) && 1350 (version == 0 || 1351 (COLRV1_ENABLE_SUBSETTING && version == 1 && 1352 baseGlyphList.sanitize (c, this) && 1353 layerList.sanitize (c, this) && 1354 clipList.sanitize (c, this) && 1355 varIdxMap.sanitize (c, this) && 1356 varStore.sanitize (c, this)))); 1357 } 1358 1359 template<typename BaseIterator, typename LayerIterator, 1360 hb_requires (hb_is_iterator (BaseIterator)), 1361 hb_requires (hb_is_iterator (LayerIterator))> serialize_V0OT::COLR1362 bool serialize_V0 (hb_serialize_context_t *c, 1363 unsigned version, 1364 BaseIterator base_it, 1365 LayerIterator layer_it) 1366 { 1367 TRACE_SERIALIZE (this); 1368 if (unlikely (base_it.len () != layer_it.len ())) 1369 return_trace (false); 1370 1371 this->version = version; 1372 numLayers = 0; 1373 numBaseGlyphs = base_it.len (); 1374 if (numBaseGlyphs == 0) 1375 { 1376 baseGlyphsZ = 0; 1377 layersZ = 0; 1378 return_trace (true); 1379 } 1380 1381 c->push (); 1382 for (const hb_item_type<BaseIterator> _ : + base_it.iter ()) 1383 { 1384 auto* record = c->embed (_); 1385 if (unlikely (!record)) return_trace (false); 1386 record->firstLayerIdx = numLayers; 1387 numLayers += record->numLayers; 1388 } 1389 c->add_link (baseGlyphsZ, c->pop_pack ()); 1390 1391 c->push (); 1392 for (const hb_item_type<LayerIterator>& _ : + layer_it.iter ()) 1393 _.as_array ().copy (c); 1394 1395 c->add_link (layersZ, c->pop_pack ()); 1396 1397 return_trace (true); 1398 } 1399 get_base_glyph_recordOT::COLR1400 const BaseGlyphRecord* get_base_glyph_record (hb_codepoint_t gid) const 1401 { 1402 if ((unsigned int) gid == 0) // Ignore notdef. 1403 return nullptr; 1404 const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, (unsigned int) gid); 1405 if ((record && (hb_codepoint_t) record->glyphId != gid)) 1406 record = nullptr; 1407 return record; 1408 } 1409 get_base_glyph_paintrecordOT::COLR1410 const BaseGlyphPaintRecord* get_base_glyph_paintrecord (hb_codepoint_t gid) const 1411 { 1412 const BaseGlyphPaintRecord* record = &(this+baseGlyphList).bsearch ((unsigned) gid); 1413 if ((record && (hb_codepoint_t) record->glyphId != gid)) 1414 record = nullptr; 1415 return record; 1416 } 1417 subsetOT::COLR1418 bool subset (hb_subset_context_t *c) const 1419 { 1420 TRACE_SUBSET (this); 1421 1422 const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map; 1423 1424 auto base_it = 1425 + hb_range (c->plan->num_output_glyphs ()) 1426 | hb_map_retains_sorting ([&](hb_codepoint_t new_gid) 1427 { 1428 hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid); 1429 1430 const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid); 1431 if (unlikely (!old_record)) 1432 return hb_pair_t<bool, BaseGlyphRecord> (false, Null (BaseGlyphRecord)); 1433 1434 BaseGlyphRecord new_record = {}; 1435 new_record.glyphId = new_gid; 1436 new_record.numLayers = old_record->numLayers; 1437 return hb_pair_t<bool, BaseGlyphRecord> (true, new_record); 1438 }) 1439 | hb_filter (hb_first) 1440 | hb_map_retains_sorting (hb_second) 1441 ; 1442 1443 auto layer_it = 1444 + hb_range (c->plan->num_output_glyphs ()) 1445 | hb_map (reverse_glyph_map) 1446 | hb_map_retains_sorting ([&](hb_codepoint_t old_gid) 1447 { 1448 const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid); 1449 hb_vector_t<LayerRecord> out_layers; 1450 1451 if (unlikely (!old_record || 1452 old_record->firstLayerIdx >= numLayers || 1453 old_record->firstLayerIdx + old_record->numLayers > numLayers)) 1454 return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers); 1455 1456 auto layers = (this+layersZ).as_array (numLayers).sub_array (old_record->firstLayerIdx, 1457 old_record->numLayers); 1458 out_layers.resize (layers.length); 1459 for (unsigned int i = 0; i < layers.length; i++) { 1460 out_layers[i] = layers[i]; 1461 hb_codepoint_t new_gid = 0; 1462 if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid))) 1463 return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers); 1464 out_layers[i].glyphId = new_gid; 1465 out_layers[i].colorIdx = c->plan->colr_palettes->get (layers[i].colorIdx); 1466 } 1467 1468 return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers); 1469 }) 1470 | hb_filter (hb_first) 1471 | hb_map_retains_sorting (hb_second) 1472 ; 1473 1474 if (version == 0 && (!base_it || !layer_it)) 1475 return_trace (false); 1476 1477 COLR *colr_prime = c->serializer->start_embed<COLR> (); 1478 if (unlikely (!c->serializer->extend_min (colr_prime))) return_trace (false); 1479 1480 if (version == 0) 1481 return_trace (colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)); 1482 1483 auto snap = c->serializer->snapshot (); 1484 if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false); 1485 if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this)) 1486 { 1487 if (c->serializer->in_error ()) return_trace (false); 1488 //no more COLRv1 glyphs: downgrade to version 0 1489 c->serializer->revert (snap); 1490 return_trace (colr_prime->serialize_V0 (c->serializer, 0, base_it, layer_it)); 1491 } 1492 1493 if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false); 1494 1495 colr_prime->layerList.serialize_subset (c, layerList, this); 1496 colr_prime->clipList.serialize_subset (c, clipList, this); 1497 colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this); 1498 //TODO: subset varStore once it's implemented in fonttools 1499 return_trace (true); 1500 } 1501 1502 protected: 1503 HBUINT16 version; /* Table version number (starts at 0). */ 1504 HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records. */ 1505 NNOffset32To<SortedUnsizedArrayOf<BaseGlyphRecord>> 1506 baseGlyphsZ; /* Offset to Base Glyph records. */ 1507 NNOffset32To<UnsizedArrayOf<LayerRecord>> 1508 layersZ; /* Offset to Layer Records. */ 1509 HBUINT16 numLayers; /* Number of Layer Records. */ 1510 // Version-1 additions 1511 Offset32To<BaseGlyphList> baseGlyphList; 1512 Offset32To<LayerList> layerList; 1513 Offset32To<ClipList> clipList; // Offset to ClipList table (may be NULL) 1514 Offset32To<DeltaSetIndexMap> varIdxMap; // Offset to DeltaSetIndexMap table (may be NULL) 1515 Offset32To<VariationStore> varStore; 1516 public: 1517 DEFINE_SIZE_MIN (14); 1518 }; 1519 1520 } /* namespace OT */ 1521 1522 1523 #endif /* HB_OT_COLOR_COLR_TABLE_HH */ 1524