1 /*
2  * Copyright © 2018  Ebrahim Byagowi
3  * Copyright © 2020  Google, Inc.
4  *
5  *  This is part of HarfBuzz, a text shaping library.
6  *
7  * Permission is hereby granted, without written agreement and without
8  * license or royalty fees, to use, copy, modify, and distribute this
9  * software and its documentation for any purpose, provided that the
10  * above copyright notice and the following two paragraphs appear in
11  * all copies of this software.
12  *
13  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17  * DAMAGE.
18  *
19  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24  *
25  * Google Author(s): Calder Kitagawa
26  */
27 
28 #ifndef HB_OT_COLOR_COLR_TABLE_HH
29 #define HB_OT_COLOR_COLR_TABLE_HH
30 
31 #include "hb-open-type.hh"
32 #include "hb-ot-layout-common.hh"
33 #include "hb-ot-var-common.hh"
34 
35 /*
36  * COLR -- Color
37  * https://docs.microsoft.com/en-us/typography/opentype/spec/colr
38  */
39 #define HB_OT_TAG_COLR HB_TAG('C','O','L','R')
40 
41 #ifndef HB_COLRV1_MAX_NESTING_LEVEL
42 #define HB_COLRV1_MAX_NESTING_LEVEL	100
43 #endif
44 
45 #ifndef COLRV1_ENABLE_SUBSETTING
46 #define COLRV1_ENABLE_SUBSETTING 1
47 #endif
48 
49 namespace OT {
50 
51 struct COLR;
52 struct hb_colrv1_closure_context_t :
53        hb_dispatch_context_t<hb_colrv1_closure_context_t>
54 {
55   template <typename T>
dispatchOT::hb_colrv1_closure_context_t56   return_t dispatch (const T &obj)
57   {
58     if (unlikely (nesting_level_left == 0))
59       return hb_empty_t ();
60 
61     if (paint_visited (&obj))
62       return hb_empty_t ();
63 
64     nesting_level_left--;
65     obj.closurev1 (this);
66     nesting_level_left++;
67     return hb_empty_t ();
68   }
default_return_valueOT::hb_colrv1_closure_context_t69   static return_t default_return_value () { return hb_empty_t (); }
70 
paint_visitedOT::hb_colrv1_closure_context_t71   bool paint_visited (const void *paint)
72   {
73     hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) paint - (uintptr_t) base);
74     if (visited_paint.in_error() || visited_paint.has (delta))
75       return true;
76 
77     visited_paint.add (delta);
78     return false;
79   }
80 
get_colr_tableOT::hb_colrv1_closure_context_t81   const COLR* get_colr_table () const
82   { return reinterpret_cast<const COLR *> (base); }
83 
add_glyphOT::hb_colrv1_closure_context_t84   void add_glyph (unsigned glyph_id)
85   { glyphs->add (glyph_id); }
86 
add_layer_indicesOT::hb_colrv1_closure_context_t87   void add_layer_indices (unsigned first_layer_index, unsigned num_of_layers)
88   { layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1); }
89 
add_palette_indexOT::hb_colrv1_closure_context_t90   void add_palette_index (unsigned palette_index)
91   { palette_indices->add (palette_index); }
92 
93   public:
94   const void *base;
95   hb_set_t visited_paint;
96   hb_set_t *glyphs;
97   hb_set_t *layer_indices;
98   hb_set_t *palette_indices;
99   unsigned nesting_level_left;
100 
hb_colrv1_closure_context_tOT::hb_colrv1_closure_context_t101   hb_colrv1_closure_context_t (const void *base_,
102                                hb_set_t *glyphs_,
103                                hb_set_t *layer_indices_,
104                                hb_set_t *palette_indices_,
105                                unsigned nesting_level_left_ = HB_COLRV1_MAX_NESTING_LEVEL) :
106                           base (base_),
107                           glyphs (glyphs_),
108                           layer_indices (layer_indices_),
109                           palette_indices (palette_indices_),
110                           nesting_level_left (nesting_level_left_)
111   {}
112 };
113 
114 struct LayerRecord
115 {
operator hb_ot_color_layer_tOT::LayerRecord116   operator hb_ot_color_layer_t () const { return {glyphId, colorIdx}; }
117 
sanitizeOT::LayerRecord118   bool sanitize (hb_sanitize_context_t *c) const
119   {
120     TRACE_SANITIZE (this);
121     return_trace (c->check_struct (this));
122   }
123 
124   public:
125   HBGlyphID16	glyphId;	/* Glyph ID of layer glyph */
126   Index		colorIdx;	/* Index value to use with a
127 				 * selected color palette.
128 				 * An index value of 0xFFFF
129 				 * is a special case indicating
130 				 * that the text foreground
131 				 * color (defined by a
132 				 * higher-level client) should
133 				 * be used and shall not be
134 				 * treated as actual index
135 				 * into CPAL ColorRecord array. */
136   public:
137   DEFINE_SIZE_STATIC (4);
138 };
139 
140 struct BaseGlyphRecord
141 {
cmpOT::BaseGlyphRecord142   int cmp (hb_codepoint_t g) const
143   { return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
144 
sanitizeOT::BaseGlyphRecord145   bool sanitize (hb_sanitize_context_t *c) const
146   {
147     TRACE_SANITIZE (this);
148     return_trace (likely (c->check_struct (this)));
149   }
150 
151   public:
152   HBGlyphID16	glyphId;	/* Glyph ID of reference glyph */
153   HBUINT16	firstLayerIdx;	/* Index (from beginning of
154 				 * the Layer Records) to the
155 				 * layer record. There will be
156 				 * numLayers consecutive entries
157 				 * for this base glyph. */
158   HBUINT16	numLayers;	/* Number of color layers
159 				 * associated with this glyph */
160   public:
161   DEFINE_SIZE_STATIC (6);
162 };
163 
164 template <typename T>
165 struct Variable
166 {
copyOT::Variable167   Variable<T>* copy (hb_serialize_context_t *c) const
168   {
169     TRACE_SERIALIZE (this);
170     return_trace (c->embed (this));
171   }
172 
closurev1OT::Variable173   void closurev1 (hb_colrv1_closure_context_t* c) const
174   { value.closurev1 (c); }
175 
subsetOT::Variable176   bool subset (hb_subset_context_t *c) const
177   {
178     TRACE_SUBSET (this);
179     if (!value.subset (c)) return_trace (false);
180     return_trace (c->serializer->embed (varIdxBase));
181   }
182 
sanitizeOT::Variable183   bool sanitize (hb_sanitize_context_t *c) const
184   {
185     TRACE_SANITIZE (this);
186     return_trace (c->check_struct (this) && value.sanitize (c));
187   }
188 
189   protected:
190   T      value;
191   VarIdx varIdxBase;
192   public:
193   DEFINE_SIZE_STATIC (4 + T::static_size);
194 };
195 
196 template <typename T>
197 struct NoVariable
198 {
copyOT::NoVariable199   NoVariable<T>* copy (hb_serialize_context_t *c) const
200   {
201     TRACE_SERIALIZE (this);
202     return_trace (c->embed (this));
203   }
204 
closurev1OT::NoVariable205   void closurev1 (hb_colrv1_closure_context_t* c) const
206   { value.closurev1 (c); }
207 
subsetOT::NoVariable208   bool subset (hb_subset_context_t *c) const
209   {
210     TRACE_SUBSET (this);
211     return_trace (value.subset (c));
212   }
213 
sanitizeOT::NoVariable214   bool sanitize (hb_sanitize_context_t *c) const
215   {
216     TRACE_SANITIZE (this);
217     return_trace (c->check_struct (this) && value.sanitize (c));
218   }
219 
220   T      value;
221   public:
222   DEFINE_SIZE_STATIC (T::static_size);
223 };
224 
225 // Color structures
226 
227 struct ColorStop
228 {
closurev1OT::ColorStop229   void closurev1 (hb_colrv1_closure_context_t* c) const
230   { c->add_palette_index (paletteIndex); }
231 
subsetOT::ColorStop232   bool subset (hb_subset_context_t *c) const
233   {
234     TRACE_SUBSET (this);
235     auto *out = c->serializer->embed (*this);
236     if (unlikely (!out)) return_trace (false);
237     return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex),
238                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
239   }
240 
sanitizeOT::ColorStop241   bool sanitize (hb_sanitize_context_t *c) const
242   {
243     TRACE_SANITIZE (this);
244     return_trace (c->check_struct (this));
245   }
246 
247   F2DOT14	stopOffset;
248   HBUINT16	paletteIndex;
249   F2DOT14	alpha;
250   public:
251   DEFINE_SIZE_STATIC (2 + 2 * F2DOT14::static_size);
252 };
253 
254 struct Extend : HBUINT8
255 {
256   enum {
257     EXTEND_PAD     = 0,
258     EXTEND_REPEAT  = 1,
259     EXTEND_REFLECT = 2,
260   };
261   public:
262   DEFINE_SIZE_STATIC (1);
263 };
264 
265 template <template<typename> class Var>
266 struct ColorLine
267 {
closurev1OT::ColorLine268   void closurev1 (hb_colrv1_closure_context_t* c) const
269   {
270     for (const auto &stop : stops.iter ())
271       stop.closurev1 (c);
272   }
273 
subsetOT::ColorLine274   bool subset (hb_subset_context_t *c) const
275   {
276     TRACE_SUBSET (this);
277     auto *out = c->serializer->start_embed (this);
278     if (unlikely (!out)) return_trace (false);
279     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
280 
281     if (!c->serializer->check_assign (out->extend, extend, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
282     if (!c->serializer->check_assign (out->stops.len, stops.len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)) return_trace (false);
283 
284     for (const auto& stop : stops.iter ())
285     {
286       if (!stop.subset (c)) return_trace (false);
287     }
288     return_trace (true);
289   }
290 
sanitizeOT::ColorLine291   bool sanitize (hb_sanitize_context_t *c) const
292   {
293     TRACE_SANITIZE (this);
294     return_trace (c->check_struct (this) &&
295                   stops.sanitize (c));
296   }
297 
298   Extend	extend;
299   Array16Of<Var<ColorStop>>	stops;
300   public:
301   DEFINE_SIZE_ARRAY_SIZED (3, stops);
302 };
303 
304 // Composition modes
305 
306 // Compositing modes are taken from https://www.w3.org/TR/compositing-1/
307 // NOTE: a brief audit of major implementations suggests most support most
308 // or all of the specified modes.
309 struct CompositeMode : HBUINT8
310 {
311   enum {
312     // Porter-Duff modes
313     // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators
314     COMPOSITE_CLEAR          =  0,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_clear
315     COMPOSITE_SRC            =  1,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_src
316     COMPOSITE_DEST           =  2,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dst
317     COMPOSITE_SRC_OVER       =  3,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcover
318     COMPOSITE_DEST_OVER      =  4,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstover
319     COMPOSITE_SRC_IN         =  5,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcin
320     COMPOSITE_DEST_IN        =  6,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstin
321     COMPOSITE_SRC_OUT        =  7,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcout
322     COMPOSITE_DEST_OUT       =  8,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstout
323     COMPOSITE_SRC_ATOP       =  9,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcatop
324     COMPOSITE_DEST_ATOP      = 10,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstatop
325     COMPOSITE_XOR            = 11,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_xor
326     COMPOSITE_PLUS           = 12,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_plus
327 
328     // Blend modes
329     // https://www.w3.org/TR/compositing-1/#blending
330     COMPOSITE_SCREEN         = 13,  // https://www.w3.org/TR/compositing-1/#blendingscreen
331     COMPOSITE_OVERLAY        = 14,  // https://www.w3.org/TR/compositing-1/#blendingoverlay
332     COMPOSITE_DARKEN         = 15,  // https://www.w3.org/TR/compositing-1/#blendingdarken
333     COMPOSITE_LIGHTEN        = 16,  // https://www.w3.org/TR/compositing-1/#blendinglighten
334     COMPOSITE_COLOR_DODGE    = 17,  // https://www.w3.org/TR/compositing-1/#blendingcolordodge
335     COMPOSITE_COLOR_BURN     = 18,  // https://www.w3.org/TR/compositing-1/#blendingcolorburn
336     COMPOSITE_HARD_LIGHT     = 19,  // https://www.w3.org/TR/compositing-1/#blendinghardlight
337     COMPOSITE_SOFT_LIGHT     = 20,  // https://www.w3.org/TR/compositing-1/#blendingsoftlight
338     COMPOSITE_DIFFERENCE     = 21,  // https://www.w3.org/TR/compositing-1/#blendingdifference
339     COMPOSITE_EXCLUSION      = 22,  // https://www.w3.org/TR/compositing-1/#blendingexclusion
340     COMPOSITE_MULTIPLY       = 23,  // https://www.w3.org/TR/compositing-1/#blendingmultiply
341 
342     // Modes that, uniquely, do not operate on components
343     // https://www.w3.org/TR/compositing-1/#blendingnonseparable
344     COMPOSITE_HSL_HUE        = 24,  // https://www.w3.org/TR/compositing-1/#blendinghue
345     COMPOSITE_HSL_SATURATION = 25,  // https://www.w3.org/TR/compositing-1/#blendingsaturation
346     COMPOSITE_HSL_COLOR      = 26,  // https://www.w3.org/TR/compositing-1/#blendingcolor
347     COMPOSITE_HSL_LUMINOSITY = 27,  // https://www.w3.org/TR/compositing-1/#blendingluminosity
348   };
349   public:
350   DEFINE_SIZE_STATIC (1);
351 };
352 
353 struct Affine2x3
354 {
sanitizeOT::Affine2x3355   bool sanitize (hb_sanitize_context_t *c) const
356   {
357     TRACE_SANITIZE (this);
358     return_trace (c->check_struct (this));
359   }
360 
361   HBFixed xx;
362   HBFixed yx;
363   HBFixed xy;
364   HBFixed yy;
365   HBFixed dx;
366   HBFixed dy;
367   public:
368   DEFINE_SIZE_STATIC (6 * HBFixed::static_size);
369 };
370 
371 struct PaintColrLayers
372 {
373   void closurev1 (hb_colrv1_closure_context_t* c) const;
374 
subsetOT::PaintColrLayers375   bool subset (hb_subset_context_t *c) const
376   {
377     TRACE_SUBSET (this);
378     auto *out = c->serializer->embed (this);
379     if (unlikely (!out)) return_trace (false);
380     return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers->get (firstLayerIndex),
381                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
382 
383     return_trace (true);
384   }
385 
sanitizeOT::PaintColrLayers386   bool sanitize (hb_sanitize_context_t *c) const
387   {
388     TRACE_SANITIZE (this);
389     return_trace (c->check_struct (this));
390   }
391 
392   HBUINT8	format; /* format = 1 */
393   HBUINT8	numLayers;
394   HBUINT32	firstLayerIndex;  /* index into COLRv1::layerList */
395   public:
396   DEFINE_SIZE_STATIC (6);
397 };
398 
399 struct PaintSolid
400 {
closurev1OT::PaintSolid401   void closurev1 (hb_colrv1_closure_context_t* c) const
402   { c->add_palette_index (paletteIndex); }
403 
subsetOT::PaintSolid404   bool subset (hb_subset_context_t *c) const
405   {
406     TRACE_SUBSET (this);
407     auto *out = c->serializer->embed (*this);
408     if (unlikely (!out)) return_trace (false);
409     return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex),
410                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
411   }
412 
sanitizeOT::PaintSolid413   bool sanitize (hb_sanitize_context_t *c) const
414   {
415     TRACE_SANITIZE (this);
416     return_trace (c->check_struct (this));
417   }
418 
419   HBUINT8	format; /* format = 2(noVar) or 3(Var)*/
420   HBUINT16	paletteIndex;
421   F2DOT14	alpha;
422   public:
423   DEFINE_SIZE_STATIC (3 + F2DOT14::static_size);
424 };
425 
426 template <template<typename> class Var>
427 struct PaintLinearGradient
428 {
closurev1OT::PaintLinearGradient429   void closurev1 (hb_colrv1_closure_context_t* c) const
430   { (this+colorLine).closurev1 (c); }
431 
subsetOT::PaintLinearGradient432   bool subset (hb_subset_context_t *c) const
433   {
434     TRACE_SUBSET (this);
435     auto *out = c->serializer->embed (this);
436     if (unlikely (!out)) return_trace (false);
437 
438     return_trace (out->colorLine.serialize_subset (c, colorLine, this));
439   }
440 
sanitizeOT::PaintLinearGradient441   bool sanitize (hb_sanitize_context_t *c) const
442   {
443     TRACE_SANITIZE (this);
444     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
445   }
446 
447   HBUINT8			format; /* format = 4(noVar) or 5 (Var) */
448   Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintLinearGradient
449                                             * table) to ColorLine subtable. */
450   FWORD			x0;
451   FWORD			y0;
452   FWORD			x1;
453   FWORD			y1;
454   FWORD			x2;
455   FWORD			y2;
456   public:
457   DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size);
458 };
459 
460 template <template<typename> class Var>
461 struct PaintRadialGradient
462 {
closurev1OT::PaintRadialGradient463   void closurev1 (hb_colrv1_closure_context_t* c) const
464   { (this+colorLine).closurev1 (c); }
465 
subsetOT::PaintRadialGradient466   bool subset (hb_subset_context_t *c) const
467   {
468     TRACE_SUBSET (this);
469     auto *out = c->serializer->embed (this);
470     if (unlikely (!out)) return_trace (false);
471 
472     return_trace (out->colorLine.serialize_subset (c, colorLine, this));
473   }
474 
sanitizeOT::PaintRadialGradient475   bool sanitize (hb_sanitize_context_t *c) const
476   {
477     TRACE_SANITIZE (this);
478     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
479   }
480 
481   HBUINT8			format; /* format = 6(noVar) or 7 (Var) */
482   Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintRadialGradient
483                                             * table) to ColorLine subtable. */
484   FWORD			x0;
485   FWORD			y0;
486   UFWORD		radius0;
487   FWORD			x1;
488   FWORD			y1;
489   UFWORD		radius1;
490   public:
491   DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size);
492 };
493 
494 template <template<typename> class Var>
495 struct PaintSweepGradient
496 {
closurev1OT::PaintSweepGradient497   void closurev1 (hb_colrv1_closure_context_t* c) const
498   { (this+colorLine).closurev1 (c); }
499 
subsetOT::PaintSweepGradient500   bool subset (hb_subset_context_t *c) const
501   {
502     TRACE_SUBSET (this);
503     auto *out = c->serializer->embed (this);
504     if (unlikely (!out)) return_trace (false);
505 
506     return_trace (out->colorLine.serialize_subset (c, colorLine, this));
507   }
508 
sanitizeOT::PaintSweepGradient509   bool sanitize (hb_sanitize_context_t *c) const
510   {
511     TRACE_SANITIZE (this);
512     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
513   }
514 
515   HBUINT8			format; /* format = 8(noVar) or 9 (Var) */
516   Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintSweepGradient
517                                             * table) to ColorLine subtable. */
518   FWORD			centerX;
519   FWORD			centerY;
520   F2DOT14		startAngle;
521   F2DOT14		endAngle;
522   public:
523   DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size + 2 * F2DOT14::static_size);
524 };
525 
526 struct Paint;
527 // Paint a non-COLR glyph, filled as indicated by paint.
528 struct PaintGlyph
529 {
530   void closurev1 (hb_colrv1_closure_context_t* c) const;
531 
subsetOT::PaintGlyph532   bool subset (hb_subset_context_t *c) const
533   {
534     TRACE_SUBSET (this);
535     auto *out = c->serializer->embed (this);
536     if (unlikely (!out)) return_trace (false);
537 
538     if (! c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid),
539                                        HB_SERIALIZE_ERROR_INT_OVERFLOW))
540       return_trace (false);
541 
542     return_trace (out->paint.serialize_subset (c, paint, this));
543   }
544 
sanitizeOT::PaintGlyph545   bool sanitize (hb_sanitize_context_t *c) const
546   {
547     TRACE_SANITIZE (this);
548     return_trace (c->check_struct (this) && paint.sanitize (c, this));
549   }
550 
551   HBUINT8		format; /* format = 10 */
552   Offset24To<Paint>	paint;  /* Offset (from beginning of PaintGlyph table) to Paint subtable. */
553   HBUINT16		gid;
554   public:
555   DEFINE_SIZE_STATIC (6);
556 };
557 
558 struct PaintColrGlyph
559 {
560   void closurev1 (hb_colrv1_closure_context_t* c) const;
561 
subsetOT::PaintColrGlyph562   bool subset (hb_subset_context_t *c) const
563   {
564     TRACE_SUBSET (this);
565     auto *out = c->serializer->embed (this);
566     if (unlikely (!out)) return_trace (false);
567 
568     return_trace (c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid),
569                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
570   }
571 
sanitizeOT::PaintColrGlyph572   bool sanitize (hb_sanitize_context_t *c) const
573   {
574     TRACE_SANITIZE (this);
575     return_trace (c->check_struct (this));
576   }
577 
578   HBUINT8	format; /* format = 11 */
579   HBUINT16	gid;
580   public:
581   DEFINE_SIZE_STATIC (3);
582 };
583 
584 template <template<typename> class Var>
585 struct PaintTransform
586 {
587   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
588 
subsetOT::PaintTransform589   bool subset (hb_subset_context_t *c) const
590   {
591     TRACE_SUBSET (this);
592     auto *out = c->serializer->embed (this);
593     if (unlikely (!out)) return_trace (false);
594     if (!out->transform.serialize_copy (c->serializer, transform, this)) return_trace (false);
595     return_trace (out->src.serialize_subset (c, src, this));
596   }
597 
sanitizeOT::PaintTransform598   bool sanitize (hb_sanitize_context_t *c) const
599   {
600     TRACE_SANITIZE (this);
601     return_trace (c->check_struct (this) &&
602                   src.sanitize (c, this) &&
603                   transform.sanitize (c, this));
604   }
605 
606   HBUINT8			format; /* format = 12(noVar) or 13 (Var) */
607   Offset24To<Paint>		src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */
608   Offset24To<Var<Affine2x3>>	transform;
609   public:
610   DEFINE_SIZE_STATIC (7);
611 };
612 
613 struct PaintTranslate
614 {
615   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
616 
subsetOT::PaintTranslate617   bool subset (hb_subset_context_t *c) const
618   {
619     TRACE_SUBSET (this);
620     auto *out = c->serializer->embed (this);
621     if (unlikely (!out)) return_trace (false);
622 
623     return_trace (out->src.serialize_subset (c, src, this));
624   }
625 
sanitizeOT::PaintTranslate626   bool sanitize (hb_sanitize_context_t *c) const
627   {
628     TRACE_SANITIZE (this);
629     return_trace (c->check_struct (this) && src.sanitize (c, this));
630   }
631 
632   HBUINT8		format; /* format = 14(noVar) or 15 (Var) */
633   Offset24To<Paint>	src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */
634   FWORD		dx;
635   FWORD		dy;
636   public:
637   DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size);
638 };
639 
640 struct PaintScale
641 {
642   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
643 
subsetOT::PaintScale644   bool subset (hb_subset_context_t *c) const
645   {
646     TRACE_SUBSET (this);
647     auto *out = c->serializer->embed (this);
648     if (unlikely (!out)) return_trace (false);
649 
650     return_trace (out->src.serialize_subset (c, src, this));
651   }
652 
sanitizeOT::PaintScale653   bool sanitize (hb_sanitize_context_t *c) const
654   {
655     TRACE_SANITIZE (this);
656     return_trace (c->check_struct (this) && src.sanitize (c, this));
657   }
658 
659   HBUINT8		format; /* format = 16 (noVar) or 17(Var) */
660   Offset24To<Paint>	src; /* Offset (from beginning of PaintScale table) to Paint subtable. */
661   F2DOT14		scaleX;
662   F2DOT14		scaleY;
663   public:
664   DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size);
665 };
666 
667 struct PaintScaleAroundCenter
668 {
669   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
670 
subsetOT::PaintScaleAroundCenter671   bool subset (hb_subset_context_t *c) const
672   {
673     TRACE_SUBSET (this);
674     auto *out = c->serializer->embed (this);
675     if (unlikely (!out)) return_trace (false);
676 
677     return_trace (out->src.serialize_subset (c, src, this));
678   }
679 
sanitizeOT::PaintScaleAroundCenter680   bool sanitize (hb_sanitize_context_t *c) const
681   {
682     TRACE_SANITIZE (this);
683     return_trace (c->check_struct (this) && src.sanitize (c, this));
684   }
685 
686   HBUINT8		format; /* format = 18 (noVar) or 19(Var) */
687   Offset24To<Paint>	src; /* Offset (from beginning of PaintScaleAroundCenter table) to Paint subtable. */
688   F2DOT14	scaleX;
689   F2DOT14	scaleY;
690   FWORD		centerX;
691   FWORD		centerY;
692   public:
693   DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size + 2 * FWORD::static_size);
694 };
695 
696 struct PaintScaleUniform
697 {
698   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
699 
subsetOT::PaintScaleUniform700   bool subset (hb_subset_context_t *c) const
701   {
702     TRACE_SUBSET (this);
703     auto *out = c->serializer->embed (this);
704     if (unlikely (!out)) return_trace (false);
705 
706     return_trace (out->src.serialize_subset (c, src, this));
707   }
708 
sanitizeOT::PaintScaleUniform709   bool sanitize (hb_sanitize_context_t *c) const
710   {
711     TRACE_SANITIZE (this);
712     return_trace (c->check_struct (this) && src.sanitize (c, this));
713   }
714 
715   HBUINT8		format; /* format = 20 (noVar) or 21(Var) */
716   Offset24To<Paint>	src; /* Offset (from beginning of PaintScaleUniform table) to Paint subtable. */
717   F2DOT14		scale;
718   public:
719   DEFINE_SIZE_STATIC (4 + F2DOT14::static_size);
720 };
721 
722 struct PaintScaleUniformAroundCenter
723 {
724   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
725 
subsetOT::PaintScaleUniformAroundCenter726   bool subset (hb_subset_context_t *c) const
727   {
728     TRACE_SUBSET (this);
729     auto *out = c->serializer->embed (this);
730     if (unlikely (!out)) return_trace (false);
731 
732     return_trace (out->src.serialize_subset (c, src, this));
733   }
734 
sanitizeOT::PaintScaleUniformAroundCenter735   bool sanitize (hb_sanitize_context_t *c) const
736   {
737     TRACE_SANITIZE (this);
738     return_trace (c->check_struct (this) && src.sanitize (c, this));
739   }
740 
741   HBUINT8		format; /* format = 22 (noVar) or 23(Var) */
742   Offset24To<Paint>	src; /* Offset (from beginning of PaintScaleUniformAroundCenter table) to Paint subtable. */
743   F2DOT14	scale;
744   FWORD		centerX;
745   FWORD		centerY;
746   public:
747   DEFINE_SIZE_STATIC (4 + F2DOT14::static_size + 2 * FWORD::static_size);
748 };
749 
750 struct PaintRotate
751 {
752   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
753 
subsetOT::PaintRotate754   bool subset (hb_subset_context_t *c) const
755   {
756     TRACE_SUBSET (this);
757     auto *out = c->serializer->embed (this);
758     if (unlikely (!out)) return_trace (false);
759 
760     return_trace (out->src.serialize_subset (c, src, this));
761   }
762 
sanitizeOT::PaintRotate763   bool sanitize (hb_sanitize_context_t *c) const
764   {
765     TRACE_SANITIZE (this);
766     return_trace (c->check_struct (this) && src.sanitize (c, this));
767   }
768 
769   HBUINT8		format; /* format = 24 (noVar) or 25(Var) */
770   Offset24To<Paint>	src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */
771   F2DOT14		angle;
772   public:
773   DEFINE_SIZE_STATIC (4 + F2DOT14::static_size);
774 };
775 
776 struct PaintRotateAroundCenter
777 {
778   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
779 
subsetOT::PaintRotateAroundCenter780   bool subset (hb_subset_context_t *c) const
781   {
782     TRACE_SUBSET (this);
783     auto *out = c->serializer->embed (this);
784     if (unlikely (!out)) return_trace (false);
785 
786     return_trace (out->src.serialize_subset (c, src, this));
787   }
788 
sanitizeOT::PaintRotateAroundCenter789   bool sanitize (hb_sanitize_context_t *c) const
790   {
791     TRACE_SANITIZE (this);
792     return_trace (c->check_struct (this) && src.sanitize (c, this));
793   }
794 
795   HBUINT8		format; /* format = 26 (noVar) or 27(Var) */
796   Offset24To<Paint>	src; /* Offset (from beginning of PaintRotateAroundCenter table) to Paint subtable. */
797   F2DOT14	angle;
798   FWORD		centerX;
799   FWORD		centerY;
800   public:
801   DEFINE_SIZE_STATIC (4 + F2DOT14::static_size + 2 * FWORD::static_size);
802 };
803 
804 struct PaintSkew
805 {
806   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
807 
subsetOT::PaintSkew808   bool subset (hb_subset_context_t *c) const
809   {
810     TRACE_SUBSET (this);
811     auto *out = c->serializer->embed (this);
812     if (unlikely (!out)) return_trace (false);
813 
814     return_trace (out->src.serialize_subset (c, src, this));
815   }
816 
sanitizeOT::PaintSkew817   bool sanitize (hb_sanitize_context_t *c) const
818   {
819     TRACE_SANITIZE (this);
820     return_trace (c->check_struct (this) && src.sanitize (c, this));
821   }
822 
823   HBUINT8		format; /* format = 28(noVar) or 29 (Var) */
824   Offset24To<Paint>	src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */
825   F2DOT14		xSkewAngle;
826   F2DOT14		ySkewAngle;
827   public:
828   DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size);
829 };
830 
831 struct PaintSkewAroundCenter
832 {
833   HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
834 
subsetOT::PaintSkewAroundCenter835   bool subset (hb_subset_context_t *c) const
836   {
837     TRACE_SUBSET (this);
838     auto *out = c->serializer->embed (this);
839     if (unlikely (!out)) return_trace (false);
840 
841     return_trace (out->src.serialize_subset (c, src, this));
842   }
843 
sanitizeOT::PaintSkewAroundCenter844   bool sanitize (hb_sanitize_context_t *c) const
845   {
846     TRACE_SANITIZE (this);
847     return_trace (c->check_struct (this) && src.sanitize (c, this));
848   }
849 
850   HBUINT8		format; /* format = 30(noVar) or 31 (Var) */
851   Offset24To<Paint>	src; /* Offset (from beginning of PaintSkewAroundCenter table) to Paint subtable. */
852   F2DOT14	xSkewAngle;
853   F2DOT14	ySkewAngle;
854   FWORD		centerX;
855   FWORD		centerY;
856   public:
857   DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size + 2 * FWORD::static_size);
858 };
859 
860 struct PaintComposite
861 {
862   void closurev1 (hb_colrv1_closure_context_t* c) const;
863 
subsetOT::PaintComposite864   bool subset (hb_subset_context_t *c) const
865   {
866     TRACE_SUBSET (this);
867     auto *out = c->serializer->embed (this);
868     if (unlikely (!out)) return_trace (false);
869 
870     if (!out->src.serialize_subset (c, src, this)) return_trace (false);
871     return_trace (out->backdrop.serialize_subset (c, backdrop, this));
872   }
873 
sanitizeOT::PaintComposite874   bool sanitize (hb_sanitize_context_t *c) const
875   {
876     TRACE_SANITIZE (this);
877     return_trace (c->check_struct (this) &&
878                   src.sanitize (c, this) &&
879                   backdrop.sanitize (c, this));
880   }
881 
882   HBUINT8		format; /* format = 32 */
883   Offset24To<Paint>	src; /* Offset (from beginning of PaintComposite table) to source Paint subtable. */
884   CompositeMode		mode;   /* If mode is unrecognized use COMPOSITE_CLEAR */
885   Offset24To<Paint>	backdrop; /* Offset (from beginning of PaintComposite table) to backdrop Paint subtable. */
886   public:
887   DEFINE_SIZE_STATIC (8);
888 };
889 
890 struct ClipBoxFormat1
891 {
sanitizeOT::ClipBoxFormat1892   bool sanitize (hb_sanitize_context_t *c) const
893   {
894     TRACE_SANITIZE (this);
895     return_trace (c->check_struct (this));
896   }
897 
898   public:
899   HBUINT8	format; /* format = 1(noVar) or 2(Var)*/
900   FWORD		xMin;
901   FWORD		yMin;
902   FWORD		xMax;
903   FWORD		yMax;
904   public:
905   DEFINE_SIZE_STATIC (1 + 4 * FWORD::static_size);
906 };
907 
908 struct ClipBoxFormat2 : Variable<ClipBoxFormat1> {};
909 
910 struct ClipBox
911 {
copyOT::ClipBox912   ClipBox* copy (hb_serialize_context_t *c) const
913   {
914     TRACE_SERIALIZE (this);
915     switch (u.format) {
916     case 1: return_trace (reinterpret_cast<ClipBox *> (c->embed (u.format1)));
917     case 2: return_trace (reinterpret_cast<ClipBox *> (c->embed (u.format2)));
918     default:return_trace (nullptr);
919     }
920   }
921 
922   template <typename context_t, typename ...Ts>
dispatchOT::ClipBox923   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
924   {
925     TRACE_DISPATCH (this, u.format);
926     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
927     switch (u.format) {
928     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
929     case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
930     default:return_trace (c->default_return_value ());
931     }
932   }
933 
934   protected:
935   union {
936   HBUINT8		format;         /* Format identifier */
937   ClipBoxFormat1	format1;
938   ClipBoxFormat2	format2;
939   } u;
940 };
941 
942 struct ClipRecord
943 {
copyOT::ClipRecord944   ClipRecord* copy (hb_serialize_context_t *c, const void *base) const
945   {
946     TRACE_SERIALIZE (this);
947     auto *out = c->embed (this);
948     if (unlikely (!out)) return_trace (nullptr);
949     if (!out->clipBox.serialize_copy (c, clipBox, base)) return_trace (nullptr);
950     return_trace (out);
951   }
952 
sanitizeOT::ClipRecord953   bool sanitize (hb_sanitize_context_t *c, const void *base) const
954   {
955     TRACE_SANITIZE (this);
956     return_trace (c->check_struct (this) && clipBox.sanitize (c, base));
957   }
958 
959   public:
960   HBUINT16		startGlyphID;  // first gid clip applies to
961   HBUINT16		endGlyphID;    // last gid clip applies to, inclusive
962   Offset24To<ClipBox>	clipBox;   // Box or VarBox
963   public:
964   DEFINE_SIZE_STATIC (7);
965 };
966 
967 struct ClipList
968 {
serialize_clip_recordsOT::ClipList969   unsigned serialize_clip_records (hb_serialize_context_t *c,
970                                    const hb_set_t& gids,
971                                    const hb_map_t& gid_offset_map) const
972   {
973     TRACE_SERIALIZE (this);
974     if (gids.is_empty () ||
975         gid_offset_map.get_population () != gids.get_population ())
976       return_trace (0);
977 
978     unsigned count  = 0;
979 
980     hb_codepoint_t start_gid= gids.get_min ();
981     hb_codepoint_t prev_gid = start_gid;
982 
983     unsigned offset = gid_offset_map.get (start_gid);
984     unsigned prev_offset = offset;
985     for (const hb_codepoint_t _ : gids.iter ())
986     {
987       if (_ == start_gid) continue;
988 
989       offset = gid_offset_map.get (_);
990       if (_ == prev_gid + 1 &&  offset == prev_offset)
991       {
992         prev_gid = _;
993         continue;
994       }
995 
996       ClipRecord record;
997       record.startGlyphID = start_gid;
998       record.endGlyphID = prev_gid;
999       record.clipBox = prev_offset;
1000 
1001       if (!c->copy (record, this)) return_trace (0);
1002       count++;
1003 
1004       start_gid = _;
1005       prev_gid = _;
1006       prev_offset = offset;
1007     }
1008 
1009     //last one
1010     {
1011       ClipRecord record;
1012       record.startGlyphID = start_gid;
1013       record.endGlyphID = prev_gid;
1014       record.clipBox = prev_offset;
1015       if (!c->copy (record, this)) return_trace (0);
1016       count++;
1017     }
1018     return_trace (count);
1019   }
1020 
subsetOT::ClipList1021   bool subset (hb_subset_context_t *c) const
1022   {
1023     TRACE_SUBSET (this);
1024     auto *out = c->serializer->start_embed (*this);
1025     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
1026     if (!c->serializer->check_assign (out->format, format, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
1027 
1028     const hb_set_t& glyphset = *c->plan->_glyphset_colred;
1029     const hb_map_t &glyph_map = *c->plan->glyph_map;
1030 
1031     hb_map_t new_gid_offset_map;
1032     hb_set_t new_gids;
1033     for (const ClipRecord& record : clips.iter ())
1034     {
1035       unsigned start_gid = record.startGlyphID;
1036       unsigned end_gid = record.endGlyphID;
1037       for (unsigned gid = start_gid; gid <= end_gid; gid++)
1038       {
1039         if (!glyphset.has (gid) || !glyph_map.has (gid)) continue;
1040         unsigned new_gid = glyph_map.get (gid);
1041         new_gid_offset_map.set (new_gid, record.clipBox);
1042         new_gids.add (new_gid);
1043       }
1044     }
1045 
1046     unsigned count = serialize_clip_records (c->serializer, new_gids, new_gid_offset_map);
1047     if (!count) return_trace (false);
1048     return_trace (c->serializer->check_assign (out->clips.len, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
1049   }
1050 
sanitizeOT::ClipList1051   bool sanitize (hb_sanitize_context_t *c) const
1052   {
1053     TRACE_SANITIZE (this);
1054     return_trace (c->check_struct (this) && clips.sanitize (c, this));
1055   }
1056 
1057   HBUINT8			format;  // Set to 1.
1058   Array32Of<ClipRecord>		clips;  // Clip records, sorted by startGlyphID
1059   public:
1060   DEFINE_SIZE_ARRAY_SIZED (5, clips);
1061 };
1062 
1063 struct Paint
1064 {
1065 
1066   template <typename ...Ts>
sanitizeOT::Paint1067   bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
1068   {
1069     TRACE_SANITIZE (this);
1070 
1071     if (unlikely (!c->check_start_recursion (HB_COLRV1_MAX_NESTING_LEVEL)))
1072       return_trace (c->no_dispatch_return_value ());
1073 
1074     return_trace (c->end_recursion (this->dispatch (c, std::forward<Ts> (ds)...)));
1075   }
1076 
1077   template <typename context_t, typename ...Ts>
dispatchOT::Paint1078   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1079   {
1080     TRACE_DISPATCH (this, u.format);
1081     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1082     switch (u.format) {
1083     case 1: return_trace (c->dispatch (u.paintformat1, std::forward<Ts> (ds)...));
1084     case 2: return_trace (c->dispatch (u.paintformat2, std::forward<Ts> (ds)...));
1085     case 3: return_trace (c->dispatch (u.paintformat3, std::forward<Ts> (ds)...));
1086     case 4: return_trace (c->dispatch (u.paintformat4, std::forward<Ts> (ds)...));
1087     case 5: return_trace (c->dispatch (u.paintformat5, std::forward<Ts> (ds)...));
1088     case 6: return_trace (c->dispatch (u.paintformat6, std::forward<Ts> (ds)...));
1089     case 7: return_trace (c->dispatch (u.paintformat7, std::forward<Ts> (ds)...));
1090     case 8: return_trace (c->dispatch (u.paintformat8, std::forward<Ts> (ds)...));
1091     case 9: return_trace (c->dispatch (u.paintformat9, std::forward<Ts> (ds)...));
1092     case 10: return_trace (c->dispatch (u.paintformat10, std::forward<Ts> (ds)...));
1093     case 11: return_trace (c->dispatch (u.paintformat11, std::forward<Ts> (ds)...));
1094     case 12: return_trace (c->dispatch (u.paintformat12, std::forward<Ts> (ds)...));
1095     case 13: return_trace (c->dispatch (u.paintformat13, std::forward<Ts> (ds)...));
1096     case 14: return_trace (c->dispatch (u.paintformat14, std::forward<Ts> (ds)...));
1097     case 15: return_trace (c->dispatch (u.paintformat15, std::forward<Ts> (ds)...));
1098     case 16: return_trace (c->dispatch (u.paintformat16, std::forward<Ts> (ds)...));
1099     case 17: return_trace (c->dispatch (u.paintformat17, std::forward<Ts> (ds)...));
1100     case 18: return_trace (c->dispatch (u.paintformat18, std::forward<Ts> (ds)...));
1101     case 19: return_trace (c->dispatch (u.paintformat19, std::forward<Ts> (ds)...));
1102     case 20: return_trace (c->dispatch (u.paintformat20, std::forward<Ts> (ds)...));
1103     case 21: return_trace (c->dispatch (u.paintformat21, std::forward<Ts> (ds)...));
1104     case 22: return_trace (c->dispatch (u.paintformat22, std::forward<Ts> (ds)...));
1105     case 23: return_trace (c->dispatch (u.paintformat23, std::forward<Ts> (ds)...));
1106     case 24: return_trace (c->dispatch (u.paintformat24, std::forward<Ts> (ds)...));
1107     case 25: return_trace (c->dispatch (u.paintformat25, std::forward<Ts> (ds)...));
1108     case 26: return_trace (c->dispatch (u.paintformat26, std::forward<Ts> (ds)...));
1109     case 27: return_trace (c->dispatch (u.paintformat27, std::forward<Ts> (ds)...));
1110     case 28: return_trace (c->dispatch (u.paintformat28, std::forward<Ts> (ds)...));
1111     case 29: return_trace (c->dispatch (u.paintformat29, std::forward<Ts> (ds)...));
1112     case 30: return_trace (c->dispatch (u.paintformat30, std::forward<Ts> (ds)...));
1113     case 31: return_trace (c->dispatch (u.paintformat31, std::forward<Ts> (ds)...));
1114     case 32: return_trace (c->dispatch (u.paintformat32, std::forward<Ts> (ds)...));
1115     default:return_trace (c->default_return_value ());
1116     }
1117   }
1118 
1119   protected:
1120   union {
1121   HBUINT8					format;
1122   PaintColrLayers				paintformat1;
1123   PaintSolid					paintformat2;
1124   Variable<PaintSolid>				paintformat3;
1125   PaintLinearGradient<NoVariable>		paintformat4;
1126   Variable<PaintLinearGradient<Variable>>	paintformat5;
1127   PaintRadialGradient<NoVariable>		paintformat6;
1128   Variable<PaintRadialGradient<Variable>>	paintformat7;
1129   PaintSweepGradient<NoVariable>		paintformat8;
1130   Variable<PaintSweepGradient<Variable>>	paintformat9;
1131   PaintGlyph					paintformat10;
1132   PaintColrGlyph				paintformat11;
1133   PaintTransform<NoVariable>			paintformat12;
1134   PaintTransform<Variable>			paintformat13;
1135   PaintTranslate				paintformat14;
1136   Variable<PaintTranslate>			paintformat15;
1137   PaintScale					paintformat16;
1138   Variable<PaintScale>				paintformat17;
1139   PaintScaleAroundCenter			paintformat18;
1140   Variable<PaintScaleAroundCenter>		paintformat19;
1141   PaintScaleUniform				paintformat20;
1142   Variable<PaintScaleUniform>			paintformat21;
1143   PaintScaleUniformAroundCenter			paintformat22;
1144   Variable<PaintScaleUniformAroundCenter>	paintformat23;
1145   PaintRotate					paintformat24;
1146   Variable<PaintRotate>				paintformat25;
1147   PaintRotateAroundCenter			paintformat26;
1148   Variable<PaintRotateAroundCenter>		paintformat27;
1149   PaintSkew					paintformat28;
1150   Variable<PaintSkew>				paintformat29;
1151   PaintSkewAroundCenter				paintformat30;
1152   Variable<PaintSkewAroundCenter>		paintformat31;
1153   PaintComposite				paintformat32;
1154   } u;
1155 };
1156 
1157 struct BaseGlyphPaintRecord
1158 {
cmpOT::BaseGlyphPaintRecord1159   int cmp (hb_codepoint_t g) const
1160   { return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
1161 
serializeOT::BaseGlyphPaintRecord1162   bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map,
1163                   const void* src_base, hb_subset_context_t *c) const
1164   {
1165     TRACE_SERIALIZE (this);
1166     auto *out = s->embed (this);
1167     if (unlikely (!out)) return_trace (false);
1168     if (!s->check_assign (out->glyphId, glyph_map->get (glyphId),
1169                           HB_SERIALIZE_ERROR_INT_OVERFLOW))
1170       return_trace (false);
1171 
1172     return_trace (out->paint.serialize_subset (c, paint, src_base));
1173   }
1174 
sanitizeOT::BaseGlyphPaintRecord1175   bool sanitize (hb_sanitize_context_t *c, const void *base) const
1176   {
1177     TRACE_SANITIZE (this);
1178     return_trace (likely (c->check_struct (this) && paint.sanitize (c, base)));
1179   }
1180 
1181   public:
1182   HBGlyphID16		glyphId;    /* Glyph ID of reference glyph */
1183   Offset32To<Paint>	paint;      /* Offset (from beginning of BaseGlyphPaintRecord array) to Paint,
1184                                      * Typically PaintColrLayers */
1185   public:
1186   DEFINE_SIZE_STATIC (6);
1187 };
1188 
1189 struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
1190 {
subsetOT::BaseGlyphList1191   bool subset (hb_subset_context_t *c) const
1192   {
1193     TRACE_SUBSET (this);
1194     auto *out = c->serializer->start_embed (this);
1195     if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
1196     const hb_set_t* glyphset = c->plan->_glyphset_colred;
1197 
1198     for (const auto& _ : as_array ())
1199     {
1200       unsigned gid = _.glyphId;
1201       if (!glyphset->has (gid)) continue;
1202 
1203       if (_.serialize (c->serializer, c->plan->glyph_map, this, c)) out->len++;
1204       else return_trace (false);
1205     }
1206 
1207     return_trace (out->len != 0);
1208   }
1209 
sanitizeOT::BaseGlyphList1210   bool sanitize (hb_sanitize_context_t *c) const
1211   {
1212     TRACE_SANITIZE (this);
1213     return_trace (SortedArray32Of<BaseGlyphPaintRecord>::sanitize (c, this));
1214   }
1215 };
1216 
1217 struct LayerList : Array32OfOffset32To<Paint>
1218 {
get_paintOT::LayerList1219   const Paint& get_paint (unsigned i) const
1220   { return this+(*this)[i]; }
1221 
subsetOT::LayerList1222   bool subset (hb_subset_context_t *c) const
1223   {
1224     TRACE_SUBSET (this);
1225     auto *out = c->serializer->start_embed (this);
1226     if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
1227 
1228     for (const auto& _ : + hb_enumerate (*this)
1229                          | hb_filter (c->plan->colrv1_layers, hb_first))
1230 
1231     {
1232       auto *o = out->serialize_append (c->serializer);
1233       if (unlikely (!o) || !o->serialize_subset (c, _.second, this))
1234         return_trace (false);
1235     }
1236     return_trace (true);
1237   }
1238 
sanitizeOT::LayerList1239   bool sanitize (hb_sanitize_context_t *c) const
1240   {
1241     TRACE_SANITIZE (this);
1242     return_trace (Array32OfOffset32To<Paint>::sanitize (c, this));
1243   }
1244 };
1245 
1246 struct COLR
1247 {
1248   static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
1249 
has_dataOT::COLR1250   bool has_data () const { return numBaseGlyphs; }
1251 
get_glyph_layersOT::COLR1252   unsigned int get_glyph_layers (hb_codepoint_t       glyph,
1253 				 unsigned int         start_offset,
1254 				 unsigned int        *count, /* IN/OUT.  May be NULL. */
1255 				 hb_ot_color_layer_t *layers /* OUT.     May be NULL. */) const
1256   {
1257     const BaseGlyphRecord &record = (this+baseGlyphsZ).bsearch (numBaseGlyphs, glyph);
1258 
1259     hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
1260     hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
1261 								       record.numLayers);
1262     if (count)
1263     {
1264       + glyph_layers.sub_array (start_offset, count)
1265       | hb_sink (hb_array (layers, *count))
1266       ;
1267     }
1268     return glyph_layers.length;
1269   }
1270 
1271   struct accelerator_t
1272   {
accelerator_tOT::COLR::accelerator_t1273     accelerator_t (hb_face_t *face)
1274     { colr = hb_sanitize_context_t ().reference_table<COLR> (face); }
~accelerator_tOT::COLR::accelerator_t1275     ~accelerator_t () { this->colr.destroy (); }
1276 
is_validOT::COLR::accelerator_t1277     bool is_valid () { return colr.get_blob ()->length; }
1278 
closure_glyphsOT::COLR::accelerator_t1279     void closure_glyphs (hb_codepoint_t glyph,
1280 			 hb_set_t *related_ids /* OUT */) const
1281     { colr->closure_glyphs (glyph, related_ids); }
1282 
closure_V0palette_indicesOT::COLR::accelerator_t1283     void closure_V0palette_indices (const hb_set_t *glyphs,
1284 				    hb_set_t *palettes /* OUT */) const
1285     { colr->closure_V0palette_indices (glyphs, palettes); }
1286 
closure_forV1OT::COLR::accelerator_t1287     void closure_forV1 (hb_set_t *glyphset,
1288                         hb_set_t *layer_indices,
1289                         hb_set_t *palette_indices) const
1290     { colr->closure_forV1 (glyphset, layer_indices, palette_indices); }
1291 
1292     private:
1293     hb_blob_ptr_t<COLR> colr;
1294   };
1295 
closure_glyphsOT::COLR1296   void closure_glyphs (hb_codepoint_t glyph,
1297 		       hb_set_t *related_ids /* OUT */) const
1298   {
1299     const BaseGlyphRecord *record = get_base_glyph_record (glyph);
1300     if (!record) return;
1301 
1302     auto glyph_layers = (this+layersZ).as_array (numLayers).sub_array (record->firstLayerIdx,
1303 								       record->numLayers);
1304     if (!glyph_layers.length) return;
1305     related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size);
1306   }
1307 
closure_V0palette_indicesOT::COLR1308   void closure_V0palette_indices (const hb_set_t *glyphs,
1309 				  hb_set_t *palettes /* OUT */) const
1310   {
1311     if (!numBaseGlyphs || !numLayers) return;
1312     hb_array_t<const BaseGlyphRecord> baseGlyphs = (this+baseGlyphsZ).as_array (numBaseGlyphs);
1313     hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
1314 
1315     for (const BaseGlyphRecord record : baseGlyphs)
1316     {
1317       if (!glyphs->has (record.glyphId)) continue;
1318       hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
1319                                                                    record.numLayers);
1320       for (const LayerRecord layer : glyph_layers)
1321         palettes->add (layer.colorIdx);
1322     }
1323   }
1324 
closure_forV1OT::COLR1325   void closure_forV1 (hb_set_t *glyphset,
1326                       hb_set_t *layer_indices,
1327                       hb_set_t *palette_indices) const
1328   {
1329     if (version != 1) return;
1330     hb_set_t visited_glyphs;
1331 
1332     hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices);
1333     const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList;
1334 
1335     for (const BaseGlyphPaintRecord &baseglyph_paintrecord: baseglyph_paintrecords.iter ())
1336     {
1337       unsigned gid = baseglyph_paintrecord.glyphId;
1338       if (!glyphset->has (gid)) continue;
1339 
1340       const Paint &paint = &baseglyph_paintrecords+baseglyph_paintrecord.paint;
1341       paint.dispatch (&c);
1342     }
1343     hb_set_union (glyphset, &visited_glyphs);
1344   }
1345 
get_layerListOT::COLR1346   const LayerList& get_layerList () const
1347   { return (this+layerList); }
1348 
get_baseglyphListOT::COLR1349   const BaseGlyphList& get_baseglyphList () const
1350   { return (this+baseGlyphList); }
1351 
sanitizeOT::COLR1352   bool sanitize (hb_sanitize_context_t *c) const
1353   {
1354     TRACE_SANITIZE (this);
1355     return_trace (c->check_struct (this) &&
1356                   (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
1357                   (this+layersZ).sanitize (c, numLayers) &&
1358                   (version == 0 ||
1359 		   (COLRV1_ENABLE_SUBSETTING && version == 1 &&
1360 		    baseGlyphList.sanitize (c, this) &&
1361 		    layerList.sanitize (c, this) &&
1362 		    clipList.sanitize (c, this) &&
1363 		    varIdxMap.sanitize (c, this) &&
1364 		    varStore.sanitize (c, this))));
1365   }
1366 
1367   template<typename BaseIterator, typename LayerIterator,
1368 	   hb_requires (hb_is_iterator (BaseIterator)),
1369 	   hb_requires (hb_is_iterator (LayerIterator))>
serialize_V0OT::COLR1370   bool serialize_V0 (hb_serialize_context_t *c,
1371 		     unsigned version,
1372 		     BaseIterator base_it,
1373 		     LayerIterator layer_it)
1374   {
1375     TRACE_SERIALIZE (this);
1376     if (unlikely (base_it.len () != layer_it.len ()))
1377       return_trace (false);
1378 
1379     this->version = version;
1380     numLayers = 0;
1381     numBaseGlyphs = base_it.len ();
1382     if (numBaseGlyphs == 0)
1383     {
1384       baseGlyphsZ = 0;
1385       layersZ = 0;
1386       return_trace (true);
1387     }
1388 
1389     c->push ();
1390     for (const hb_item_type<BaseIterator> _ : + base_it.iter ())
1391     {
1392       auto* record = c->embed (_);
1393       if (unlikely (!record)) return_trace (false);
1394       record->firstLayerIdx = numLayers;
1395       numLayers += record->numLayers;
1396     }
1397     c->add_link (baseGlyphsZ, c->pop_pack ());
1398 
1399     c->push ();
1400     for (const hb_item_type<LayerIterator>& _ : + layer_it.iter ())
1401       _.as_array ().copy (c);
1402 
1403     c->add_link (layersZ, c->pop_pack ());
1404 
1405     return_trace (true);
1406   }
1407 
get_base_glyph_recordOT::COLR1408   const BaseGlyphRecord* get_base_glyph_record (hb_codepoint_t gid) const
1409   {
1410     const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, (unsigned int) gid);
1411     if (record == &Null (BaseGlyphRecord) ||
1412         (record && (hb_codepoint_t) record->glyphId != gid))
1413       record = nullptr;
1414     return record;
1415   }
1416 
get_base_glyph_paintrecordOT::COLR1417   const BaseGlyphPaintRecord* get_base_glyph_paintrecord (hb_codepoint_t gid) const
1418   {
1419     const BaseGlyphPaintRecord* record = &(this+baseGlyphList).bsearch ((unsigned) gid);
1420     if ((record && (hb_codepoint_t) record->glyphId != gid))
1421       record = nullptr;
1422     return record;
1423   }
1424 
subsetOT::COLR1425   bool subset (hb_subset_context_t *c) const
1426   {
1427     TRACE_SUBSET (this);
1428 
1429     const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
1430     const hb_set_t& glyphset = *c->plan->_glyphset_colred;
1431 
1432     auto base_it =
1433     + hb_range (c->plan->num_output_glyphs ())
1434     | hb_filter ([&](hb_codepoint_t new_gid)
1435 		 {
1436 		    hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
1437 		    if (glyphset.has (old_gid)) return true;
1438 		    return false;
1439 		 })
1440     | hb_map_retains_sorting ([&](hb_codepoint_t new_gid)
1441 			      {
1442 				hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
1443 
1444 				const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
1445 				if (unlikely (!old_record))
1446 				  return hb_pair_t<bool, BaseGlyphRecord> (false, Null (BaseGlyphRecord));
1447 				BaseGlyphRecord new_record = {};
1448 				new_record.glyphId = new_gid;
1449 				new_record.numLayers = old_record->numLayers;
1450 				return hb_pair_t<bool, BaseGlyphRecord> (true, new_record);
1451 			      })
1452     | hb_filter (hb_first)
1453     | hb_map_retains_sorting (hb_second)
1454     ;
1455 
1456     auto layer_it =
1457     + hb_range (c->plan->num_output_glyphs ())
1458     | hb_map (reverse_glyph_map)
1459     | hb_filter (glyphset)
1460     | hb_map_retains_sorting ([&](hb_codepoint_t old_gid)
1461 			      {
1462 				const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
1463 				hb_vector_t<LayerRecord> out_layers;
1464 
1465 				if (unlikely (!old_record ||
1466 					      old_record->firstLayerIdx >= numLayers ||
1467 					      old_record->firstLayerIdx + old_record->numLayers > numLayers))
1468 				  return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
1469 
1470 				auto layers = (this+layersZ).as_array (numLayers).sub_array (old_record->firstLayerIdx,
1471 											     old_record->numLayers);
1472 				out_layers.resize (layers.length);
1473 				for (unsigned int i = 0; i < layers.length; i++) {
1474 				  out_layers[i] = layers[i];
1475 				  hb_codepoint_t new_gid = 0;
1476 				  if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid)))
1477 				    return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
1478 				  out_layers[i].glyphId = new_gid;
1479 				  out_layers[i].colorIdx = c->plan->colr_palettes->get (layers[i].colorIdx);
1480 				}
1481 
1482 				return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers);
1483 			      })
1484     | hb_filter (hb_first)
1485     | hb_map_retains_sorting (hb_second)
1486     ;
1487 
1488     if (version == 0 && (!base_it || !layer_it))
1489       return_trace (false);
1490 
1491     COLR *colr_prime = c->serializer->start_embed<COLR> ();
1492     if (unlikely (!c->serializer->extend_min (colr_prime)))  return_trace (false);
1493 
1494     if (version == 0)
1495     return_trace (colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it));
1496 
1497     auto snap = c->serializer->snapshot ();
1498     if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false);
1499     if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this))
1500     {
1501       if (c->serializer->in_error ()) return_trace (false);
1502       //no more COLRv1 glyphs: downgrade to version 0
1503       c->serializer->revert (snap);
1504       return_trace (colr_prime->serialize_V0 (c->serializer, 0, base_it, layer_it));
1505     }
1506 
1507     if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false);
1508 
1509     colr_prime->layerList.serialize_subset (c, layerList, this);
1510     colr_prime->clipList.serialize_subset (c, clipList, this);
1511     colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this);
1512     //TODO: subset varStore once it's implemented in fonttools
1513     return_trace (true);
1514   }
1515 
1516   protected:
1517   HBUINT16	version;	/* Table version number (starts at 0). */
1518   HBUINT16	numBaseGlyphs;	/* Number of Base Glyph Records. */
1519   NNOffset32To<SortedUnsizedArrayOf<BaseGlyphRecord>>
1520 		baseGlyphsZ;	/* Offset to Base Glyph records. */
1521   NNOffset32To<UnsizedArrayOf<LayerRecord>>
1522 		layersZ;	/* Offset to Layer Records. */
1523   HBUINT16	numLayers;	/* Number of Layer Records. */
1524   // Version-1 additions
1525   Offset32To<BaseGlyphList>		baseGlyphList;
1526   Offset32To<LayerList>			layerList;
1527   Offset32To<ClipList>			clipList;   // Offset to ClipList table (may be NULL)
1528   Offset32To<DeltaSetIndexMap>		varIdxMap;  // Offset to DeltaSetIndexMap table (may be NULL)
1529   Offset32To<VariationStore>		varStore;
1530   public:
1531   DEFINE_SIZE_MIN (14);
1532 };
1533 
1534 struct COLR_accelerator_t : COLR::accelerator_t {
COLR_accelerator_tOT::COLR_accelerator_t1535   COLR_accelerator_t (hb_face_t *face) : COLR::accelerator_t (face) {}
1536 };
1537 
1538 } /* namespace OT */
1539 
1540 
1541 #endif /* HB_OT_COLOR_COLR_TABLE_HH */
1542