2 * Copyright © 2018 Ebrahim Byagowi
3 * Copyright © 2020 Google, Inc.
5 * This is part of HarfBuzz, a text shaping library.
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.
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
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.
25 * Google Author(s): Calder Kitagawa
28 #ifndef OT_COLOR_COLR_COLR_HH
29 #define OT_COLOR_COLR_COLR_HH
31 #include "../../../hb.hh"
32 #include "../../../hb-open-type.hh"
33 #include "../../../hb-ot-var-common.hh"
34 #include "../../../hb-paint.hh"
35 #include "../../../hb-paint-extents.hh"
39 * https://docs.microsoft.com/en-us/typography/opentype/spec/colr
41 #define HB_OT_TAG_COLR HB_TAG('C','O','L','R')
44 struct hb_paint_context_t;
53 struct hb_paint_context_t :
54 hb_dispatch_context_t<hb_paint_context_t>
56 const char *get_name () { return "PAINT"; }
58 return_t dispatch (const T &obj) { obj.paint_glyph (this); return hb_empty_t (); }
59 static return_t default_return_value () { return hb_empty_t (); }
61 const COLR* get_colr_table () const
62 { return reinterpret_cast<const COLR *> (base); }
66 hb_paint_funcs_t *funcs;
69 unsigned int palette_index;
70 hb_color_t foreground;
71 VarStoreInstancer &instancer;
72 hb_map_t current_glyphs;
73 hb_map_t current_layers;
74 int depth_left = HB_MAX_NESTING_LEVEL;
75 int edge_count = HB_COLRV1_MAX_EDGE_COUNT;
77 hb_paint_context_t (const void *base_,
78 hb_paint_funcs_t *funcs_,
81 unsigned int palette_,
82 hb_color_t foreground_,
83 VarStoreInstancer &instancer_) :
88 palette_index (palette_),
89 foreground (foreground_),
90 instancer (instancer_)
93 hb_color_t get_color (unsigned int color_index, float alpha, hb_bool_t *is_foreground)
95 hb_color_t color = foreground;
97 *is_foreground = true;
99 if (color_index != 0xffff)
101 if (!funcs->custom_palette_color (data, color_index, &color))
103 unsigned int clen = 1;
104 hb_face_t *face = hb_font_get_face (font);
106 hb_ot_color_palette_get_colors (face, palette_index, color_index, &clen, &color);
109 *is_foreground = false;
112 return HB_COLOR (hb_color_get_blue (color),
113 hb_color_get_green (color),
114 hb_color_get_red (color),
115 hb_color_get_alpha (color) * alpha);
118 inline void recurse (const Paint &paint);
121 struct hb_colrv1_closure_context_t :
122 hb_dispatch_context_t<hb_colrv1_closure_context_t>
124 template <typename T>
125 return_t dispatch (const T &obj)
127 if (unlikely (nesting_level_left == 0))
128 return hb_empty_t ();
130 if (paint_visited (&obj))
131 return hb_empty_t ();
133 nesting_level_left--;
134 obj.closurev1 (this);
135 nesting_level_left++;
136 return hb_empty_t ();
138 static return_t default_return_value () { return hb_empty_t (); }
140 bool paint_visited (const void *paint)
142 hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) paint - (uintptr_t) base);
143 if (visited_paint.in_error() || visited_paint.has (delta))
146 visited_paint.add (delta);
150 const COLR* get_colr_table () const
151 { return reinterpret_cast<const COLR *> (base); }
153 void add_glyph (unsigned glyph_id)
154 { glyphs->add (glyph_id); }
156 void add_layer_indices (unsigned first_layer_index, unsigned num_of_layers)
157 { layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1); }
159 void add_palette_index (unsigned palette_index)
160 { palette_indices->add (palette_index); }
164 hb_set_t visited_paint;
166 hb_set_t *layer_indices;
167 hb_set_t *palette_indices;
168 unsigned nesting_level_left;
170 hb_colrv1_closure_context_t (const void *base_,
172 hb_set_t *layer_indices_,
173 hb_set_t *palette_indices_,
174 unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
177 layer_indices (layer_indices_),
178 palette_indices (palette_indices_),
179 nesting_level_left (nesting_level_left_)
185 operator hb_ot_color_layer_t () const { return {glyphId, colorIdx}; }
187 bool sanitize (hb_sanitize_context_t *c) const
189 TRACE_SANITIZE (this);
190 return_trace (c->check_struct (this));
194 HBGlyphID16 glyphId; /* Glyph ID of layer glyph */
195 Index colorIdx; /* Index value to use with a
196 * selected color palette.
197 * An index value of 0xFFFF
198 * is a special case indicating
199 * that the text foreground
200 * color (defined by a
201 * higher-level client) should
202 * be used and shall not be
203 * treated as actual index
204 * into CPAL ColorRecord array. */
206 DEFINE_SIZE_STATIC (4);
209 struct BaseGlyphRecord
211 int cmp (hb_codepoint_t g) const
212 { return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
214 bool sanitize (hb_sanitize_context_t *c) const
216 TRACE_SANITIZE (this);
217 return_trace (c->check_struct (this));
221 HBGlyphID16 glyphId; /* Glyph ID of reference glyph */
222 HBUINT16 firstLayerIdx; /* Index (from beginning of
223 * the Layer Records) to the
224 * layer record. There will be
225 * numLayers consecutive entries
226 * for this base glyph. */
227 HBUINT16 numLayers; /* Number of color layers
228 * associated with this glyph */
230 DEFINE_SIZE_STATIC (6);
233 template <typename T>
236 static constexpr bool is_variable = true;
238 Variable<T>* copy (hb_serialize_context_t *c) const
240 TRACE_SERIALIZE (this);
241 return_trace (c->embed (this));
244 void closurev1 (hb_colrv1_closure_context_t* c) const
245 { value.closurev1 (c); }
247 bool subset (hb_subset_context_t *c,
248 const VarStoreInstancer &instancer) const
251 if (!value.subset (c, instancer, varIdxBase)) return_trace (false);
252 if (c->plan->all_axes_pinned)
255 //TODO: update varIdxBase for partial-instancing
256 return_trace (c->serializer->embed (varIdxBase));
259 bool sanitize (hb_sanitize_context_t *c) const
261 TRACE_SANITIZE (this);
262 return_trace (c->check_struct (this) && value.sanitize (c));
265 void paint_glyph (hb_paint_context_t *c) const
268 value.paint_glyph (c, varIdxBase);
271 void get_color_stop (hb_paint_context_t *c,
272 hb_color_stop_t *stop,
273 const VarStoreInstancer &instancer) const
275 value.get_color_stop (c, stop, varIdxBase, instancer);
278 hb_paint_extend_t get_extend () const
280 return value.get_extend ();
288 DEFINE_SIZE_MIN (VarIdx::static_size + T::min_size);
291 template <typename T>
294 static constexpr bool is_variable = false;
296 static constexpr uint32_t varIdxBase = VarIdx::NO_VARIATION;
298 NoVariable<T>* copy (hb_serialize_context_t *c) const
300 TRACE_SERIALIZE (this);
301 return_trace (c->embed (this));
304 void closurev1 (hb_colrv1_closure_context_t* c) const
305 { value.closurev1 (c); }
307 bool subset (hb_subset_context_t *c,
308 const VarStoreInstancer &instancer) const
311 return_trace (value.subset (c, instancer, varIdxBase));
314 bool sanitize (hb_sanitize_context_t *c) const
316 TRACE_SANITIZE (this);
317 return_trace (c->check_struct (this) && value.sanitize (c));
320 void paint_glyph (hb_paint_context_t *c) const
323 value.paint_glyph (c, varIdxBase);
326 void get_color_stop (hb_paint_context_t *c,
327 hb_color_stop_t *stop,
328 const VarStoreInstancer &instancer) const
330 value.get_color_stop (c, stop, VarIdx::NO_VARIATION, instancer);
333 hb_paint_extend_t get_extend () const
335 return value.get_extend ();
340 DEFINE_SIZE_MIN (T::min_size);
347 void closurev1 (hb_colrv1_closure_context_t* c) const
348 { c->add_palette_index (paletteIndex); }
350 bool subset (hb_subset_context_t *c,
351 const VarStoreInstancer &instancer,
352 uint32_t varIdxBase) const
355 auto *out = c->serializer->embed (*this);
356 if (unlikely (!out)) return_trace (false);
358 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
360 out->stopOffset.set_float (stopOffset.to_float(instancer (varIdxBase, 0)));
361 out->alpha.set_float (alpha.to_float (instancer (varIdxBase, 1)));
364 return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex),
365 HB_SERIALIZE_ERROR_INT_OVERFLOW));
368 bool sanitize (hb_sanitize_context_t *c) const
370 TRACE_SANITIZE (this);
371 return_trace (c->check_struct (this));
374 void get_color_stop (hb_paint_context_t *c,
375 hb_color_stop_t *out,
377 const VarStoreInstancer &instancer) const
379 out->offset = stopOffset.to_float(instancer (varIdx, 0));
380 out->color = c->get_color (paletteIndex,
381 alpha.to_float (instancer (varIdx, 1)),
382 &out->is_foreground);
386 HBUINT16 paletteIndex;
389 DEFINE_SIZE_STATIC (2 + 2 * F2DOT14::static_size);
392 struct Extend : HBUINT8
400 DEFINE_SIZE_STATIC (1);
403 template <template<typename> class Var>
406 void closurev1 (hb_colrv1_closure_context_t* c) const
408 for (const auto &stop : stops.iter ())
412 bool subset (hb_subset_context_t *c,
413 const VarStoreInstancer &instancer) const
416 auto *out = c->serializer->start_embed (this);
417 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
419 if (!c->serializer->check_assign (out->extend, extend, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
420 if (!c->serializer->check_assign (out->stops.len, stops.len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)) return_trace (false);
422 for (const auto& stop : stops.iter ())
424 if (!stop.subset (c, instancer)) return_trace (false);
429 bool sanitize (hb_sanitize_context_t *c) const
431 TRACE_SANITIZE (this);
432 return_trace (c->check_struct (this) &&
436 /* get up to count stops from start */
438 get_color_stops (hb_paint_context_t *c,
441 hb_color_stop_t *color_stops,
442 const VarStoreInstancer &instancer) const
444 unsigned int len = stops.len;
446 if (count && color_stops)
449 for (i = 0; i < *count && start + i < len; i++)
450 stops[start + i].get_color_stop (c, &color_stops[i], instancer);
457 HB_INTERNAL static unsigned int static_get_color_stops (hb_color_line_t *color_line,
458 void *color_line_data,
461 hb_color_stop_t *color_stops,
464 const ColorLine *thiz = (const ColorLine *) color_line_data;
465 hb_paint_context_t *c = (hb_paint_context_t *) user_data;
466 return thiz->get_color_stops (c, start, count, color_stops, c->instancer);
469 hb_paint_extend_t get_extend () const
471 return (hb_paint_extend_t) (unsigned int) extend;
474 HB_INTERNAL static hb_paint_extend_t static_get_extend (hb_color_line_t *color_line,
475 void *color_line_data,
478 const ColorLine *thiz = (const ColorLine *) color_line_data;
479 return thiz->get_extend ();
483 Array16Of<Var<ColorStop>> stops;
485 DEFINE_SIZE_ARRAY_SIZED (3, stops);
490 // Compositing modes are taken from https://www.w3.org/TR/compositing-1/
491 // NOTE: a brief audit of major implementations suggests most support most
492 // or all of the specified modes.
493 struct CompositeMode : HBUINT8
497 // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators
498 COMPOSITE_CLEAR = 0, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_clear
499 COMPOSITE_SRC = 1, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_src
500 COMPOSITE_DEST = 2, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dst
501 COMPOSITE_SRC_OVER = 3, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcover
502 COMPOSITE_DEST_OVER = 4, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstover
503 COMPOSITE_SRC_IN = 5, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcin
504 COMPOSITE_DEST_IN = 6, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstin
505 COMPOSITE_SRC_OUT = 7, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcout
506 COMPOSITE_DEST_OUT = 8, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstout
507 COMPOSITE_SRC_ATOP = 9, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcatop
508 COMPOSITE_DEST_ATOP = 10, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstatop
509 COMPOSITE_XOR = 11, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_xor
510 COMPOSITE_PLUS = 12, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_plus
513 // https://www.w3.org/TR/compositing-1/#blending
514 COMPOSITE_SCREEN = 13, // https://www.w3.org/TR/compositing-1/#blendingscreen
515 COMPOSITE_OVERLAY = 14, // https://www.w3.org/TR/compositing-1/#blendingoverlay
516 COMPOSITE_DARKEN = 15, // https://www.w3.org/TR/compositing-1/#blendingdarken
517 COMPOSITE_LIGHTEN = 16, // https://www.w3.org/TR/compositing-1/#blendinglighten
518 COMPOSITE_COLOR_DODGE = 17, // https://www.w3.org/TR/compositing-1/#blendingcolordodge
519 COMPOSITE_COLOR_BURN = 18, // https://www.w3.org/TR/compositing-1/#blendingcolorburn
520 COMPOSITE_HARD_LIGHT = 19, // https://www.w3.org/TR/compositing-1/#blendinghardlight
521 COMPOSITE_SOFT_LIGHT = 20, // https://www.w3.org/TR/compositing-1/#blendingsoftlight
522 COMPOSITE_DIFFERENCE = 21, // https://www.w3.org/TR/compositing-1/#blendingdifference
523 COMPOSITE_EXCLUSION = 22, // https://www.w3.org/TR/compositing-1/#blendingexclusion
524 COMPOSITE_MULTIPLY = 23, // https://www.w3.org/TR/compositing-1/#blendingmultiply
526 // Modes that, uniquely, do not operate on components
527 // https://www.w3.org/TR/compositing-1/#blendingnonseparable
528 COMPOSITE_HSL_HUE = 24, // https://www.w3.org/TR/compositing-1/#blendinghue
529 COMPOSITE_HSL_SATURATION = 25, // https://www.w3.org/TR/compositing-1/#blendingsaturation
530 COMPOSITE_HSL_COLOR = 26, // https://www.w3.org/TR/compositing-1/#blendingcolor
531 COMPOSITE_HSL_LUMINOSITY = 27, // https://www.w3.org/TR/compositing-1/#blendingluminosity
534 DEFINE_SIZE_STATIC (1);
539 bool sanitize (hb_sanitize_context_t *c) const
541 TRACE_SANITIZE (this);
542 return_trace (c->check_struct (this));
545 bool subset (hb_subset_context_t *c,
546 const VarStoreInstancer &instancer,
547 uint32_t varIdxBase) const
550 auto *out = c->serializer->embed (*this);
551 if (unlikely (!out)) return_trace (false);
552 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
554 out->xx.set_float (xx.to_float(instancer (varIdxBase, 0)));
555 out->yx.set_float (yx.to_float(instancer (varIdxBase, 1)));
556 out->xy.set_float (xy.to_float(instancer (varIdxBase, 2)));
557 out->yy.set_float (yy.to_float(instancer (varIdxBase, 3)));
558 out->dx.set_float (dx.to_float(instancer (varIdxBase, 4)));
559 out->dy.set_float (dy.to_float(instancer (varIdxBase, 5)));
564 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
567 c->funcs->push_transform (c->data,
568 xx.to_float (c->instancer (varIdxBase, 0)),
569 yx.to_float (c->instancer (varIdxBase, 1)),
570 xy.to_float (c->instancer (varIdxBase, 2)),
571 yy.to_float (c->instancer (varIdxBase, 3)),
572 dx.to_float (c->instancer (varIdxBase, 4)),
573 dy.to_float (c->instancer (varIdxBase, 5)));
583 DEFINE_SIZE_STATIC (6 * F16DOT16::static_size);
586 struct PaintColrLayers
588 void closurev1 (hb_colrv1_closure_context_t* c) const;
590 bool subset (hb_subset_context_t *c,
591 const VarStoreInstancer &instancer HB_UNUSED) const
594 auto *out = c->serializer->embed (this);
595 if (unlikely (!out)) return_trace (false);
596 return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers.get (firstLayerIndex),
597 HB_SERIALIZE_ERROR_INT_OVERFLOW));
602 bool sanitize (hb_sanitize_context_t *c) const
604 TRACE_SANITIZE (this);
605 return_trace (c->check_struct (this));
608 inline void paint_glyph (hb_paint_context_t *c) const;
610 HBUINT8 format; /* format = 1 */
612 HBUINT32 firstLayerIndex; /* index into COLRv1::layerList */
614 DEFINE_SIZE_STATIC (6);
619 void closurev1 (hb_colrv1_closure_context_t* c) const
620 { c->add_palette_index (paletteIndex); }
622 bool subset (hb_subset_context_t *c,
623 const VarStoreInstancer &instancer,
624 uint32_t varIdxBase) const
627 auto *out = c->serializer->embed (*this);
628 if (unlikely (!out)) return_trace (false);
630 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
631 out->alpha.set_float (alpha.to_float (instancer (varIdxBase, 0)));
633 if (format == 3 && c->plan->all_axes_pinned)
636 return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex),
637 HB_SERIALIZE_ERROR_INT_OVERFLOW));
640 bool sanitize (hb_sanitize_context_t *c) const
642 TRACE_SANITIZE (this);
643 return_trace (c->check_struct (this));
646 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
649 hb_bool_t is_foreground;
652 color = c->get_color (paletteIndex,
653 alpha.to_float (c->instancer (varIdxBase, 0)),
655 c->funcs->color (c->data, is_foreground, color);
658 HBUINT8 format; /* format = 2(noVar) or 3(Var)*/
659 HBUINT16 paletteIndex;
662 DEFINE_SIZE_STATIC (3 + F2DOT14::static_size);
665 template <template<typename> class Var>
666 struct PaintLinearGradient
668 void closurev1 (hb_colrv1_closure_context_t* c) const
669 { (this+colorLine).closurev1 (c); }
671 bool subset (hb_subset_context_t *c,
672 const VarStoreInstancer &instancer,
673 uint32_t varIdxBase) const
676 auto *out = c->serializer->embed (this);
677 if (unlikely (!out)) return_trace (false);
679 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
681 out->x0 = x0 + (int) roundf (instancer (varIdxBase, 0));
682 out->y0 = y0 + (int) roundf (instancer (varIdxBase, 1));
683 out->x1 = x1 + (int) roundf (instancer (varIdxBase, 2));
684 out->y1 = y1 + (int) roundf (instancer (varIdxBase, 3));
685 out->x2 = x2 + (int) roundf (instancer (varIdxBase, 4));
686 out->y2 = y2 + (int) roundf (instancer (varIdxBase, 5));
689 if (format == 5 && c->plan->all_axes_pinned)
692 return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer));
695 bool sanitize (hb_sanitize_context_t *c) const
697 TRACE_SANITIZE (this);
698 return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
701 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
704 hb_color_line_t cl = {
705 (void *) &(this+colorLine),
706 (this+colorLine).static_get_color_stops, c,
707 (this+colorLine).static_get_extend, nullptr
710 c->funcs->linear_gradient (c->data, &cl,
711 x0 + c->instancer (varIdxBase, 0),
712 y0 + c->instancer (varIdxBase, 1),
713 x1 + c->instancer (varIdxBase, 2),
714 y1 + c->instancer (varIdxBase, 3),
715 x2 + c->instancer (varIdxBase, 4),
716 y2 + c->instancer (varIdxBase, 5));
719 HBUINT8 format; /* format = 4(noVar) or 5 (Var) */
720 Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintLinearGradient
721 * table) to ColorLine subtable. */
729 DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size);
732 template <template<typename> class Var>
733 struct PaintRadialGradient
735 void closurev1 (hb_colrv1_closure_context_t* c) const
736 { (this+colorLine).closurev1 (c); }
738 bool subset (hb_subset_context_t *c,
739 const VarStoreInstancer &instancer,
740 uint32_t varIdxBase) const
743 auto *out = c->serializer->embed (this);
744 if (unlikely (!out)) return_trace (false);
746 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
748 out->x0 = x0 + (int) roundf (instancer (varIdxBase, 0));
749 out->y0 = y0 + (int) roundf (instancer (varIdxBase, 1));
750 out->radius0 = radius0 + (unsigned) roundf (instancer (varIdxBase, 2));
751 out->x1 = x1 + (int) roundf (instancer (varIdxBase, 3));
752 out->y1 = y1 + (int) roundf (instancer (varIdxBase, 4));
753 out->radius1 = radius1 + (unsigned) roundf (instancer (varIdxBase, 5));
756 if (format == 7 && c->plan->all_axes_pinned)
759 return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer));
762 bool sanitize (hb_sanitize_context_t *c) const
764 TRACE_SANITIZE (this);
765 return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
768 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
771 hb_color_line_t cl = {
772 (void *) &(this+colorLine),
773 (this+colorLine).static_get_color_stops, c,
774 (this+colorLine).static_get_extend, nullptr
777 c->funcs->radial_gradient (c->data, &cl,
778 x0 + c->instancer (varIdxBase, 0),
779 y0 + c->instancer (varIdxBase, 1),
780 radius0 + c->instancer (varIdxBase, 2),
781 x1 + c->instancer (varIdxBase, 3),
782 y1 + c->instancer (varIdxBase, 4),
783 radius1 + c->instancer (varIdxBase, 5));
786 HBUINT8 format; /* format = 6(noVar) or 7 (Var) */
787 Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintRadialGradient
788 * table) to ColorLine subtable. */
796 DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size);
799 template <template<typename> class Var>
800 struct PaintSweepGradient
802 void closurev1 (hb_colrv1_closure_context_t* c) const
803 { (this+colorLine).closurev1 (c); }
805 bool subset (hb_subset_context_t *c,
806 const VarStoreInstancer &instancer,
807 uint32_t varIdxBase) const
810 auto *out = c->serializer->embed (this);
811 if (unlikely (!out)) return_trace (false);
813 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
815 out->centerX = centerX + (int) roundf (instancer (varIdxBase, 0));
816 out->centerY = centerY + (int) roundf (instancer (varIdxBase, 1));
817 out->startAngle.set_float (startAngle.to_float (instancer (varIdxBase, 2)));
818 out->endAngle.set_float (endAngle.to_float (instancer (varIdxBase, 3)));
821 if (format == 9 && c->plan->all_axes_pinned)
824 return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer));
827 bool sanitize (hb_sanitize_context_t *c) const
829 TRACE_SANITIZE (this);
830 return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
833 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
836 hb_color_line_t cl = {
837 (void *) &(this+colorLine),
838 (this+colorLine).static_get_color_stops, c,
839 (this+colorLine).static_get_extend, nullptr
842 c->funcs->sweep_gradient (c->data, &cl,
843 centerX + c->instancer (varIdxBase, 0),
844 centerY + c->instancer (varIdxBase, 1),
845 (startAngle.to_float (c->instancer (varIdxBase, 2)) + 1) * HB_PI,
846 (endAngle.to_float (c->instancer (varIdxBase, 3)) + 1) * HB_PI);
849 HBUINT8 format; /* format = 8(noVar) or 9 (Var) */
850 Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintSweepGradient
851 * table) to ColorLine subtable. */
857 DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size + 2 * F2DOT14::static_size);
860 // Paint a non-COLR glyph, filled as indicated by paint.
863 void closurev1 (hb_colrv1_closure_context_t* c) const;
865 bool subset (hb_subset_context_t *c,
866 const VarStoreInstancer &instancer) const
869 auto *out = c->serializer->embed (this);
870 if (unlikely (!out)) return_trace (false);
872 if (! c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid),
873 HB_SERIALIZE_ERROR_INT_OVERFLOW))
874 return_trace (false);
876 return_trace (out->paint.serialize_subset (c, paint, this, instancer));
879 bool sanitize (hb_sanitize_context_t *c) const
881 TRACE_SANITIZE (this);
882 return_trace (c->check_struct (this) && paint.sanitize (c, this));
885 void paint_glyph (hb_paint_context_t *c) const
888 c->funcs->push_inverse_root_transform (c->data, c->font);
889 c->funcs->push_clip_glyph (c->data, gid, c->font);
890 c->funcs->push_root_transform (c->data, c->font);
891 c->recurse (this+paint);
892 c->funcs->pop_transform (c->data);
893 c->funcs->pop_clip (c->data);
894 c->funcs->pop_transform (c->data);
897 HBUINT8 format; /* format = 10 */
898 Offset24To<Paint> paint; /* Offset (from beginning of PaintGlyph table) to Paint subtable. */
901 DEFINE_SIZE_STATIC (6);
904 struct PaintColrGlyph
906 void closurev1 (hb_colrv1_closure_context_t* c) const;
908 bool subset (hb_subset_context_t *c,
909 const VarStoreInstancer &instancer HB_UNUSED) const
912 auto *out = c->serializer->embed (this);
913 if (unlikely (!out)) return_trace (false);
915 return_trace (c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid),
916 HB_SERIALIZE_ERROR_INT_OVERFLOW));
919 bool sanitize (hb_sanitize_context_t *c) const
921 TRACE_SANITIZE (this);
922 return_trace (c->check_struct (this));
925 inline void paint_glyph (hb_paint_context_t *c) const;
927 HBUINT8 format; /* format = 11 */
930 DEFINE_SIZE_STATIC (3);
933 template <template<typename> class Var>
934 struct PaintTransform
936 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
938 bool subset (hb_subset_context_t *c,
939 const VarStoreInstancer &instancer) const
942 auto *out = c->serializer->embed (this);
943 if (unlikely (!out)) return_trace (false);
944 if (!out->transform.serialize_subset (c, transform, this, instancer)) return_trace (false);
945 if (format == 13 && c->plan->all_axes_pinned)
947 return_trace (out->src.serialize_subset (c, src, this, instancer));
950 bool sanitize (hb_sanitize_context_t *c) const
952 TRACE_SANITIZE (this);
953 return_trace (c->check_struct (this) &&
954 src.sanitize (c, this) &&
955 transform.sanitize (c, this));
958 void paint_glyph (hb_paint_context_t *c) const
961 (this+transform).paint_glyph (c);
962 c->recurse (this+src);
963 c->funcs->pop_transform (c->data);
966 HBUINT8 format; /* format = 12(noVar) or 13 (Var) */
967 Offset24To<Paint> src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */
968 Offset24To<Var<Affine2x3>> transform;
970 DEFINE_SIZE_STATIC (7);
973 struct PaintTranslate
975 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
977 bool subset (hb_subset_context_t *c,
978 const VarStoreInstancer &instancer,
979 uint32_t varIdxBase) const
982 auto *out = c->serializer->embed (this);
983 if (unlikely (!out)) return_trace (false);
985 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
987 out->dx = dx + (int) roundf (instancer (varIdxBase, 0));
988 out->dy = dy + (int) roundf (instancer (varIdxBase, 1));
991 if (format == 15 && c->plan->all_axes_pinned)
994 return_trace (out->src.serialize_subset (c, src, this, instancer));
997 bool sanitize (hb_sanitize_context_t *c) const
999 TRACE_SANITIZE (this);
1000 return_trace (c->check_struct (this) && src.sanitize (c, this));
1003 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1006 float ddx = dx + c->instancer (varIdxBase, 0);
1007 float ddy = dy + c->instancer (varIdxBase, 1);
1009 bool p1 = c->funcs->push_translate (c->data, ddx, ddy);
1010 c->recurse (this+src);
1011 if (p1) c->funcs->pop_transform (c->data);
1014 HBUINT8 format; /* format = 14(noVar) or 15 (Var) */
1015 Offset24To<Paint> src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */
1019 DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size);
1024 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1026 bool subset (hb_subset_context_t *c,
1027 const VarStoreInstancer &instancer,
1028 uint32_t varIdxBase) const
1030 TRACE_SUBSET (this);
1031 auto *out = c->serializer->embed (this);
1032 if (unlikely (!out)) return_trace (false);
1034 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1036 out->scaleX.set_float (scaleX.to_float (instancer (varIdxBase, 0)));
1037 out->scaleY.set_float (scaleY.to_float (instancer (varIdxBase, 1)));
1040 if (format == 17 && c->plan->all_axes_pinned)
1043 return_trace (out->src.serialize_subset (c, src, this, instancer));
1046 bool sanitize (hb_sanitize_context_t *c) const
1048 TRACE_SANITIZE (this);
1049 return_trace (c->check_struct (this) && src.sanitize (c, this));
1052 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1055 float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
1056 float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
1058 bool p1 = c->funcs->push_scale (c->data, sx, sy);
1059 c->recurse (this+src);
1060 if (p1) c->funcs->pop_transform (c->data);
1063 HBUINT8 format; /* format = 16 (noVar) or 17(Var) */
1064 Offset24To<Paint> src; /* Offset (from beginning of PaintScale table) to Paint subtable. */
1068 DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size);
1071 struct PaintScaleAroundCenter
1073 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1075 bool subset (hb_subset_context_t *c,
1076 const VarStoreInstancer &instancer,
1077 uint32_t varIdxBase) const
1079 TRACE_SUBSET (this);
1080 auto *out = c->serializer->embed (this);
1081 if (unlikely (!out)) return_trace (false);
1083 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1085 out->scaleX.set_float (scaleX.to_float (instancer (varIdxBase, 0)));
1086 out->scaleY.set_float (scaleY.to_float (instancer (varIdxBase, 1)));
1087 out->centerX = centerX + (int) roundf (instancer (varIdxBase, 2));
1088 out->centerY = centerY + (int) roundf (instancer (varIdxBase, 3));
1091 if (format == 19 && c->plan->all_axes_pinned)
1094 return_trace (out->src.serialize_subset (c, src, this, instancer));
1097 bool sanitize (hb_sanitize_context_t *c) const
1099 TRACE_SANITIZE (this);
1100 return_trace (c->check_struct (this) && src.sanitize (c, this));
1103 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1106 float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
1107 float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
1108 float tCenterX = centerX + c->instancer (varIdxBase, 2);
1109 float tCenterY = centerY + c->instancer (varIdxBase, 3);
1111 bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
1112 bool p2 = c->funcs->push_scale (c->data, sx, sy);
1113 bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
1114 c->recurse (this+src);
1115 if (p3) c->funcs->pop_transform (c->data);
1116 if (p2) c->funcs->pop_transform (c->data);
1117 if (p1) c->funcs->pop_transform (c->data);
1120 HBUINT8 format; /* format = 18 (noVar) or 19(Var) */
1121 Offset24To<Paint> src; /* Offset (from beginning of PaintScaleAroundCenter table) to Paint subtable. */
1127 DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size + 2 * FWORD::static_size);
1130 struct PaintScaleUniform
1132 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1134 bool subset (hb_subset_context_t *c,
1135 const VarStoreInstancer &instancer,
1136 uint32_t varIdxBase) const
1138 TRACE_SUBSET (this);
1139 auto *out = c->serializer->embed (this);
1140 if (unlikely (!out)) return_trace (false);
1142 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1143 out->scale.set_float (scale.to_float (instancer (varIdxBase, 0)));
1145 if (format == 21 && c->plan->all_axes_pinned)
1148 return_trace (out->src.serialize_subset (c, src, this, instancer));
1151 bool sanitize (hb_sanitize_context_t *c) const
1153 TRACE_SANITIZE (this);
1154 return_trace (c->check_struct (this) && src.sanitize (c, this));
1157 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1160 float s = scale.to_float (c->instancer (varIdxBase, 0));
1162 bool p1 = c->funcs->push_scale (c->data, s, s);
1163 c->recurse (this+src);
1164 if (p1) c->funcs->pop_transform (c->data);
1167 HBUINT8 format; /* format = 20 (noVar) or 21(Var) */
1168 Offset24To<Paint> src; /* Offset (from beginning of PaintScaleUniform table) to Paint subtable. */
1171 DEFINE_SIZE_STATIC (4 + F2DOT14::static_size);
1174 struct PaintScaleUniformAroundCenter
1176 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1178 bool subset (hb_subset_context_t *c,
1179 const VarStoreInstancer &instancer,
1180 uint32_t varIdxBase) const
1182 TRACE_SUBSET (this);
1183 auto *out = c->serializer->embed (this);
1184 if (unlikely (!out)) return_trace (false);
1186 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1188 out->scale.set_float (scale.to_float (instancer (varIdxBase, 0)));
1189 out->centerX = centerX + (int) roundf (instancer (varIdxBase, 1));
1190 out->centerY = centerY + (int) roundf (instancer (varIdxBase, 2));
1193 if (format == 23 && c->plan->all_axes_pinned)
1196 return_trace (out->src.serialize_subset (c, src, this, instancer));
1199 bool sanitize (hb_sanitize_context_t *c) const
1201 TRACE_SANITIZE (this);
1202 return_trace (c->check_struct (this) && src.sanitize (c, this));
1205 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1208 float s = scale.to_float (c->instancer (varIdxBase, 0));
1209 float tCenterX = centerX + c->instancer (varIdxBase, 1);
1210 float tCenterY = centerY + c->instancer (varIdxBase, 2);
1212 bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
1213 bool p2 = c->funcs->push_scale (c->data, s, s);
1214 bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
1215 c->recurse (this+src);
1216 if (p3) c->funcs->pop_transform (c->data);
1217 if (p2) c->funcs->pop_transform (c->data);
1218 if (p1) c->funcs->pop_transform (c->data);
1221 HBUINT8 format; /* format = 22 (noVar) or 23(Var) */
1222 Offset24To<Paint> src; /* Offset (from beginning of PaintScaleUniformAroundCenter table) to Paint subtable. */
1227 DEFINE_SIZE_STATIC (4 + F2DOT14::static_size + 2 * FWORD::static_size);
1232 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1234 bool subset (hb_subset_context_t *c,
1235 const VarStoreInstancer &instancer,
1236 uint32_t varIdxBase) const
1238 TRACE_SUBSET (this);
1239 auto *out = c->serializer->embed (this);
1240 if (unlikely (!out)) return_trace (false);
1242 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1243 out->angle.set_float (angle.to_float (instancer (varIdxBase, 0)));
1245 if (format == 25 && c->plan->all_axes_pinned)
1248 return_trace (out->src.serialize_subset (c, src, this, instancer));
1251 bool sanitize (hb_sanitize_context_t *c) const
1253 TRACE_SANITIZE (this);
1254 return_trace (c->check_struct (this) && src.sanitize (c, this));
1257 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1260 float a = angle.to_float (c->instancer (varIdxBase, 0));
1262 bool p1 = c->funcs->push_rotate (c->data, a);
1263 c->recurse (this+src);
1264 if (p1) c->funcs->pop_transform (c->data);
1267 HBUINT8 format; /* format = 24 (noVar) or 25(Var) */
1268 Offset24To<Paint> src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */
1271 DEFINE_SIZE_STATIC (4 + F2DOT14::static_size);
1274 struct PaintRotateAroundCenter
1276 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1278 bool subset (hb_subset_context_t *c,
1279 const VarStoreInstancer &instancer,
1280 uint32_t varIdxBase) const
1282 TRACE_SUBSET (this);
1283 auto *out = c->serializer->embed (this);
1284 if (unlikely (!out)) return_trace (false);
1286 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1288 out->angle.set_float (angle.to_float (instancer (varIdxBase, 0)));
1289 out->centerX = centerX + (int) roundf (instancer (varIdxBase, 1));
1290 out->centerY = centerY + (int) roundf (instancer (varIdxBase, 2));
1293 if (format ==27 && c->plan->all_axes_pinned)
1296 return_trace (out->src.serialize_subset (c, src, this, instancer));
1299 bool sanitize (hb_sanitize_context_t *c) const
1301 TRACE_SANITIZE (this);
1302 return_trace (c->check_struct (this) && src.sanitize (c, this));
1305 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1308 float a = angle.to_float (c->instancer (varIdxBase, 0));
1309 float tCenterX = centerX + c->instancer (varIdxBase, 1);
1310 float tCenterY = centerY + c->instancer (varIdxBase, 2);
1312 bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
1313 bool p2 = c->funcs->push_rotate (c->data, a);
1314 bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
1315 c->recurse (this+src);
1316 if (p3) c->funcs->pop_transform (c->data);
1317 if (p2) c->funcs->pop_transform (c->data);
1318 if (p1) c->funcs->pop_transform (c->data);
1321 HBUINT8 format; /* format = 26 (noVar) or 27(Var) */
1322 Offset24To<Paint> src; /* Offset (from beginning of PaintRotateAroundCenter table) to Paint subtable. */
1327 DEFINE_SIZE_STATIC (4 + F2DOT14::static_size + 2 * FWORD::static_size);
1332 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1334 bool subset (hb_subset_context_t *c,
1335 const VarStoreInstancer &instancer,
1336 uint32_t varIdxBase) const
1338 TRACE_SUBSET (this);
1339 auto *out = c->serializer->embed (this);
1340 if (unlikely (!out)) return_trace (false);
1342 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1344 out->xSkewAngle.set_float (xSkewAngle.to_float (instancer (varIdxBase, 0)));
1345 out->ySkewAngle.set_float (ySkewAngle.to_float (instancer (varIdxBase, 1)));
1348 if (format == 29 && c->plan->all_axes_pinned)
1351 return_trace (out->src.serialize_subset (c, src, this, instancer));
1354 bool sanitize (hb_sanitize_context_t *c) const
1356 TRACE_SANITIZE (this);
1357 return_trace (c->check_struct (this) && src.sanitize (c, this));
1360 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1363 float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
1364 float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
1366 bool p1 = c->funcs->push_skew (c->data, sx, sy);
1367 c->recurse (this+src);
1368 if (p1) c->funcs->pop_transform (c->data);
1371 HBUINT8 format; /* format = 28(noVar) or 29 (Var) */
1372 Offset24To<Paint> src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */
1376 DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size);
1379 struct PaintSkewAroundCenter
1381 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1383 bool subset (hb_subset_context_t *c,
1384 const VarStoreInstancer &instancer,
1385 uint32_t varIdxBase) const
1387 TRACE_SUBSET (this);
1388 auto *out = c->serializer->embed (this);
1389 if (unlikely (!out)) return_trace (false);
1391 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1393 out->xSkewAngle.set_float (xSkewAngle.to_float (instancer (varIdxBase, 0)));
1394 out->ySkewAngle.set_float (ySkewAngle.to_float (instancer (varIdxBase, 1)));
1395 out->centerX = centerX + (int) roundf (instancer (varIdxBase, 2));
1396 out->centerY = centerY + (int) roundf (instancer (varIdxBase, 3));
1399 if (format == 31 && c->plan->all_axes_pinned)
1402 return_trace (out->src.serialize_subset (c, src, this, instancer));
1405 bool sanitize (hb_sanitize_context_t *c) const
1407 TRACE_SANITIZE (this);
1408 return_trace (c->check_struct (this) && src.sanitize (c, this));
1411 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1414 float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
1415 float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
1416 float tCenterX = centerX + c->instancer (varIdxBase, 2);
1417 float tCenterY = centerY + c->instancer (varIdxBase, 3);
1419 bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
1420 bool p2 = c->funcs->push_skew (c->data, sx, sy);
1421 bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
1422 c->recurse (this+src);
1423 if (p3) c->funcs->pop_transform (c->data);
1424 if (p2) c->funcs->pop_transform (c->data);
1425 if (p1) c->funcs->pop_transform (c->data);
1428 HBUINT8 format; /* format = 30(noVar) or 31 (Var) */
1429 Offset24To<Paint> src; /* Offset (from beginning of PaintSkewAroundCenter table) to Paint subtable. */
1435 DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size + 2 * FWORD::static_size);
1438 struct PaintComposite
1440 void closurev1 (hb_colrv1_closure_context_t* c) const;
1442 bool subset (hb_subset_context_t *c,
1443 const VarStoreInstancer &instancer) const
1445 TRACE_SUBSET (this);
1446 auto *out = c->serializer->embed (this);
1447 if (unlikely (!out)) return_trace (false);
1450 ret |= out->src.serialize_subset (c, src, this, instancer);
1451 ret |= out->backdrop.serialize_subset (c, backdrop, this, instancer);
1455 bool sanitize (hb_sanitize_context_t *c) const
1457 TRACE_SANITIZE (this);
1458 return_trace (c->check_struct (this) &&
1459 c->check_ops (this->min_size) && // PainComposite can get exponential
1460 src.sanitize (c, this) &&
1461 backdrop.sanitize (c, this));
1464 void paint_glyph (hb_paint_context_t *c) const
1467 c->recurse (this+backdrop);
1468 c->funcs->push_group (c->data);
1469 c->recurse (this+src);
1470 c->funcs->pop_group (c->data, (hb_paint_composite_mode_t) (int) mode);
1473 HBUINT8 format; /* format = 32 */
1474 Offset24To<Paint> src; /* Offset (from beginning of PaintComposite table) to source Paint subtable. */
1475 CompositeMode mode; /* If mode is unrecognized use COMPOSITE_CLEAR */
1476 Offset24To<Paint> backdrop; /* Offset (from beginning of PaintComposite table) to backdrop Paint subtable. */
1478 DEFINE_SIZE_STATIC (8);
1483 int xMin, yMin, xMax, yMax;
1486 struct ClipBoxFormat1
1488 bool sanitize (hb_sanitize_context_t *c) const
1490 TRACE_SANITIZE (this);
1491 return_trace (c->check_struct (this));
1494 void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer HB_UNUSED) const
1496 clip_box.xMin = xMin;
1497 clip_box.yMin = yMin;
1498 clip_box.xMax = xMax;
1499 clip_box.yMax = yMax;
1502 bool subset (hb_subset_context_t *c,
1503 const VarStoreInstancer &instancer,
1504 uint32_t varIdxBase) const
1506 TRACE_SUBSET (this);
1507 auto *out = c->serializer->embed (*this);
1508 if (unlikely (!out)) return_trace (false);
1510 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1512 out->xMin = xMin + (int) roundf (instancer (varIdxBase, 0));
1513 out->yMin = yMin + (int) roundf (instancer (varIdxBase, 1));
1514 out->xMax = xMax + (int) roundf (instancer (varIdxBase, 2));
1515 out->yMax = yMax + (int) roundf (instancer (varIdxBase, 3));
1518 if (format == 2 && c->plan->all_axes_pinned)
1521 return_trace (true);
1525 HBUINT8 format; /* format = 1(noVar) or 2(Var)*/
1531 DEFINE_SIZE_STATIC (1 + 4 * FWORD::static_size);
1534 struct ClipBoxFormat2 : Variable<ClipBoxFormat1>
1536 void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer) const
1538 value.get_clip_box(clip_box, instancer);
1541 clip_box.xMin += roundf (instancer (varIdxBase, 0));
1542 clip_box.yMin += roundf (instancer (varIdxBase, 1));
1543 clip_box.xMax += roundf (instancer (varIdxBase, 2));
1544 clip_box.yMax += roundf (instancer (varIdxBase, 3));
1551 bool subset (hb_subset_context_t *c,
1552 const VarStoreInstancer &instancer) const
1554 TRACE_SUBSET (this);
1556 case 1: return_trace (u.format1.subset (c, instancer, VarIdx::NO_VARIATION));
1557 case 2: return_trace (u.format2.subset (c, instancer));
1558 default:return_trace (c->default_return_value ());
1562 template <typename context_t, typename ...Ts>
1563 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1565 if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
1566 TRACE_DISPATCH (this, u.format);
1568 case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
1569 case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
1570 default:return_trace (c->default_return_value ());
1574 bool get_extents (hb_glyph_extents_t *extents,
1575 const VarStoreInstancer &instancer) const
1577 ClipBoxData clip_box;
1580 u.format1.get_clip_box (clip_box, instancer);
1583 u.format2.get_clip_box (clip_box, instancer);
1589 extents->x_bearing = clip_box.xMin;
1590 extents->y_bearing = clip_box.yMax;
1591 extents->width = clip_box.xMax - clip_box.xMin;
1592 extents->height = clip_box.yMin - clip_box.yMax;
1598 HBUINT8 format; /* Format identifier */
1599 ClipBoxFormat1 format1;
1600 ClipBoxFormat2 format2;
1606 int cmp (hb_codepoint_t g) const
1607 { return g < startGlyphID ? -1 : g <= endGlyphID ? 0 : +1; }
1609 bool subset (hb_subset_context_t *c,
1611 const VarStoreInstancer &instancer) const
1613 TRACE_SUBSET (this);
1614 auto *out = c->serializer->embed (*this);
1615 if (unlikely (!out)) return_trace (false);
1617 return_trace (out->clipBox.serialize_subset (c, clipBox, base, instancer));
1620 bool sanitize (hb_sanitize_context_t *c, const void *base) const
1622 TRACE_SANITIZE (this);
1623 return_trace (c->check_struct (this) && clipBox.sanitize (c, base));
1626 bool get_extents (hb_glyph_extents_t *extents,
1628 const VarStoreInstancer &instancer) const
1630 return (base+clipBox).get_extents (extents, instancer);
1634 HBUINT16 startGlyphID; // first gid clip applies to
1635 HBUINT16 endGlyphID; // last gid clip applies to, inclusive
1636 Offset24To<ClipBox> clipBox; // Box or VarBox
1638 DEFINE_SIZE_STATIC (7);
1640 DECLARE_NULL_NAMESPACE_BYTES (OT, ClipRecord);
1644 unsigned serialize_clip_records (hb_subset_context_t *c,
1645 const VarStoreInstancer &instancer,
1646 const hb_set_t& gids,
1647 const hb_map_t& gid_offset_map) const
1649 TRACE_SERIALIZE (this);
1650 if (gids.is_empty () ||
1651 gid_offset_map.get_population () != gids.get_population ())
1656 hb_codepoint_t start_gid= gids.get_min ();
1657 hb_codepoint_t prev_gid = start_gid;
1659 unsigned offset = gid_offset_map.get (start_gid);
1660 unsigned prev_offset = offset;
1661 for (const hb_codepoint_t _ : gids.iter ())
1663 if (_ == start_gid) continue;
1665 offset = gid_offset_map.get (_);
1666 if (_ == prev_gid + 1 && offset == prev_offset)
1673 record.startGlyphID = start_gid;
1674 record.endGlyphID = prev_gid;
1675 record.clipBox = prev_offset;
1677 if (!record.subset (c, this, instancer)) return_trace (0);
1682 prev_offset = offset;
1688 record.startGlyphID = start_gid;
1689 record.endGlyphID = prev_gid;
1690 record.clipBox = prev_offset;
1691 if (!record.subset (c, this, instancer)) return_trace (0);
1694 return_trace (count);
1697 bool subset (hb_subset_context_t *c,
1698 const VarStoreInstancer &instancer) const
1700 TRACE_SUBSET (this);
1701 auto *out = c->serializer->start_embed (*this);
1702 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
1703 if (!c->serializer->check_assign (out->format, format, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
1705 const hb_set_t& glyphset = c->plan->_glyphset_colred;
1706 const hb_map_t &glyph_map = *c->plan->glyph_map;
1708 hb_map_t new_gid_offset_map;
1710 for (const ClipRecord& record : clips.iter ())
1712 unsigned start_gid = record.startGlyphID;
1713 unsigned end_gid = record.endGlyphID;
1714 for (unsigned gid = start_gid; gid <= end_gid; gid++)
1716 if (!glyphset.has (gid) || !glyph_map.has (gid)) continue;
1717 unsigned new_gid = glyph_map.get (gid);
1718 new_gid_offset_map.set (new_gid, record.clipBox);
1719 new_gids.add (new_gid);
1723 unsigned count = serialize_clip_records (c, instancer, new_gids, new_gid_offset_map);
1724 if (!count) return_trace (false);
1725 return_trace (c->serializer->check_assign (out->clips.len, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
1728 bool sanitize (hb_sanitize_context_t *c) const
1730 TRACE_SANITIZE (this);
1731 // TODO Make a formatted struct!
1732 return_trace (c->check_struct (this) && clips.sanitize (c, this));
1736 get_extents (hb_codepoint_t gid,
1737 hb_glyph_extents_t *extents,
1738 const VarStoreInstancer &instancer) const
1740 auto *rec = clips.as_array ().bsearch (gid);
1743 rec->get_extents (extents, this, instancer);
1749 HBUINT8 format; // Set to 1.
1750 SortedArray32Of<ClipRecord> clips; // Clip records, sorted by startGlyphID
1752 DEFINE_SIZE_ARRAY_SIZED (5, clips);
1758 template <typename ...Ts>
1759 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
1761 TRACE_SANITIZE (this);
1763 if (unlikely (!c->check_start_recursion (HB_MAX_NESTING_LEVEL)))
1764 return_trace (c->no_dispatch_return_value ());
1766 return_trace (c->end_recursion (this->dispatch (c, std::forward<Ts> (ds)...)));
1769 template <typename context_t, typename ...Ts>
1770 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1772 if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
1773 TRACE_DISPATCH (this, u.format);
1775 case 1: return_trace (c->dispatch (u.paintformat1, std::forward<Ts> (ds)...));
1776 case 2: return_trace (c->dispatch (u.paintformat2, std::forward<Ts> (ds)...));
1777 case 3: return_trace (c->dispatch (u.paintformat3, std::forward<Ts> (ds)...));
1778 case 4: return_trace (c->dispatch (u.paintformat4, std::forward<Ts> (ds)...));
1779 case 5: return_trace (c->dispatch (u.paintformat5, std::forward<Ts> (ds)...));
1780 case 6: return_trace (c->dispatch (u.paintformat6, std::forward<Ts> (ds)...));
1781 case 7: return_trace (c->dispatch (u.paintformat7, std::forward<Ts> (ds)...));
1782 case 8: return_trace (c->dispatch (u.paintformat8, std::forward<Ts> (ds)...));
1783 case 9: return_trace (c->dispatch (u.paintformat9, std::forward<Ts> (ds)...));
1784 case 10: return_trace (c->dispatch (u.paintformat10, std::forward<Ts> (ds)...));
1785 case 11: return_trace (c->dispatch (u.paintformat11, std::forward<Ts> (ds)...));
1786 case 12: return_trace (c->dispatch (u.paintformat12, std::forward<Ts> (ds)...));
1787 case 13: return_trace (c->dispatch (u.paintformat13, std::forward<Ts> (ds)...));
1788 case 14: return_trace (c->dispatch (u.paintformat14, std::forward<Ts> (ds)...));
1789 case 15: return_trace (c->dispatch (u.paintformat15, std::forward<Ts> (ds)...));
1790 case 16: return_trace (c->dispatch (u.paintformat16, std::forward<Ts> (ds)...));
1791 case 17: return_trace (c->dispatch (u.paintformat17, std::forward<Ts> (ds)...));
1792 case 18: return_trace (c->dispatch (u.paintformat18, std::forward<Ts> (ds)...));
1793 case 19: return_trace (c->dispatch (u.paintformat19, std::forward<Ts> (ds)...));
1794 case 20: return_trace (c->dispatch (u.paintformat20, std::forward<Ts> (ds)...));
1795 case 21: return_trace (c->dispatch (u.paintformat21, std::forward<Ts> (ds)...));
1796 case 22: return_trace (c->dispatch (u.paintformat22, std::forward<Ts> (ds)...));
1797 case 23: return_trace (c->dispatch (u.paintformat23, std::forward<Ts> (ds)...));
1798 case 24: return_trace (c->dispatch (u.paintformat24, std::forward<Ts> (ds)...));
1799 case 25: return_trace (c->dispatch (u.paintformat25, std::forward<Ts> (ds)...));
1800 case 26: return_trace (c->dispatch (u.paintformat26, std::forward<Ts> (ds)...));
1801 case 27: return_trace (c->dispatch (u.paintformat27, std::forward<Ts> (ds)...));
1802 case 28: return_trace (c->dispatch (u.paintformat28, std::forward<Ts> (ds)...));
1803 case 29: return_trace (c->dispatch (u.paintformat29, std::forward<Ts> (ds)...));
1804 case 30: return_trace (c->dispatch (u.paintformat30, std::forward<Ts> (ds)...));
1805 case 31: return_trace (c->dispatch (u.paintformat31, std::forward<Ts> (ds)...));
1806 case 32: return_trace (c->dispatch (u.paintformat32, std::forward<Ts> (ds)...));
1807 default:return_trace (c->default_return_value ());
1814 PaintColrLayers paintformat1;
1815 NoVariable<PaintSolid> paintformat2;
1816 Variable<PaintSolid> paintformat3;
1817 NoVariable<PaintLinearGradient<NoVariable>> paintformat4;
1818 Variable<PaintLinearGradient<Variable>> paintformat5;
1819 NoVariable<PaintRadialGradient<NoVariable>> paintformat6;
1820 Variable<PaintRadialGradient<Variable>> paintformat7;
1821 NoVariable<PaintSweepGradient<NoVariable>> paintformat8;
1822 Variable<PaintSweepGradient<Variable>> paintformat9;
1823 PaintGlyph paintformat10;
1824 PaintColrGlyph paintformat11;
1825 PaintTransform<NoVariable> paintformat12;
1826 PaintTransform<Variable> paintformat13;
1827 NoVariable<PaintTranslate> paintformat14;
1828 Variable<PaintTranslate> paintformat15;
1829 NoVariable<PaintScale> paintformat16;
1830 Variable<PaintScale> paintformat17;
1831 NoVariable<PaintScaleAroundCenter> paintformat18;
1832 Variable<PaintScaleAroundCenter> paintformat19;
1833 NoVariable<PaintScaleUniform> paintformat20;
1834 Variable<PaintScaleUniform> paintformat21;
1835 NoVariable<PaintScaleUniformAroundCenter> paintformat22;
1836 Variable<PaintScaleUniformAroundCenter> paintformat23;
1837 NoVariable<PaintRotate> paintformat24;
1838 Variable<PaintRotate> paintformat25;
1839 NoVariable<PaintRotateAroundCenter> paintformat26;
1840 Variable<PaintRotateAroundCenter> paintformat27;
1841 NoVariable<PaintSkew> paintformat28;
1842 Variable<PaintSkew> paintformat29;
1843 NoVariable<PaintSkewAroundCenter> paintformat30;
1844 Variable<PaintSkewAroundCenter> paintformat31;
1845 PaintComposite paintformat32;
1848 DEFINE_SIZE_MIN (2);
1851 struct BaseGlyphPaintRecord
1853 int cmp (hb_codepoint_t g) const
1854 { return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
1856 bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map,
1857 const void* src_base, hb_subset_context_t *c,
1858 const VarStoreInstancer &instancer) const
1860 TRACE_SERIALIZE (this);
1861 auto *out = s->embed (this);
1862 if (unlikely (!out)) return_trace (false);
1863 if (!s->check_assign (out->glyphId, glyph_map->get (glyphId),
1864 HB_SERIALIZE_ERROR_INT_OVERFLOW))
1865 return_trace (false);
1867 return_trace (out->paint.serialize_subset (c, paint, src_base, instancer));
1870 bool sanitize (hb_sanitize_context_t *c, const void *base) const
1872 TRACE_SANITIZE (this);
1873 return_trace (likely (c->check_struct (this) && paint.sanitize (c, base)));
1877 HBGlyphID16 glyphId; /* Glyph ID of reference glyph */
1878 Offset32To<Paint> paint; /* Offset (from beginning of BaseGlyphPaintRecord array) to Paint,
1879 * Typically PaintColrLayers */
1881 DEFINE_SIZE_STATIC (6);
1884 struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
1886 bool subset (hb_subset_context_t *c,
1887 const VarStoreInstancer &instancer) const
1889 TRACE_SUBSET (this);
1890 auto *out = c->serializer->start_embed (this);
1891 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
1892 const hb_set_t* glyphset = &c->plan->_glyphset_colred;
1894 for (const auto& _ : as_array ())
1896 unsigned gid = _.glyphId;
1897 if (!glyphset->has (gid)) continue;
1899 if (_.serialize (c->serializer, c->plan->glyph_map, this, c, instancer)) out->len++;
1900 else return_trace (false);
1903 return_trace (out->len != 0);
1906 bool sanitize (hb_sanitize_context_t *c) const
1908 TRACE_SANITIZE (this);
1909 return_trace (SortedArray32Of<BaseGlyphPaintRecord>::sanitize (c, this));
1913 struct LayerList : Array32OfOffset32To<Paint>
1915 const Paint& get_paint (unsigned i) const
1916 { return this+(*this)[i]; }
1918 bool subset (hb_subset_context_t *c,
1919 const VarStoreInstancer &instancer) const
1921 TRACE_SUBSET (this);
1922 auto *out = c->serializer->start_embed (this);
1923 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
1926 for (const auto& _ : + hb_enumerate (*this)
1927 | hb_filter (c->plan->colrv1_layers, hb_first))
1930 auto *o = out->serialize_append (c->serializer);
1931 if (unlikely (!o)) return_trace (false);
1932 ret |= o->serialize_subset (c, _.second, this, instancer);
1937 bool sanitize (hb_sanitize_context_t *c) const
1939 TRACE_SANITIZE (this);
1940 return_trace (Array32OfOffset32To<Paint>::sanitize (c, this));
1946 static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
1948 bool has_v0_data () const { return numBaseGlyphs; }
1949 bool has_v1_data () const
1952 return (this+baseGlyphList).len > 0;
1957 unsigned int get_glyph_layers (hb_codepoint_t glyph,
1958 unsigned int start_offset,
1959 unsigned int *count, /* IN/OUT. May be NULL. */
1960 hb_ot_color_layer_t *layers /* OUT. May be NULL. */) const
1962 const BaseGlyphRecord &record = (this+baseGlyphsZ).bsearch (numBaseGlyphs, glyph);
1964 hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
1965 hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
1969 + glyph_layers.sub_array (start_offset, count)
1970 | hb_sink (hb_array (layers, *count))
1973 return glyph_layers.length;
1976 struct accelerator_t
1978 accelerator_t (hb_face_t *face)
1979 { colr = hb_sanitize_context_t ().reference_table<COLR> (face); }
1980 ~accelerator_t () { this->colr.destroy (); }
1982 bool is_valid () { return colr.get_blob ()->length; }
1984 void closure_glyphs (hb_codepoint_t glyph,
1985 hb_set_t *related_ids /* OUT */) const
1986 { colr->closure_glyphs (glyph, related_ids); }
1988 void closure_V0palette_indices (const hb_set_t *glyphs,
1989 hb_set_t *palettes /* OUT */) const
1990 { colr->closure_V0palette_indices (glyphs, palettes); }
1992 void closure_forV1 (hb_set_t *glyphset,
1993 hb_set_t *layer_indices,
1994 hb_set_t *palette_indices) const
1995 { colr->closure_forV1 (glyphset, layer_indices, palette_indices); }
1998 hb_blob_ptr_t<COLR> colr;
2001 void closure_glyphs (hb_codepoint_t glyph,
2002 hb_set_t *related_ids /* OUT */) const
2004 const BaseGlyphRecord *record = get_base_glyph_record (glyph);
2005 if (!record) return;
2007 auto glyph_layers = (this+layersZ).as_array (numLayers).sub_array (record->firstLayerIdx,
2009 if (!glyph_layers.length) return;
2010 related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size);
2013 void closure_V0palette_indices (const hb_set_t *glyphs,
2014 hb_set_t *palettes /* OUT */) const
2016 if (!numBaseGlyphs || !numLayers) return;
2017 hb_array_t<const BaseGlyphRecord> baseGlyphs = (this+baseGlyphsZ).as_array (numBaseGlyphs);
2018 hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
2020 for (const BaseGlyphRecord record : baseGlyphs)
2022 if (!glyphs->has (record.glyphId)) continue;
2023 hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
2025 for (const LayerRecord layer : glyph_layers)
2026 palettes->add (layer.colorIdx);
2030 void closure_forV1 (hb_set_t *glyphset,
2031 hb_set_t *layer_indices,
2032 hb_set_t *palette_indices) const
2034 if (version != 1) return;
2035 hb_set_t visited_glyphs;
2037 hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices);
2038 const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList;
2040 for (const BaseGlyphPaintRecord &baseglyph_paintrecord: baseglyph_paintrecords.iter ())
2042 unsigned gid = baseglyph_paintrecord.glyphId;
2043 if (!glyphset->has (gid)) continue;
2045 const Paint &paint = &baseglyph_paintrecords+baseglyph_paintrecord.paint;
2046 paint.dispatch (&c);
2048 hb_set_union (glyphset, &visited_glyphs);
2051 const LayerList& get_layerList () const
2052 { return (this+layerList); }
2054 const BaseGlyphList& get_baseglyphList () const
2055 { return (this+baseGlyphList); }
2057 bool sanitize (hb_sanitize_context_t *c) const
2059 TRACE_SANITIZE (this);
2060 return_trace (c->check_struct (this) &&
2061 (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
2062 (this+layersZ).sanitize (c, numLayers) &&
2065 baseGlyphList.sanitize (c, this) &&
2066 layerList.sanitize (c, this) &&
2067 clipList.sanitize (c, this) &&
2068 varIdxMap.sanitize (c, this) &&
2069 varStore.sanitize (c, this))));
2072 template<typename BaseIterator, typename LayerIterator,
2073 hb_requires (hb_is_iterator (BaseIterator)),
2074 hb_requires (hb_is_iterator (LayerIterator))>
2075 bool serialize_V0 (hb_serialize_context_t *c,
2077 BaseIterator base_it,
2078 LayerIterator layer_it)
2080 TRACE_SERIALIZE (this);
2081 if (unlikely (base_it.len () != layer_it.len ()))
2082 return_trace (false);
2084 this->version = version;
2086 numBaseGlyphs = base_it.len ();
2087 if (numBaseGlyphs == 0)
2091 return_trace (true);
2095 for (const hb_item_type<BaseIterator> _ : + base_it.iter ())
2097 auto* record = c->embed (_);
2098 if (unlikely (!record)) return_trace (false);
2099 record->firstLayerIdx = numLayers;
2100 numLayers += record->numLayers;
2102 c->add_link (baseGlyphsZ, c->pop_pack ());
2105 for (const hb_item_type<LayerIterator>& _ : + layer_it.iter ())
2106 _.as_array ().copy (c);
2108 c->add_link (layersZ, c->pop_pack ());
2110 return_trace (true);
2113 const BaseGlyphRecord* get_base_glyph_record (hb_codepoint_t gid) const
2115 const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, (unsigned int) gid);
2116 if (record == &Null (BaseGlyphRecord) ||
2117 (record && (hb_codepoint_t) record->glyphId != gid))
2122 const BaseGlyphPaintRecord* get_base_glyph_paintrecord (hb_codepoint_t gid) const
2124 const BaseGlyphPaintRecord* record = &(this+baseGlyphList).bsearch ((unsigned) gid);
2125 if ((record && (hb_codepoint_t) record->glyphId != gid))
2130 bool subset (hb_subset_context_t *c) const
2132 TRACE_SUBSET (this);
2133 const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
2134 const hb_set_t& glyphset = c->plan->_glyphset_colred;
2137 + hb_range (c->plan->num_output_glyphs ())
2138 | hb_filter ([&](hb_codepoint_t new_gid)
2140 hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
2141 if (glyphset.has (old_gid)) return true;
2144 | hb_map_retains_sorting ([&](hb_codepoint_t new_gid)
2146 hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
2148 const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
2149 if (unlikely (!old_record))
2150 return hb_pair_t<bool, BaseGlyphRecord> (false, Null (BaseGlyphRecord));
2151 BaseGlyphRecord new_record = {};
2152 new_record.glyphId = new_gid;
2153 new_record.numLayers = old_record->numLayers;
2154 return hb_pair_t<bool, BaseGlyphRecord> (true, new_record);
2156 | hb_filter (hb_first)
2157 | hb_map_retains_sorting (hb_second)
2161 + hb_range (c->plan->num_output_glyphs ())
2162 | hb_map (reverse_glyph_map)
2163 | hb_filter (glyphset)
2164 | hb_map_retains_sorting ([&](hb_codepoint_t old_gid)
2166 const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
2167 hb_vector_t<LayerRecord> out_layers;
2169 if (unlikely (!old_record ||
2170 old_record->firstLayerIdx >= numLayers ||
2171 old_record->firstLayerIdx + old_record->numLayers > numLayers))
2172 return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
2174 auto layers = (this+layersZ).as_array (numLayers).sub_array (old_record->firstLayerIdx,
2175 old_record->numLayers);
2176 out_layers.resize (layers.length);
2177 for (unsigned int i = 0; i < layers.length; i++) {
2178 out_layers[i] = layers[i];
2179 hb_codepoint_t new_gid = 0;
2180 if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid)))
2181 return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
2182 out_layers[i].glyphId = new_gid;
2183 out_layers[i].colorIdx = c->plan->colr_palettes.get (layers[i].colorIdx);
2186 return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers);
2188 | hb_filter (hb_first)
2189 | hb_map_retains_sorting (hb_second)
2192 if (version == 0 && (!base_it || !layer_it))
2193 return_trace (false);
2195 auto *colr_prime = c->serializer->start_embed<COLR> ();
2196 if (unlikely (!c->serializer->extend_min (colr_prime))) return_trace (false);
2199 return_trace (colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it));
2201 auto snap = c->serializer->snapshot ();
2202 if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false);
2204 VarStoreInstancer instancer (varStore ? &(this+varStore) : nullptr,
2205 varIdxMap ? &(this+varIdxMap) : nullptr,
2206 c->plan->normalized_coords.as_array ());
2208 if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this, instancer))
2210 if (c->serializer->in_error ()) return_trace (false);
2211 //no more COLRv1 glyphs: downgrade to version 0
2212 c->serializer->revert (snap);
2213 return_trace (colr_prime->serialize_V0 (c->serializer, 0, base_it, layer_it));
2216 if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false);
2218 colr_prime->layerList.serialize_subset (c, layerList, this, instancer);
2219 colr_prime->clipList.serialize_subset (c, clipList, this, instancer);
2220 if (!varStore || c->plan->all_axes_pinned)
2221 return_trace (true);
2223 colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this);
2224 colr_prime->varStore.serialize_copy (c->serializer, varStore, this);
2225 return_trace (true);
2228 const Paint *get_base_glyph_paint (hb_codepoint_t glyph) const
2230 const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList;
2231 const BaseGlyphPaintRecord* record = get_base_glyph_paintrecord (glyph);
2234 const Paint &paint = &baseglyph_paintrecords+record->paint;
2243 get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
2248 VarStoreInstancer instancer (&(this+varStore),
2250 hb_array (font->coords, font->num_coords));
2252 if (get_clip (glyph, extents, instancer))
2254 font->scale_glyph_extents (extents);
2258 auto *extents_funcs = hb_paint_extents_get_funcs ();
2259 hb_paint_extents_context_t extents_data;
2260 bool ret = paint_glyph (font, glyph, extents_funcs, &extents_data, 0, HB_COLOR(0,0,0,0));
2262 hb_extents_t e = extents_data.get_extents ();
2265 extents->x_bearing = 0;
2266 extents->y_bearing = 0;
2268 extents->height = 0;
2272 extents->x_bearing = e.xmin;
2273 extents->y_bearing = e.ymax;
2274 extents->width = e.xmax - e.xmin;
2275 extents->height = e.ymin - e.ymax;
2283 has_paint_for_glyph (hb_codepoint_t glyph) const
2287 const Paint *paint = get_base_glyph_paint (glyph);
2289 return paint != nullptr;
2295 bool get_clip (hb_codepoint_t glyph,
2296 hb_glyph_extents_t *extents,
2297 const VarStoreInstancer instancer) const
2299 return (this+clipList).get_extents (glyph,
2306 paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const
2308 VarStoreInstancer instancer (&(this+varStore),
2310 hb_array (font->coords, font->num_coords));
2311 hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer);
2312 c.current_glyphs.add (glyph);
2316 const Paint *paint = get_base_glyph_paint (glyph);
2321 VarStoreInstancer instancer (&(this+varStore),
2323 hb_array (font->coords, font->num_coords));
2325 bool is_bounded = true;
2328 hb_glyph_extents_t extents;
2329 if (get_clip (glyph, &extents, instancer))
2331 font->scale_glyph_extents (&extents);
2332 c.funcs->push_clip_rectangle (c.data,
2334 extents.y_bearing + extents.height,
2335 extents.x_bearing + extents.width,
2340 auto *extents_funcs = hb_paint_extents_get_funcs ();
2341 hb_paint_extents_context_t extents_data;
2343 paint_glyph (font, glyph,
2344 extents_funcs, &extents_data,
2345 palette_index, foreground,
2348 hb_extents_t extents = extents_data.get_extents ();
2349 is_bounded = extents_data.is_bounded ();
2351 c.funcs->push_clip_rectangle (c.data,
2359 c.funcs->push_root_transform (c.data, font);
2364 c.funcs->pop_transform (c.data);
2367 c.funcs->pop_clip (c.data);
2373 const BaseGlyphRecord *record = get_base_glyph_record (glyph);
2374 if (record && ((hb_codepoint_t) record->glyphId == glyph))
2377 for (const auto &r : (this+layersZ).as_array (numLayers)
2378 .sub_array (record->firstLayerIdx, record->numLayers))
2380 hb_bool_t is_foreground;
2381 hb_color_t color = c.get_color (r.colorIdx, 1., &is_foreground);
2382 c.funcs->push_clip_glyph (c.data, r.glyphId, c.font);
2383 c.funcs->color (c.data, is_foreground, color);
2384 c.funcs->pop_clip (c.data);
2395 HBUINT16 version; /* Table version number (starts at 0). */
2396 HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records. */
2397 NNOffset32To<SortedUnsizedArrayOf<BaseGlyphRecord>>
2398 baseGlyphsZ; /* Offset to Base Glyph records. */
2399 NNOffset32To<UnsizedArrayOf<LayerRecord>>
2400 layersZ; /* Offset to Layer Records. */
2401 HBUINT16 numLayers; /* Number of Layer Records. */
2402 // Version-1 additions
2403 Offset32To<BaseGlyphList> baseGlyphList;
2404 Offset32To<LayerList> layerList;
2405 Offset32To<ClipList> clipList; // Offset to ClipList table (may be NULL)
2406 Offset32To<DeltaSetIndexMap> varIdxMap; // Offset to DeltaSetIndexMap table (may be NULL)
2407 Offset32To<VariationStore> varStore;
2409 DEFINE_SIZE_MIN (14);
2412 struct COLR_accelerator_t : COLR::accelerator_t {
2413 COLR_accelerator_t (hb_face_t *face) : COLR::accelerator_t (face) {}
2417 hb_paint_context_t::recurse (const Paint &paint)
2419 if (unlikely (depth_left <= 0 || edge_count <= 0)) return;
2422 paint.dispatch (this);
2426 void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const
2429 const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList ();
2430 for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++)
2432 if (unlikely (c->current_layers.has (i)))
2435 c->current_layers.add (i);
2437 const Paint &paint = paint_offset_lists.get_paint (i);
2438 c->funcs->push_group (c->data);
2440 c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
2442 c->current_layers.del (i);
2446 void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
2450 if (unlikely (c->current_glyphs.has (gid)))
2453 c->current_glyphs.add (gid);
2455 c->funcs->push_inverse_root_transform (c->data, c->font);
2456 if (c->funcs->color_glyph (c->data, gid, c->font))
2458 c->funcs->pop_transform (c->data);
2459 c->current_glyphs.del (gid);
2462 c->funcs->pop_transform (c->data);
2464 const COLR *colr_table = c->get_colr_table ();
2465 const Paint *paint = colr_table->get_base_glyph_paint (gid);
2467 hb_glyph_extents_t extents = {0};
2468 bool has_clip_box = colr_table->get_clip (gid, &extents, c->instancer);
2471 c->funcs->push_clip_rectangle (c->data,
2473 extents.y_bearing + extents.height,
2474 extents.x_bearing + extents.width,
2478 c->recurse (*paint);
2481 c->funcs->pop_clip (c->data);
2483 c->current_glyphs.del (gid);
2486 } /* namespace OT */
2488 #endif /* OT_COLOR_COLR_COLR_HH */