Merge branch 'upstream' into tizen
[platform/upstream/harfbuzz.git] / src / OT / Color / COLR / COLR.hh
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 {
56   const char *get_name () { return "PAINT"; }
57   template <typename T>
58   return_t dispatch (const T &obj) { obj.paint_glyph (this); return hb_empty_t (); }
59   static return_t default_return_value () { return hb_empty_t (); }
60
61   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   VarStoreInstancer &instancer;
72   hb_map_t current_glyphs;
73   hb_map_t current_layers;
74   int depth_left = HB_MAX_NESTING_LEVEL;
75   int edge_count = HB_COLRV1_MAX_EDGE_COUNT;
76
77   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                       VarStoreInstancer &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
93   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>
125   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   }
138   static return_t default_return_value () { return hb_empty_t (); }
139
140   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
150   const COLR* get_colr_table () const
151   { return reinterpret_cast<const COLR *> (base); }
152
153   void add_glyph (unsigned glyph_id)
154   { glyphs->add (glyph_id); }
155
156   void add_layer_indices (unsigned first_layer_index, unsigned num_of_layers)
157   { layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1); }
158
159   void add_palette_index (unsigned palette_index)
160   { palette_indices->add (palette_index); }
161
162   public:
163   const void *base;
164   hb_set_t visited_paint;
165   hb_set_t *glyphs;
166   hb_set_t *layer_indices;
167   hb_set_t *palette_indices;
168   unsigned nesting_level_left;
169
170   hb_colrv1_closure_context_t (const void *base_,
171                                hb_set_t *glyphs_,
172                                hb_set_t *layer_indices_,
173                                hb_set_t *palette_indices_,
174                                unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
175                           base (base_),
176                           glyphs (glyphs_),
177                           layer_indices (layer_indices_),
178                           palette_indices (palette_indices_),
179                           nesting_level_left (nesting_level_left_)
180   {}
181 };
182
183 struct LayerRecord
184 {
185   operator hb_ot_color_layer_t () const { return {glyphId, colorIdx}; }
186
187   bool sanitize (hb_sanitize_context_t *c) const
188   {
189     TRACE_SANITIZE (this);
190     return_trace (c->check_struct (this));
191   }
192
193   public:
194   HBGlyphID16   glyphId;        /* Glyph ID of layer glyph */
195   Index         colorIdx;       /* Index value to use with a
196                                  * selected color palette.
197                                  * An index value of 0xFFFF
198                                  * is a special case indicating
199                                  * that the text foreground
200                                  * color (defined by a
201                                  * higher-level client) should
202                                  * be used and shall not be
203                                  * treated as actual index
204                                  * into CPAL ColorRecord array. */
205   public:
206   DEFINE_SIZE_STATIC (4);
207 };
208
209 struct BaseGlyphRecord
210 {
211   int cmp (hb_codepoint_t g) const
212   { return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
213
214   bool sanitize (hb_sanitize_context_t *c) const
215   {
216     TRACE_SANITIZE (this);
217     return_trace (c->check_struct (this));
218   }
219
220   public:
221   HBGlyphID16   glyphId;        /* Glyph ID of reference glyph */
222   HBUINT16      firstLayerIdx;  /* Index (from beginning of
223                                  * the Layer Records) to the
224                                  * layer record. There will be
225                                  * numLayers consecutive entries
226                                  * for this base glyph. */
227   HBUINT16      numLayers;      /* Number of color layers
228                                  * associated with this glyph */
229   public:
230   DEFINE_SIZE_STATIC (6);
231 };
232
233 template <typename T>
234 struct Variable
235 {
236   static constexpr bool is_variable = true;
237
238   Variable<T>* copy (hb_serialize_context_t *c) const
239   {
240     TRACE_SERIALIZE (this);
241     return_trace (c->embed (this));
242   }
243
244   void closurev1 (hb_colrv1_closure_context_t* c) const
245   { value.closurev1 (c); }
246
247   bool subset (hb_subset_context_t *c,
248                const VarStoreInstancer &instancer) const
249   {
250     TRACE_SUBSET (this);
251     if (!value.subset (c, instancer, varIdxBase)) return_trace (false);
252     if (c->plan->all_axes_pinned)
253       return_trace (true);
254
255     //TODO: update varIdxBase for partial-instancing
256     return_trace (c->serializer->embed (varIdxBase));
257   }
258
259   bool sanitize (hb_sanitize_context_t *c) const
260   {
261     TRACE_SANITIZE (this);
262     return_trace (c->check_struct (this) && value.sanitize (c));
263   }
264
265   void paint_glyph (hb_paint_context_t *c) const
266   {
267     TRACE_PAINT (this);
268     value.paint_glyph (c, varIdxBase);
269   }
270
271   void get_color_stop (hb_paint_context_t *c,
272                        hb_color_stop_t *stop,
273                        const VarStoreInstancer &instancer) const
274   {
275     value.get_color_stop (c, stop, varIdxBase, instancer);
276   }
277
278   hb_paint_extend_t get_extend () const
279   {
280     return value.get_extend ();
281   }
282
283   protected:
284   T      value;
285   public:
286   VarIdx varIdxBase;
287   public:
288   DEFINE_SIZE_MIN (VarIdx::static_size + T::min_size);
289 };
290
291 template <typename T>
292 struct NoVariable
293 {
294   static constexpr bool is_variable = false;
295
296   static constexpr uint32_t varIdxBase = VarIdx::NO_VARIATION;
297
298   NoVariable<T>* copy (hb_serialize_context_t *c) const
299   {
300     TRACE_SERIALIZE (this);
301     return_trace (c->embed (this));
302   }
303
304   void closurev1 (hb_colrv1_closure_context_t* c) const
305   { value.closurev1 (c); }
306
307   bool subset (hb_subset_context_t *c,
308                const VarStoreInstancer &instancer) const
309   {
310     TRACE_SUBSET (this);
311     return_trace (value.subset (c, instancer, varIdxBase));
312   }
313
314   bool sanitize (hb_sanitize_context_t *c) const
315   {
316     TRACE_SANITIZE (this);
317     return_trace (c->check_struct (this) && value.sanitize (c));
318   }
319
320   void paint_glyph (hb_paint_context_t *c) const
321   {
322     TRACE_PAINT (this);
323     value.paint_glyph (c, varIdxBase);
324   }
325
326   void get_color_stop (hb_paint_context_t *c,
327                        hb_color_stop_t *stop,
328                        const VarStoreInstancer &instancer) const
329   {
330     value.get_color_stop (c, stop, VarIdx::NO_VARIATION, instancer);
331   }
332
333   hb_paint_extend_t get_extend () const
334   {
335     return value.get_extend ();
336   }
337
338   T      value;
339   public:
340   DEFINE_SIZE_MIN (T::min_size);
341 };
342
343 // Color structures
344
345 struct ColorStop
346 {
347   void closurev1 (hb_colrv1_closure_context_t* c) const
348   { c->add_palette_index (paletteIndex); }
349
350   bool subset (hb_subset_context_t *c,
351                const VarStoreInstancer &instancer,
352                uint32_t varIdxBase) const
353   {
354     TRACE_SUBSET (this);
355     auto *out = c->serializer->embed (*this);
356     if (unlikely (!out)) return_trace (false);
357
358     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
359     {
360       out->stopOffset.set_float (stopOffset.to_float(instancer (varIdxBase, 0)));
361       out->alpha.set_float (alpha.to_float (instancer (varIdxBase, 1)));
362     }
363
364     return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex),
365                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
366   }
367
368   bool sanitize (hb_sanitize_context_t *c) const
369   {
370     TRACE_SANITIZE (this);
371     return_trace (c->check_struct (this));
372   }
373
374   void get_color_stop (hb_paint_context_t *c,
375                        hb_color_stop_t *out,
376                        uint32_t varIdx,
377                        const VarStoreInstancer &instancer) const
378   {
379     out->offset = stopOffset.to_float(instancer (varIdx, 0));
380     out->color = c->get_color (paletteIndex,
381                                alpha.to_float (instancer (varIdx, 1)),
382                                &out->is_foreground);
383   }
384
385   F2DOT14       stopOffset;
386   HBUINT16      paletteIndex;
387   F2DOT14       alpha;
388   public:
389   DEFINE_SIZE_STATIC (2 + 2 * F2DOT14::static_size);
390 };
391
392 struct Extend : HBUINT8
393 {
394   enum {
395     EXTEND_PAD     = 0,
396     EXTEND_REPEAT  = 1,
397     EXTEND_REFLECT = 2,
398   };
399   public:
400   DEFINE_SIZE_STATIC (1);
401 };
402
403 template <template<typename> class Var>
404 struct ColorLine
405 {
406   void closurev1 (hb_colrv1_closure_context_t* c) const
407   {
408     for (const auto &stop : stops.iter ())
409       stop.closurev1 (c);
410   }
411
412   bool subset (hb_subset_context_t *c,
413                const VarStoreInstancer &instancer) const
414   {
415     TRACE_SUBSET (this);
416     auto *out = c->serializer->start_embed (this);
417     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
418
419     if (!c->serializer->check_assign (out->extend, extend, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
420     if (!c->serializer->check_assign (out->stops.len, stops.len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)) return_trace (false);
421
422     for (const auto& stop : stops.iter ())
423     {
424       if (!stop.subset (c, instancer)) return_trace (false);
425     }
426     return_trace (true);
427   }
428
429   bool sanitize (hb_sanitize_context_t *c) const
430   {
431     TRACE_SANITIZE (this);
432     return_trace (c->check_struct (this) &&
433                   stops.sanitize (c));
434   }
435
436   /* get up to count stops from start */
437   unsigned int
438   get_color_stops (hb_paint_context_t *c,
439                    unsigned int start,
440                    unsigned int *count,
441                    hb_color_stop_t *color_stops,
442                    const VarStoreInstancer &instancer) const
443   {
444     unsigned int len = stops.len;
445
446     if (count && color_stops)
447     {
448       unsigned int i;
449       for (i = 0; i < *count && start + i < len; i++)
450         stops[start + i].get_color_stop (c, &color_stops[i], instancer);
451       *count = i;
452     }
453
454     return len;
455   }
456
457   HB_INTERNAL static unsigned int static_get_color_stops (hb_color_line_t *color_line,
458                                                           void *color_line_data,
459                                                           unsigned int start,
460                                                           unsigned int *count,
461                                                           hb_color_stop_t *color_stops,
462                                                           void *user_data)
463   {
464     const ColorLine *thiz = (const ColorLine *) color_line_data;
465     hb_paint_context_t *c = (hb_paint_context_t *) user_data;
466     return thiz->get_color_stops (c, start, count, color_stops, c->instancer);
467   }
468
469   hb_paint_extend_t get_extend () const
470   {
471     return (hb_paint_extend_t) (unsigned int) extend;
472   }
473
474   HB_INTERNAL static hb_paint_extend_t static_get_extend (hb_color_line_t *color_line,
475                                                           void *color_line_data,
476                                                           void *user_data)
477   {
478     const ColorLine *thiz = (const ColorLine *) color_line_data;
479     return thiz->get_extend ();
480   }
481
482   Extend        extend;
483   Array16Of<Var<ColorStop>>     stops;
484   public:
485   DEFINE_SIZE_ARRAY_SIZED (3, stops);
486 };
487
488 // Composition modes
489
490 // Compositing modes are taken from https://www.w3.org/TR/compositing-1/
491 // NOTE: a brief audit of major implementations suggests most support most
492 // or all of the specified modes.
493 struct CompositeMode : HBUINT8
494 {
495   enum {
496     // Porter-Duff modes
497     // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators
498     COMPOSITE_CLEAR          =  0,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_clear
499     COMPOSITE_SRC            =  1,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_src
500     COMPOSITE_DEST           =  2,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dst
501     COMPOSITE_SRC_OVER       =  3,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcover
502     COMPOSITE_DEST_OVER      =  4,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstover
503     COMPOSITE_SRC_IN         =  5,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcin
504     COMPOSITE_DEST_IN        =  6,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstin
505     COMPOSITE_SRC_OUT        =  7,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcout
506     COMPOSITE_DEST_OUT       =  8,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstout
507     COMPOSITE_SRC_ATOP       =  9,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcatop
508     COMPOSITE_DEST_ATOP      = 10,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstatop
509     COMPOSITE_XOR            = 11,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_xor
510     COMPOSITE_PLUS           = 12,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_plus
511
512     // Blend modes
513     // https://www.w3.org/TR/compositing-1/#blending
514     COMPOSITE_SCREEN         = 13,  // https://www.w3.org/TR/compositing-1/#blendingscreen
515     COMPOSITE_OVERLAY        = 14,  // https://www.w3.org/TR/compositing-1/#blendingoverlay
516     COMPOSITE_DARKEN         = 15,  // https://www.w3.org/TR/compositing-1/#blendingdarken
517     COMPOSITE_LIGHTEN        = 16,  // https://www.w3.org/TR/compositing-1/#blendinglighten
518     COMPOSITE_COLOR_DODGE    = 17,  // https://www.w3.org/TR/compositing-1/#blendingcolordodge
519     COMPOSITE_COLOR_BURN     = 18,  // https://www.w3.org/TR/compositing-1/#blendingcolorburn
520     COMPOSITE_HARD_LIGHT     = 19,  // https://www.w3.org/TR/compositing-1/#blendinghardlight
521     COMPOSITE_SOFT_LIGHT     = 20,  // https://www.w3.org/TR/compositing-1/#blendingsoftlight
522     COMPOSITE_DIFFERENCE     = 21,  // https://www.w3.org/TR/compositing-1/#blendingdifference
523     COMPOSITE_EXCLUSION      = 22,  // https://www.w3.org/TR/compositing-1/#blendingexclusion
524     COMPOSITE_MULTIPLY       = 23,  // https://www.w3.org/TR/compositing-1/#blendingmultiply
525
526     // Modes that, uniquely, do not operate on components
527     // https://www.w3.org/TR/compositing-1/#blendingnonseparable
528     COMPOSITE_HSL_HUE        = 24,  // https://www.w3.org/TR/compositing-1/#blendinghue
529     COMPOSITE_HSL_SATURATION = 25,  // https://www.w3.org/TR/compositing-1/#blendingsaturation
530     COMPOSITE_HSL_COLOR      = 26,  // https://www.w3.org/TR/compositing-1/#blendingcolor
531     COMPOSITE_HSL_LUMINOSITY = 27,  // https://www.w3.org/TR/compositing-1/#blendingluminosity
532   };
533   public:
534   DEFINE_SIZE_STATIC (1);
535 };
536
537 struct Affine2x3
538 {
539   bool sanitize (hb_sanitize_context_t *c) const
540   {
541     TRACE_SANITIZE (this);
542     return_trace (c->check_struct (this));
543   }
544
545   bool subset (hb_subset_context_t *c,
546                const VarStoreInstancer &instancer,
547                uint32_t varIdxBase) const
548   {
549     TRACE_SUBSET (this);
550     auto *out = c->serializer->embed (*this);
551     if (unlikely (!out)) return_trace (false);
552     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
553     {
554       out->xx.set_float (xx.to_float(instancer (varIdxBase, 0)));
555       out->yx.set_float (yx.to_float(instancer (varIdxBase, 1)));
556       out->xy.set_float (xy.to_float(instancer (varIdxBase, 2)));
557       out->yy.set_float (yy.to_float(instancer (varIdxBase, 3)));
558       out->dx.set_float (dx.to_float(instancer (varIdxBase, 4)));
559       out->dy.set_float (dy.to_float(instancer (varIdxBase, 5)));
560     }
561     return_trace (true);
562   }
563
564   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
565   {
566     TRACE_PAINT (this);
567     c->funcs->push_transform (c->data,
568                               xx.to_float (c->instancer (varIdxBase, 0)),
569                               yx.to_float (c->instancer (varIdxBase, 1)),
570                               xy.to_float (c->instancer (varIdxBase, 2)),
571                               yy.to_float (c->instancer (varIdxBase, 3)),
572                               dx.to_float (c->instancer (varIdxBase, 4)),
573                               dy.to_float (c->instancer (varIdxBase, 5)));
574   }
575
576   F16DOT16 xx;
577   F16DOT16 yx;
578   F16DOT16 xy;
579   F16DOT16 yy;
580   F16DOT16 dx;
581   F16DOT16 dy;
582   public:
583   DEFINE_SIZE_STATIC (6 * F16DOT16::static_size);
584 };
585
586 struct PaintColrLayers
587 {
588   void closurev1 (hb_colrv1_closure_context_t* c) const;
589
590   bool subset (hb_subset_context_t *c,
591                const VarStoreInstancer &instancer HB_UNUSED) const
592   {
593     TRACE_SUBSET (this);
594     auto *out = c->serializer->embed (this);
595     if (unlikely (!out)) return_trace (false);
596     return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers.get (firstLayerIndex),
597                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
598
599     return_trace (true);
600   }
601
602   bool sanitize (hb_sanitize_context_t *c) const
603   {
604     TRACE_SANITIZE (this);
605     return_trace (c->check_struct (this));
606   }
607
608   inline void paint_glyph (hb_paint_context_t *c) const;
609
610   HBUINT8       format; /* format = 1 */
611   HBUINT8       numLayers;
612   HBUINT32      firstLayerIndex;  /* index into COLRv1::layerList */
613   public:
614   DEFINE_SIZE_STATIC (6);
615 };
616
617 struct PaintSolid
618 {
619   void closurev1 (hb_colrv1_closure_context_t* c) const
620   { c->add_palette_index (paletteIndex); }
621
622   bool subset (hb_subset_context_t *c,
623                const VarStoreInstancer &instancer,
624                uint32_t varIdxBase) const
625   {
626     TRACE_SUBSET (this);
627     auto *out = c->serializer->embed (*this);
628     if (unlikely (!out)) return_trace (false);
629
630     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
631       out->alpha.set_float (alpha.to_float (instancer (varIdxBase, 0)));
632
633     if (format == 3 && c->plan->all_axes_pinned)
634         out->format = 2;
635
636     return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex),
637                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
638   }
639
640   bool sanitize (hb_sanitize_context_t *c) const
641   {
642     TRACE_SANITIZE (this);
643     return_trace (c->check_struct (this));
644   }
645
646   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
647   {
648     TRACE_PAINT (this);
649     hb_bool_t is_foreground;
650     hb_color_t color;
651
652     color = c->get_color (paletteIndex,
653                           alpha.to_float (c->instancer (varIdxBase, 0)),
654                           &is_foreground);
655     c->funcs->color (c->data, is_foreground, color);
656   }
657
658   HBUINT8       format; /* format = 2(noVar) or 3(Var)*/
659   HBUINT16      paletteIndex;
660   F2DOT14       alpha;
661   public:
662   DEFINE_SIZE_STATIC (3 + F2DOT14::static_size);
663 };
664
665 template <template<typename> class Var>
666 struct PaintLinearGradient
667 {
668   void closurev1 (hb_colrv1_closure_context_t* c) const
669   { (this+colorLine).closurev1 (c); }
670
671   bool subset (hb_subset_context_t *c,
672                const VarStoreInstancer &instancer,
673                uint32_t varIdxBase) const
674   {
675     TRACE_SUBSET (this);
676     auto *out = c->serializer->embed (this);
677     if (unlikely (!out)) return_trace (false);
678
679     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
680     {
681       out->x0 = x0 + (int) roundf (instancer (varIdxBase, 0));
682       out->y0 = y0 + (int) roundf (instancer (varIdxBase, 1));
683       out->x1 = x1 + (int) roundf (instancer (varIdxBase, 2));
684       out->y1 = y1 + (int) roundf (instancer (varIdxBase, 3));
685       out->x2 = x2 + (int) roundf (instancer (varIdxBase, 4));
686       out->y2 = y2 + (int) roundf (instancer (varIdxBase, 5));
687     }
688
689     if (format == 5 && c->plan->all_axes_pinned)
690         out->format = 4;
691
692     return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer));
693   }
694
695   bool sanitize (hb_sanitize_context_t *c) const
696   {
697     TRACE_SANITIZE (this);
698     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
699   }
700
701   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
702   {
703     TRACE_PAINT (this);
704     hb_color_line_t cl = {
705       (void *) &(this+colorLine),
706       (this+colorLine).static_get_color_stops, c,
707       (this+colorLine).static_get_extend, nullptr
708     };
709
710     c->funcs->linear_gradient (c->data, &cl,
711                                x0 + c->instancer (varIdxBase, 0),
712                                y0 + c->instancer (varIdxBase, 1),
713                                x1 + c->instancer (varIdxBase, 2),
714                                y1 + c->instancer (varIdxBase, 3),
715                                x2 + c->instancer (varIdxBase, 4),
716                                y2 + c->instancer (varIdxBase, 5));
717   }
718
719   HBUINT8                       format; /* format = 4(noVar) or 5 (Var) */
720   Offset24To<ColorLine<Var>>    colorLine; /* Offset (from beginning of PaintLinearGradient
721                                             * table) to ColorLine subtable. */
722   FWORD                 x0;
723   FWORD                 y0;
724   FWORD                 x1;
725   FWORD                 y1;
726   FWORD                 x2;
727   FWORD                 y2;
728   public:
729   DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size);
730 };
731
732 template <template<typename> class Var>
733 struct PaintRadialGradient
734 {
735   void closurev1 (hb_colrv1_closure_context_t* c) const
736   { (this+colorLine).closurev1 (c); }
737
738   bool subset (hb_subset_context_t *c,
739                const VarStoreInstancer &instancer,
740                uint32_t varIdxBase) const
741   {
742     TRACE_SUBSET (this);
743     auto *out = c->serializer->embed (this);
744     if (unlikely (!out)) return_trace (false);
745
746     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
747     {
748       out->x0 = x0 + (int) roundf (instancer (varIdxBase, 0));
749       out->y0 = y0 + (int) roundf (instancer (varIdxBase, 1));
750       out->radius0 = radius0 + (unsigned) roundf (instancer (varIdxBase, 2));
751       out->x1 = x1 + (int) roundf (instancer (varIdxBase, 3));
752       out->y1 = y1 + (int) roundf (instancer (varIdxBase, 4));
753       out->radius1 = radius1 + (unsigned) roundf (instancer (varIdxBase, 5));
754     }
755
756     if (format == 7 && c->plan->all_axes_pinned)
757         out->format = 6;
758
759     return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer));
760   }
761
762   bool sanitize (hb_sanitize_context_t *c) const
763   {
764     TRACE_SANITIZE (this);
765     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
766   }
767
768   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
769   {
770     TRACE_PAINT (this);
771     hb_color_line_t cl = {
772       (void *) &(this+colorLine),
773       (this+colorLine).static_get_color_stops, c,
774       (this+colorLine).static_get_extend, nullptr
775     };
776
777     c->funcs->radial_gradient (c->data, &cl,
778                                x0 + c->instancer (varIdxBase, 0),
779                                y0 + c->instancer (varIdxBase, 1),
780                                radius0 + c->instancer (varIdxBase, 2),
781                                x1 + c->instancer (varIdxBase, 3),
782                                y1 + c->instancer (varIdxBase, 4),
783                                radius1 + c->instancer (varIdxBase, 5));
784   }
785
786   HBUINT8                       format; /* format = 6(noVar) or 7 (Var) */
787   Offset24To<ColorLine<Var>>    colorLine; /* Offset (from beginning of PaintRadialGradient
788                                             * table) to ColorLine subtable. */
789   FWORD                 x0;
790   FWORD                 y0;
791   UFWORD                radius0;
792   FWORD                 x1;
793   FWORD                 y1;
794   UFWORD                radius1;
795   public:
796   DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size);
797 };
798
799 template <template<typename> class Var>
800 struct PaintSweepGradient
801 {
802   void closurev1 (hb_colrv1_closure_context_t* c) const
803   { (this+colorLine).closurev1 (c); }
804
805   bool subset (hb_subset_context_t *c,
806                const VarStoreInstancer &instancer,
807                uint32_t varIdxBase) const
808   {
809     TRACE_SUBSET (this);
810     auto *out = c->serializer->embed (this);
811     if (unlikely (!out)) return_trace (false);
812
813     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
814     {
815       out->centerX = centerX + (int) roundf (instancer (varIdxBase, 0));
816       out->centerY = centerY + (int) roundf (instancer (varIdxBase, 1));
817       out->startAngle.set_float (startAngle.to_float (instancer (varIdxBase, 2)));
818       out->endAngle.set_float (endAngle.to_float (instancer (varIdxBase, 3)));
819     }
820
821     if (format == 9 && c->plan->all_axes_pinned)
822         out->format = 8;
823
824     return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer));
825   }
826
827   bool sanitize (hb_sanitize_context_t *c) const
828   {
829     TRACE_SANITIZE (this);
830     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
831   }
832
833   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
834   {
835     TRACE_PAINT (this);
836     hb_color_line_t cl = {
837       (void *) &(this+colorLine),
838       (this+colorLine).static_get_color_stops, c,
839       (this+colorLine).static_get_extend, nullptr
840     };
841
842     c->funcs->sweep_gradient (c->data, &cl,
843                               centerX + c->instancer (varIdxBase, 0),
844                               centerY + c->instancer (varIdxBase, 1),
845                               (startAngle.to_float (c->instancer (varIdxBase, 2)) + 1) * HB_PI,
846                               (endAngle.to_float   (c->instancer (varIdxBase, 3)) + 1) * HB_PI);
847   }
848
849   HBUINT8                       format; /* format = 8(noVar) or 9 (Var) */
850   Offset24To<ColorLine<Var>>    colorLine; /* Offset (from beginning of PaintSweepGradient
851                                             * table) to ColorLine subtable. */
852   FWORD                 centerX;
853   FWORD                 centerY;
854   F2DOT14               startAngle;
855   F2DOT14               endAngle;
856   public:
857   DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size + 2 * F2DOT14::static_size);
858 };
859
860 // Paint a non-COLR glyph, filled as indicated by paint.
861 struct PaintGlyph
862 {
863   void closurev1 (hb_colrv1_closure_context_t* c) const;
864
865   bool subset (hb_subset_context_t *c,
866                const VarStoreInstancer &instancer) const
867   {
868     TRACE_SUBSET (this);
869     auto *out = c->serializer->embed (this);
870     if (unlikely (!out)) return_trace (false);
871
872     if (! c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid),
873                                        HB_SERIALIZE_ERROR_INT_OVERFLOW))
874       return_trace (false);
875
876     return_trace (out->paint.serialize_subset (c, paint, this, instancer));
877   }
878
879   bool sanitize (hb_sanitize_context_t *c) const
880   {
881     TRACE_SANITIZE (this);
882     return_trace (c->check_struct (this) && paint.sanitize (c, this));
883   }
884
885   void paint_glyph (hb_paint_context_t *c) const
886   {
887     TRACE_PAINT (this);
888     c->funcs->push_inverse_root_transform (c->data, c->font);
889     c->funcs->push_clip_glyph (c->data, gid, c->font);
890     c->funcs->push_root_transform (c->data, c->font);
891     c->recurse (this+paint);
892     c->funcs->pop_transform (c->data);
893     c->funcs->pop_clip (c->data);
894     c->funcs->pop_transform (c->data);
895   }
896
897   HBUINT8               format; /* format = 10 */
898   Offset24To<Paint>     paint;  /* Offset (from beginning of PaintGlyph table) to Paint subtable. */
899   HBUINT16              gid;
900   public:
901   DEFINE_SIZE_STATIC (6);
902 };
903
904 struct PaintColrGlyph
905 {
906   void closurev1 (hb_colrv1_closure_context_t* c) const;
907
908   bool subset (hb_subset_context_t *c,
909                const VarStoreInstancer &instancer HB_UNUSED) const
910   {
911     TRACE_SUBSET (this);
912     auto *out = c->serializer->embed (this);
913     if (unlikely (!out)) return_trace (false);
914
915     return_trace (c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid),
916                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
917   }
918
919   bool sanitize (hb_sanitize_context_t *c) const
920   {
921     TRACE_SANITIZE (this);
922     return_trace (c->check_struct (this));
923   }
924
925   inline void paint_glyph (hb_paint_context_t *c) const;
926
927   HBUINT8       format; /* format = 11 */
928   HBUINT16      gid;
929   public:
930   DEFINE_SIZE_STATIC (3);
931 };
932
933 template <template<typename> class Var>
934 struct PaintTransform
935 {
936   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
937
938   bool subset (hb_subset_context_t *c,
939                const VarStoreInstancer &instancer) const
940   {
941     TRACE_SUBSET (this);
942     auto *out = c->serializer->embed (this);
943     if (unlikely (!out)) return_trace (false);
944     if (!out->transform.serialize_subset (c, transform, this, instancer)) return_trace (false);
945     if (format == 13 && c->plan->all_axes_pinned)
946       out->format = 12;
947     return_trace (out->src.serialize_subset (c, src, this, instancer));
948   }
949
950   bool sanitize (hb_sanitize_context_t *c) const
951   {
952     TRACE_SANITIZE (this);
953     return_trace (c->check_struct (this) &&
954                   src.sanitize (c, this) &&
955                   transform.sanitize (c, this));
956   }
957
958   void paint_glyph (hb_paint_context_t *c) const
959   {
960     TRACE_PAINT (this);
961     (this+transform).paint_glyph (c);
962     c->recurse (this+src);
963     c->funcs->pop_transform (c->data);
964   }
965
966   HBUINT8                       format; /* format = 12(noVar) or 13 (Var) */
967   Offset24To<Paint>             src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */
968   Offset24To<Var<Affine2x3>>    transform;
969   public:
970   DEFINE_SIZE_STATIC (7);
971 };
972
973 struct PaintTranslate
974 {
975   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
976
977   bool subset (hb_subset_context_t *c,
978                const VarStoreInstancer &instancer,
979                uint32_t varIdxBase) const
980   {
981     TRACE_SUBSET (this);
982     auto *out = c->serializer->embed (this);
983     if (unlikely (!out)) return_trace (false);
984
985     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
986     {
987       out->dx = dx + (int) roundf (instancer (varIdxBase, 0));
988       out->dy = dy + (int) roundf (instancer (varIdxBase, 1));
989     }
990
991     if (format == 15 && c->plan->all_axes_pinned)
992         out->format = 14;
993
994     return_trace (out->src.serialize_subset (c, src, this, instancer));
995   }
996
997   bool sanitize (hb_sanitize_context_t *c) const
998   {
999     TRACE_SANITIZE (this);
1000     return_trace (c->check_struct (this) && src.sanitize (c, this));
1001   }
1002
1003   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1004   {
1005     TRACE_PAINT (this);
1006     float ddx = dx + c->instancer (varIdxBase, 0);
1007     float ddy = dy + c->instancer (varIdxBase, 1);
1008
1009     bool p1 = c->funcs->push_translate (c->data, ddx, ddy);
1010     c->recurse (this+src);
1011     if (p1) c->funcs->pop_transform (c->data);
1012   }
1013
1014   HBUINT8               format; /* format = 14(noVar) or 15 (Var) */
1015   Offset24To<Paint>     src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */
1016   FWORD         dx;
1017   FWORD         dy;
1018   public:
1019   DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size);
1020 };
1021
1022 struct PaintScale
1023 {
1024   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1025
1026   bool subset (hb_subset_context_t *c,
1027                const VarStoreInstancer &instancer,
1028                uint32_t varIdxBase) const
1029   {
1030     TRACE_SUBSET (this);
1031     auto *out = c->serializer->embed (this);
1032     if (unlikely (!out)) return_trace (false);
1033
1034     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1035     {
1036       out->scaleX.set_float (scaleX.to_float (instancer (varIdxBase, 0)));
1037       out->scaleY.set_float (scaleY.to_float (instancer (varIdxBase, 1)));
1038     }
1039
1040     if (format == 17 && c->plan->all_axes_pinned)
1041         out->format = 16;
1042
1043     return_trace (out->src.serialize_subset (c, src, this, instancer));
1044   }
1045
1046   bool sanitize (hb_sanitize_context_t *c) const
1047   {
1048     TRACE_SANITIZE (this);
1049     return_trace (c->check_struct (this) && src.sanitize (c, this));
1050   }
1051
1052   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1053   {
1054     TRACE_PAINT (this);
1055     float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
1056     float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
1057
1058     bool p1 = c->funcs->push_scale (c->data, sx, sy);
1059     c->recurse (this+src);
1060     if (p1) c->funcs->pop_transform (c->data);
1061   }
1062
1063   HBUINT8               format; /* format = 16 (noVar) or 17(Var) */
1064   Offset24To<Paint>     src; /* Offset (from beginning of PaintScale table) to Paint subtable. */
1065   F2DOT14               scaleX;
1066   F2DOT14               scaleY;
1067   public:
1068   DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size);
1069 };
1070
1071 struct PaintScaleAroundCenter
1072 {
1073   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1074
1075   bool subset (hb_subset_context_t *c,
1076                const VarStoreInstancer &instancer,
1077                uint32_t varIdxBase) const
1078   {
1079     TRACE_SUBSET (this);
1080     auto *out = c->serializer->embed (this);
1081     if (unlikely (!out)) return_trace (false);
1082
1083     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1084     {
1085       out->scaleX.set_float (scaleX.to_float (instancer (varIdxBase, 0)));
1086       out->scaleY.set_float (scaleY.to_float (instancer (varIdxBase, 1)));
1087       out->centerX = centerX + (int) roundf (instancer (varIdxBase, 2));
1088       out->centerY = centerY + (int) roundf (instancer (varIdxBase, 3));
1089     }
1090
1091     if (format == 19 && c->plan->all_axes_pinned)
1092         out->format = 18;
1093
1094     return_trace (out->src.serialize_subset (c, src, this, instancer));
1095   }
1096
1097   bool sanitize (hb_sanitize_context_t *c) const
1098   {
1099     TRACE_SANITIZE (this);
1100     return_trace (c->check_struct (this) && src.sanitize (c, this));
1101   }
1102
1103   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1104   {
1105     TRACE_PAINT (this);
1106     float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
1107     float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
1108     float tCenterX = centerX + c->instancer (varIdxBase, 2);
1109     float tCenterY = centerY + c->instancer (varIdxBase, 3);
1110
1111     bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
1112     bool p2 = c->funcs->push_scale (c->data, sx, sy);
1113     bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
1114     c->recurse (this+src);
1115     if (p3) c->funcs->pop_transform (c->data);
1116     if (p2) c->funcs->pop_transform (c->data);
1117     if (p1) c->funcs->pop_transform (c->data);
1118   }
1119
1120   HBUINT8               format; /* format = 18 (noVar) or 19(Var) */
1121   Offset24To<Paint>     src; /* Offset (from beginning of PaintScaleAroundCenter table) to Paint subtable. */
1122   F2DOT14       scaleX;
1123   F2DOT14       scaleY;
1124   FWORD         centerX;
1125   FWORD         centerY;
1126   public:
1127   DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size + 2 * FWORD::static_size);
1128 };
1129
1130 struct PaintScaleUniform
1131 {
1132   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1133
1134   bool subset (hb_subset_context_t *c,
1135                const VarStoreInstancer &instancer,
1136                uint32_t varIdxBase) const
1137   {
1138     TRACE_SUBSET (this);
1139     auto *out = c->serializer->embed (this);
1140     if (unlikely (!out)) return_trace (false);
1141
1142     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1143       out->scale.set_float (scale.to_float (instancer (varIdxBase, 0)));
1144
1145     if (format == 21 && c->plan->all_axes_pinned)
1146         out->format = 20;
1147
1148     return_trace (out->src.serialize_subset (c, src, this, instancer));
1149   }
1150
1151   bool sanitize (hb_sanitize_context_t *c) const
1152   {
1153     TRACE_SANITIZE (this);
1154     return_trace (c->check_struct (this) && src.sanitize (c, this));
1155   }
1156
1157   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1158   {
1159     TRACE_PAINT (this);
1160     float s = scale.to_float (c->instancer (varIdxBase, 0));
1161
1162     bool p1 = c->funcs->push_scale (c->data, s, s);
1163     c->recurse (this+src);
1164     if (p1) c->funcs->pop_transform (c->data);
1165   }
1166
1167   HBUINT8               format; /* format = 20 (noVar) or 21(Var) */
1168   Offset24To<Paint>     src; /* Offset (from beginning of PaintScaleUniform table) to Paint subtable. */
1169   F2DOT14               scale;
1170   public:
1171   DEFINE_SIZE_STATIC (4 + F2DOT14::static_size);
1172 };
1173
1174 struct PaintScaleUniformAroundCenter
1175 {
1176   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1177
1178   bool subset (hb_subset_context_t *c,
1179                const VarStoreInstancer &instancer,
1180                uint32_t varIdxBase) const
1181   {
1182     TRACE_SUBSET (this);
1183     auto *out = c->serializer->embed (this);
1184     if (unlikely (!out)) return_trace (false);
1185
1186     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1187     {
1188       out->scale.set_float (scale.to_float (instancer (varIdxBase, 0)));
1189       out->centerX = centerX + (int) roundf (instancer (varIdxBase, 1));
1190       out->centerY = centerY + (int) roundf (instancer (varIdxBase, 2));
1191     }
1192
1193     if (format == 23 && c->plan->all_axes_pinned)
1194         out->format = 22;
1195
1196     return_trace (out->src.serialize_subset (c, src, this, instancer));
1197   }
1198
1199   bool sanitize (hb_sanitize_context_t *c) const
1200   {
1201     TRACE_SANITIZE (this);
1202     return_trace (c->check_struct (this) && src.sanitize (c, this));
1203   }
1204
1205   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1206   {
1207     TRACE_PAINT (this);
1208     float s = scale.to_float (c->instancer (varIdxBase, 0));
1209     float tCenterX = centerX + c->instancer (varIdxBase, 1);
1210     float tCenterY = centerY + c->instancer (varIdxBase, 2);
1211
1212     bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
1213     bool p2 = c->funcs->push_scale (c->data, s, s);
1214     bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
1215     c->recurse (this+src);
1216     if (p3) c->funcs->pop_transform (c->data);
1217     if (p2) c->funcs->pop_transform (c->data);
1218     if (p1) c->funcs->pop_transform (c->data);
1219   }
1220
1221   HBUINT8               format; /* format = 22 (noVar) or 23(Var) */
1222   Offset24To<Paint>     src; /* Offset (from beginning of PaintScaleUniformAroundCenter table) to Paint subtable. */
1223   F2DOT14       scale;
1224   FWORD         centerX;
1225   FWORD         centerY;
1226   public:
1227   DEFINE_SIZE_STATIC (4 + F2DOT14::static_size + 2 * FWORD::static_size);
1228 };
1229
1230 struct PaintRotate
1231 {
1232   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1233
1234   bool subset (hb_subset_context_t *c,
1235                const VarStoreInstancer &instancer,
1236                uint32_t varIdxBase) const
1237   {
1238     TRACE_SUBSET (this);
1239     auto *out = c->serializer->embed (this);
1240     if (unlikely (!out)) return_trace (false);
1241
1242     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1243       out->angle.set_float (angle.to_float (instancer (varIdxBase, 0)));
1244
1245     if (format == 25 && c->plan->all_axes_pinned)
1246       out->format = 24;
1247
1248     return_trace (out->src.serialize_subset (c, src, this, instancer));
1249   }
1250
1251   bool sanitize (hb_sanitize_context_t *c) const
1252   {
1253     TRACE_SANITIZE (this);
1254     return_trace (c->check_struct (this) && src.sanitize (c, this));
1255   }
1256
1257   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1258   {
1259     TRACE_PAINT (this);
1260     float a = angle.to_float (c->instancer (varIdxBase, 0));
1261
1262     bool p1 = c->funcs->push_rotate (c->data, a);
1263     c->recurse (this+src);
1264     if (p1) c->funcs->pop_transform (c->data);
1265   }
1266
1267   HBUINT8               format; /* format = 24 (noVar) or 25(Var) */
1268   Offset24To<Paint>     src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */
1269   F2DOT14               angle;
1270   public:
1271   DEFINE_SIZE_STATIC (4 + F2DOT14::static_size);
1272 };
1273
1274 struct PaintRotateAroundCenter
1275 {
1276   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1277
1278   bool subset (hb_subset_context_t *c,
1279                const VarStoreInstancer &instancer,
1280                uint32_t varIdxBase) const
1281   {
1282     TRACE_SUBSET (this);
1283     auto *out = c->serializer->embed (this);
1284     if (unlikely (!out)) return_trace (false);
1285
1286     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1287     {
1288       out->angle.set_float (angle.to_float (instancer (varIdxBase, 0)));
1289       out->centerX = centerX + (int) roundf (instancer (varIdxBase, 1));
1290       out->centerY = centerY + (int) roundf (instancer (varIdxBase, 2));
1291     }
1292
1293     if (format ==27 && c->plan->all_axes_pinned)
1294         out->format = 26;
1295
1296     return_trace (out->src.serialize_subset (c, src, this, instancer));
1297   }
1298
1299   bool sanitize (hb_sanitize_context_t *c) const
1300   {
1301     TRACE_SANITIZE (this);
1302     return_trace (c->check_struct (this) && src.sanitize (c, this));
1303   }
1304
1305   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1306   {
1307     TRACE_PAINT (this);
1308     float a = angle.to_float (c->instancer (varIdxBase, 0));
1309     float tCenterX = centerX + c->instancer (varIdxBase, 1);
1310     float tCenterY = centerY + c->instancer (varIdxBase, 2);
1311
1312     bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
1313     bool p2 = c->funcs->push_rotate (c->data, a);
1314     bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
1315     c->recurse (this+src);
1316     if (p3) c->funcs->pop_transform (c->data);
1317     if (p2) c->funcs->pop_transform (c->data);
1318     if (p1) c->funcs->pop_transform (c->data);
1319   }
1320
1321   HBUINT8               format; /* format = 26 (noVar) or 27(Var) */
1322   Offset24To<Paint>     src; /* Offset (from beginning of PaintRotateAroundCenter table) to Paint subtable. */
1323   F2DOT14       angle;
1324   FWORD         centerX;
1325   FWORD         centerY;
1326   public:
1327   DEFINE_SIZE_STATIC (4 + F2DOT14::static_size + 2 * FWORD::static_size);
1328 };
1329
1330 struct PaintSkew
1331 {
1332   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1333
1334   bool subset (hb_subset_context_t *c,
1335                const VarStoreInstancer &instancer,
1336                uint32_t varIdxBase) const
1337   {
1338     TRACE_SUBSET (this);
1339     auto *out = c->serializer->embed (this);
1340     if (unlikely (!out)) return_trace (false);
1341
1342     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1343     {
1344       out->xSkewAngle.set_float (xSkewAngle.to_float (instancer (varIdxBase, 0)));
1345       out->ySkewAngle.set_float (ySkewAngle.to_float (instancer (varIdxBase, 1)));
1346     }
1347
1348     if (format == 29 && c->plan->all_axes_pinned)
1349         out->format = 28;
1350
1351     return_trace (out->src.serialize_subset (c, src, this, instancer));
1352   }
1353
1354   bool sanitize (hb_sanitize_context_t *c) const
1355   {
1356     TRACE_SANITIZE (this);
1357     return_trace (c->check_struct (this) && src.sanitize (c, this));
1358   }
1359
1360   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1361   {
1362     TRACE_PAINT (this);
1363     float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
1364     float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
1365
1366     bool p1 = c->funcs->push_skew (c->data, sx, sy);
1367     c->recurse (this+src);
1368     if (p1) c->funcs->pop_transform (c->data);
1369   }
1370
1371   HBUINT8               format; /* format = 28(noVar) or 29 (Var) */
1372   Offset24To<Paint>     src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */
1373   F2DOT14               xSkewAngle;
1374   F2DOT14               ySkewAngle;
1375   public:
1376   DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size);
1377 };
1378
1379 struct PaintSkewAroundCenter
1380 {
1381   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1382
1383   bool subset (hb_subset_context_t *c,
1384                const VarStoreInstancer &instancer,
1385                uint32_t varIdxBase) const
1386   {
1387     TRACE_SUBSET (this);
1388     auto *out = c->serializer->embed (this);
1389     if (unlikely (!out)) return_trace (false);
1390
1391     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1392     {
1393       out->xSkewAngle.set_float (xSkewAngle.to_float (instancer (varIdxBase, 0)));
1394       out->ySkewAngle.set_float (ySkewAngle.to_float (instancer (varIdxBase, 1)));
1395       out->centerX = centerX + (int) roundf (instancer (varIdxBase, 2));
1396       out->centerY = centerY + (int) roundf (instancer (varIdxBase, 3));
1397     }
1398
1399     if (format == 31 && c->plan->all_axes_pinned)
1400         out->format = 30;
1401
1402     return_trace (out->src.serialize_subset (c, src, this, instancer));
1403   }
1404
1405   bool sanitize (hb_sanitize_context_t *c) const
1406   {
1407     TRACE_SANITIZE (this);
1408     return_trace (c->check_struct (this) && src.sanitize (c, this));
1409   }
1410
1411   void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1412   {
1413     TRACE_PAINT (this);
1414     float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
1415     float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
1416     float tCenterX = centerX + c->instancer (varIdxBase, 2);
1417     float tCenterY = centerY + c->instancer (varIdxBase, 3);
1418
1419     bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
1420     bool p2 = c->funcs->push_skew (c->data, sx, sy);
1421     bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
1422     c->recurse (this+src);
1423     if (p3) c->funcs->pop_transform (c->data);
1424     if (p2) c->funcs->pop_transform (c->data);
1425     if (p1) c->funcs->pop_transform (c->data);
1426   }
1427
1428   HBUINT8               format; /* format = 30(noVar) or 31 (Var) */
1429   Offset24To<Paint>     src; /* Offset (from beginning of PaintSkewAroundCenter table) to Paint subtable. */
1430   F2DOT14       xSkewAngle;
1431   F2DOT14       ySkewAngle;
1432   FWORD         centerX;
1433   FWORD         centerY;
1434   public:
1435   DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size + 2 * FWORD::static_size);
1436 };
1437
1438 struct PaintComposite
1439 {
1440   void closurev1 (hb_colrv1_closure_context_t* c) const;
1441
1442   bool subset (hb_subset_context_t *c,
1443                const VarStoreInstancer &instancer) const
1444   {
1445     TRACE_SUBSET (this);
1446     auto *out = c->serializer->embed (this);
1447     if (unlikely (!out)) return_trace (false);
1448
1449     bool ret = false;
1450     ret |= out->src.serialize_subset (c, src, this, instancer);
1451     ret |= out->backdrop.serialize_subset (c, backdrop, this, instancer);
1452     return_trace (ret);
1453   }
1454
1455   bool sanitize (hb_sanitize_context_t *c) const
1456   {
1457     TRACE_SANITIZE (this);
1458     return_trace (c->check_struct (this) &&
1459                   c->check_ops (this->min_size) && // PainComposite can get exponential
1460                   src.sanitize (c, this) &&
1461                   backdrop.sanitize (c, this));
1462   }
1463
1464   void paint_glyph (hb_paint_context_t *c) const
1465   {
1466     TRACE_PAINT (this);
1467     c->recurse (this+backdrop);
1468     c->funcs->push_group (c->data);
1469     c->recurse (this+src);
1470     c->funcs->pop_group (c->data, (hb_paint_composite_mode_t) (int) mode);
1471   }
1472
1473   HBUINT8               format; /* format = 32 */
1474   Offset24To<Paint>     src; /* Offset (from beginning of PaintComposite table) to source Paint subtable. */
1475   CompositeMode         mode;   /* If mode is unrecognized use COMPOSITE_CLEAR */
1476   Offset24To<Paint>     backdrop; /* Offset (from beginning of PaintComposite table) to backdrop Paint subtable. */
1477   public:
1478   DEFINE_SIZE_STATIC (8);
1479 };
1480
1481 struct ClipBoxData
1482 {
1483   int xMin, yMin, xMax, yMax;
1484 };
1485
1486 struct ClipBoxFormat1
1487 {
1488   bool sanitize (hb_sanitize_context_t *c) const
1489   {
1490     TRACE_SANITIZE (this);
1491     return_trace (c->check_struct (this));
1492   }
1493
1494   void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer HB_UNUSED) const
1495   {
1496     clip_box.xMin = xMin;
1497     clip_box.yMin = yMin;
1498     clip_box.xMax = xMax;
1499     clip_box.yMax = yMax;
1500   }
1501
1502   bool subset (hb_subset_context_t *c,
1503                const VarStoreInstancer &instancer,
1504                uint32_t varIdxBase) const
1505   {
1506     TRACE_SUBSET (this);
1507     auto *out = c->serializer->embed (*this);
1508     if (unlikely (!out)) return_trace (false);
1509
1510     if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1511     {
1512       out->xMin = xMin + (int) roundf (instancer (varIdxBase, 0));
1513       out->yMin = yMin + (int) roundf (instancer (varIdxBase, 1));
1514       out->xMax = xMax + (int) roundf (instancer (varIdxBase, 2));
1515       out->yMax = yMax + (int) roundf (instancer (varIdxBase, 3));
1516     }
1517
1518     if (format == 2 && c->plan->all_axes_pinned)
1519         out->format = 1;
1520
1521     return_trace (true);
1522   }
1523
1524   public:
1525   HBUINT8       format; /* format = 1(noVar) or 2(Var)*/
1526   FWORD         xMin;
1527   FWORD         yMin;
1528   FWORD         xMax;
1529   FWORD         yMax;
1530   public:
1531   DEFINE_SIZE_STATIC (1 + 4 * FWORD::static_size);
1532 };
1533
1534 struct ClipBoxFormat2 : Variable<ClipBoxFormat1>
1535 {
1536   void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer) const
1537   {
1538     value.get_clip_box(clip_box, instancer);
1539     if (instancer)
1540     {
1541       clip_box.xMin += roundf (instancer (varIdxBase, 0));
1542       clip_box.yMin += roundf (instancer (varIdxBase, 1));
1543       clip_box.xMax += roundf (instancer (varIdxBase, 2));
1544       clip_box.yMax += roundf (instancer (varIdxBase, 3));
1545     }
1546   }
1547 };
1548
1549 struct ClipBox
1550 {
1551   bool subset (hb_subset_context_t *c,
1552                const VarStoreInstancer &instancer) const
1553   {
1554     TRACE_SUBSET (this);
1555     switch (u.format) {
1556     case 1: return_trace (u.format1.subset (c, instancer, VarIdx::NO_VARIATION));
1557     case 2: return_trace (u.format2.subset (c, instancer));
1558     default:return_trace (c->default_return_value ());
1559     }
1560   }
1561
1562   template <typename context_t, typename ...Ts>
1563   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1564   {
1565     if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
1566     TRACE_DISPATCH (this, u.format);
1567     switch (u.format) {
1568     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
1569     case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
1570     default:return_trace (c->default_return_value ());
1571     }
1572   }
1573
1574   bool get_extents (hb_glyph_extents_t *extents,
1575                     const VarStoreInstancer &instancer) const
1576   {
1577     ClipBoxData clip_box;
1578     switch (u.format) {
1579     case 1:
1580       u.format1.get_clip_box (clip_box, instancer);
1581       break;
1582     case 2:
1583       u.format2.get_clip_box (clip_box, instancer);
1584       break;
1585     default:
1586       return false;
1587     }
1588
1589     extents->x_bearing = clip_box.xMin;
1590     extents->y_bearing = clip_box.yMax;
1591     extents->width = clip_box.xMax - clip_box.xMin;
1592     extents->height = clip_box.yMin - clip_box.yMax;
1593     return true;
1594   }
1595
1596   protected:
1597   union {
1598   HBUINT8               format;         /* Format identifier */
1599   ClipBoxFormat1        format1;
1600   ClipBoxFormat2        format2;
1601   } u;
1602 };
1603
1604 struct ClipRecord
1605 {
1606   int cmp (hb_codepoint_t g) const
1607   { return g < startGlyphID ? -1 : g <= endGlyphID ? 0 : +1; }
1608
1609   bool subset (hb_subset_context_t *c,
1610                const void *base,
1611                const VarStoreInstancer &instancer) const
1612   {
1613     TRACE_SUBSET (this);
1614     auto *out = c->serializer->embed (*this);
1615     if (unlikely (!out)) return_trace (false);
1616
1617     return_trace (out->clipBox.serialize_subset (c, clipBox, base, instancer));
1618   }
1619
1620   bool sanitize (hb_sanitize_context_t *c, const void *base) const
1621   {
1622     TRACE_SANITIZE (this);
1623     return_trace (c->check_struct (this) && clipBox.sanitize (c, base));
1624   }
1625
1626   bool get_extents (hb_glyph_extents_t *extents,
1627                     const void *base,
1628                     const VarStoreInstancer &instancer) const
1629   {
1630     return (base+clipBox).get_extents (extents, instancer);
1631   }
1632
1633   public:
1634   HBUINT16              startGlyphID;  // first gid clip applies to
1635   HBUINT16              endGlyphID;    // last gid clip applies to, inclusive
1636   Offset24To<ClipBox>   clipBox;   // Box or VarBox
1637   public:
1638   DEFINE_SIZE_STATIC (7);
1639 };
1640 DECLARE_NULL_NAMESPACE_BYTES (OT, ClipRecord);
1641
1642 struct ClipList
1643 {
1644   unsigned serialize_clip_records (hb_subset_context_t *c,
1645                                    const VarStoreInstancer &instancer,
1646                                    const hb_set_t& gids,
1647                                    const hb_map_t& gid_offset_map) const
1648   {
1649     TRACE_SERIALIZE (this);
1650     if (gids.is_empty () ||
1651         gid_offset_map.get_population () != gids.get_population ())
1652       return_trace (0);
1653
1654     unsigned count  = 0;
1655
1656     hb_codepoint_t start_gid= gids.get_min ();
1657     hb_codepoint_t prev_gid = start_gid;
1658
1659     unsigned offset = gid_offset_map.get (start_gid);
1660     unsigned prev_offset = offset;
1661     for (const hb_codepoint_t _ : gids.iter ())
1662     {
1663       if (_ == start_gid) continue;
1664
1665       offset = gid_offset_map.get (_);
1666       if (_ == prev_gid + 1 &&  offset == prev_offset)
1667       {
1668         prev_gid = _;
1669         continue;
1670       }
1671
1672       ClipRecord record;
1673       record.startGlyphID = start_gid;
1674       record.endGlyphID = prev_gid;
1675       record.clipBox = prev_offset;
1676
1677       if (!record.subset (c, this, instancer)) return_trace (0);
1678       count++;
1679
1680       start_gid = _;
1681       prev_gid = _;
1682       prev_offset = offset;
1683     }
1684
1685     //last one
1686     {
1687       ClipRecord record;
1688       record.startGlyphID = start_gid;
1689       record.endGlyphID = prev_gid;
1690       record.clipBox = prev_offset;
1691       if (!record.subset (c, this, instancer)) return_trace (0);
1692       count++;
1693     }
1694     return_trace (count);
1695   }
1696
1697   bool subset (hb_subset_context_t *c,
1698                const VarStoreInstancer &instancer) const
1699   {
1700     TRACE_SUBSET (this);
1701     auto *out = c->serializer->start_embed (*this);
1702     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
1703     if (!c->serializer->check_assign (out->format, format, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
1704
1705     const hb_set_t& glyphset = c->plan->_glyphset_colred;
1706     const hb_map_t &glyph_map = *c->plan->glyph_map;
1707
1708     hb_map_t new_gid_offset_map;
1709     hb_set_t new_gids;
1710     for (const ClipRecord& record : clips.iter ())
1711     {
1712       unsigned start_gid = record.startGlyphID;
1713       unsigned end_gid = record.endGlyphID;
1714       for (unsigned gid = start_gid; gid <= end_gid; gid++)
1715       {
1716         if (!glyphset.has (gid) || !glyph_map.has (gid)) continue;
1717         unsigned new_gid = glyph_map.get (gid);
1718         new_gid_offset_map.set (new_gid, record.clipBox);
1719         new_gids.add (new_gid);
1720       }
1721     }
1722
1723     unsigned count = serialize_clip_records (c, instancer, new_gids, new_gid_offset_map);
1724     if (!count) return_trace (false);
1725     return_trace (c->serializer->check_assign (out->clips.len, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
1726   }
1727
1728   bool sanitize (hb_sanitize_context_t *c) const
1729   {
1730     TRACE_SANITIZE (this);
1731     // TODO Make a formatted struct!
1732     return_trace (c->check_struct (this) && clips.sanitize (c, this));
1733   }
1734
1735   bool
1736   get_extents (hb_codepoint_t gid,
1737                hb_glyph_extents_t *extents,
1738                const VarStoreInstancer &instancer) const
1739   {
1740     auto *rec = clips.as_array ().bsearch (gid);
1741     if (rec)
1742     {
1743       rec->get_extents (extents, this, instancer);
1744       return true;
1745     }
1746     return false;
1747   }
1748
1749   HBUINT8                       format;  // Set to 1.
1750   SortedArray32Of<ClipRecord>   clips;  // Clip records, sorted by startGlyphID
1751   public:
1752   DEFINE_SIZE_ARRAY_SIZED (5, clips);
1753 };
1754
1755 struct Paint
1756 {
1757
1758   template <typename ...Ts>
1759   bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
1760   {
1761     TRACE_SANITIZE (this);
1762
1763     if (unlikely (!c->check_start_recursion (HB_MAX_NESTING_LEVEL)))
1764       return_trace (c->no_dispatch_return_value ());
1765
1766     return_trace (c->end_recursion (this->dispatch (c, std::forward<Ts> (ds)...)));
1767   }
1768
1769   template <typename context_t, typename ...Ts>
1770   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1771   {
1772     if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
1773     TRACE_DISPATCH (this, u.format);
1774     switch (u.format) {
1775     case 1: return_trace (c->dispatch (u.paintformat1, std::forward<Ts> (ds)...));
1776     case 2: return_trace (c->dispatch (u.paintformat2, std::forward<Ts> (ds)...));
1777     case 3: return_trace (c->dispatch (u.paintformat3, std::forward<Ts> (ds)...));
1778     case 4: return_trace (c->dispatch (u.paintformat4, std::forward<Ts> (ds)...));
1779     case 5: return_trace (c->dispatch (u.paintformat5, std::forward<Ts> (ds)...));
1780     case 6: return_trace (c->dispatch (u.paintformat6, std::forward<Ts> (ds)...));
1781     case 7: return_trace (c->dispatch (u.paintformat7, std::forward<Ts> (ds)...));
1782     case 8: return_trace (c->dispatch (u.paintformat8, std::forward<Ts> (ds)...));
1783     case 9: return_trace (c->dispatch (u.paintformat9, std::forward<Ts> (ds)...));
1784     case 10: return_trace (c->dispatch (u.paintformat10, std::forward<Ts> (ds)...));
1785     case 11: return_trace (c->dispatch (u.paintformat11, std::forward<Ts> (ds)...));
1786     case 12: return_trace (c->dispatch (u.paintformat12, std::forward<Ts> (ds)...));
1787     case 13: return_trace (c->dispatch (u.paintformat13, std::forward<Ts> (ds)...));
1788     case 14: return_trace (c->dispatch (u.paintformat14, std::forward<Ts> (ds)...));
1789     case 15: return_trace (c->dispatch (u.paintformat15, std::forward<Ts> (ds)...));
1790     case 16: return_trace (c->dispatch (u.paintformat16, std::forward<Ts> (ds)...));
1791     case 17: return_trace (c->dispatch (u.paintformat17, std::forward<Ts> (ds)...));
1792     case 18: return_trace (c->dispatch (u.paintformat18, std::forward<Ts> (ds)...));
1793     case 19: return_trace (c->dispatch (u.paintformat19, std::forward<Ts> (ds)...));
1794     case 20: return_trace (c->dispatch (u.paintformat20, std::forward<Ts> (ds)...));
1795     case 21: return_trace (c->dispatch (u.paintformat21, std::forward<Ts> (ds)...));
1796     case 22: return_trace (c->dispatch (u.paintformat22, std::forward<Ts> (ds)...));
1797     case 23: return_trace (c->dispatch (u.paintformat23, std::forward<Ts> (ds)...));
1798     case 24: return_trace (c->dispatch (u.paintformat24, std::forward<Ts> (ds)...));
1799     case 25: return_trace (c->dispatch (u.paintformat25, std::forward<Ts> (ds)...));
1800     case 26: return_trace (c->dispatch (u.paintformat26, std::forward<Ts> (ds)...));
1801     case 27: return_trace (c->dispatch (u.paintformat27, std::forward<Ts> (ds)...));
1802     case 28: return_trace (c->dispatch (u.paintformat28, std::forward<Ts> (ds)...));
1803     case 29: return_trace (c->dispatch (u.paintformat29, std::forward<Ts> (ds)...));
1804     case 30: return_trace (c->dispatch (u.paintformat30, std::forward<Ts> (ds)...));
1805     case 31: return_trace (c->dispatch (u.paintformat31, std::forward<Ts> (ds)...));
1806     case 32: return_trace (c->dispatch (u.paintformat32, std::forward<Ts> (ds)...));
1807     default:return_trace (c->default_return_value ());
1808     }
1809   }
1810
1811   protected:
1812   union {
1813   HBUINT8                                       format;
1814   PaintColrLayers                               paintformat1;
1815   NoVariable<PaintSolid>                        paintformat2;
1816   Variable<PaintSolid>                          paintformat3;
1817   NoVariable<PaintLinearGradient<NoVariable>>   paintformat4;
1818   Variable<PaintLinearGradient<Variable>>       paintformat5;
1819   NoVariable<PaintRadialGradient<NoVariable>>   paintformat6;
1820   Variable<PaintRadialGradient<Variable>>       paintformat7;
1821   NoVariable<PaintSweepGradient<NoVariable>>    paintformat8;
1822   Variable<PaintSweepGradient<Variable>>        paintformat9;
1823   PaintGlyph                                    paintformat10;
1824   PaintColrGlyph                                paintformat11;
1825   PaintTransform<NoVariable>                    paintformat12;
1826   PaintTransform<Variable>                      paintformat13;
1827   NoVariable<PaintTranslate>                    paintformat14;
1828   Variable<PaintTranslate>                      paintformat15;
1829   NoVariable<PaintScale>                        paintformat16;
1830   Variable<PaintScale>                          paintformat17;
1831   NoVariable<PaintScaleAroundCenter>            paintformat18;
1832   Variable<PaintScaleAroundCenter>              paintformat19;
1833   NoVariable<PaintScaleUniform>                 paintformat20;
1834   Variable<PaintScaleUniform>                   paintformat21;
1835   NoVariable<PaintScaleUniformAroundCenter>     paintformat22;
1836   Variable<PaintScaleUniformAroundCenter>       paintformat23;
1837   NoVariable<PaintRotate>                       paintformat24;
1838   Variable<PaintRotate>                         paintformat25;
1839   NoVariable<PaintRotateAroundCenter>           paintformat26;
1840   Variable<PaintRotateAroundCenter>             paintformat27;
1841   NoVariable<PaintSkew>                         paintformat28;
1842   Variable<PaintSkew>                           paintformat29;
1843   NoVariable<PaintSkewAroundCenter>             paintformat30;
1844   Variable<PaintSkewAroundCenter>               paintformat31;
1845   PaintComposite                                paintformat32;
1846   } u;
1847   public:
1848   DEFINE_SIZE_MIN (2);
1849 };
1850
1851 struct BaseGlyphPaintRecord
1852 {
1853   int cmp (hb_codepoint_t g) const
1854   { return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
1855
1856   bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map,
1857                   const void* src_base, hb_subset_context_t *c,
1858                   const VarStoreInstancer &instancer) const
1859   {
1860     TRACE_SERIALIZE (this);
1861     auto *out = s->embed (this);
1862     if (unlikely (!out)) return_trace (false);
1863     if (!s->check_assign (out->glyphId, glyph_map->get (glyphId),
1864                           HB_SERIALIZE_ERROR_INT_OVERFLOW))
1865       return_trace (false);
1866
1867     return_trace (out->paint.serialize_subset (c, paint, src_base, instancer));
1868   }
1869
1870   bool sanitize (hb_sanitize_context_t *c, const void *base) const
1871   {
1872     TRACE_SANITIZE (this);
1873     return_trace (likely (c->check_struct (this) && paint.sanitize (c, base)));
1874   }
1875
1876   public:
1877   HBGlyphID16           glyphId;    /* Glyph ID of reference glyph */
1878   Offset32To<Paint>     paint;      /* Offset (from beginning of BaseGlyphPaintRecord array) to Paint,
1879                                      * Typically PaintColrLayers */
1880   public:
1881   DEFINE_SIZE_STATIC (6);
1882 };
1883
1884 struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
1885 {
1886   bool subset (hb_subset_context_t *c,
1887                const VarStoreInstancer &instancer) const
1888   {
1889     TRACE_SUBSET (this);
1890     auto *out = c->serializer->start_embed (this);
1891     if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
1892     const hb_set_t* glyphset = &c->plan->_glyphset_colred;
1893
1894     for (const auto& _ : as_array ())
1895     {
1896       unsigned gid = _.glyphId;
1897       if (!glyphset->has (gid)) continue;
1898
1899       if (_.serialize (c->serializer, c->plan->glyph_map, this, c, instancer)) out->len++;
1900       else return_trace (false);
1901     }
1902
1903     return_trace (out->len != 0);
1904   }
1905
1906   bool sanitize (hb_sanitize_context_t *c) const
1907   {
1908     TRACE_SANITIZE (this);
1909     return_trace (SortedArray32Of<BaseGlyphPaintRecord>::sanitize (c, this));
1910   }
1911 };
1912
1913 struct LayerList : Array32OfOffset32To<Paint>
1914 {
1915   const Paint& get_paint (unsigned i) const
1916   { return this+(*this)[i]; }
1917
1918   bool subset (hb_subset_context_t *c,
1919                const VarStoreInstancer &instancer) const
1920   {
1921     TRACE_SUBSET (this);
1922     auto *out = c->serializer->start_embed (this);
1923     if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
1924
1925     bool ret = false;
1926     for (const auto& _ : + hb_enumerate (*this)
1927                          | hb_filter (c->plan->colrv1_layers, hb_first))
1928
1929     {
1930       auto *o = out->serialize_append (c->serializer);
1931       if (unlikely (!o)) return_trace (false);
1932       ret |= o->serialize_subset (c, _.second, this, instancer);
1933     }
1934     return_trace (ret);
1935   }
1936
1937   bool sanitize (hb_sanitize_context_t *c) const
1938   {
1939     TRACE_SANITIZE (this);
1940     return_trace (Array32OfOffset32To<Paint>::sanitize (c, this));
1941   }
1942 };
1943
1944 struct COLR
1945 {
1946   static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
1947
1948   bool has_v0_data () const { return numBaseGlyphs; }
1949   bool has_v1_data () const
1950   {
1951     if (version == 1)
1952       return (this+baseGlyphList).len > 0;
1953
1954     return false;
1955   }
1956
1957   unsigned int get_glyph_layers (hb_codepoint_t       glyph,
1958                                  unsigned int         start_offset,
1959                                  unsigned int        *count, /* IN/OUT.  May be NULL. */
1960                                  hb_ot_color_layer_t *layers /* OUT.     May be NULL. */) const
1961   {
1962     const BaseGlyphRecord &record = (this+baseGlyphsZ).bsearch (numBaseGlyphs, glyph);
1963
1964     hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
1965     hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
1966                                                                        record.numLayers);
1967     if (count)
1968     {
1969       + glyph_layers.sub_array (start_offset, count)
1970       | hb_sink (hb_array (layers, *count))
1971       ;
1972     }
1973     return glyph_layers.length;
1974   }
1975
1976   struct accelerator_t
1977   {
1978     accelerator_t (hb_face_t *face)
1979     { colr = hb_sanitize_context_t ().reference_table<COLR> (face); }
1980     ~accelerator_t () { this->colr.destroy (); }
1981
1982     bool is_valid () { return colr.get_blob ()->length; }
1983
1984     void closure_glyphs (hb_codepoint_t glyph,
1985                          hb_set_t *related_ids /* OUT */) const
1986     { colr->closure_glyphs (glyph, related_ids); }
1987
1988     void closure_V0palette_indices (const hb_set_t *glyphs,
1989                                     hb_set_t *palettes /* OUT */) const
1990     { colr->closure_V0palette_indices (glyphs, palettes); }
1991
1992     void closure_forV1 (hb_set_t *glyphset,
1993                         hb_set_t *layer_indices,
1994                         hb_set_t *palette_indices) const
1995     { colr->closure_forV1 (glyphset, layer_indices, palette_indices); }
1996
1997     private:
1998     hb_blob_ptr_t<COLR> colr;
1999   };
2000
2001   void closure_glyphs (hb_codepoint_t glyph,
2002                        hb_set_t *related_ids /* OUT */) const
2003   {
2004     const BaseGlyphRecord *record = get_base_glyph_record (glyph);
2005     if (!record) return;
2006
2007     auto glyph_layers = (this+layersZ).as_array (numLayers).sub_array (record->firstLayerIdx,
2008                                                                        record->numLayers);
2009     if (!glyph_layers.length) return;
2010     related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size);
2011   }
2012
2013   void closure_V0palette_indices (const hb_set_t *glyphs,
2014                                   hb_set_t *palettes /* OUT */) const
2015   {
2016     if (!numBaseGlyphs || !numLayers) return;
2017     hb_array_t<const BaseGlyphRecord> baseGlyphs = (this+baseGlyphsZ).as_array (numBaseGlyphs);
2018     hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
2019
2020     for (const BaseGlyphRecord record : baseGlyphs)
2021     {
2022       if (!glyphs->has (record.glyphId)) continue;
2023       hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
2024                                                                    record.numLayers);
2025       for (const LayerRecord layer : glyph_layers)
2026         palettes->add (layer.colorIdx);
2027     }
2028   }
2029
2030   void closure_forV1 (hb_set_t *glyphset,
2031                       hb_set_t *layer_indices,
2032                       hb_set_t *palette_indices) const
2033   {
2034     if (version != 1) return;
2035     hb_set_t visited_glyphs;
2036
2037     hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices);
2038     const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList;
2039
2040     for (const BaseGlyphPaintRecord &baseglyph_paintrecord: baseglyph_paintrecords.iter ())
2041     {
2042       unsigned gid = baseglyph_paintrecord.glyphId;
2043       if (!glyphset->has (gid)) continue;
2044
2045       const Paint &paint = &baseglyph_paintrecords+baseglyph_paintrecord.paint;
2046       paint.dispatch (&c);
2047     }
2048     hb_set_union (glyphset, &visited_glyphs);
2049   }
2050
2051   const LayerList& get_layerList () const
2052   { return (this+layerList); }
2053
2054   const BaseGlyphList& get_baseglyphList () const
2055   { return (this+baseGlyphList); }
2056
2057   bool sanitize (hb_sanitize_context_t *c) const
2058   {
2059     TRACE_SANITIZE (this);
2060     return_trace (c->check_struct (this) &&
2061                   (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
2062                   (this+layersZ).sanitize (c, numLayers) &&
2063                   (version == 0 ||
2064                    (version == 1 &&
2065                     baseGlyphList.sanitize (c, this) &&
2066                     layerList.sanitize (c, this) &&
2067                     clipList.sanitize (c, this) &&
2068                     varIdxMap.sanitize (c, this) &&
2069                     varStore.sanitize (c, this))));
2070   }
2071
2072   template<typename BaseIterator, typename LayerIterator,
2073            hb_requires (hb_is_iterator (BaseIterator)),
2074            hb_requires (hb_is_iterator (LayerIterator))>
2075   bool serialize_V0 (hb_serialize_context_t *c,
2076                      unsigned version,
2077                      BaseIterator base_it,
2078                      LayerIterator layer_it)
2079   {
2080     TRACE_SERIALIZE (this);
2081     if (unlikely (base_it.len () != layer_it.len ()))
2082       return_trace (false);
2083
2084     this->version = version;
2085     numLayers = 0;
2086     numBaseGlyphs = base_it.len ();
2087     if (numBaseGlyphs == 0)
2088     {
2089       baseGlyphsZ = 0;
2090       layersZ = 0;
2091       return_trace (true);
2092     }
2093
2094     c->push ();
2095     for (const hb_item_type<BaseIterator> _ : + base_it.iter ())
2096     {
2097       auto* record = c->embed (_);
2098       if (unlikely (!record)) return_trace (false);
2099       record->firstLayerIdx = numLayers;
2100       numLayers += record->numLayers;
2101     }
2102     c->add_link (baseGlyphsZ, c->pop_pack ());
2103
2104     c->push ();
2105     for (const hb_item_type<LayerIterator>& _ : + layer_it.iter ())
2106       _.as_array ().copy (c);
2107
2108     c->add_link (layersZ, c->pop_pack ());
2109
2110     return_trace (true);
2111   }
2112
2113   const BaseGlyphRecord* get_base_glyph_record (hb_codepoint_t gid) const
2114   {
2115     const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, (unsigned int) gid);
2116     if (record == &Null (BaseGlyphRecord) ||
2117         (record && (hb_codepoint_t) record->glyphId != gid))
2118       record = nullptr;
2119     return record;
2120   }
2121
2122   const BaseGlyphPaintRecord* get_base_glyph_paintrecord (hb_codepoint_t gid) const
2123   {
2124     const BaseGlyphPaintRecord* record = &(this+baseGlyphList).bsearch ((unsigned) gid);
2125     if ((record && (hb_codepoint_t) record->glyphId != gid))
2126       record = nullptr;
2127     return record;
2128   }
2129
2130   bool subset (hb_subset_context_t *c) const
2131   {
2132     TRACE_SUBSET (this);
2133     const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
2134     const hb_set_t& glyphset = c->plan->_glyphset_colred;
2135
2136     auto base_it =
2137     + hb_range (c->plan->num_output_glyphs ())
2138     | hb_filter ([&](hb_codepoint_t new_gid)
2139                  {
2140                     hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
2141                     if (glyphset.has (old_gid)) return true;
2142                     return false;
2143                  })
2144     | hb_map_retains_sorting ([&](hb_codepoint_t new_gid)
2145                               {
2146                                 hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
2147
2148                                 const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
2149                                 if (unlikely (!old_record))
2150                                   return hb_pair_t<bool, BaseGlyphRecord> (false, Null (BaseGlyphRecord));
2151                                 BaseGlyphRecord new_record = {};
2152                                 new_record.glyphId = new_gid;
2153                                 new_record.numLayers = old_record->numLayers;
2154                                 return hb_pair_t<bool, BaseGlyphRecord> (true, new_record);
2155                               })
2156     | hb_filter (hb_first)
2157     | hb_map_retains_sorting (hb_second)
2158     ;
2159
2160     auto layer_it =
2161     + hb_range (c->plan->num_output_glyphs ())
2162     | hb_map (reverse_glyph_map)
2163     | hb_filter (glyphset)
2164     | hb_map_retains_sorting ([&](hb_codepoint_t old_gid)
2165                               {
2166                                 const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
2167                                 hb_vector_t<LayerRecord> out_layers;
2168
2169                                 if (unlikely (!old_record ||
2170                                               old_record->firstLayerIdx >= numLayers ||
2171                                               old_record->firstLayerIdx + old_record->numLayers > numLayers))
2172                                   return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
2173
2174                                 auto layers = (this+layersZ).as_array (numLayers).sub_array (old_record->firstLayerIdx,
2175                                                                                              old_record->numLayers);
2176                                 out_layers.resize (layers.length);
2177                                 for (unsigned int i = 0; i < layers.length; i++) {
2178                                   out_layers[i] = layers[i];
2179                                   hb_codepoint_t new_gid = 0;
2180                                   if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid)))
2181                                     return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
2182                                   out_layers[i].glyphId = new_gid;
2183                                   out_layers[i].colorIdx = c->plan->colr_palettes.get (layers[i].colorIdx);
2184                                 }
2185
2186                                 return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers);
2187                               })
2188     | hb_filter (hb_first)
2189     | hb_map_retains_sorting (hb_second)
2190     ;
2191
2192     if (version == 0 && (!base_it || !layer_it))
2193       return_trace (false);
2194
2195     auto *colr_prime = c->serializer->start_embed<COLR> ();
2196     if (unlikely (!c->serializer->extend_min (colr_prime)))  return_trace (false);
2197
2198     if (version == 0)
2199     return_trace (colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it));
2200
2201     auto snap = c->serializer->snapshot ();
2202     if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false);
2203
2204     VarStoreInstancer instancer (varStore ? &(this+varStore) : nullptr,
2205                                  varIdxMap ? &(this+varIdxMap) : nullptr,
2206                                  c->plan->normalized_coords.as_array ());
2207
2208     if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this, instancer))
2209     {
2210       if (c->serializer->in_error ()) return_trace (false);
2211       //no more COLRv1 glyphs: downgrade to version 0
2212       c->serializer->revert (snap);
2213       return_trace (colr_prime->serialize_V0 (c->serializer, 0, base_it, layer_it));
2214     }
2215
2216     if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false);
2217
2218     colr_prime->layerList.serialize_subset (c, layerList, this, instancer);
2219     colr_prime->clipList.serialize_subset (c, clipList, this, instancer);
2220     if (!varStore || c->plan->all_axes_pinned)
2221       return_trace (true);
2222
2223     colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this);
2224     colr_prime->varStore.serialize_copy (c->serializer, varStore, this);
2225     return_trace (true);
2226   }
2227
2228   const Paint *get_base_glyph_paint (hb_codepoint_t glyph) const
2229   {
2230     const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList;
2231     const BaseGlyphPaintRecord* record = get_base_glyph_paintrecord (glyph);
2232     if (record)
2233     {
2234       const Paint &paint = &baseglyph_paintrecords+record->paint;
2235       return &paint;
2236     }
2237     else
2238       return nullptr;
2239   }
2240
2241 #ifndef HB_NO_PAINT
2242   bool
2243   get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
2244   {
2245     if (version != 1)
2246       return false;
2247
2248     VarStoreInstancer instancer (&(this+varStore),
2249                                  &(this+varIdxMap),
2250                                  hb_array (font->coords, font->num_coords));
2251
2252     if (get_clip (glyph, extents, instancer))
2253     {
2254       font->scale_glyph_extents (extents);
2255       return true;
2256     }
2257
2258     auto *extents_funcs = hb_paint_extents_get_funcs ();
2259     hb_paint_extents_context_t extents_data;
2260     bool ret = paint_glyph (font, glyph, extents_funcs, &extents_data, 0, HB_COLOR(0,0,0,0));
2261
2262     hb_extents_t e = extents_data.get_extents ();
2263     if (e.is_void ())
2264     {
2265       extents->x_bearing = 0;
2266       extents->y_bearing = 0;
2267       extents->width = 0;
2268       extents->height = 0;
2269     }
2270     else
2271     {
2272       extents->x_bearing = e.xmin;
2273       extents->y_bearing = e.ymax;
2274       extents->width = e.xmax - e.xmin;
2275       extents->height = e.ymin - e.ymax;
2276     }
2277
2278     return ret;
2279   }
2280 #endif
2281
2282   bool
2283   has_paint_for_glyph (hb_codepoint_t glyph) const
2284   {
2285     if (version == 1)
2286     {
2287       const Paint *paint = get_base_glyph_paint (glyph);
2288
2289       return paint != nullptr;
2290     }
2291
2292     return false;
2293   }
2294
2295   bool get_clip (hb_codepoint_t glyph,
2296                  hb_glyph_extents_t *extents,
2297                  const VarStoreInstancer instancer) const
2298   {
2299     return (this+clipList).get_extents (glyph,
2300                                         extents,
2301                                         instancer);
2302   }
2303
2304 #ifndef HB_NO_PAINT
2305   bool
2306   paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const
2307   {
2308     VarStoreInstancer instancer (&(this+varStore),
2309                                  &(this+varIdxMap),
2310                                  hb_array (font->coords, font->num_coords));
2311     hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer);
2312     c.current_glyphs.add (glyph);
2313
2314     if (version == 1)
2315     {
2316       const Paint *paint = get_base_glyph_paint (glyph);
2317       if (paint)
2318       {
2319         // COLRv1 glyph
2320
2321         VarStoreInstancer instancer (&(this+varStore),
2322                                      &(this+varIdxMap),
2323                                      hb_array (font->coords, font->num_coords));
2324
2325         bool is_bounded = true;
2326         if (clip)
2327         {
2328           hb_glyph_extents_t extents;
2329           if (get_clip (glyph, &extents, instancer))
2330           {
2331             font->scale_glyph_extents (&extents);
2332             c.funcs->push_clip_rectangle (c.data,
2333                                           extents.x_bearing,
2334                                           extents.y_bearing + extents.height,
2335                                           extents.x_bearing + extents.width,
2336                                           extents.y_bearing);
2337           }
2338           else
2339           {
2340             auto *extents_funcs = hb_paint_extents_get_funcs ();
2341             hb_paint_extents_context_t extents_data;
2342
2343             paint_glyph (font, glyph,
2344                          extents_funcs, &extents_data,
2345                          palette_index, foreground,
2346                          false);
2347
2348             hb_extents_t extents = extents_data.get_extents ();
2349             is_bounded = extents_data.is_bounded ();
2350
2351             c.funcs->push_clip_rectangle (c.data,
2352                                           extents.xmin,
2353                                           extents.ymin,
2354                                           extents.xmax,
2355                                           extents.ymax);
2356           }
2357         }
2358
2359         c.funcs->push_root_transform (c.data, font);
2360
2361         if (is_bounded)
2362           c.recurse (*paint);
2363
2364         c.funcs->pop_transform (c.data);
2365
2366         if (clip)
2367           c.funcs->pop_clip (c.data);
2368
2369         return true;
2370       }
2371     }
2372
2373     const BaseGlyphRecord *record = get_base_glyph_record (glyph);
2374     if (record && ((hb_codepoint_t) record->glyphId == glyph))
2375     {
2376       // COLRv0 glyph
2377       for (const auto &r : (this+layersZ).as_array (numLayers)
2378                            .sub_array (record->firstLayerIdx, record->numLayers))
2379       {
2380         hb_bool_t is_foreground;
2381         hb_color_t color = c.get_color (r.colorIdx, 1., &is_foreground);
2382         c.funcs->push_clip_glyph (c.data, r.glyphId, c.font);
2383         c.funcs->color (c.data, is_foreground, color);
2384         c.funcs->pop_clip (c.data);
2385       }
2386
2387       return true;
2388     }
2389
2390     return false;
2391   }
2392 #endif
2393
2394   protected:
2395   HBUINT16      version;        /* Table version number (starts at 0). */
2396   HBUINT16      numBaseGlyphs;  /* Number of Base Glyph Records. */
2397   NNOffset32To<SortedUnsizedArrayOf<BaseGlyphRecord>>
2398                 baseGlyphsZ;    /* Offset to Base Glyph records. */
2399   NNOffset32To<UnsizedArrayOf<LayerRecord>>
2400                 layersZ;        /* Offset to Layer Records. */
2401   HBUINT16      numLayers;      /* Number of Layer Records. */
2402   // Version-1 additions
2403   Offset32To<BaseGlyphList>             baseGlyphList;
2404   Offset32To<LayerList>                 layerList;
2405   Offset32To<ClipList>                  clipList;   // Offset to ClipList table (may be NULL)
2406   Offset32To<DeltaSetIndexMap>          varIdxMap;  // Offset to DeltaSetIndexMap table (may be NULL)
2407   Offset32To<VariationStore>            varStore;
2408   public:
2409   DEFINE_SIZE_MIN (14);
2410 };
2411
2412 struct COLR_accelerator_t : COLR::accelerator_t {
2413   COLR_accelerator_t (hb_face_t *face) : COLR::accelerator_t (face) {}
2414 };
2415
2416 void
2417 hb_paint_context_t::recurse (const Paint &paint)
2418 {
2419   if (unlikely (depth_left <= 0 || edge_count <= 0)) return;
2420   depth_left--;
2421   edge_count--;
2422   paint.dispatch (this);
2423   depth_left++;
2424 }
2425
2426 void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const
2427 {
2428   TRACE_PAINT (this);
2429   const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList ();
2430   for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++)
2431   {
2432     if (unlikely (c->current_layers.has (i)))
2433       continue;
2434
2435     c->current_layers.add (i);
2436
2437     const Paint &paint = paint_offset_lists.get_paint (i);
2438     c->funcs->push_group (c->data);
2439     c->recurse (paint);
2440     c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
2441
2442     c->current_layers.del (i);
2443   }
2444 }
2445
2446 void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
2447 {
2448   TRACE_PAINT (this);
2449
2450   if (unlikely (c->current_glyphs.has (gid)))
2451     return;
2452
2453   c->current_glyphs.add (gid);
2454
2455   c->funcs->push_inverse_root_transform (c->data, c->font);
2456   if (c->funcs->color_glyph (c->data, gid, c->font))
2457   {
2458     c->funcs->pop_transform (c->data);
2459     c->current_glyphs.del (gid);
2460     return;
2461   }
2462   c->funcs->pop_transform (c->data);
2463
2464   const COLR *colr_table = c->get_colr_table ();
2465   const Paint *paint = colr_table->get_base_glyph_paint (gid);
2466
2467   hb_glyph_extents_t extents = {0};
2468   bool has_clip_box = colr_table->get_clip (gid, &extents, c->instancer);
2469
2470   if (has_clip_box)
2471     c->funcs->push_clip_rectangle (c->data,
2472                                    extents.x_bearing,
2473                                    extents.y_bearing + extents.height,
2474                                    extents.x_bearing + extents.width,
2475                                    extents.y_bearing);
2476
2477   if (paint)
2478     c->recurse (*paint);
2479
2480   if (has_clip_box)
2481     c->funcs->pop_clip (c->data);
2482
2483   c->current_glyphs.del (gid);
2484 }
2485
2486 } /* namespace OT */
2487
2488 #endif /* OT_COLOR_COLR_COLR_HH */