xref: /aosp_15_r20/external/harfbuzz_ng/src/OT/Color/COLR/COLR.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
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 OT_COLOR_COLR_COLR_HH
29 #define OT_COLOR_COLR_COLR_HH
30 
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"
36 
37 /*
38  * COLR -- Color
39  * https://docs.microsoft.com/en-us/typography/opentype/spec/colr
40  */
41 #define HB_OT_TAG_COLR HB_TAG('C','O','L','R')
42 
43 namespace OT {
44 struct hb_paint_context_t;
45 }
46 
47 namespace OT {
48 
49 struct COLR;
50 
51 struct Paint;
52 
53 struct hb_paint_context_t :
54        hb_dispatch_context_t<hb_paint_context_t>
55 {
get_nameOT::hb_paint_context_t56   const char *get_name () { return "PAINT"; }
57   template <typename T>
dispatchOT::hb_paint_context_t58   return_t dispatch (const T &obj) { obj.paint_glyph (this); return hb_empty_t (); }
default_return_valueOT::hb_paint_context_t59   static return_t default_return_value () { return hb_empty_t (); }
60 
get_colr_tableOT::hb_paint_context_t61   const COLR* get_colr_table () const
62   { return reinterpret_cast<const COLR *> (base); }
63 
64 public:
65   const void *base;
66   hb_paint_funcs_t *funcs;
67   void *data;
68   hb_font_t *font;
69   unsigned int palette_index;
70   hb_color_t foreground;
71   ItemVarStoreInstancer &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_MAX_GRAPH_EDGE_COUNT;
76 
hb_paint_context_tOT::hb_paint_context_t77   hb_paint_context_t (const void *base_,
78 		      hb_paint_funcs_t *funcs_,
79 		      void *data_,
80                       hb_font_t *font_,
81                       unsigned int palette_,
82                       hb_color_t foreground_,
83 		      ItemVarStoreInstancer &instancer_) :
84     base (base_),
85     funcs (funcs_),
86     data (data_),
87     font (font_),
88     palette_index (palette_),
89     foreground (foreground_),
90     instancer (instancer_)
91   { }
92 
get_colorOT::hb_paint_context_t93   hb_color_t get_color (unsigned int color_index, float alpha, hb_bool_t *is_foreground)
94   {
95     hb_color_t color = foreground;
96 
97     *is_foreground = true;
98 
99     if (color_index != 0xffff)
100     {
101       if (!funcs->custom_palette_color (data, color_index, &color))
102       {
103 	unsigned int clen = 1;
104 	hb_face_t *face = hb_font_get_face (font);
105 
106 	hb_ot_color_palette_get_colors (face, palette_index, color_index, &clen, &color);
107       }
108 
109       *is_foreground = false;
110     }
111 
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);
116   }
117 
118   inline void recurse (const Paint &paint);
119 };
120 
121 struct hb_colrv1_closure_context_t :
122        hb_dispatch_context_t<hb_colrv1_closure_context_t>
123 {
124   template <typename T>
dispatchOT::hb_colrv1_closure_context_t125   return_t dispatch (const T &obj)
126   {
127     if (unlikely (nesting_level_left == 0))
128       return hb_empty_t ();
129 
130     if (paint_visited (&obj))
131       return hb_empty_t ();
132 
133     nesting_level_left--;
134     obj.closurev1 (this);
135     nesting_level_left++;
136     return hb_empty_t ();
137   }
default_return_valueOT::hb_colrv1_closure_context_t138   static return_t default_return_value () { return hb_empty_t (); }
139 
paint_visitedOT::hb_colrv1_closure_context_t140   bool paint_visited (const void *paint)
141   {
142     hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) paint - (uintptr_t) base);
143     if (visited_paint.in_error() || visited_paint.has (delta))
144       return true;
145 
146     visited_paint.add (delta);
147     return false;
148   }
149 
get_colr_tableOT::hb_colrv1_closure_context_t150   const COLR* get_colr_table () const
151   { return reinterpret_cast<const COLR *> (base); }
152 
add_glyphOT::hb_colrv1_closure_context_t153   void add_glyph (unsigned glyph_id)
154   { glyphs->add (glyph_id); }
155 
add_layer_indicesOT::hb_colrv1_closure_context_t156   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); }
158 
add_palette_indexOT::hb_colrv1_closure_context_t159   void add_palette_index (unsigned palette_index)
160   { palette_indices->add (palette_index); }
161 
add_var_idxesOT::hb_colrv1_closure_context_t162   void add_var_idxes (unsigned first_var_idx, unsigned num_idxes)
163   {
164     if (!num_idxes || first_var_idx == VarIdx::NO_VARIATION) return;
165     variation_indices->add_range (first_var_idx, first_var_idx + num_idxes - 1);
166   }
167 
168   public:
169   const void *base;
170   hb_set_t visited_paint;
171   hb_set_t *glyphs;
172   hb_set_t *layer_indices;
173   hb_set_t *palette_indices;
174   hb_set_t *variation_indices;
175   unsigned num_var_idxes;
176   unsigned nesting_level_left;
177 
hb_colrv1_closure_context_tOT::hb_colrv1_closure_context_t178   hb_colrv1_closure_context_t (const void *base_,
179                                hb_set_t *glyphs_,
180                                hb_set_t *layer_indices_,
181                                hb_set_t *palette_indices_,
182                                hb_set_t *variation_indices_,
183                                unsigned num_var_idxes_ = 1,
184                                unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
185                           base (base_),
186                           glyphs (glyphs_),
187                           layer_indices (layer_indices_),
188                           palette_indices (palette_indices_),
189                           variation_indices (variation_indices_),
190                           num_var_idxes (num_var_idxes_),
191                           nesting_level_left (nesting_level_left_)
192   {}
193 };
194 
195 struct LayerRecord
196 {
operator hb_ot_color_layer_tOT::LayerRecord197   operator hb_ot_color_layer_t () const { return {glyphId, colorIdx}; }
198 
sanitizeOT::LayerRecord199   bool sanitize (hb_sanitize_context_t *c) const
200   {
201     TRACE_SANITIZE (this);
202     return_trace (c->check_struct (this));
203   }
204 
205   public:
206   HBGlyphID16	glyphId;	/* Glyph ID of layer glyph */
207   Index		colorIdx;	/* Index value to use with a
208 				 * selected color palette.
209 				 * An index value of 0xFFFF
210 				 * is a special case indicating
211 				 * that the text foreground
212 				 * color (defined by a
213 				 * higher-level client) should
214 				 * be used and shall not be
215 				 * treated as actual index
216 				 * into CPAL ColorRecord array. */
217   public:
218   DEFINE_SIZE_STATIC (4);
219 };
220 
221 struct BaseGlyphRecord
222 {
cmpOT::BaseGlyphRecord223   int cmp (hb_codepoint_t g) const
224   { return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
225 
sanitizeOT::BaseGlyphRecord226   bool sanitize (hb_sanitize_context_t *c) const
227   {
228     TRACE_SANITIZE (this);
229     return_trace (c->check_struct (this));
230   }
231 
232   public:
233   HBGlyphID16	glyphId;	/* Glyph ID of reference glyph */
234   HBUINT16	firstLayerIdx;	/* Index (from beginning of
235 				 * the Layer Records) to the
236 				 * layer record. There will be
237 				 * numLayers consecutive entries
238 				 * for this base glyph. */
239   HBUINT16	numLayers;	/* Number of color layers
240 				 * associated with this glyph */
241   public:
242   DEFINE_SIZE_STATIC (6);
243 };
244 
245 template <typename T>
246 struct Variable
247 {
248   static constexpr bool is_variable = true;
249 
copyOT::Variable250   Variable<T>* copy (hb_serialize_context_t *c) const
251   {
252     TRACE_SERIALIZE (this);
253     return_trace (c->embed (this));
254   }
255 
closurev1OT::Variable256   void closurev1 (hb_colrv1_closure_context_t* c) const
257   {
258     c->num_var_idxes = 0;
259     // update c->num_var_idxes during value closure
260     value.closurev1 (c);
261     c->add_var_idxes (varIdxBase, c->num_var_idxes);
262   }
263 
subsetOT::Variable264   bool subset (hb_subset_context_t *c,
265                const ItemVarStoreInstancer &instancer) const
266   {
267     TRACE_SUBSET (this);
268     if (!value.subset (c, instancer, varIdxBase)) return_trace (false);
269     if (c->plan->all_axes_pinned)
270       return_trace (true);
271 
272     VarIdx new_varidx;
273     new_varidx = varIdxBase;
274     if (varIdxBase != VarIdx::NO_VARIATION)
275     {
276       hb_pair_t<unsigned, int> *new_varidx_delta;
277       if (!c->plan->colrv1_variation_idx_delta_map.has (varIdxBase, &new_varidx_delta))
278         return_trace (false);
279 
280       new_varidx = hb_first (*new_varidx_delta);
281     }
282 
283     return_trace (c->serializer->embed (new_varidx));
284   }
285 
sanitizeOT::Variable286   bool sanitize (hb_sanitize_context_t *c) const
287   {
288     TRACE_SANITIZE (this);
289     return_trace (c->check_struct (this) && value.sanitize (c));
290   }
291 
paint_glyphOT::Variable292   void paint_glyph (hb_paint_context_t *c) const
293   {
294     TRACE_PAINT (this);
295     value.paint_glyph (c, varIdxBase);
296   }
297 
get_color_stopOT::Variable298   void get_color_stop (hb_paint_context_t *c,
299                        hb_color_stop_t *stop,
300 		       const ItemVarStoreInstancer &instancer) const
301   {
302     value.get_color_stop (c, stop, varIdxBase, instancer);
303   }
304 
get_extendOT::Variable305   hb_paint_extend_t get_extend () const
306   {
307     return value.get_extend ();
308   }
309 
310   protected:
311   T      value;
312   public:
313   VarIdx varIdxBase;
314   public:
315   DEFINE_SIZE_MIN (VarIdx::static_size + T::min_size);
316 };
317 
318 template <typename T>
319 struct NoVariable
320 {
321   static constexpr bool is_variable = false;
322 
323   static constexpr uint32_t varIdxBase = VarIdx::NO_VARIATION;
324 
copyOT::NoVariable325   NoVariable<T>* copy (hb_serialize_context_t *c) const
326   {
327     TRACE_SERIALIZE (this);
328     return_trace (c->embed (this));
329   }
330 
closurev1OT::NoVariable331   void closurev1 (hb_colrv1_closure_context_t* c) const
332   { value.closurev1 (c); }
333 
subsetOT::NoVariable334   bool subset (hb_subset_context_t *c,
335                const ItemVarStoreInstancer &instancer) const
336   {
337     TRACE_SUBSET (this);
338     return_trace (value.subset (c, instancer, varIdxBase));
339   }
340 
sanitizeOT::NoVariable341   bool sanitize (hb_sanitize_context_t *c) const
342   {
343     TRACE_SANITIZE (this);
344     return_trace (c->check_struct (this) && value.sanitize (c));
345   }
346 
paint_glyphOT::NoVariable347   void paint_glyph (hb_paint_context_t *c) const
348   {
349     TRACE_PAINT (this);
350     value.paint_glyph (c, varIdxBase);
351   }
352 
get_color_stopOT::NoVariable353   void get_color_stop (hb_paint_context_t *c,
354                        hb_color_stop_t *stop,
355 		       const ItemVarStoreInstancer &instancer) const
356   {
357     value.get_color_stop (c, stop, VarIdx::NO_VARIATION, instancer);
358   }
359 
get_extendOT::NoVariable360   hb_paint_extend_t get_extend () const
361   {
362     return value.get_extend ();
363   }
364 
365   T      value;
366   public:
367   DEFINE_SIZE_MIN (T::min_size);
368 };
369 
370 // Color structures
371 
372 struct ColorStop
373 {
closurev1OT::ColorStop374   void closurev1 (hb_colrv1_closure_context_t* c) const
375   {
376     c->add_palette_index (paletteIndex);
377     c->num_var_idxes = 2;
378   }
379 
subsetOT::ColorStop380   bool subset (hb_subset_context_t *c,
381                const ItemVarStoreInstancer &instancer,
382                uint32_t varIdxBase) const
383   {
384     TRACE_SUBSET (this);
385     auto *out = c->serializer->embed (*this);
386     if (unlikely (!out)) return_trace (false);
387 
388     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
389     {
390       out->stopOffset.set_float (stopOffset.to_float(instancer (varIdxBase, 0)));
391       out->alpha.set_float (alpha.to_float (instancer (varIdxBase, 1)));
392     }
393 
394     return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex),
395                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
396   }
397 
sanitizeOT::ColorStop398   bool sanitize (hb_sanitize_context_t *c) const
399   {
400     TRACE_SANITIZE (this);
401     return_trace (c->check_struct (this));
402   }
403 
get_color_stopOT::ColorStop404   void get_color_stop (hb_paint_context_t *c,
405                        hb_color_stop_t *out,
406 		       uint32_t varIdx,
407 		       const ItemVarStoreInstancer &instancer) const
408   {
409     out->offset = stopOffset.to_float(instancer (varIdx, 0));
410     out->color = c->get_color (paletteIndex,
411                                alpha.to_float (instancer (varIdx, 1)),
412                                &out->is_foreground);
413   }
414 
415   F2DOT14	stopOffset;
416   HBUINT16	paletteIndex;
417   F2DOT14	alpha;
418   public:
419   DEFINE_SIZE_STATIC (2 + 2 * F2DOT14::static_size);
420 };
421 
422 struct Extend : HBUINT8
423 {
424   enum {
425     EXTEND_PAD     = 0,
426     EXTEND_REPEAT  = 1,
427     EXTEND_REFLECT = 2,
428   };
429   public:
430   DEFINE_SIZE_STATIC (1);
431 };
432 
433 template <template<typename> class Var>
434 struct ColorLine
435 {
closurev1OT::ColorLine436   void closurev1 (hb_colrv1_closure_context_t* c) const
437   {
438     for (const auto &stop : stops.iter ())
439       stop.closurev1 (c);
440   }
441 
subsetOT::ColorLine442   bool subset (hb_subset_context_t *c,
443                const ItemVarStoreInstancer &instancer) const
444   {
445     TRACE_SUBSET (this);
446     auto *out = c->serializer->start_embed (this);
447     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
448 
449     if (!c->serializer->check_assign (out->extend, extend, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
450     if (!c->serializer->check_assign (out->stops.len, stops.len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)) return_trace (false);
451 
452     for (const auto& stop : stops.iter ())
453     {
454       if (!stop.subset (c, instancer)) return_trace (false);
455     }
456     return_trace (true);
457   }
458 
sanitizeOT::ColorLine459   bool sanitize (hb_sanitize_context_t *c) const
460   {
461     TRACE_SANITIZE (this);
462     return_trace (c->check_struct (this) &&
463                   stops.sanitize (c));
464   }
465 
466   /* get up to count stops from start */
467   unsigned int
get_color_stopsOT::ColorLine468   get_color_stops (hb_paint_context_t *c,
469                    unsigned int start,
470 		   unsigned int *count,
471 		   hb_color_stop_t *color_stops,
472 		   const ItemVarStoreInstancer &instancer) const
473   {
474     unsigned int len = stops.len;
475 
476     if (count && color_stops)
477     {
478       unsigned int i;
479       for (i = 0; i < *count && start + i < len; i++)
480         stops[start + i].get_color_stop (c, &color_stops[i], instancer);
481       *count = i;
482     }
483 
484     return len;
485   }
486 
static_get_color_stopsOT::ColorLine487   HB_INTERNAL static unsigned int static_get_color_stops (hb_color_line_t *color_line,
488 							  void *color_line_data,
489 							  unsigned int start,
490 							  unsigned int *count,
491 							  hb_color_stop_t *color_stops,
492 							  void *user_data)
493   {
494     const ColorLine *thiz = (const ColorLine *) color_line_data;
495     hb_paint_context_t *c = (hb_paint_context_t *) user_data;
496     return thiz->get_color_stops (c, start, count, color_stops, c->instancer);
497   }
498 
get_extendOT::ColorLine499   hb_paint_extend_t get_extend () const
500   {
501     return (hb_paint_extend_t) (unsigned int) extend;
502   }
503 
static_get_extendOT::ColorLine504   HB_INTERNAL static hb_paint_extend_t static_get_extend (hb_color_line_t *color_line,
505 							  void *color_line_data,
506 							  void *user_data)
507   {
508     const ColorLine *thiz = (const ColorLine *) color_line_data;
509     return thiz->get_extend ();
510   }
511 
512   Extend	extend;
513   Array16Of<Var<ColorStop>>	stops;
514   public:
515   DEFINE_SIZE_ARRAY_SIZED (3, stops);
516 };
517 
518 // Composition modes
519 
520 // Compositing modes are taken from https://www.w3.org/TR/compositing-1/
521 // NOTE: a brief audit of major implementations suggests most support most
522 // or all of the specified modes.
523 struct CompositeMode : HBUINT8
524 {
525   enum {
526     // Porter-Duff modes
527     // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators
528     COMPOSITE_CLEAR          =  0,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_clear
529     COMPOSITE_SRC            =  1,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_src
530     COMPOSITE_DEST           =  2,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dst
531     COMPOSITE_SRC_OVER       =  3,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcover
532     COMPOSITE_DEST_OVER      =  4,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstover
533     COMPOSITE_SRC_IN         =  5,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcin
534     COMPOSITE_DEST_IN        =  6,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstin
535     COMPOSITE_SRC_OUT        =  7,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcout
536     COMPOSITE_DEST_OUT       =  8,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstout
537     COMPOSITE_SRC_ATOP       =  9,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcatop
538     COMPOSITE_DEST_ATOP      = 10,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstatop
539     COMPOSITE_XOR            = 11,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_xor
540     COMPOSITE_PLUS           = 12,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_plus
541 
542     // Blend modes
543     // https://www.w3.org/TR/compositing-1/#blending
544     COMPOSITE_SCREEN         = 13,  // https://www.w3.org/TR/compositing-1/#blendingscreen
545     COMPOSITE_OVERLAY        = 14,  // https://www.w3.org/TR/compositing-1/#blendingoverlay
546     COMPOSITE_DARKEN         = 15,  // https://www.w3.org/TR/compositing-1/#blendingdarken
547     COMPOSITE_LIGHTEN        = 16,  // https://www.w3.org/TR/compositing-1/#blendinglighten
548     COMPOSITE_COLOR_DODGE    = 17,  // https://www.w3.org/TR/compositing-1/#blendingcolordodge
549     COMPOSITE_COLOR_BURN     = 18,  // https://www.w3.org/TR/compositing-1/#blendingcolorburn
550     COMPOSITE_HARD_LIGHT     = 19,  // https://www.w3.org/TR/compositing-1/#blendinghardlight
551     COMPOSITE_SOFT_LIGHT     = 20,  // https://www.w3.org/TR/compositing-1/#blendingsoftlight
552     COMPOSITE_DIFFERENCE     = 21,  // https://www.w3.org/TR/compositing-1/#blendingdifference
553     COMPOSITE_EXCLUSION      = 22,  // https://www.w3.org/TR/compositing-1/#blendingexclusion
554     COMPOSITE_MULTIPLY       = 23,  // https://www.w3.org/TR/compositing-1/#blendingmultiply
555 
556     // Modes that, uniquely, do not operate on components
557     // https://www.w3.org/TR/compositing-1/#blendingnonseparable
558     COMPOSITE_HSL_HUE        = 24,  // https://www.w3.org/TR/compositing-1/#blendinghue
559     COMPOSITE_HSL_SATURATION = 25,  // https://www.w3.org/TR/compositing-1/#blendingsaturation
560     COMPOSITE_HSL_COLOR      = 26,  // https://www.w3.org/TR/compositing-1/#blendingcolor
561     COMPOSITE_HSL_LUMINOSITY = 27,  // https://www.w3.org/TR/compositing-1/#blendingluminosity
562   };
563   public:
564   DEFINE_SIZE_STATIC (1);
565 };
566 
567 struct Affine2x3
568 {
sanitizeOT::Affine2x3569   bool sanitize (hb_sanitize_context_t *c) const
570   {
571     TRACE_SANITIZE (this);
572     return_trace (c->check_struct (this));
573   }
574 
closurev1OT::Affine2x3575   void closurev1 (hb_colrv1_closure_context_t* c) const
576   { c->num_var_idxes = 6; }
577 
subsetOT::Affine2x3578   bool subset (hb_subset_context_t *c,
579                const ItemVarStoreInstancer &instancer,
580                uint32_t varIdxBase) const
581   {
582     TRACE_SUBSET (this);
583     auto *out = c->serializer->embed (*this);
584     if (unlikely (!out)) return_trace (false);
585     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
586     {
587       out->xx.set_float (xx.to_float(instancer (varIdxBase, 0)));
588       out->yx.set_float (yx.to_float(instancer (varIdxBase, 1)));
589       out->xy.set_float (xy.to_float(instancer (varIdxBase, 2)));
590       out->yy.set_float (yy.to_float(instancer (varIdxBase, 3)));
591       out->dx.set_float (dx.to_float(instancer (varIdxBase, 4)));
592       out->dy.set_float (dy.to_float(instancer (varIdxBase, 5)));
593     }
594     return_trace (true);
595   }
596 
paint_glyphOT::Affine2x3597   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
598   {
599     TRACE_PAINT (this);
600     c->funcs->push_transform (c->data,
601 			      xx.to_float (c->instancer (varIdxBase, 0)),
602 			      yx.to_float (c->instancer (varIdxBase, 1)),
603                               xy.to_float (c->instancer (varIdxBase, 2)),
604 			      yy.to_float (c->instancer (varIdxBase, 3)),
605                               dx.to_float (c->instancer (varIdxBase, 4)),
606 			      dy.to_float (c->instancer (varIdxBase, 5)));
607   }
608 
609   F16DOT16 xx;
610   F16DOT16 yx;
611   F16DOT16 xy;
612   F16DOT16 yy;
613   F16DOT16 dx;
614   F16DOT16 dy;
615   public:
616   DEFINE_SIZE_STATIC (6 * F16DOT16::static_size);
617 };
618 
619 struct PaintColrLayers
620 {
621   void closurev1 (hb_colrv1_closure_context_t* c) const;
622 
subsetOT::PaintColrLayers623   bool subset (hb_subset_context_t *c,
624                const ItemVarStoreInstancer &instancer HB_UNUSED) const
625   {
626     TRACE_SUBSET (this);
627     auto *out = c->serializer->embed (this);
628     if (unlikely (!out)) return_trace (false);
629     return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers.get (firstLayerIndex),
630                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
631 
632     return_trace (true);
633   }
634 
sanitizeOT::PaintColrLayers635   bool sanitize (hb_sanitize_context_t *c) const
636   {
637     TRACE_SANITIZE (this);
638     return_trace (c->check_struct (this));
639   }
640 
641   inline void paint_glyph (hb_paint_context_t *c) const;
642 
643   HBUINT8	format; /* format = 1 */
644   HBUINT8	numLayers;
645   HBUINT32	firstLayerIndex;  /* index into COLRv1::layerList */
646   public:
647   DEFINE_SIZE_STATIC (6);
648 };
649 
650 struct PaintSolid
651 {
closurev1OT::PaintSolid652   void closurev1 (hb_colrv1_closure_context_t* c) const
653   {
654     c->add_palette_index (paletteIndex);
655     c->num_var_idxes = 1;
656   }
657 
subsetOT::PaintSolid658   bool subset (hb_subset_context_t *c,
659                const ItemVarStoreInstancer &instancer,
660                uint32_t varIdxBase) const
661   {
662     TRACE_SUBSET (this);
663     auto *out = c->serializer->embed (*this);
664     if (unlikely (!out)) return_trace (false);
665 
666     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
667       out->alpha.set_float (alpha.to_float (instancer (varIdxBase, 0)));
668 
669     if (format == 3 && c->plan->all_axes_pinned)
670         out->format = 2;
671 
672     return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex),
673                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
674   }
675 
sanitizeOT::PaintSolid676   bool sanitize (hb_sanitize_context_t *c) const
677   {
678     TRACE_SANITIZE (this);
679     return_trace (c->check_struct (this));
680   }
681 
paint_glyphOT::PaintSolid682   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
683   {
684     TRACE_PAINT (this);
685     hb_bool_t is_foreground;
686     hb_color_t color;
687 
688     color = c->get_color (paletteIndex,
689                           alpha.to_float (c->instancer (varIdxBase, 0)),
690                           &is_foreground);
691     c->funcs->color (c->data, is_foreground, color);
692   }
693 
694   HBUINT8	format; /* format = 2(noVar) or 3(Var)*/
695   HBUINT16	paletteIndex;
696   F2DOT14	alpha;
697   public:
698   DEFINE_SIZE_STATIC (3 + F2DOT14::static_size);
699 };
700 
701 template <template<typename> class Var>
702 struct PaintLinearGradient
703 {
closurev1OT::PaintLinearGradient704   void closurev1 (hb_colrv1_closure_context_t* c) const
705   {
706     (this+colorLine).closurev1 (c);
707     c->num_var_idxes = 6;
708   }
709 
subsetOT::PaintLinearGradient710   bool subset (hb_subset_context_t *c,
711                const ItemVarStoreInstancer &instancer,
712                uint32_t varIdxBase) const
713   {
714     TRACE_SUBSET (this);
715     auto *out = c->serializer->embed (this);
716     if (unlikely (!out)) return_trace (false);
717 
718     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
719     {
720       out->x0 = x0 + (int) roundf (instancer (varIdxBase, 0));
721       out->y0 = y0 + (int) roundf (instancer (varIdxBase, 1));
722       out->x1 = x1 + (int) roundf (instancer (varIdxBase, 2));
723       out->y1 = y1 + (int) roundf (instancer (varIdxBase, 3));
724       out->x2 = x2 + (int) roundf (instancer (varIdxBase, 4));
725       out->y2 = y2 + (int) roundf (instancer (varIdxBase, 5));
726     }
727 
728     if (format == 5 && c->plan->all_axes_pinned)
729         out->format = 4;
730 
731     return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer));
732   }
733 
sanitizeOT::PaintLinearGradient734   bool sanitize (hb_sanitize_context_t *c) const
735   {
736     TRACE_SANITIZE (this);
737     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
738   }
739 
paint_glyphOT::PaintLinearGradient740   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
741   {
742     TRACE_PAINT (this);
743     hb_color_line_t cl = {
744       (void *) &(this+colorLine),
745       (this+colorLine).static_get_color_stops, c,
746       (this+colorLine).static_get_extend, nullptr
747     };
748 
749     c->funcs->linear_gradient (c->data, &cl,
750 			       x0 + c->instancer (varIdxBase, 0),
751 			       y0 + c->instancer (varIdxBase, 1),
752 			       x1 + c->instancer (varIdxBase, 2),
753 			       y1 + c->instancer (varIdxBase, 3),
754 			       x2 + c->instancer (varIdxBase, 4),
755 			       y2 + c->instancer (varIdxBase, 5));
756   }
757 
758   HBUINT8			format; /* format = 4(noVar) or 5 (Var) */
759   Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintLinearGradient
760                                             * table) to ColorLine subtable. */
761   FWORD			x0;
762   FWORD			y0;
763   FWORD			x1;
764   FWORD			y1;
765   FWORD			x2;
766   FWORD			y2;
767   public:
768   DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size);
769 };
770 
771 template <template<typename> class Var>
772 struct PaintRadialGradient
773 {
closurev1OT::PaintRadialGradient774   void closurev1 (hb_colrv1_closure_context_t* c) const
775   {
776     (this+colorLine).closurev1 (c);
777     c->num_var_idxes = 6;
778   }
779 
subsetOT::PaintRadialGradient780   bool subset (hb_subset_context_t *c,
781                const ItemVarStoreInstancer &instancer,
782                uint32_t varIdxBase) const
783   {
784     TRACE_SUBSET (this);
785     auto *out = c->serializer->embed (this);
786     if (unlikely (!out)) return_trace (false);
787 
788     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
789     {
790       out->x0 = x0 + (int) roundf (instancer (varIdxBase, 0));
791       out->y0 = y0 + (int) roundf (instancer (varIdxBase, 1));
792       out->radius0 = radius0 + (unsigned) roundf (instancer (varIdxBase, 2));
793       out->x1 = x1 + (int) roundf (instancer (varIdxBase, 3));
794       out->y1 = y1 + (int) roundf (instancer (varIdxBase, 4));
795       out->radius1 = radius1 + (unsigned) roundf (instancer (varIdxBase, 5));
796     }
797 
798     if (format == 7 && c->plan->all_axes_pinned)
799         out->format = 6;
800 
801     return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer));
802   }
803 
sanitizeOT::PaintRadialGradient804   bool sanitize (hb_sanitize_context_t *c) const
805   {
806     TRACE_SANITIZE (this);
807     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
808   }
809 
paint_glyphOT::PaintRadialGradient810   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
811   {
812     TRACE_PAINT (this);
813     hb_color_line_t cl = {
814       (void *) &(this+colorLine),
815       (this+colorLine).static_get_color_stops, c,
816       (this+colorLine).static_get_extend, nullptr
817     };
818 
819     c->funcs->radial_gradient (c->data, &cl,
820 			       x0 + c->instancer (varIdxBase, 0),
821 			       y0 + c->instancer (varIdxBase, 1),
822 			       radius0 + c->instancer (varIdxBase, 2),
823 			       x1 + c->instancer (varIdxBase, 3),
824 			       y1 + c->instancer (varIdxBase, 4),
825 			       radius1 + c->instancer (varIdxBase, 5));
826   }
827 
828   HBUINT8			format; /* format = 6(noVar) or 7 (Var) */
829   Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintRadialGradient
830                                             * table) to ColorLine subtable. */
831   FWORD			x0;
832   FWORD			y0;
833   UFWORD		radius0;
834   FWORD			x1;
835   FWORD			y1;
836   UFWORD		radius1;
837   public:
838   DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size);
839 };
840 
841 template <template<typename> class Var>
842 struct PaintSweepGradient
843 {
closurev1OT::PaintSweepGradient844   void closurev1 (hb_colrv1_closure_context_t* c) const
845   {
846     (this+colorLine).closurev1 (c);
847     c->num_var_idxes = 4;
848   }
849 
subsetOT::PaintSweepGradient850   bool subset (hb_subset_context_t *c,
851                const ItemVarStoreInstancer &instancer,
852                uint32_t varIdxBase) const
853   {
854     TRACE_SUBSET (this);
855     auto *out = c->serializer->embed (this);
856     if (unlikely (!out)) return_trace (false);
857 
858     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
859     {
860       out->centerX = centerX + (int) roundf (instancer (varIdxBase, 0));
861       out->centerY = centerY + (int) roundf (instancer (varIdxBase, 1));
862       out->startAngle.set_float (startAngle.to_float (instancer (varIdxBase, 2)));
863       out->endAngle.set_float (endAngle.to_float (instancer (varIdxBase, 3)));
864     }
865 
866     if (format == 9 && c->plan->all_axes_pinned)
867         out->format = 8;
868 
869     return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer));
870   }
871 
sanitizeOT::PaintSweepGradient872   bool sanitize (hb_sanitize_context_t *c) const
873   {
874     TRACE_SANITIZE (this);
875     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
876   }
877 
paint_glyphOT::PaintSweepGradient878   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
879   {
880     TRACE_PAINT (this);
881     hb_color_line_t cl = {
882       (void *) &(this+colorLine),
883       (this+colorLine).static_get_color_stops, c,
884       (this+colorLine).static_get_extend, nullptr
885     };
886 
887     c->funcs->sweep_gradient (c->data, &cl,
888 			      centerX + c->instancer (varIdxBase, 0),
889 			      centerY + c->instancer (varIdxBase, 1),
890                               (startAngle.to_float (c->instancer (varIdxBase, 2)) + 1) * HB_PI,
891                               (endAngle.to_float   (c->instancer (varIdxBase, 3)) + 1) * HB_PI);
892   }
893 
894   HBUINT8			format; /* format = 8(noVar) or 9 (Var) */
895   Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintSweepGradient
896                                             * table) to ColorLine subtable. */
897   FWORD			centerX;
898   FWORD			centerY;
899   F2DOT14		startAngle;
900   F2DOT14		endAngle;
901   public:
902   DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size + 2 * F2DOT14::static_size);
903 };
904 
905 // Paint a non-COLR glyph, filled as indicated by paint.
906 struct PaintGlyph
907 {
908   void closurev1 (hb_colrv1_closure_context_t* c) const;
909 
subsetOT::PaintGlyph910   bool subset (hb_subset_context_t *c,
911                const ItemVarStoreInstancer &instancer) const
912   {
913     TRACE_SUBSET (this);
914     auto *out = c->serializer->embed (this);
915     if (unlikely (!out)) return_trace (false);
916 
917     if (! c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid),
918                                        HB_SERIALIZE_ERROR_INT_OVERFLOW))
919       return_trace (false);
920 
921     return_trace (out->paint.serialize_subset (c, paint, this, instancer));
922   }
923 
sanitizeOT::PaintGlyph924   bool sanitize (hb_sanitize_context_t *c) const
925   {
926     TRACE_SANITIZE (this);
927     return_trace (c->check_struct (this) && paint.sanitize (c, this));
928   }
929 
paint_glyphOT::PaintGlyph930   void paint_glyph (hb_paint_context_t *c) const
931   {
932     TRACE_PAINT (this);
933     c->funcs->push_inverse_root_transform (c->data, c->font);
934     c->funcs->push_clip_glyph (c->data, gid, c->font);
935     c->funcs->push_root_transform (c->data, c->font);
936     c->recurse (this+paint);
937     c->funcs->pop_transform (c->data);
938     c->funcs->pop_clip (c->data);
939     c->funcs->pop_transform (c->data);
940   }
941 
942   HBUINT8		format; /* format = 10 */
943   Offset24To<Paint>	paint;  /* Offset (from beginning of PaintGlyph table) to Paint subtable. */
944   HBUINT16		gid;
945   public:
946   DEFINE_SIZE_STATIC (6);
947 };
948 
949 struct PaintColrGlyph
950 {
951   void closurev1 (hb_colrv1_closure_context_t* c) const;
952 
subsetOT::PaintColrGlyph953   bool subset (hb_subset_context_t *c,
954                const ItemVarStoreInstancer &instancer HB_UNUSED) const
955   {
956     TRACE_SUBSET (this);
957     auto *out = c->serializer->embed (this);
958     if (unlikely (!out)) return_trace (false);
959 
960     return_trace (c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid),
961                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
962   }
963 
sanitizeOT::PaintColrGlyph964   bool sanitize (hb_sanitize_context_t *c) const
965   {
966     TRACE_SANITIZE (this);
967     return_trace (c->check_struct (this));
968   }
969 
970   inline void paint_glyph (hb_paint_context_t *c) const;
971 
972   HBUINT8	format; /* format = 11 */
973   HBUINT16	gid;
974   public:
975   DEFINE_SIZE_STATIC (3);
976 };
977 
978 template <template<typename> class Var>
979 struct PaintTransform
980 {
981   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
982 
subsetOT::PaintTransform983   bool subset (hb_subset_context_t *c,
984                const ItemVarStoreInstancer &instancer) const
985   {
986     TRACE_SUBSET (this);
987     auto *out = c->serializer->embed (this);
988     if (unlikely (!out)) return_trace (false);
989     if (!out->transform.serialize_subset (c, transform, this, instancer)) return_trace (false);
990     if (format == 13 && c->plan->all_axes_pinned)
991       out->format = 12;
992     return_trace (out->src.serialize_subset (c, src, this, instancer));
993   }
994 
sanitizeOT::PaintTransform995   bool sanitize (hb_sanitize_context_t *c) const
996   {
997     TRACE_SANITIZE (this);
998     return_trace (c->check_struct (this) &&
999                   src.sanitize (c, this) &&
1000                   transform.sanitize (c, this));
1001   }
1002 
paint_glyphOT::PaintTransform1003   void paint_glyph (hb_paint_context_t *c) const
1004   {
1005     TRACE_PAINT (this);
1006     (this+transform).paint_glyph (c);
1007     c->recurse (this+src);
1008     c->funcs->pop_transform (c->data);
1009   }
1010 
1011   HBUINT8			format; /* format = 12(noVar) or 13 (Var) */
1012   Offset24To<Paint>		src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */
1013   Offset24To<Var<Affine2x3>>	transform;
1014   public:
1015   DEFINE_SIZE_STATIC (7);
1016 };
1017 
1018 struct PaintTranslate
1019 {
1020   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1021 
subsetOT::PaintTranslate1022   bool subset (hb_subset_context_t *c,
1023                const ItemVarStoreInstancer &instancer,
1024                uint32_t varIdxBase) const
1025   {
1026     TRACE_SUBSET (this);
1027     auto *out = c->serializer->embed (this);
1028     if (unlikely (!out)) return_trace (false);
1029 
1030     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1031     {
1032       out->dx = dx + (int) roundf (instancer (varIdxBase, 0));
1033       out->dy = dy + (int) roundf (instancer (varIdxBase, 1));
1034     }
1035 
1036     if (format == 15 && c->plan->all_axes_pinned)
1037         out->format = 14;
1038 
1039     return_trace (out->src.serialize_subset (c, src, this, instancer));
1040   }
1041 
sanitizeOT::PaintTranslate1042   bool sanitize (hb_sanitize_context_t *c) const
1043   {
1044     TRACE_SANITIZE (this);
1045     return_trace (c->check_struct (this) && src.sanitize (c, this));
1046   }
1047 
paint_glyphOT::PaintTranslate1048   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1049   {
1050     TRACE_PAINT (this);
1051     float ddx = dx + c->instancer (varIdxBase, 0);
1052     float ddy = dy + c->instancer (varIdxBase, 1);
1053 
1054     bool p1 = c->funcs->push_translate (c->data, ddx, ddy);
1055     c->recurse (this+src);
1056     if (p1) c->funcs->pop_transform (c->data);
1057   }
1058 
1059   HBUINT8		format; /* format = 14(noVar) or 15 (Var) */
1060   Offset24To<Paint>	src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */
1061   FWORD		dx;
1062   FWORD		dy;
1063   public:
1064   DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size);
1065 };
1066 
1067 struct PaintScale
1068 {
1069   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1070 
subsetOT::PaintScale1071   bool subset (hb_subset_context_t *c,
1072                const ItemVarStoreInstancer &instancer,
1073                uint32_t varIdxBase) const
1074   {
1075     TRACE_SUBSET (this);
1076     auto *out = c->serializer->embed (this);
1077     if (unlikely (!out)) return_trace (false);
1078 
1079     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1080     {
1081       out->scaleX.set_float (scaleX.to_float (instancer (varIdxBase, 0)));
1082       out->scaleY.set_float (scaleY.to_float (instancer (varIdxBase, 1)));
1083     }
1084 
1085     if (format == 17 && c->plan->all_axes_pinned)
1086         out->format = 16;
1087 
1088     return_trace (out->src.serialize_subset (c, src, this, instancer));
1089   }
1090 
sanitizeOT::PaintScale1091   bool sanitize (hb_sanitize_context_t *c) const
1092   {
1093     TRACE_SANITIZE (this);
1094     return_trace (c->check_struct (this) && src.sanitize (c, this));
1095   }
1096 
paint_glyphOT::PaintScale1097   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1098   {
1099     TRACE_PAINT (this);
1100     float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
1101     float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
1102 
1103     bool p1 = c->funcs->push_scale (c->data, sx, sy);
1104     c->recurse (this+src);
1105     if (p1) c->funcs->pop_transform (c->data);
1106   }
1107 
1108   HBUINT8		format; /* format = 16 (noVar) or 17(Var) */
1109   Offset24To<Paint>	src; /* Offset (from beginning of PaintScale table) to Paint subtable. */
1110   F2DOT14		scaleX;
1111   F2DOT14		scaleY;
1112   public:
1113   DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size);
1114 };
1115 
1116 struct PaintScaleAroundCenter
1117 {
1118   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1119 
subsetOT::PaintScaleAroundCenter1120   bool subset (hb_subset_context_t *c,
1121                const ItemVarStoreInstancer &instancer,
1122                uint32_t varIdxBase) const
1123   {
1124     TRACE_SUBSET (this);
1125     auto *out = c->serializer->embed (this);
1126     if (unlikely (!out)) return_trace (false);
1127 
1128     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1129     {
1130       out->scaleX.set_float (scaleX.to_float (instancer (varIdxBase, 0)));
1131       out->scaleY.set_float (scaleY.to_float (instancer (varIdxBase, 1)));
1132       out->centerX = centerX + (int) roundf (instancer (varIdxBase, 2));
1133       out->centerY = centerY + (int) roundf (instancer (varIdxBase, 3));
1134     }
1135 
1136     if (format == 19 && c->plan->all_axes_pinned)
1137         out->format = 18;
1138 
1139     return_trace (out->src.serialize_subset (c, src, this, instancer));
1140   }
1141 
sanitizeOT::PaintScaleAroundCenter1142   bool sanitize (hb_sanitize_context_t *c) const
1143   {
1144     TRACE_SANITIZE (this);
1145     return_trace (c->check_struct (this) && src.sanitize (c, this));
1146   }
1147 
paint_glyphOT::PaintScaleAroundCenter1148   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1149   {
1150     TRACE_PAINT (this);
1151     float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
1152     float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
1153     float tCenterX = centerX + c->instancer (varIdxBase, 2);
1154     float tCenterY = centerY + c->instancer (varIdxBase, 3);
1155 
1156     bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
1157     bool p2 = c->funcs->push_scale (c->data, sx, sy);
1158     bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
1159     c->recurse (this+src);
1160     if (p3) c->funcs->pop_transform (c->data);
1161     if (p2) c->funcs->pop_transform (c->data);
1162     if (p1) c->funcs->pop_transform (c->data);
1163   }
1164 
1165   HBUINT8		format; /* format = 18 (noVar) or 19(Var) */
1166   Offset24To<Paint>	src; /* Offset (from beginning of PaintScaleAroundCenter table) to Paint subtable. */
1167   F2DOT14	scaleX;
1168   F2DOT14	scaleY;
1169   FWORD		centerX;
1170   FWORD		centerY;
1171   public:
1172   DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size + 2 * FWORD::static_size);
1173 };
1174 
1175 struct PaintScaleUniform
1176 {
1177   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1178 
subsetOT::PaintScaleUniform1179   bool subset (hb_subset_context_t *c,
1180                const ItemVarStoreInstancer &instancer,
1181                uint32_t varIdxBase) const
1182   {
1183     TRACE_SUBSET (this);
1184     auto *out = c->serializer->embed (this);
1185     if (unlikely (!out)) return_trace (false);
1186 
1187     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1188       out->scale.set_float (scale.to_float (instancer (varIdxBase, 0)));
1189 
1190     if (format == 21 && c->plan->all_axes_pinned)
1191         out->format = 20;
1192 
1193     return_trace (out->src.serialize_subset (c, src, this, instancer));
1194   }
1195 
sanitizeOT::PaintScaleUniform1196   bool sanitize (hb_sanitize_context_t *c) const
1197   {
1198     TRACE_SANITIZE (this);
1199     return_trace (c->check_struct (this) && src.sanitize (c, this));
1200   }
1201 
paint_glyphOT::PaintScaleUniform1202   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1203   {
1204     TRACE_PAINT (this);
1205     float s = scale.to_float (c->instancer (varIdxBase, 0));
1206 
1207     bool p1 = c->funcs->push_scale (c->data, s, s);
1208     c->recurse (this+src);
1209     if (p1) c->funcs->pop_transform (c->data);
1210   }
1211 
1212   HBUINT8		format; /* format = 20 (noVar) or 21(Var) */
1213   Offset24To<Paint>	src; /* Offset (from beginning of PaintScaleUniform table) to Paint subtable. */
1214   F2DOT14		scale;
1215   public:
1216   DEFINE_SIZE_STATIC (4 + F2DOT14::static_size);
1217 };
1218 
1219 struct PaintScaleUniformAroundCenter
1220 {
1221   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1222 
subsetOT::PaintScaleUniformAroundCenter1223   bool subset (hb_subset_context_t *c,
1224                const ItemVarStoreInstancer &instancer,
1225                uint32_t varIdxBase) const
1226   {
1227     TRACE_SUBSET (this);
1228     auto *out = c->serializer->embed (this);
1229     if (unlikely (!out)) return_trace (false);
1230 
1231     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1232     {
1233       out->scale.set_float (scale.to_float (instancer (varIdxBase, 0)));
1234       out->centerX = centerX + (int) roundf (instancer (varIdxBase, 1));
1235       out->centerY = centerY + (int) roundf (instancer (varIdxBase, 2));
1236     }
1237 
1238     if (format == 23 && c->plan->all_axes_pinned)
1239         out->format = 22;
1240 
1241     return_trace (out->src.serialize_subset (c, src, this, instancer));
1242   }
1243 
sanitizeOT::PaintScaleUniformAroundCenter1244   bool sanitize (hb_sanitize_context_t *c) const
1245   {
1246     TRACE_SANITIZE (this);
1247     return_trace (c->check_struct (this) && src.sanitize (c, this));
1248   }
1249 
paint_glyphOT::PaintScaleUniformAroundCenter1250   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1251   {
1252     TRACE_PAINT (this);
1253     float s = scale.to_float (c->instancer (varIdxBase, 0));
1254     float tCenterX = centerX + c->instancer (varIdxBase, 1);
1255     float tCenterY = centerY + c->instancer (varIdxBase, 2);
1256 
1257     bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
1258     bool p2 = c->funcs->push_scale (c->data, s, s);
1259     bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
1260     c->recurse (this+src);
1261     if (p3) c->funcs->pop_transform (c->data);
1262     if (p2) c->funcs->pop_transform (c->data);
1263     if (p1) c->funcs->pop_transform (c->data);
1264   }
1265 
1266   HBUINT8		format; /* format = 22 (noVar) or 23(Var) */
1267   Offset24To<Paint>	src; /* Offset (from beginning of PaintScaleUniformAroundCenter table) to Paint subtable. */
1268   F2DOT14	scale;
1269   FWORD		centerX;
1270   FWORD		centerY;
1271   public:
1272   DEFINE_SIZE_STATIC (4 + F2DOT14::static_size + 2 * FWORD::static_size);
1273 };
1274 
1275 struct PaintRotate
1276 {
1277   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1278 
subsetOT::PaintRotate1279   bool subset (hb_subset_context_t *c,
1280                const ItemVarStoreInstancer &instancer,
1281                uint32_t varIdxBase) const
1282   {
1283     TRACE_SUBSET (this);
1284     auto *out = c->serializer->embed (this);
1285     if (unlikely (!out)) return_trace (false);
1286 
1287     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1288       out->angle.set_float (angle.to_float (instancer (varIdxBase, 0)));
1289 
1290     if (format == 25 && c->plan->all_axes_pinned)
1291       out->format = 24;
1292 
1293     return_trace (out->src.serialize_subset (c, src, this, instancer));
1294   }
1295 
sanitizeOT::PaintRotate1296   bool sanitize (hb_sanitize_context_t *c) const
1297   {
1298     TRACE_SANITIZE (this);
1299     return_trace (c->check_struct (this) && src.sanitize (c, this));
1300   }
1301 
paint_glyphOT::PaintRotate1302   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1303   {
1304     TRACE_PAINT (this);
1305     float a = angle.to_float (c->instancer (varIdxBase, 0));
1306 
1307     bool p1 = c->funcs->push_rotate (c->data, a);
1308     c->recurse (this+src);
1309     if (p1) c->funcs->pop_transform (c->data);
1310   }
1311 
1312   HBUINT8		format; /* format = 24 (noVar) or 25(Var) */
1313   Offset24To<Paint>	src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */
1314   F2DOT14		angle;
1315   public:
1316   DEFINE_SIZE_STATIC (4 + F2DOT14::static_size);
1317 };
1318 
1319 struct PaintRotateAroundCenter
1320 {
1321   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1322 
subsetOT::PaintRotateAroundCenter1323   bool subset (hb_subset_context_t *c,
1324                const ItemVarStoreInstancer &instancer,
1325                uint32_t varIdxBase) const
1326   {
1327     TRACE_SUBSET (this);
1328     auto *out = c->serializer->embed (this);
1329     if (unlikely (!out)) return_trace (false);
1330 
1331     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1332     {
1333       out->angle.set_float (angle.to_float (instancer (varIdxBase, 0)));
1334       out->centerX = centerX + (int) roundf (instancer (varIdxBase, 1));
1335       out->centerY = centerY + (int) roundf (instancer (varIdxBase, 2));
1336     }
1337 
1338     if (format ==27 && c->plan->all_axes_pinned)
1339         out->format = 26;
1340 
1341     return_trace (out->src.serialize_subset (c, src, this, instancer));
1342   }
1343 
sanitizeOT::PaintRotateAroundCenter1344   bool sanitize (hb_sanitize_context_t *c) const
1345   {
1346     TRACE_SANITIZE (this);
1347     return_trace (c->check_struct (this) && src.sanitize (c, this));
1348   }
1349 
paint_glyphOT::PaintRotateAroundCenter1350   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1351   {
1352     TRACE_PAINT (this);
1353     float a = angle.to_float (c->instancer (varIdxBase, 0));
1354     float tCenterX = centerX + c->instancer (varIdxBase, 1);
1355     float tCenterY = centerY + c->instancer (varIdxBase, 2);
1356 
1357     bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
1358     bool p2 = c->funcs->push_rotate (c->data, a);
1359     bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
1360     c->recurse (this+src);
1361     if (p3) c->funcs->pop_transform (c->data);
1362     if (p2) c->funcs->pop_transform (c->data);
1363     if (p1) c->funcs->pop_transform (c->data);
1364   }
1365 
1366   HBUINT8		format; /* format = 26 (noVar) or 27(Var) */
1367   Offset24To<Paint>	src; /* Offset (from beginning of PaintRotateAroundCenter table) to Paint subtable. */
1368   F2DOT14	angle;
1369   FWORD		centerX;
1370   FWORD		centerY;
1371   public:
1372   DEFINE_SIZE_STATIC (4 + F2DOT14::static_size + 2 * FWORD::static_size);
1373 };
1374 
1375 struct PaintSkew
1376 {
1377   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1378 
subsetOT::PaintSkew1379   bool subset (hb_subset_context_t *c,
1380                const ItemVarStoreInstancer &instancer,
1381                uint32_t varIdxBase) const
1382   {
1383     TRACE_SUBSET (this);
1384     auto *out = c->serializer->embed (this);
1385     if (unlikely (!out)) return_trace (false);
1386 
1387     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1388     {
1389       out->xSkewAngle.set_float (xSkewAngle.to_float (instancer (varIdxBase, 0)));
1390       out->ySkewAngle.set_float (ySkewAngle.to_float (instancer (varIdxBase, 1)));
1391     }
1392 
1393     if (format == 29 && c->plan->all_axes_pinned)
1394         out->format = 28;
1395 
1396     return_trace (out->src.serialize_subset (c, src, this, instancer));
1397   }
1398 
sanitizeOT::PaintSkew1399   bool sanitize (hb_sanitize_context_t *c) const
1400   {
1401     TRACE_SANITIZE (this);
1402     return_trace (c->check_struct (this) && src.sanitize (c, this));
1403   }
1404 
paint_glyphOT::PaintSkew1405   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1406   {
1407     TRACE_PAINT (this);
1408     float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
1409     float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
1410 
1411     bool p1 = c->funcs->push_skew (c->data, sx, sy);
1412     c->recurse (this+src);
1413     if (p1) c->funcs->pop_transform (c->data);
1414   }
1415 
1416   HBUINT8		format; /* format = 28(noVar) or 29 (Var) */
1417   Offset24To<Paint>	src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */
1418   F2DOT14		xSkewAngle;
1419   F2DOT14		ySkewAngle;
1420   public:
1421   DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size);
1422 };
1423 
1424 struct PaintSkewAroundCenter
1425 {
1426   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1427 
subsetOT::PaintSkewAroundCenter1428   bool subset (hb_subset_context_t *c,
1429                const ItemVarStoreInstancer &instancer,
1430                uint32_t varIdxBase) const
1431   {
1432     TRACE_SUBSET (this);
1433     auto *out = c->serializer->embed (this);
1434     if (unlikely (!out)) return_trace (false);
1435 
1436     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1437     {
1438       out->xSkewAngle.set_float (xSkewAngle.to_float (instancer (varIdxBase, 0)));
1439       out->ySkewAngle.set_float (ySkewAngle.to_float (instancer (varIdxBase, 1)));
1440       out->centerX = centerX + (int) roundf (instancer (varIdxBase, 2));
1441       out->centerY = centerY + (int) roundf (instancer (varIdxBase, 3));
1442     }
1443 
1444     if (format == 31 && c->plan->all_axes_pinned)
1445         out->format = 30;
1446 
1447     return_trace (out->src.serialize_subset (c, src, this, instancer));
1448   }
1449 
sanitizeOT::PaintSkewAroundCenter1450   bool sanitize (hb_sanitize_context_t *c) const
1451   {
1452     TRACE_SANITIZE (this);
1453     return_trace (c->check_struct (this) && src.sanitize (c, this));
1454   }
1455 
paint_glyphOT::PaintSkewAroundCenter1456   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1457   {
1458     TRACE_PAINT (this);
1459     float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
1460     float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
1461     float tCenterX = centerX + c->instancer (varIdxBase, 2);
1462     float tCenterY = centerY + c->instancer (varIdxBase, 3);
1463 
1464     bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
1465     bool p2 = c->funcs->push_skew (c->data, sx, sy);
1466     bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
1467     c->recurse (this+src);
1468     if (p3) c->funcs->pop_transform (c->data);
1469     if (p2) c->funcs->pop_transform (c->data);
1470     if (p1) c->funcs->pop_transform (c->data);
1471   }
1472 
1473   HBUINT8		format; /* format = 30(noVar) or 31 (Var) */
1474   Offset24To<Paint>	src; /* Offset (from beginning of PaintSkewAroundCenter table) to Paint subtable. */
1475   F2DOT14	xSkewAngle;
1476   F2DOT14	ySkewAngle;
1477   FWORD		centerX;
1478   FWORD		centerY;
1479   public:
1480   DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size + 2 * FWORD::static_size);
1481 };
1482 
1483 struct PaintComposite
1484 {
1485   void closurev1 (hb_colrv1_closure_context_t* c) const;
1486 
subsetOT::PaintComposite1487   bool subset (hb_subset_context_t *c,
1488                const ItemVarStoreInstancer &instancer) const
1489   {
1490     TRACE_SUBSET (this);
1491     auto *out = c->serializer->embed (this);
1492     if (unlikely (!out)) return_trace (false);
1493 
1494     bool ret = false;
1495     ret |= out->src.serialize_subset (c, src, this, instancer);
1496     ret |= out->backdrop.serialize_subset (c, backdrop, this, instancer);
1497     return_trace (ret);
1498   }
1499 
sanitizeOT::PaintComposite1500   bool sanitize (hb_sanitize_context_t *c) const
1501   {
1502     TRACE_SANITIZE (this);
1503     return_trace (c->check_struct (this) &&
1504 		  c->check_ops (this->min_size) && // PainComposite can get exponential
1505                   src.sanitize (c, this) &&
1506                   backdrop.sanitize (c, this));
1507   }
1508 
paint_glyphOT::PaintComposite1509   void paint_glyph (hb_paint_context_t *c) const
1510   {
1511     TRACE_PAINT (this);
1512     c->recurse (this+backdrop);
1513     c->funcs->push_group (c->data);
1514     c->recurse (this+src);
1515     c->funcs->pop_group (c->data, (hb_paint_composite_mode_t) (int) mode);
1516   }
1517 
1518   HBUINT8		format; /* format = 32 */
1519   Offset24To<Paint>	src; /* Offset (from beginning of PaintComposite table) to source Paint subtable. */
1520   CompositeMode		mode;   /* If mode is unrecognized use COMPOSITE_CLEAR */
1521   Offset24To<Paint>	backdrop; /* Offset (from beginning of PaintComposite table) to backdrop Paint subtable. */
1522   public:
1523   DEFINE_SIZE_STATIC (8);
1524 };
1525 
1526 struct ClipBoxData
1527 {
1528   int xMin, yMin, xMax, yMax;
1529 };
1530 
1531 struct ClipBoxFormat1
1532 {
sanitizeOT::ClipBoxFormat11533   bool sanitize (hb_sanitize_context_t *c) const
1534   {
1535     TRACE_SANITIZE (this);
1536     return_trace (c->check_struct (this));
1537   }
1538 
get_clip_boxOT::ClipBoxFormat11539   void get_clip_box (ClipBoxData &clip_box, const ItemVarStoreInstancer &instancer HB_UNUSED) const
1540   {
1541     clip_box.xMin = xMin;
1542     clip_box.yMin = yMin;
1543     clip_box.xMax = xMax;
1544     clip_box.yMax = yMax;
1545   }
1546 
subsetOT::ClipBoxFormat11547   bool subset (hb_subset_context_t *c,
1548                const ItemVarStoreInstancer &instancer,
1549                uint32_t varIdxBase) const
1550   {
1551     TRACE_SUBSET (this);
1552     auto *out = c->serializer->embed (*this);
1553     if (unlikely (!out)) return_trace (false);
1554 
1555     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1556     {
1557       out->xMin = xMin + (int) roundf (instancer (varIdxBase, 0));
1558       out->yMin = yMin + (int) roundf (instancer (varIdxBase, 1));
1559       out->xMax = xMax + (int) roundf (instancer (varIdxBase, 2));
1560       out->yMax = yMax + (int) roundf (instancer (varIdxBase, 3));
1561     }
1562 
1563     if (format == 2 && c->plan->all_axes_pinned)
1564         out->format = 1;
1565 
1566     return_trace (true);
1567   }
1568 
1569   public:
1570   HBUINT8	format; /* format = 1(noVar) or 2(Var)*/
1571   FWORD		xMin;
1572   FWORD		yMin;
1573   FWORD		xMax;
1574   FWORD		yMax;
1575   public:
1576   DEFINE_SIZE_STATIC (1 + 4 * FWORD::static_size);
1577 };
1578 
1579 struct ClipBoxFormat2 : Variable<ClipBoxFormat1>
1580 {
get_clip_boxOT::ClipBoxFormat21581   void get_clip_box (ClipBoxData &clip_box, const ItemVarStoreInstancer &instancer) const
1582   {
1583     value.get_clip_box(clip_box, instancer);
1584     if (instancer)
1585     {
1586       clip_box.xMin += roundf (instancer (varIdxBase, 0));
1587       clip_box.yMin += roundf (instancer (varIdxBase, 1));
1588       clip_box.xMax += roundf (instancer (varIdxBase, 2));
1589       clip_box.yMax += roundf (instancer (varIdxBase, 3));
1590     }
1591   }
1592 
closurev1OT::ClipBoxFormat21593   void closurev1 (hb_colrv1_closure_context_t* c) const
1594   { c->variation_indices->add_range (varIdxBase, varIdxBase + 3); }
1595 };
1596 
1597 struct ClipBox
1598 {
subsetOT::ClipBox1599   bool subset (hb_subset_context_t *c,
1600                const ItemVarStoreInstancer &instancer) const
1601   {
1602     TRACE_SUBSET (this);
1603     switch (u.format) {
1604     case 1: return_trace (u.format1.subset (c, instancer, VarIdx::NO_VARIATION));
1605     case 2: return_trace (u.format2.subset (c, instancer));
1606     default:return_trace (c->default_return_value ());
1607     }
1608   }
1609 
closurev1OT::ClipBox1610   void closurev1 (hb_colrv1_closure_context_t* c) const
1611   {
1612     switch (u.format) {
1613     case 2: u.format2.closurev1 (c);
1614     default:return;
1615     }
1616   }
1617 
1618   template <typename context_t, typename ...Ts>
dispatchOT::ClipBox1619   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1620   {
1621     if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
1622     TRACE_DISPATCH (this, u.format);
1623     switch (u.format) {
1624     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
1625     case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
1626     default:return_trace (c->default_return_value ());
1627     }
1628   }
1629 
get_extentsOT::ClipBox1630   bool get_extents (hb_glyph_extents_t *extents,
1631                     const ItemVarStoreInstancer &instancer) const
1632   {
1633     ClipBoxData clip_box;
1634     switch (u.format) {
1635     case 1:
1636       u.format1.get_clip_box (clip_box, instancer);
1637       break;
1638     case 2:
1639       u.format2.get_clip_box (clip_box, instancer);
1640       break;
1641     default:
1642       return false;
1643     }
1644 
1645     extents->x_bearing = clip_box.xMin;
1646     extents->y_bearing = clip_box.yMax;
1647     extents->width = clip_box.xMax - clip_box.xMin;
1648     extents->height = clip_box.yMin - clip_box.yMax;
1649     return true;
1650   }
1651 
1652   protected:
1653   union {
1654   HBUINT8		format;         /* Format identifier */
1655   ClipBoxFormat1	format1;
1656   ClipBoxFormat2	format2;
1657   } u;
1658 };
1659 
1660 struct ClipRecord
1661 {
cmpOT::ClipRecord1662   int cmp (hb_codepoint_t g) const
1663   { return g < startGlyphID ? -1 : g <= endGlyphID ? 0 : +1; }
1664 
closurev1OT::ClipRecord1665   void closurev1 (hb_colrv1_closure_context_t* c, const void *base) const
1666   {
1667     if (!c->glyphs->intersects (startGlyphID, endGlyphID)) return;
1668     (base+clipBox).closurev1 (c);
1669   }
1670 
subsetOT::ClipRecord1671   bool subset (hb_subset_context_t *c,
1672                const void *base,
1673                const ItemVarStoreInstancer &instancer) const
1674   {
1675     TRACE_SUBSET (this);
1676     auto *out = c->serializer->embed (*this);
1677     if (unlikely (!out)) return_trace (false);
1678 
1679     return_trace (out->clipBox.serialize_subset (c, clipBox, base, instancer));
1680   }
1681 
sanitizeOT::ClipRecord1682   bool sanitize (hb_sanitize_context_t *c, const void *base) const
1683   {
1684     TRACE_SANITIZE (this);
1685     return_trace (c->check_struct (this) && clipBox.sanitize (c, base));
1686   }
1687 
get_extentsOT::ClipRecord1688   bool get_extents (hb_glyph_extents_t *extents,
1689 		    const void *base,
1690 		    const ItemVarStoreInstancer &instancer) const
1691   {
1692     return (base+clipBox).get_extents (extents, instancer);
1693   }
1694 
1695   public:
1696   HBUINT16		startGlyphID;  // first gid clip applies to
1697   HBUINT16		endGlyphID;    // last gid clip applies to, inclusive
1698   Offset24To<ClipBox>	clipBox;   // Box or VarBox
1699   public:
1700   DEFINE_SIZE_STATIC (7);
1701 };
1702 DECLARE_NULL_NAMESPACE_BYTES (OT, ClipRecord);
1703 
1704 struct ClipList
1705 {
serialize_clip_recordsOT::ClipList1706   unsigned serialize_clip_records (hb_subset_context_t *c,
1707                                    const ItemVarStoreInstancer &instancer,
1708                                    const hb_set_t& gids,
1709                                    const hb_map_t& gid_offset_map) const
1710   {
1711     TRACE_SERIALIZE (this);
1712     if (gids.is_empty () ||
1713         gid_offset_map.get_population () != gids.get_population ())
1714       return_trace (0);
1715 
1716     unsigned count  = 0;
1717 
1718     hb_codepoint_t start_gid= gids.get_min ();
1719     hb_codepoint_t prev_gid = start_gid;
1720 
1721     unsigned offset = gid_offset_map.get (start_gid);
1722     unsigned prev_offset = offset;
1723     for (const hb_codepoint_t _ : gids.iter ())
1724     {
1725       if (_ == start_gid) continue;
1726 
1727       offset = gid_offset_map.get (_);
1728       if (_ == prev_gid + 1 &&  offset == prev_offset)
1729       {
1730         prev_gid = _;
1731         continue;
1732       }
1733 
1734       ClipRecord record;
1735       record.startGlyphID = start_gid;
1736       record.endGlyphID = prev_gid;
1737       record.clipBox = prev_offset;
1738 
1739       if (!record.subset (c, this, instancer)) return_trace (0);
1740       count++;
1741 
1742       start_gid = _;
1743       prev_gid = _;
1744       prev_offset = offset;
1745     }
1746 
1747     //last one
1748     {
1749       ClipRecord record;
1750       record.startGlyphID = start_gid;
1751       record.endGlyphID = prev_gid;
1752       record.clipBox = prev_offset;
1753       if (!record.subset (c, this, instancer)) return_trace (0);
1754       count++;
1755     }
1756     return_trace (count);
1757   }
1758 
subsetOT::ClipList1759   bool subset (hb_subset_context_t *c,
1760                const ItemVarStoreInstancer &instancer) const
1761   {
1762     TRACE_SUBSET (this);
1763     auto *out = c->serializer->start_embed (*this);
1764     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
1765     if (!c->serializer->check_assign (out->format, format, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
1766 
1767     const hb_set_t& glyphset = c->plan->_glyphset_colred;
1768     const hb_map_t &glyph_map = *c->plan->glyph_map;
1769 
1770     hb_map_t new_gid_offset_map;
1771     hb_set_t new_gids;
1772     for (const ClipRecord& record : clips.iter ())
1773     {
1774       unsigned start_gid = record.startGlyphID;
1775       unsigned end_gid = record.endGlyphID;
1776       for (unsigned gid = start_gid; gid <= end_gid; gid++)
1777       {
1778         if (!glyphset.has (gid) || !glyph_map.has (gid)) continue;
1779         unsigned new_gid = glyph_map.get (gid);
1780         new_gid_offset_map.set (new_gid, record.clipBox);
1781         new_gids.add (new_gid);
1782       }
1783     }
1784 
1785     unsigned count = serialize_clip_records (c, instancer, new_gids, new_gid_offset_map);
1786     if (!count) return_trace (false);
1787     return_trace (c->serializer->check_assign (out->clips.len, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
1788   }
1789 
sanitizeOT::ClipList1790   bool sanitize (hb_sanitize_context_t *c) const
1791   {
1792     TRACE_SANITIZE (this);
1793     // TODO Make a formatted struct!
1794     return_trace (c->check_struct (this) && clips.sanitize (c, this));
1795   }
1796 
1797   bool
get_extentsOT::ClipList1798   get_extents (hb_codepoint_t gid,
1799 	       hb_glyph_extents_t *extents,
1800 	       const ItemVarStoreInstancer &instancer) const
1801   {
1802     auto *rec = clips.as_array ().bsearch (gid);
1803     if (rec)
1804     {
1805       rec->get_extents (extents, this, instancer);
1806       return true;
1807     }
1808     return false;
1809   }
1810 
1811   HBUINT8			format;  // Set to 1.
1812   SortedArray32Of<ClipRecord>	clips;  // Clip records, sorted by startGlyphID
1813   public:
1814   DEFINE_SIZE_ARRAY_SIZED (5, clips);
1815 };
1816 
1817 struct Paint
1818 {
1819 
1820   template <typename ...Ts>
sanitizeOT::Paint1821   bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
1822   {
1823     TRACE_SANITIZE (this);
1824 
1825     if (unlikely (!c->check_start_recursion (HB_MAX_NESTING_LEVEL)))
1826       return_trace (c->no_dispatch_return_value ());
1827 
1828     return_trace (c->end_recursion (this->dispatch (c, std::forward<Ts> (ds)...)));
1829   }
1830 
1831   template <typename context_t, typename ...Ts>
dispatchOT::Paint1832   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1833   {
1834     if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
1835     TRACE_DISPATCH (this, u.format);
1836     switch (u.format) {
1837     case 1: return_trace (c->dispatch (u.paintformat1, std::forward<Ts> (ds)...));
1838     case 2: return_trace (c->dispatch (u.paintformat2, std::forward<Ts> (ds)...));
1839     case 3: return_trace (c->dispatch (u.paintformat3, std::forward<Ts> (ds)...));
1840     case 4: return_trace (c->dispatch (u.paintformat4, std::forward<Ts> (ds)...));
1841     case 5: return_trace (c->dispatch (u.paintformat5, std::forward<Ts> (ds)...));
1842     case 6: return_trace (c->dispatch (u.paintformat6, std::forward<Ts> (ds)...));
1843     case 7: return_trace (c->dispatch (u.paintformat7, std::forward<Ts> (ds)...));
1844     case 8: return_trace (c->dispatch (u.paintformat8, std::forward<Ts> (ds)...));
1845     case 9: return_trace (c->dispatch (u.paintformat9, std::forward<Ts> (ds)...));
1846     case 10: return_trace (c->dispatch (u.paintformat10, std::forward<Ts> (ds)...));
1847     case 11: return_trace (c->dispatch (u.paintformat11, std::forward<Ts> (ds)...));
1848     case 12: return_trace (c->dispatch (u.paintformat12, std::forward<Ts> (ds)...));
1849     case 13: return_trace (c->dispatch (u.paintformat13, std::forward<Ts> (ds)...));
1850     case 14: return_trace (c->dispatch (u.paintformat14, std::forward<Ts> (ds)...));
1851     case 15: return_trace (c->dispatch (u.paintformat15, std::forward<Ts> (ds)...));
1852     case 16: return_trace (c->dispatch (u.paintformat16, std::forward<Ts> (ds)...));
1853     case 17: return_trace (c->dispatch (u.paintformat17, std::forward<Ts> (ds)...));
1854     case 18: return_trace (c->dispatch (u.paintformat18, std::forward<Ts> (ds)...));
1855     case 19: return_trace (c->dispatch (u.paintformat19, std::forward<Ts> (ds)...));
1856     case 20: return_trace (c->dispatch (u.paintformat20, std::forward<Ts> (ds)...));
1857     case 21: return_trace (c->dispatch (u.paintformat21, std::forward<Ts> (ds)...));
1858     case 22: return_trace (c->dispatch (u.paintformat22, std::forward<Ts> (ds)...));
1859     case 23: return_trace (c->dispatch (u.paintformat23, std::forward<Ts> (ds)...));
1860     case 24: return_trace (c->dispatch (u.paintformat24, std::forward<Ts> (ds)...));
1861     case 25: return_trace (c->dispatch (u.paintformat25, std::forward<Ts> (ds)...));
1862     case 26: return_trace (c->dispatch (u.paintformat26, std::forward<Ts> (ds)...));
1863     case 27: return_trace (c->dispatch (u.paintformat27, std::forward<Ts> (ds)...));
1864     case 28: return_trace (c->dispatch (u.paintformat28, std::forward<Ts> (ds)...));
1865     case 29: return_trace (c->dispatch (u.paintformat29, std::forward<Ts> (ds)...));
1866     case 30: return_trace (c->dispatch (u.paintformat30, std::forward<Ts> (ds)...));
1867     case 31: return_trace (c->dispatch (u.paintformat31, std::forward<Ts> (ds)...));
1868     case 32: return_trace (c->dispatch (u.paintformat32, std::forward<Ts> (ds)...));
1869     default:return_trace (c->default_return_value ());
1870     }
1871   }
1872 
1873   protected:
1874   union {
1875   HBUINT8					format;
1876   PaintColrLayers				paintformat1;
1877   NoVariable<PaintSolid>			paintformat2;
1878   Variable<PaintSolid>				paintformat3;
1879   NoVariable<PaintLinearGradient<NoVariable>>	paintformat4;
1880   Variable<PaintLinearGradient<Variable>>	paintformat5;
1881   NoVariable<PaintRadialGradient<NoVariable>>	paintformat6;
1882   Variable<PaintRadialGradient<Variable>>	paintformat7;
1883   NoVariable<PaintSweepGradient<NoVariable>>	paintformat8;
1884   Variable<PaintSweepGradient<Variable>>	paintformat9;
1885   PaintGlyph					paintformat10;
1886   PaintColrGlyph				paintformat11;
1887   PaintTransform<NoVariable>			paintformat12;
1888   PaintTransform<Variable>			paintformat13;
1889   NoVariable<PaintTranslate>			paintformat14;
1890   Variable<PaintTranslate>			paintformat15;
1891   NoVariable<PaintScale>			paintformat16;
1892   Variable<PaintScale>				paintformat17;
1893   NoVariable<PaintScaleAroundCenter>		paintformat18;
1894   Variable<PaintScaleAroundCenter>		paintformat19;
1895   NoVariable<PaintScaleUniform>			paintformat20;
1896   Variable<PaintScaleUniform>			paintformat21;
1897   NoVariable<PaintScaleUniformAroundCenter>	paintformat22;
1898   Variable<PaintScaleUniformAroundCenter>	paintformat23;
1899   NoVariable<PaintRotate>			paintformat24;
1900   Variable<PaintRotate>				paintformat25;
1901   NoVariable<PaintRotateAroundCenter>		paintformat26;
1902   Variable<PaintRotateAroundCenter>		paintformat27;
1903   NoVariable<PaintSkew>				paintformat28;
1904   Variable<PaintSkew>				paintformat29;
1905   NoVariable<PaintSkewAroundCenter>		paintformat30;
1906   Variable<PaintSkewAroundCenter>		paintformat31;
1907   PaintComposite				paintformat32;
1908   } u;
1909   public:
1910   DEFINE_SIZE_MIN (2);
1911 };
1912 
1913 struct BaseGlyphPaintRecord
1914 {
cmpOT::BaseGlyphPaintRecord1915   int cmp (hb_codepoint_t g) const
1916   { return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
1917 
serializeOT::BaseGlyphPaintRecord1918   bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map,
1919                   const void* src_base, hb_subset_context_t *c,
1920                   const ItemVarStoreInstancer &instancer) const
1921   {
1922     TRACE_SERIALIZE (this);
1923     auto *out = s->embed (this);
1924     if (unlikely (!out)) return_trace (false);
1925     if (!s->check_assign (out->glyphId, glyph_map->get (glyphId),
1926                           HB_SERIALIZE_ERROR_INT_OVERFLOW))
1927       return_trace (false);
1928 
1929     return_trace (out->paint.serialize_subset (c, paint, src_base, instancer));
1930   }
1931 
sanitizeOT::BaseGlyphPaintRecord1932   bool sanitize (hb_sanitize_context_t *c, const void *base) const
1933   {
1934     TRACE_SANITIZE (this);
1935     return_trace (likely (c->check_struct (this) && paint.sanitize (c, base)));
1936   }
1937 
1938   public:
1939   HBGlyphID16		glyphId;    /* Glyph ID of reference glyph */
1940   Offset32To<Paint>	paint;      /* Offset (from beginning of BaseGlyphPaintRecord array) to Paint,
1941                                      * Typically PaintColrLayers */
1942   public:
1943   DEFINE_SIZE_STATIC (6);
1944 };
1945 
1946 struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
1947 {
subsetOT::BaseGlyphList1948   bool subset (hb_subset_context_t *c,
1949                const ItemVarStoreInstancer &instancer) const
1950   {
1951     TRACE_SUBSET (this);
1952     auto *out = c->serializer->start_embed (this);
1953     if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
1954     const hb_set_t* glyphset = &c->plan->_glyphset_colred;
1955 
1956     for (const auto& _ : as_array ())
1957     {
1958       unsigned gid = _.glyphId;
1959       if (!glyphset->has (gid)) continue;
1960 
1961       if (_.serialize (c->serializer, c->plan->glyph_map, this, c, instancer)) out->len++;
1962       else return_trace (false);
1963     }
1964 
1965     return_trace (out->len != 0);
1966   }
1967 
sanitizeOT::BaseGlyphList1968   bool sanitize (hb_sanitize_context_t *c) const
1969   {
1970     TRACE_SANITIZE (this);
1971     return_trace (SortedArray32Of<BaseGlyphPaintRecord>::sanitize (c, this));
1972   }
1973 };
1974 
1975 struct LayerList : Array32OfOffset32To<Paint>
1976 {
get_paintOT::LayerList1977   const Paint& get_paint (unsigned i) const
1978   { return this+(*this)[i]; }
1979 
subsetOT::LayerList1980   bool subset (hb_subset_context_t *c,
1981                const ItemVarStoreInstancer &instancer) const
1982   {
1983     TRACE_SUBSET (this);
1984     auto *out = c->serializer->start_embed (this);
1985     if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
1986 
1987     bool ret = false;
1988     for (const auto& _ : + hb_enumerate (*this)
1989                          | hb_filter (c->plan->colrv1_layers, hb_first))
1990 
1991     {
1992       auto *o = out->serialize_append (c->serializer);
1993       if (unlikely (!o)) return_trace (false);
1994       ret |= o->serialize_subset (c, _.second, this, instancer);
1995     }
1996     return_trace (ret);
1997   }
1998 
sanitizeOT::LayerList1999   bool sanitize (hb_sanitize_context_t *c) const
2000   {
2001     TRACE_SANITIZE (this);
2002     return_trace (Array32OfOffset32To<Paint>::sanitize (c, this));
2003   }
2004 };
2005 
2006 struct delta_set_index_map_subset_plan_t
2007 {
get_inner_bit_countOT::delta_set_index_map_subset_plan_t2008   unsigned get_inner_bit_count () const { return inner_bit_count; }
get_widthOT::delta_set_index_map_subset_plan_t2009   unsigned get_width ()           const { return ((outer_bit_count + inner_bit_count + 7) / 8); }
get_output_mapOT::delta_set_index_map_subset_plan_t2010   hb_array_t<const uint32_t> get_output_map () const { return output_map.as_array (); }
2011 
delta_set_index_map_subset_plan_tOT::delta_set_index_map_subset_plan_t2012   delta_set_index_map_subset_plan_t (const hb_map_t &new_deltaset_idx_varidx_map)
2013   {
2014     map_count = 0;
2015     outer_bit_count = 0;
2016     inner_bit_count = 1;
2017     output_map.init ();
2018 
2019     /* search backwards */
2020     unsigned count = new_deltaset_idx_varidx_map.get_population ();
2021     if (!count) return;
2022 
2023     unsigned last_idx = (unsigned)-1;
2024     unsigned last_varidx = (unsigned)-1;
2025 
2026     for (unsigned i = count; i; i--)
2027     {
2028       unsigned delta_set_idx = i - 1;
2029       unsigned var_idx = new_deltaset_idx_varidx_map.get (delta_set_idx);
2030       if (i == count)
2031       {
2032         last_idx = delta_set_idx;
2033         last_varidx = var_idx;
2034         continue;
2035       }
2036       if (var_idx != last_varidx)
2037         break;
2038       last_idx = delta_set_idx;
2039     }
2040 
2041     map_count = last_idx + 1;
2042   }
2043 
remapOT::delta_set_index_map_subset_plan_t2044   bool remap (const hb_map_t &new_deltaset_idx_varidx_map)
2045   {
2046     /* recalculate bit_count */
2047     outer_bit_count = 1;
2048     inner_bit_count = 1;
2049 
2050     if (unlikely (!output_map.resize (map_count, false))) return false;
2051 
2052     for (unsigned idx = 0; idx < map_count; idx++)
2053     {
2054       uint32_t *var_idx;
2055       if (!new_deltaset_idx_varidx_map.has (idx, &var_idx)) return false;
2056       output_map.arrayZ[idx] = *var_idx;
2057 
2058       unsigned outer = (*var_idx) >> 16;
2059       unsigned bit_count = (outer == 0) ? 1 : hb_bit_storage (outer);
2060       outer_bit_count = hb_max (bit_count, outer_bit_count);
2061 
2062       unsigned inner = (*var_idx) & 0xFFFF;
2063       bit_count = (inner == 0) ? 1 : hb_bit_storage (inner);
2064       inner_bit_count = hb_max (bit_count, inner_bit_count);
2065     }
2066     return true;
2067   }
2068 
2069   private:
2070   unsigned map_count;
2071   unsigned outer_bit_count;
2072   unsigned inner_bit_count;
2073   hb_vector_t<uint32_t> output_map;
2074 };
2075 
2076 struct COLR
2077 {
2078   static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
2079 
has_v0_dataOT::COLR2080   bool has_v0_data () const { return numBaseGlyphs; }
has_v1_dataOT::COLR2081   bool has_v1_data () const
2082   {
2083     if (version < 1)
2084       return false;
2085     hb_barrier ();
2086 
2087     return (this+baseGlyphList).len > 0;
2088   }
2089 
get_glyph_layersOT::COLR2090   unsigned int get_glyph_layers (hb_codepoint_t       glyph,
2091 				 unsigned int         start_offset,
2092 				 unsigned int        *count, /* IN/OUT.  May be NULL. */
2093 				 hb_ot_color_layer_t *layers /* OUT.     May be NULL. */) const
2094   {
2095     const BaseGlyphRecord &record = (this+baseGlyphsZ).bsearch (numBaseGlyphs, glyph);
2096 
2097     hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
2098     hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
2099 								       record.numLayers);
2100     if (count)
2101     {
2102       + glyph_layers.sub_array (start_offset, count)
2103       | hb_sink (hb_array (layers, *count))
2104       ;
2105     }
2106     return glyph_layers.length;
2107   }
2108 
2109   struct accelerator_t
2110   {
accelerator_tOT::COLR::accelerator_t2111     accelerator_t (hb_face_t *face)
2112     { colr = hb_sanitize_context_t ().reference_table<COLR> (face); }
~accelerator_tOT::COLR::accelerator_t2113     ~accelerator_t () { this->colr.destroy (); }
2114 
is_validOT::COLR::accelerator_t2115     bool is_valid () { return colr.get_blob ()->length; }
2116 
closure_glyphsOT::COLR::accelerator_t2117     void closure_glyphs (hb_codepoint_t glyph,
2118 			 hb_set_t *related_ids /* OUT */) const
2119     { colr->closure_glyphs (glyph, related_ids); }
2120 
closure_V0palette_indicesOT::COLR::accelerator_t2121     void closure_V0palette_indices (const hb_set_t *glyphs,
2122 				    hb_set_t *palettes /* OUT */) const
2123     { colr->closure_V0palette_indices (glyphs, palettes); }
2124 
closure_forV1OT::COLR::accelerator_t2125     void closure_forV1 (hb_set_t *glyphset,
2126                         hb_set_t *layer_indices,
2127                         hb_set_t *palette_indices,
2128                         hb_set_t *variation_indices,
2129                         hb_set_t *delta_set_indices) const
2130     { colr->closure_forV1 (glyphset, layer_indices, palette_indices, variation_indices, delta_set_indices); }
2131 
has_var_storeOT::COLR::accelerator_t2132     bool has_var_store () const
2133     { return colr->has_var_store (); }
2134 
get_var_storeOT::COLR::accelerator_t2135     const ItemVariationStore &get_var_store () const
2136     { return colr->get_var_store (); }
2137 
has_delta_set_index_mapOT::COLR::accelerator_t2138     bool has_delta_set_index_map () const
2139     { return colr->has_delta_set_index_map (); }
2140 
get_delta_set_index_mapOT::COLR::accelerator_t2141     const DeltaSetIndexMap &get_delta_set_index_map () const
2142     { return colr->get_delta_set_index_map (); }
2143 
2144     private:
2145     hb_blob_ptr_t<COLR> colr;
2146   };
2147 
closure_glyphsOT::COLR2148   void closure_glyphs (hb_codepoint_t glyph,
2149 		       hb_set_t *related_ids /* OUT */) const
2150   {
2151     const BaseGlyphRecord *record = get_base_glyph_record (glyph);
2152     if (!record) return;
2153 
2154     auto glyph_layers = (this+layersZ).as_array (numLayers).sub_array (record->firstLayerIdx,
2155 								       record->numLayers);
2156     if (!glyph_layers.length) return;
2157     related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size);
2158   }
2159 
closure_V0palette_indicesOT::COLR2160   void closure_V0palette_indices (const hb_set_t *glyphs,
2161 				  hb_set_t *palettes /* OUT */) const
2162   {
2163     if (!numBaseGlyphs || !numLayers) return;
2164     hb_array_t<const BaseGlyphRecord> baseGlyphs = (this+baseGlyphsZ).as_array (numBaseGlyphs);
2165     hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
2166 
2167     for (const BaseGlyphRecord record : baseGlyphs)
2168     {
2169       if (!glyphs->has (record.glyphId)) continue;
2170       hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
2171                                                                    record.numLayers);
2172       for (const LayerRecord layer : glyph_layers)
2173         palettes->add (layer.colorIdx);
2174     }
2175   }
2176 
closure_forV1OT::COLR2177   void closure_forV1 (hb_set_t *glyphset,
2178                       hb_set_t *layer_indices,
2179                       hb_set_t *palette_indices,
2180                       hb_set_t *variation_indices,
2181                       hb_set_t *delta_set_indices) const
2182   {
2183     if (version < 1) return;
2184     hb_barrier ();
2185 
2186     hb_set_t visited_glyphs;
2187 
2188     hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices, variation_indices);
2189     const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList;
2190 
2191     for (const BaseGlyphPaintRecord &baseglyph_paintrecord: baseglyph_paintrecords.iter ())
2192     {
2193       unsigned gid = baseglyph_paintrecord.glyphId;
2194       if (!glyphset->has (gid)) continue;
2195 
2196       const Paint &paint = &baseglyph_paintrecords+baseglyph_paintrecord.paint;
2197       paint.dispatch (&c);
2198     }
2199     hb_set_union (glyphset, &visited_glyphs);
2200 
2201     const ClipList &cliplist = this+clipList;
2202     c.glyphs = glyphset;
2203     for (const ClipRecord &clip_record : cliplist.clips.iter())
2204       clip_record.closurev1 (&c, &cliplist);
2205 
2206     // if a DeltaSetIndexMap is included, collected variation indices are
2207     // actually delta set indices, we need to map them into variation indices
2208     if (has_delta_set_index_map ())
2209     {
2210       const DeltaSetIndexMap &var_idx_map = this+varIdxMap;
2211       delta_set_indices->set (*variation_indices);
2212       variation_indices->clear ();
2213       for (unsigned delta_set_idx : *delta_set_indices)
2214         variation_indices->add (var_idx_map.map (delta_set_idx));
2215     }
2216   }
2217 
get_layerListOT::COLR2218   const LayerList& get_layerList () const
2219   { return (this+layerList); }
2220 
get_baseglyphListOT::COLR2221   const BaseGlyphList& get_baseglyphList () const
2222   { return (this+baseGlyphList); }
2223 
has_var_storeOT::COLR2224   bool has_var_store () const
2225   { return version >= 1 && hb_barrier () && varStore != 0; }
2226 
has_delta_set_index_mapOT::COLR2227   bool has_delta_set_index_map () const
2228   { return version >= 1 && hb_barrier () && varIdxMap != 0; }
2229 
has_clip_listOT::COLR2230   bool has_clip_list () const
2231   { return version >= 1 && hb_barrier () && clipList != 0; }
2232 
get_delta_set_index_mapOT::COLR2233   const DeltaSetIndexMap &get_delta_set_index_map () const
2234   { return has_delta_set_index_map () && hb_barrier () ? this+varIdxMap : Null (DeltaSetIndexMap); }
2235 
get_var_storeOT::COLR2236   const ItemVariationStore &get_var_store () const
2237   { return has_var_store () && hb_barrier () ? this+varStore : Null (ItemVariationStore); }
2238 
get_clip_listOT::COLR2239   const ClipList &get_clip_list () const
2240   { return has_clip_list () && hb_barrier () ? this+clipList : Null (ClipList); }
2241 
sanitizeOT::COLR2242   bool sanitize (hb_sanitize_context_t *c) const
2243   {
2244     TRACE_SANITIZE (this);
2245     return_trace (c->check_struct (this) &&
2246 		  hb_barrier () &&
2247                   (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
2248                   (this+layersZ).sanitize (c, numLayers) &&
2249                   (version == 0 ||
2250 		   (hb_barrier () &&
2251 		    baseGlyphList.sanitize (c, this) &&
2252 		    layerList.sanitize (c, this) &&
2253 		    clipList.sanitize (c, this) &&
2254 		    varIdxMap.sanitize (c, this) &&
2255 		    varStore.sanitize (c, this))));
2256   }
2257 
2258   template<typename BaseIterator, typename LayerIterator,
2259 	   hb_requires (hb_is_iterator (BaseIterator)),
2260 	   hb_requires (hb_is_iterator (LayerIterator))>
serialize_V0OT::COLR2261   bool serialize_V0 (hb_serialize_context_t *c,
2262 		     unsigned version,
2263 		     BaseIterator base_it,
2264 		     LayerIterator layer_it)
2265   {
2266     TRACE_SERIALIZE (this);
2267     if (unlikely (base_it.len () != layer_it.len ()))
2268       return_trace (false);
2269 
2270     this->version = version;
2271     numLayers = 0;
2272     numBaseGlyphs = base_it.len ();
2273     if (numBaseGlyphs == 0)
2274     {
2275       baseGlyphsZ = 0;
2276       layersZ = 0;
2277       return_trace (true);
2278     }
2279 
2280     c->push ();
2281     for (const hb_item_type<BaseIterator> _ : + base_it.iter ())
2282     {
2283       auto* record = c->embed (_);
2284       if (unlikely (!record)) return_trace (false);
2285       record->firstLayerIdx = numLayers;
2286       numLayers += record->numLayers;
2287     }
2288     c->add_link (baseGlyphsZ, c->pop_pack ());
2289 
2290     c->push ();
2291     for (const hb_item_type<LayerIterator>& _ : + layer_it.iter ())
2292       _.as_array ().copy (c);
2293 
2294     c->add_link (layersZ, c->pop_pack ());
2295 
2296     return_trace (true);
2297   }
2298 
get_base_glyph_recordOT::COLR2299   const BaseGlyphRecord* get_base_glyph_record (hb_codepoint_t gid) const
2300   {
2301     const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, (unsigned int) gid);
2302     if (record == &Null (BaseGlyphRecord) ||
2303         (record && (hb_codepoint_t) record->glyphId != gid))
2304       record = nullptr;
2305     return record;
2306   }
2307 
get_base_glyph_paintrecordOT::COLR2308   const BaseGlyphPaintRecord* get_base_glyph_paintrecord (hb_codepoint_t gid) const
2309   {
2310     const BaseGlyphPaintRecord* record = &(this+baseGlyphList).bsearch ((unsigned) gid);
2311     if ((record && (hb_codepoint_t) record->glyphId != gid))
2312       record = nullptr;
2313     return record;
2314   }
2315 
downgrade_to_V0OT::COLR2316   bool downgrade_to_V0 (const hb_set_t &glyphset) const
2317   {
2318     //no more COLRv1 glyphs, downgrade to version 0
2319     for (const BaseGlyphPaintRecord& _ : get_baseglyphList ())
2320       if (glyphset.has (_.glyphId))
2321         return false;
2322 
2323     return true;
2324   }
2325 
subset_varstoreOT::COLR2326   bool subset_varstore (hb_subset_context_t *c,
2327                         COLR* out /* OUT */) const
2328   {
2329     TRACE_SUBSET (this);
2330     if (!varStore || c->plan->all_axes_pinned ||
2331         !c->plan->colrv1_variation_idx_delta_map)
2332       return_trace (true);
2333 
2334     const ItemVariationStore& var_store = this+varStore;
2335     if (c->plan->normalized_coords)
2336     {
2337       item_variations_t item_vars;
2338       /* turn off varstore optimization when varIdxMap is null, so we maintain
2339        * original var_idx sequence */
2340       bool optimize = (varIdxMap != 0) ? true : false;
2341       if (!item_vars.instantiate (var_store, c->plan,
2342                                   optimize, /* optimization */
2343                                   optimize, /* use_no_variation_idx = false */
2344                                   c->plan->colrv1_varstore_inner_maps.as_array ()))
2345         return_trace (false);
2346 
2347       /* do not serialize varStore if there's no variation data after
2348        * instancing: region_list or var_data is empty */
2349       if (item_vars.get_region_list () &&
2350           item_vars.get_vardata_encodings () &&
2351           !out->varStore.serialize_serialize (c->serializer,
2352                                               item_vars.has_long_word (),
2353                                               c->plan->axis_tags,
2354                                               item_vars.get_region_list (),
2355                                               item_vars.get_vardata_encodings ()))
2356         return_trace (false);
2357 
2358       /* if varstore is optimized, update colrv1_new_deltaset_idx_varidx_map in
2359        * subset plan.
2360        * If varstore is empty after instancing, varidx_map would be empty and
2361        * all var_idxes will be updated to VarIdx::NO_VARIATION */
2362       if (optimize)
2363       {
2364         const hb_map_t &varidx_map = item_vars.get_varidx_map ();
2365         for (auto _ : c->plan->colrv1_new_deltaset_idx_varidx_map.iter_ref ())
2366         {
2367           uint32_t varidx = _.second;
2368           uint32_t *new_varidx;
2369           if (varidx_map.has (varidx, &new_varidx))
2370             _.second = *new_varidx;
2371           else
2372             _.second = VarIdx::NO_VARIATION;
2373         }
2374       }
2375     }
2376     else
2377     {
2378       if (unlikely (!out->varStore.serialize_serialize (c->serializer,
2379                                                         &var_store,
2380                                                         c->plan->colrv1_varstore_inner_maps.as_array ())))
2381         return_trace (false);
2382     }
2383 
2384     return_trace (true);
2385   }
2386 
subset_delta_set_index_mapOT::COLR2387   bool subset_delta_set_index_map (hb_subset_context_t *c,
2388                                    COLR* out /* OUT */) const
2389   {
2390     TRACE_SUBSET (this);
2391     if (!varIdxMap || c->plan->all_axes_pinned ||
2392         !c->plan->colrv1_new_deltaset_idx_varidx_map)
2393       return_trace (true);
2394 
2395     const hb_map_t &deltaset_idx_varidx_map = c->plan->colrv1_new_deltaset_idx_varidx_map;
2396     delta_set_index_map_subset_plan_t index_map_plan (deltaset_idx_varidx_map);
2397 
2398     if (unlikely (!index_map_plan.remap (deltaset_idx_varidx_map)))
2399       return_trace (false);
2400 
2401     return_trace (out->varIdxMap.serialize_serialize (c->serializer, index_map_plan));
2402   }
2403 
subsetOT::COLR2404   bool subset (hb_subset_context_t *c) const
2405   {
2406     TRACE_SUBSET (this);
2407     const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
2408     const hb_set_t& glyphset = c->plan->_glyphset_colred;
2409 
2410     auto base_it =
2411     + hb_range (c->plan->num_output_glyphs ())
2412     | hb_filter ([&](hb_codepoint_t new_gid)
2413 		 {
2414 		    hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
2415 		    if (glyphset.has (old_gid)) return true;
2416 		    return false;
2417 		 })
2418     | hb_map_retains_sorting ([&](hb_codepoint_t new_gid)
2419 			      {
2420 				hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
2421 
2422 				const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
2423 				if (unlikely (!old_record))
2424 				  return hb_pair_t<bool, BaseGlyphRecord> (false, Null (BaseGlyphRecord));
2425 				BaseGlyphRecord new_record = {};
2426 				new_record.glyphId = new_gid;
2427 				new_record.numLayers = old_record->numLayers;
2428 				return hb_pair_t<bool, BaseGlyphRecord> (true, new_record);
2429 			      })
2430     | hb_filter (hb_first)
2431     | hb_map_retains_sorting (hb_second)
2432     ;
2433 
2434     auto layer_it =
2435     + hb_range (c->plan->num_output_glyphs ())
2436     | hb_map (reverse_glyph_map)
2437     | hb_filter (glyphset)
2438     | hb_map_retains_sorting ([&](hb_codepoint_t old_gid)
2439 			      {
2440 				const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
2441 				hb_vector_t<LayerRecord> out_layers;
2442 
2443 				if (unlikely (!old_record ||
2444 					      old_record->firstLayerIdx >= numLayers ||
2445 					      old_record->firstLayerIdx + old_record->numLayers > numLayers))
2446 				  return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
2447 
2448 				auto layers = (this+layersZ).as_array (numLayers).sub_array (old_record->firstLayerIdx,
2449 											     old_record->numLayers);
2450 				out_layers.resize (layers.length);
2451 				for (unsigned int i = 0; i < layers.length; i++) {
2452 				  out_layers[i] = layers[i];
2453 				  hb_codepoint_t new_gid = 0;
2454 				  if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid)))
2455 				    return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
2456 				  out_layers[i].glyphId = new_gid;
2457 				  out_layers[i].colorIdx = c->plan->colr_palettes.get (layers[i].colorIdx);
2458 				}
2459 
2460 				return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers);
2461 			      })
2462     | hb_filter (hb_first)
2463     | hb_map_retains_sorting (hb_second)
2464     ;
2465 
2466     if (version == 0 && (!base_it || !layer_it))
2467       return_trace (false);
2468 
2469     auto *colr_prime = c->serializer->start_embed<COLR> ();
2470     if (unlikely (!c->serializer->extend_min (colr_prime)))  return_trace (false);
2471 
2472     if (version == 0 || downgrade_to_V0 (glyphset))
2473       return_trace (colr_prime->serialize_V0 (c->serializer, 0, base_it, layer_it));
2474 
2475     hb_barrier ();
2476 
2477     //start version 1
2478     if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false);
2479     if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false);
2480 
2481     /* subset ItemVariationStore first, cause varidx_map needs to be updated
2482      * after instancing */
2483     if (!subset_varstore (c, colr_prime)) return_trace (false);
2484 
2485     ItemVarStoreInstancer instancer (&(get_var_store ()),
2486 	                         &(get_delta_set_index_map ()),
2487 	                         c->plan->normalized_coords.as_array ());
2488 
2489     if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this, instancer))
2490       return_trace (false);
2491 
2492     colr_prime->layerList.serialize_subset (c, layerList, this, instancer);
2493     colr_prime->clipList.serialize_subset (c, clipList, this, instancer);
2494 
2495     return_trace (subset_delta_set_index_map (c, colr_prime));
2496   }
2497 
get_base_glyph_paintOT::COLR2498   const Paint *get_base_glyph_paint (hb_codepoint_t glyph) const
2499   {
2500     const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList;
2501     const BaseGlyphPaintRecord* record = get_base_glyph_paintrecord (glyph);
2502     if (record)
2503     {
2504       const Paint &paint = &baseglyph_paintrecords+record->paint;
2505       return &paint;
2506     }
2507     else
2508       return nullptr;
2509   }
2510 
2511 #ifndef HB_NO_PAINT
2512   bool
get_extentsOT::COLR2513   get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
2514   {
2515 
2516     ItemVarStoreInstancer instancer (&(get_var_store ()),
2517                                      &(get_delta_set_index_map ()),
2518                                      hb_array (font->coords, font->num_coords));
2519 
2520     if (get_clip (glyph, extents, instancer))
2521     {
2522       font->scale_glyph_extents (extents);
2523       return true;
2524     }
2525 
2526     auto *extents_funcs = hb_paint_extents_get_funcs ();
2527     hb_paint_extents_context_t extents_data;
2528     bool ret = paint_glyph (font, glyph, extents_funcs, &extents_data, 0, HB_COLOR(0,0,0,0));
2529 
2530     hb_extents_t e = extents_data.get_extents ();
2531     if (e.is_void ())
2532     {
2533       extents->x_bearing = 0;
2534       extents->y_bearing = 0;
2535       extents->width = 0;
2536       extents->height = 0;
2537     }
2538     else
2539     {
2540       extents->x_bearing = e.xmin;
2541       extents->y_bearing = e.ymax;
2542       extents->width = e.xmax - e.xmin;
2543       extents->height = e.ymin - e.ymax;
2544     }
2545 
2546     return ret;
2547   }
2548 #endif
2549 
2550   bool
has_paint_for_glyphOT::COLR2551   has_paint_for_glyph (hb_codepoint_t glyph) const
2552   {
2553     if (version >= 1)
2554     {
2555       hb_barrier ();
2556 
2557       const Paint *paint = get_base_glyph_paint (glyph);
2558 
2559       return paint != nullptr;
2560     }
2561 
2562     return false;
2563   }
2564 
get_clipOT::COLR2565   bool get_clip (hb_codepoint_t glyph,
2566 		 hb_glyph_extents_t *extents,
2567 		 const ItemVarStoreInstancer instancer) const
2568   {
2569     return get_clip_list ().get_extents (glyph,
2570 					extents,
2571 					instancer);
2572   }
2573 
2574 #ifndef HB_NO_PAINT
2575   bool
paint_glyphOT::COLR2576   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
2577   {
2578     ItemVarStoreInstancer instancer (&(get_var_store ()),
2579 	                         &(get_delta_set_index_map ()),
2580 	                         hb_array (font->coords, font->num_coords));
2581     hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer);
2582     c.current_glyphs.add (glyph);
2583 
2584     if (version >= 1)
2585     {
2586       hb_barrier ();
2587 
2588       const Paint *paint = get_base_glyph_paint (glyph);
2589       if (paint)
2590       {
2591         // COLRv1 glyph
2592 
2593 	bool is_bounded = true;
2594 	if (clip)
2595 	{
2596 	  hb_glyph_extents_t extents;
2597 	  if (get_clip (glyph, &extents, instancer))
2598 	  {
2599 	    font->scale_glyph_extents (&extents);
2600 	    c.funcs->push_clip_rectangle (c.data,
2601 					  extents.x_bearing,
2602 					  extents.y_bearing + extents.height,
2603 					  extents.x_bearing + extents.width,
2604 					  extents.y_bearing);
2605 	  }
2606 	  else
2607 	  {
2608 	    auto *extents_funcs = hb_paint_extents_get_funcs ();
2609 	    hb_paint_extents_context_t extents_data;
2610 
2611 	    paint_glyph (font, glyph,
2612 			 extents_funcs, &extents_data,
2613 			 palette_index, foreground,
2614 			 false);
2615 
2616 	    hb_extents_t extents = extents_data.get_extents ();
2617 	    is_bounded = extents_data.is_bounded ();
2618 
2619 	    c.funcs->push_clip_rectangle (c.data,
2620 					  extents.xmin,
2621 					  extents.ymin,
2622 					  extents.xmax,
2623 					  extents.ymax);
2624 	  }
2625 	}
2626 
2627 	c.funcs->push_root_transform (c.data, font);
2628 
2629 	if (is_bounded)
2630 	  c.recurse (*paint);
2631 
2632 	c.funcs->pop_transform (c.data);
2633 
2634 	if (clip)
2635 	  c.funcs->pop_clip (c.data);
2636 
2637         return true;
2638       }
2639     }
2640 
2641     const BaseGlyphRecord *record = get_base_glyph_record (glyph);
2642     if (record && ((hb_codepoint_t) record->glyphId == glyph))
2643     {
2644       // COLRv0 glyph
2645       for (const auto &r : (this+layersZ).as_array (numLayers)
2646 			   .sub_array (record->firstLayerIdx, record->numLayers))
2647       {
2648         hb_bool_t is_foreground;
2649         hb_color_t color = c.get_color (r.colorIdx, 1., &is_foreground);
2650         c.funcs->push_clip_glyph (c.data, r.glyphId, c.font);
2651         c.funcs->color (c.data, is_foreground, color);
2652         c.funcs->pop_clip (c.data);
2653       }
2654 
2655       return true;
2656     }
2657 
2658     return false;
2659   }
2660 #endif
2661 
2662   protected:
2663   HBUINT16	version;	/* Table version number (starts at 0). */
2664   HBUINT16	numBaseGlyphs;	/* Number of Base Glyph Records. */
2665   NNOffset32To<SortedUnsizedArrayOf<BaseGlyphRecord>>
2666 		baseGlyphsZ;	/* Offset to Base Glyph records. */
2667   NNOffset32To<UnsizedArrayOf<LayerRecord>>
2668 		layersZ;	/* Offset to Layer Records. */
2669   HBUINT16	numLayers;	/* Number of Layer Records. */
2670   // Version-1 additions
2671   Offset32To<BaseGlyphList>		baseGlyphList;
2672   Offset32To<LayerList>			layerList;
2673   Offset32To<ClipList>			clipList;   // Offset to ClipList table (may be NULL)
2674   Offset32To<DeltaSetIndexMap>		varIdxMap;  // Offset to DeltaSetIndexMap table (may be NULL)
2675   Offset32To<ItemVariationStore>	varStore;
2676   public:
2677   DEFINE_SIZE_MIN (14);
2678 };
2679 
2680 struct COLR_accelerator_t : COLR::accelerator_t {
COLR_accelerator_tOT::COLR_accelerator_t2681   COLR_accelerator_t (hb_face_t *face) : COLR::accelerator_t (face) {}
2682 };
2683 
2684 void
recurse(const Paint & paint)2685 hb_paint_context_t::recurse (const Paint &paint)
2686 {
2687   if (unlikely (depth_left <= 0 || edge_count <= 0)) return;
2688   depth_left--;
2689   edge_count--;
2690   paint.dispatch (this);
2691   depth_left++;
2692 }
2693 
paint_glyph(hb_paint_context_t * c) const2694 void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const
2695 {
2696   TRACE_PAINT (this);
2697   const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList ();
2698   for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++)
2699   {
2700     if (unlikely (c->current_layers.has (i)))
2701       continue;
2702 
2703     c->current_layers.add (i);
2704 
2705     const Paint &paint = paint_offset_lists.get_paint (i);
2706     c->funcs->push_group (c->data);
2707     c->recurse (paint);
2708     c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
2709 
2710     c->current_layers.del (i);
2711   }
2712 }
2713 
paint_glyph(hb_paint_context_t * c) const2714 void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
2715 {
2716   TRACE_PAINT (this);
2717 
2718   if (unlikely (c->current_glyphs.has (gid)))
2719     return;
2720 
2721   c->current_glyphs.add (gid);
2722 
2723   c->funcs->push_inverse_root_transform (c->data, c->font);
2724   if (c->funcs->color_glyph (c->data, gid, c->font))
2725   {
2726     c->funcs->pop_transform (c->data);
2727     c->current_glyphs.del (gid);
2728     return;
2729   }
2730   c->funcs->pop_transform (c->data);
2731 
2732   const COLR *colr_table = c->get_colr_table ();
2733   const Paint *paint = colr_table->get_base_glyph_paint (gid);
2734 
2735   hb_glyph_extents_t extents = {0};
2736   bool has_clip_box = colr_table->get_clip (gid, &extents, c->instancer);
2737 
2738   if (has_clip_box)
2739     c->funcs->push_clip_rectangle (c->data,
2740 				   extents.x_bearing,
2741 				   extents.y_bearing + extents.height,
2742 				   extents.x_bearing + extents.width,
2743 				   extents.y_bearing);
2744 
2745   if (paint)
2746     c->recurse (*paint);
2747 
2748   if (has_clip_box)
2749     c->funcs->pop_clip (c->data);
2750 
2751   c->current_glyphs.del (gid);
2752 }
2753 
2754 } /* namespace OT */
2755 
2756 #endif /* OT_COLOR_COLR_COLR_HH */
2757