• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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	16
43 #endif
44 
45 namespace OT {
46 
47 struct COLR;
48 struct hb_colrv1_closure_context_t :
49        hb_dispatch_context_t<hb_colrv1_closure_context_t>
50 {
51   template <typename T>
dispatchOT::hb_colrv1_closure_context_t52   return_t dispatch (const T &obj)
53   {
54     if (unlikely (nesting_level_left == 0))
55       return hb_empty_t ();
56 
57     if (paint_visited (&obj))
58       return hb_empty_t ();
59 
60     nesting_level_left--;
61     obj.closurev1 (this);
62     nesting_level_left++;
63     return hb_empty_t ();
64   }
default_return_valueOT::hb_colrv1_closure_context_t65   static return_t default_return_value () { return hb_empty_t (); }
66 
paint_visitedOT::hb_colrv1_closure_context_t67   bool paint_visited (const void *paint)
68   {
69     hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) paint - (uintptr_t) base);
70     if (visited_paint.in_error() || visited_paint.has (delta))
71       return true;
72 
73     visited_paint.add (delta);
74     return false;
75   }
76 
get_colr_tableOT::hb_colrv1_closure_context_t77   const COLR* get_colr_table () const
78   { return reinterpret_cast<const COLR *> (base); }
79 
add_glyphOT::hb_colrv1_closure_context_t80   void add_glyph (unsigned glyph_id)
81   { glyphs->add (glyph_id); }
82 
add_layer_indicesOT::hb_colrv1_closure_context_t83   void add_layer_indices (unsigned first_layer_index, unsigned num_of_layers)
84   { layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1); }
85 
add_palette_indexOT::hb_colrv1_closure_context_t86   void add_palette_index (unsigned palette_index)
87   { palette_indices->add (palette_index); }
88 
89   public:
90   const void *base;
91   hb_set_t visited_paint;
92   hb_set_t *glyphs;
93   hb_set_t *layer_indices;
94   hb_set_t *palette_indices;
95   unsigned nesting_level_left;
96 
hb_colrv1_closure_context_tOT::hb_colrv1_closure_context_t97   hb_colrv1_closure_context_t (const void *base_,
98                                hb_set_t *glyphs_,
99                                hb_set_t *layer_indices_,
100                                hb_set_t *palette_indices_,
101                                unsigned nesting_level_left_ = HB_COLRV1_MAX_NESTING_LEVEL) :
102                           base (base_),
103                           glyphs (glyphs_),
104                           layer_indices (layer_indices_),
105                           palette_indices (palette_indices_),
106                           nesting_level_left (nesting_level_left_)
107   {}
108 };
109 
110 struct LayerRecord
111 {
operator hb_ot_color_layer_tOT::LayerRecord112   operator hb_ot_color_layer_t () const { return {glyphId, colorIdx}; }
113 
sanitizeOT::LayerRecord114   bool sanitize (hb_sanitize_context_t *c) const
115   {
116     TRACE_SANITIZE (this);
117     return_trace (c->check_struct (this));
118   }
119 
120   public:
121   HBGlyphID16	glyphId;	/* Glyph ID of layer glyph */
122   Index		colorIdx;	/* Index value to use with a
123 				 * selected color palette.
124 				 * An index value of 0xFFFF
125 				 * is a special case indicating
126 				 * that the text foreground
127 				 * color (defined by a
128 				 * higher-level client) should
129 				 * be used and shall not be
130 				 * treated as actual index
131 				 * into CPAL ColorRecord array. */
132   public:
133   DEFINE_SIZE_STATIC (4);
134 };
135 
136 struct BaseGlyphRecord
137 {
cmpOT::BaseGlyphRecord138   int cmp (hb_codepoint_t g) const
139   { return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
140 
sanitizeOT::BaseGlyphRecord141   bool sanitize (hb_sanitize_context_t *c) const
142   {
143     TRACE_SANITIZE (this);
144     return_trace (c->check_struct (this));
145   }
146 
147   public:
148   HBGlyphID16	glyphId;	/* Glyph ID of reference glyph */
149   HBUINT16	firstLayerIdx;	/* Index (from beginning of
150 				 * the Layer Records) to the
151 				 * layer record. There will be
152 				 * numLayers consecutive entries
153 				 * for this base glyph. */
154   HBUINT16	numLayers;	/* Number of color layers
155 				 * associated with this glyph */
156   public:
157   DEFINE_SIZE_STATIC (6);
158 };
159 
160 template <typename T>
161 struct Variable
162 {
copyOT::Variable163   Variable<T>* copy (hb_serialize_context_t *c) const
164   {
165     TRACE_SERIALIZE (this);
166     return_trace (c->embed (this));
167   }
168 
closurev1OT::Variable169   void closurev1 (hb_colrv1_closure_context_t* c) const
170   { value.closurev1 (c); }
171 
subsetOT::Variable172   bool subset (hb_subset_context_t *c) const
173   {
174     TRACE_SUBSET (this);
175     if (!value.subset (c)) return_trace (false);
176     return_trace (c->serializer->embed (varIdxBase));
177   }
178 
sanitizeOT::Variable179   bool sanitize (hb_sanitize_context_t *c) const
180   {
181     TRACE_SANITIZE (this);
182     return_trace (c->check_struct (this) && value.sanitize (c));
183   }
184 
185   protected:
186   T      value;
187   public:
188   VarIdx varIdxBase;
189   public:
190   DEFINE_SIZE_STATIC (4 + T::static_size);
191 };
192 
193 template <typename T>
194 struct NoVariable
195 {
196   static constexpr uint32_t varIdxBase = VarIdx::NO_VARIATION;
197 
copyOT::NoVariable198   NoVariable<T>* copy (hb_serialize_context_t *c) const
199   {
200     TRACE_SERIALIZE (this);
201     return_trace (c->embed (this));
202   }
203 
closurev1OT::NoVariable204   void closurev1 (hb_colrv1_closure_context_t* c) const
205   { value.closurev1 (c); }
206 
subsetOT::NoVariable207   bool subset (hb_subset_context_t *c) const
208   {
209     TRACE_SUBSET (this);
210     return_trace (value.subset (c));
211   }
212 
sanitizeOT::NoVariable213   bool sanitize (hb_sanitize_context_t *c) const
214   {
215     TRACE_SANITIZE (this);
216     return_trace (c->check_struct (this) && value.sanitize (c));
217   }
218 
219   T      value;
220   public:
221   DEFINE_SIZE_STATIC (T::static_size);
222 };
223 
224 // Color structures
225 
226 struct ColorStop
227 {
closurev1OT::ColorStop228   void closurev1 (hb_colrv1_closure_context_t* c) const
229   { c->add_palette_index (paletteIndex); }
230 
subsetOT::ColorStop231   bool subset (hb_subset_context_t *c) const
232   {
233     TRACE_SUBSET (this);
234     auto *out = c->serializer->embed (*this);
235     if (unlikely (!out)) return_trace (false);
236     return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex),
237                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
238   }
239 
sanitizeOT::ColorStop240   bool sanitize (hb_sanitize_context_t *c) const
241   {
242     TRACE_SANITIZE (this);
243     return_trace (c->check_struct (this));
244   }
245 
246   F2DOT14	stopOffset;
247   HBUINT16	paletteIndex;
248   F2DOT14	alpha;
249   public:
250   DEFINE_SIZE_STATIC (2 + 2 * F2DOT14::static_size);
251 };
252 
253 struct Extend : HBUINT8
254 {
255   enum {
256     EXTEND_PAD     = 0,
257     EXTEND_REPEAT  = 1,
258     EXTEND_REFLECT = 2,
259   };
260   public:
261   DEFINE_SIZE_STATIC (1);
262 };
263 
264 template <template<typename> class Var>
265 struct ColorLine
266 {
closurev1OT::ColorLine267   void closurev1 (hb_colrv1_closure_context_t* c) const
268   {
269     for (const auto &stop : stops.iter ())
270       stop.closurev1 (c);
271   }
272 
subsetOT::ColorLine273   bool subset (hb_subset_context_t *c) const
274   {
275     TRACE_SUBSET (this);
276     auto *out = c->serializer->start_embed (this);
277     if (unlikely (!out)) return_trace (false);
278     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
279 
280     if (!c->serializer->check_assign (out->extend, extend, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
281     if (!c->serializer->check_assign (out->stops.len, stops.len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)) return_trace (false);
282 
283     for (const auto& stop : stops.iter ())
284     {
285       if (!stop.subset (c)) return_trace (false);
286     }
287     return_trace (true);
288   }
289 
sanitizeOT::ColorLine290   bool sanitize (hb_sanitize_context_t *c) const
291   {
292     TRACE_SANITIZE (this);
293     return_trace (c->check_struct (this) &&
294                   stops.sanitize (c));
295   }
296 
297   Extend	extend;
298   Array16Of<Var<ColorStop>>	stops;
299   public:
300   DEFINE_SIZE_ARRAY_SIZED (3, stops);
301 };
302 
303 // Composition modes
304 
305 // Compositing modes are taken from https://www.w3.org/TR/compositing-1/
306 // NOTE: a brief audit of major implementations suggests most support most
307 // or all of the specified modes.
308 struct CompositeMode : HBUINT8
309 {
310   enum {
311     // Porter-Duff modes
312     // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators
313     COMPOSITE_CLEAR          =  0,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_clear
314     COMPOSITE_SRC            =  1,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_src
315     COMPOSITE_DEST           =  2,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dst
316     COMPOSITE_SRC_OVER       =  3,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcover
317     COMPOSITE_DEST_OVER      =  4,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstover
318     COMPOSITE_SRC_IN         =  5,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcin
319     COMPOSITE_DEST_IN        =  6,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstin
320     COMPOSITE_SRC_OUT        =  7,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcout
321     COMPOSITE_DEST_OUT       =  8,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstout
322     COMPOSITE_SRC_ATOP       =  9,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcatop
323     COMPOSITE_DEST_ATOP      = 10,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstatop
324     COMPOSITE_XOR            = 11,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_xor
325     COMPOSITE_PLUS           = 12,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_plus
326 
327     // Blend modes
328     // https://www.w3.org/TR/compositing-1/#blending
329     COMPOSITE_SCREEN         = 13,  // https://www.w3.org/TR/compositing-1/#blendingscreen
330     COMPOSITE_OVERLAY        = 14,  // https://www.w3.org/TR/compositing-1/#blendingoverlay
331     COMPOSITE_DARKEN         = 15,  // https://www.w3.org/TR/compositing-1/#blendingdarken
332     COMPOSITE_LIGHTEN        = 16,  // https://www.w3.org/TR/compositing-1/#blendinglighten
333     COMPOSITE_COLOR_DODGE    = 17,  // https://www.w3.org/TR/compositing-1/#blendingcolordodge
334     COMPOSITE_COLOR_BURN     = 18,  // https://www.w3.org/TR/compositing-1/#blendingcolorburn
335     COMPOSITE_HARD_LIGHT     = 19,  // https://www.w3.org/TR/compositing-1/#blendinghardlight
336     COMPOSITE_SOFT_LIGHT     = 20,  // https://www.w3.org/TR/compositing-1/#blendingsoftlight
337     COMPOSITE_DIFFERENCE     = 21,  // https://www.w3.org/TR/compositing-1/#blendingdifference
338     COMPOSITE_EXCLUSION      = 22,  // https://www.w3.org/TR/compositing-1/#blendingexclusion
339     COMPOSITE_MULTIPLY       = 23,  // https://www.w3.org/TR/compositing-1/#blendingmultiply
340 
341     // Modes that, uniquely, do not operate on components
342     // https://www.w3.org/TR/compositing-1/#blendingnonseparable
343     COMPOSITE_HSL_HUE        = 24,  // https://www.w3.org/TR/compositing-1/#blendinghue
344     COMPOSITE_HSL_SATURATION = 25,  // https://www.w3.org/TR/compositing-1/#blendingsaturation
345     COMPOSITE_HSL_COLOR      = 26,  // https://www.w3.org/TR/compositing-1/#blendingcolor
346     COMPOSITE_HSL_LUMINOSITY = 27,  // https://www.w3.org/TR/compositing-1/#blendingluminosity
347   };
348   public:
349   DEFINE_SIZE_STATIC (1);
350 };
351 
352 struct Affine2x3
353 {
sanitizeOT::Affine2x3354   bool sanitize (hb_sanitize_context_t *c) const
355   {
356     TRACE_SANITIZE (this);
357     return_trace (c->check_struct (this));
358   }
359 
360   F16DOT16 xx;
361   F16DOT16 yx;
362   F16DOT16 xy;
363   F16DOT16 yy;
364   F16DOT16 dx;
365   F16DOT16 dy;
366   public:
367   DEFINE_SIZE_STATIC (6 * F16DOT16::static_size);
368 };
369 
370 struct PaintColrLayers
371 {
372   void closurev1 (hb_colrv1_closure_context_t* c) const;
373 
subsetOT::PaintColrLayers374   bool subset (hb_subset_context_t *c) const
375   {
376     TRACE_SUBSET (this);
377     auto *out = c->serializer->embed (this);
378     if (unlikely (!out)) return_trace (false);
379     return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers->get (firstLayerIndex),
380                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
381 
382     return_trace (true);
383   }
384 
sanitizeOT::PaintColrLayers385   bool sanitize (hb_sanitize_context_t *c) const
386   {
387     TRACE_SANITIZE (this);
388     return_trace (c->check_struct (this));
389   }
390 
391   HBUINT8	format; /* format = 1 */
392   HBUINT8	numLayers;
393   HBUINT32	firstLayerIndex;  /* index into COLRv1::layerList */
394   public:
395   DEFINE_SIZE_STATIC (6);
396 };
397 
398 struct PaintSolid
399 {
closurev1OT::PaintSolid400   void closurev1 (hb_colrv1_closure_context_t* c) const
401   { c->add_palette_index (paletteIndex); }
402 
subsetOT::PaintSolid403   bool subset (hb_subset_context_t *c) const
404   {
405     TRACE_SUBSET (this);
406     auto *out = c->serializer->embed (*this);
407     if (unlikely (!out)) return_trace (false);
408     return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex),
409                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
410   }
411 
sanitizeOT::PaintSolid412   bool sanitize (hb_sanitize_context_t *c) const
413   {
414     TRACE_SANITIZE (this);
415     return_trace (c->check_struct (this));
416   }
417 
418   HBUINT8	format; /* format = 2(noVar) or 3(Var)*/
419   HBUINT16	paletteIndex;
420   F2DOT14	alpha;
421   public:
422   DEFINE_SIZE_STATIC (3 + F2DOT14::static_size);
423 };
424 
425 template <template<typename> class Var>
426 struct PaintLinearGradient
427 {
closurev1OT::PaintLinearGradient428   void closurev1 (hb_colrv1_closure_context_t* c) const
429   { (this+colorLine).closurev1 (c); }
430 
subsetOT::PaintLinearGradient431   bool subset (hb_subset_context_t *c) const
432   {
433     TRACE_SUBSET (this);
434     auto *out = c->serializer->embed (this);
435     if (unlikely (!out)) return_trace (false);
436 
437     return_trace (out->colorLine.serialize_subset (c, colorLine, this));
438   }
439 
sanitizeOT::PaintLinearGradient440   bool sanitize (hb_sanitize_context_t *c) const
441   {
442     TRACE_SANITIZE (this);
443     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
444   }
445 
446   HBUINT8			format; /* format = 4(noVar) or 5 (Var) */
447   Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintLinearGradient
448                                             * table) to ColorLine subtable. */
449   FWORD			x0;
450   FWORD			y0;
451   FWORD			x1;
452   FWORD			y1;
453   FWORD			x2;
454   FWORD			y2;
455   public:
456   DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size);
457 };
458 
459 template <template<typename> class Var>
460 struct PaintRadialGradient
461 {
closurev1OT::PaintRadialGradient462   void closurev1 (hb_colrv1_closure_context_t* c) const
463   { (this+colorLine).closurev1 (c); }
464 
subsetOT::PaintRadialGradient465   bool subset (hb_subset_context_t *c) const
466   {
467     TRACE_SUBSET (this);
468     auto *out = c->serializer->embed (this);
469     if (unlikely (!out)) return_trace (false);
470 
471     return_trace (out->colorLine.serialize_subset (c, colorLine, this));
472   }
473 
sanitizeOT::PaintRadialGradient474   bool sanitize (hb_sanitize_context_t *c) const
475   {
476     TRACE_SANITIZE (this);
477     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
478   }
479 
480   HBUINT8			format; /* format = 6(noVar) or 7 (Var) */
481   Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintRadialGradient
482                                             * table) to ColorLine subtable. */
483   FWORD			x0;
484   FWORD			y0;
485   UFWORD		radius0;
486   FWORD			x1;
487   FWORD			y1;
488   UFWORD		radius1;
489   public:
490   DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size);
491 };
492 
493 template <template<typename> class Var>
494 struct PaintSweepGradient
495 {
closurev1OT::PaintSweepGradient496   void closurev1 (hb_colrv1_closure_context_t* c) const
497   { (this+colorLine).closurev1 (c); }
498 
subsetOT::PaintSweepGradient499   bool subset (hb_subset_context_t *c) const
500   {
501     TRACE_SUBSET (this);
502     auto *out = c->serializer->embed (this);
503     if (unlikely (!out)) return_trace (false);
504 
505     return_trace (out->colorLine.serialize_subset (c, colorLine, this));
506   }
507 
sanitizeOT::PaintSweepGradient508   bool sanitize (hb_sanitize_context_t *c) const
509   {
510     TRACE_SANITIZE (this);
511     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
512   }
513 
514   HBUINT8			format; /* format = 8(noVar) or 9 (Var) */
515   Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintSweepGradient
516                                             * table) to ColorLine subtable. */
517   FWORD			centerX;
518   FWORD			centerY;
519   F2DOT14		startAngle;
520   F2DOT14		endAngle;
521   public:
522   DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size + 2 * F2DOT14::static_size);
523 };
524 
525 struct Paint;
526 
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 ClipBoxData
891 {
892   int xMin, yMin, xMax, yMax;
893 };
894 
895 struct ClipBoxFormat1
896 {
sanitizeOT::ClipBoxFormat1897   bool sanitize (hb_sanitize_context_t *c) const
898   {
899     TRACE_SANITIZE (this);
900     return_trace (c->check_struct (this));
901   }
902 
get_clip_boxOT::ClipBoxFormat1903   void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer HB_UNUSED) const
904   {
905     clip_box.xMin = xMin;
906     clip_box.yMin = yMin;
907     clip_box.xMax = xMax;
908     clip_box.yMax = yMax;
909   }
910 
911   public:
912   HBUINT8	format; /* format = 1(noVar) or 2(Var)*/
913   FWORD		xMin;
914   FWORD		yMin;
915   FWORD		xMax;
916   FWORD		yMax;
917   public:
918   DEFINE_SIZE_STATIC (1 + 4 * FWORD::static_size);
919 };
920 
921 struct ClipBoxFormat2 : Variable<ClipBoxFormat1>
922 {
get_clip_boxOT::ClipBoxFormat2923   void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer) const
924   {
925     value.get_clip_box(clip_box, instancer);
926     if (instancer)
927     {
928       clip_box.xMin += _hb_roundf (instancer (varIdxBase, 0));
929       clip_box.yMin += _hb_roundf (instancer (varIdxBase, 1));
930       clip_box.xMax += _hb_roundf (instancer (varIdxBase, 2));
931       clip_box.yMax += _hb_roundf (instancer (varIdxBase, 3));
932     }
933   }
934 };
935 
936 struct ClipBox
937 {
copyOT::ClipBox938   ClipBox* copy (hb_serialize_context_t *c) const
939   {
940     TRACE_SERIALIZE (this);
941     switch (u.format) {
942     case 1: return_trace (reinterpret_cast<ClipBox *> (c->embed (u.format1)));
943     case 2: return_trace (reinterpret_cast<ClipBox *> (c->embed (u.format2)));
944     default:return_trace (nullptr);
945     }
946   }
947 
948   template <typename context_t, typename ...Ts>
dispatchOT::ClipBox949   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
950   {
951     TRACE_DISPATCH (this, u.format);
952     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
953     switch (u.format) {
954     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
955     case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
956     default:return_trace (c->default_return_value ());
957     }
958   }
959 
get_extentsOT::ClipBox960   bool get_extents (hb_glyph_extents_t *extents,
961                     const VarStoreInstancer &instancer) const
962   {
963     ClipBoxData clip_box;
964     switch (u.format) {
965     case 1:
966       u.format1.get_clip_box (clip_box, instancer);
967       break;
968     case 2:
969       u.format2.get_clip_box (clip_box, instancer);
970       break;
971     default:
972       return false;
973     }
974 
975     extents->x_bearing = clip_box.xMin;
976     extents->y_bearing = clip_box.yMax;
977     extents->width = clip_box.xMax - clip_box.xMin;
978     extents->height = clip_box.yMin - clip_box.yMax;
979     return true;
980   }
981 
982   protected:
983   union {
984   HBUINT8		format;         /* Format identifier */
985   ClipBoxFormat1	format1;
986   ClipBoxFormat2	format2;
987   } u;
988 };
989 
990 struct ClipRecord
991 {
cmpOT::ClipRecord992   int cmp (hb_codepoint_t g) const
993   { return g < startGlyphID ? -1 : g <= endGlyphID ? 0 : +1; }
994 
copyOT::ClipRecord995   ClipRecord* copy (hb_serialize_context_t *c, const void *base) const
996   {
997     TRACE_SERIALIZE (this);
998     auto *out = c->embed (this);
999     if (unlikely (!out)) return_trace (nullptr);
1000     if (!out->clipBox.serialize_copy (c, clipBox, base)) return_trace (nullptr);
1001     return_trace (out);
1002   }
1003 
sanitizeOT::ClipRecord1004   bool sanitize (hb_sanitize_context_t *c, const void *base) const
1005   {
1006     TRACE_SANITIZE (this);
1007     return_trace (c->check_struct (this) && clipBox.sanitize (c, base));
1008   }
1009 
get_extentsOT::ClipRecord1010   bool get_extents (hb_glyph_extents_t *extents,
1011 		    const void *base,
1012 		    const VarStoreInstancer &instancer) const
1013   {
1014     return (base+clipBox).get_extents (extents, instancer);
1015   }
1016 
1017   public:
1018   HBUINT16		startGlyphID;  // first gid clip applies to
1019   HBUINT16		endGlyphID;    // last gid clip applies to, inclusive
1020   Offset24To<ClipBox>	clipBox;   // Box or VarBox
1021   public:
1022   DEFINE_SIZE_STATIC (7);
1023 };
1024 DECLARE_NULL_NAMESPACE_BYTES (OT, ClipRecord);
1025 
1026 struct ClipList
1027 {
serialize_clip_recordsOT::ClipList1028   unsigned serialize_clip_records (hb_serialize_context_t *c,
1029                                    const hb_set_t& gids,
1030                                    const hb_map_t& gid_offset_map) const
1031   {
1032     TRACE_SERIALIZE (this);
1033     if (gids.is_empty () ||
1034         gid_offset_map.get_population () != gids.get_population ())
1035       return_trace (0);
1036 
1037     unsigned count  = 0;
1038 
1039     hb_codepoint_t start_gid= gids.get_min ();
1040     hb_codepoint_t prev_gid = start_gid;
1041 
1042     unsigned offset = gid_offset_map.get (start_gid);
1043     unsigned prev_offset = offset;
1044     for (const hb_codepoint_t _ : gids.iter ())
1045     {
1046       if (_ == start_gid) continue;
1047 
1048       offset = gid_offset_map.get (_);
1049       if (_ == prev_gid + 1 &&  offset == prev_offset)
1050       {
1051         prev_gid = _;
1052         continue;
1053       }
1054 
1055       ClipRecord record;
1056       record.startGlyphID = start_gid;
1057       record.endGlyphID = prev_gid;
1058       record.clipBox = prev_offset;
1059 
1060       if (!c->copy (record, this)) return_trace (0);
1061       count++;
1062 
1063       start_gid = _;
1064       prev_gid = _;
1065       prev_offset = offset;
1066     }
1067 
1068     //last one
1069     {
1070       ClipRecord record;
1071       record.startGlyphID = start_gid;
1072       record.endGlyphID = prev_gid;
1073       record.clipBox = prev_offset;
1074       if (!c->copy (record, this)) return_trace (0);
1075       count++;
1076     }
1077     return_trace (count);
1078   }
1079 
subsetOT::ClipList1080   bool subset (hb_subset_context_t *c) const
1081   {
1082     TRACE_SUBSET (this);
1083     auto *out = c->serializer->start_embed (*this);
1084     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
1085     if (!c->serializer->check_assign (out->format, format, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
1086 
1087     const hb_set_t& glyphset = *c->plan->_glyphset_colred;
1088     const hb_map_t &glyph_map = *c->plan->glyph_map;
1089 
1090     hb_map_t new_gid_offset_map;
1091     hb_set_t new_gids;
1092     for (const ClipRecord& record : clips.iter ())
1093     {
1094       unsigned start_gid = record.startGlyphID;
1095       unsigned end_gid = record.endGlyphID;
1096       for (unsigned gid = start_gid; gid <= end_gid; gid++)
1097       {
1098         if (!glyphset.has (gid) || !glyph_map.has (gid)) continue;
1099         unsigned new_gid = glyph_map.get (gid);
1100         new_gid_offset_map.set (new_gid, record.clipBox);
1101         new_gids.add (new_gid);
1102       }
1103     }
1104 
1105     unsigned count = serialize_clip_records (c->serializer, new_gids, new_gid_offset_map);
1106     if (!count) return_trace (false);
1107     return_trace (c->serializer->check_assign (out->clips.len, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
1108   }
1109 
sanitizeOT::ClipList1110   bool sanitize (hb_sanitize_context_t *c) const
1111   {
1112     TRACE_SANITIZE (this);
1113     // TODO Make a formatted struct!
1114     return_trace (c->check_struct (this) && clips.sanitize (c, this));
1115   }
1116 
1117   bool
get_extentsOT::ClipList1118   get_extents (hb_codepoint_t gid,
1119 	       hb_glyph_extents_t *extents,
1120 	       const VarStoreInstancer &instancer) const
1121   {
1122     auto *rec = clips.as_array ().bsearch (gid);
1123     if (rec)
1124     {
1125       rec->get_extents (extents, this, instancer);
1126       return true;
1127     }
1128     return false;
1129   }
1130 
1131   HBUINT8			format;  // Set to 1.
1132   SortedArray32Of<ClipRecord>	clips;  // Clip records, sorted by startGlyphID
1133   public:
1134   DEFINE_SIZE_ARRAY_SIZED (5, clips);
1135 };
1136 
1137 struct Paint
1138 {
1139 
1140   template <typename ...Ts>
sanitizeOT::Paint1141   bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
1142   {
1143     TRACE_SANITIZE (this);
1144 
1145     if (unlikely (!c->check_start_recursion (HB_COLRV1_MAX_NESTING_LEVEL)))
1146       return_trace (c->no_dispatch_return_value ());
1147 
1148     return_trace (c->end_recursion (this->dispatch (c, std::forward<Ts> (ds)...)));
1149   }
1150 
1151   template <typename context_t, typename ...Ts>
dispatchOT::Paint1152   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1153   {
1154     TRACE_DISPATCH (this, u.format);
1155     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1156     switch (u.format) {
1157     case 1: return_trace (c->dispatch (u.paintformat1, std::forward<Ts> (ds)...));
1158     case 2: return_trace (c->dispatch (u.paintformat2, std::forward<Ts> (ds)...));
1159     case 3: return_trace (c->dispatch (u.paintformat3, std::forward<Ts> (ds)...));
1160     case 4: return_trace (c->dispatch (u.paintformat4, std::forward<Ts> (ds)...));
1161     case 5: return_trace (c->dispatch (u.paintformat5, std::forward<Ts> (ds)...));
1162     case 6: return_trace (c->dispatch (u.paintformat6, std::forward<Ts> (ds)...));
1163     case 7: return_trace (c->dispatch (u.paintformat7, std::forward<Ts> (ds)...));
1164     case 8: return_trace (c->dispatch (u.paintformat8, std::forward<Ts> (ds)...));
1165     case 9: return_trace (c->dispatch (u.paintformat9, std::forward<Ts> (ds)...));
1166     case 10: return_trace (c->dispatch (u.paintformat10, std::forward<Ts> (ds)...));
1167     case 11: return_trace (c->dispatch (u.paintformat11, std::forward<Ts> (ds)...));
1168     case 12: return_trace (c->dispatch (u.paintformat12, std::forward<Ts> (ds)...));
1169     case 13: return_trace (c->dispatch (u.paintformat13, std::forward<Ts> (ds)...));
1170     case 14: return_trace (c->dispatch (u.paintformat14, std::forward<Ts> (ds)...));
1171     case 15: return_trace (c->dispatch (u.paintformat15, std::forward<Ts> (ds)...));
1172     case 16: return_trace (c->dispatch (u.paintformat16, std::forward<Ts> (ds)...));
1173     case 17: return_trace (c->dispatch (u.paintformat17, std::forward<Ts> (ds)...));
1174     case 18: return_trace (c->dispatch (u.paintformat18, std::forward<Ts> (ds)...));
1175     case 19: return_trace (c->dispatch (u.paintformat19, std::forward<Ts> (ds)...));
1176     case 20: return_trace (c->dispatch (u.paintformat20, std::forward<Ts> (ds)...));
1177     case 21: return_trace (c->dispatch (u.paintformat21, std::forward<Ts> (ds)...));
1178     case 22: return_trace (c->dispatch (u.paintformat22, std::forward<Ts> (ds)...));
1179     case 23: return_trace (c->dispatch (u.paintformat23, std::forward<Ts> (ds)...));
1180     case 24: return_trace (c->dispatch (u.paintformat24, std::forward<Ts> (ds)...));
1181     case 25: return_trace (c->dispatch (u.paintformat25, std::forward<Ts> (ds)...));
1182     case 26: return_trace (c->dispatch (u.paintformat26, std::forward<Ts> (ds)...));
1183     case 27: return_trace (c->dispatch (u.paintformat27, std::forward<Ts> (ds)...));
1184     case 28: return_trace (c->dispatch (u.paintformat28, std::forward<Ts> (ds)...));
1185     case 29: return_trace (c->dispatch (u.paintformat29, std::forward<Ts> (ds)...));
1186     case 30: return_trace (c->dispatch (u.paintformat30, std::forward<Ts> (ds)...));
1187     case 31: return_trace (c->dispatch (u.paintformat31, std::forward<Ts> (ds)...));
1188     case 32: return_trace (c->dispatch (u.paintformat32, std::forward<Ts> (ds)...));
1189     default:return_trace (c->default_return_value ());
1190     }
1191   }
1192 
1193   protected:
1194   union {
1195   HBUINT8					format;
1196   PaintColrLayers				paintformat1;
1197   PaintSolid					paintformat2;
1198   Variable<PaintSolid>				paintformat3;
1199   PaintLinearGradient<NoVariable>		paintformat4;
1200   Variable<PaintLinearGradient<Variable>>	paintformat5;
1201   PaintRadialGradient<NoVariable>		paintformat6;
1202   Variable<PaintRadialGradient<Variable>>	paintformat7;
1203   PaintSweepGradient<NoVariable>		paintformat8;
1204   Variable<PaintSweepGradient<Variable>>	paintformat9;
1205   PaintGlyph					paintformat10;
1206   PaintColrGlyph				paintformat11;
1207   PaintTransform<NoVariable>			paintformat12;
1208   PaintTransform<Variable>			paintformat13;
1209   PaintTranslate				paintformat14;
1210   Variable<PaintTranslate>			paintformat15;
1211   PaintScale					paintformat16;
1212   Variable<PaintScale>				paintformat17;
1213   PaintScaleAroundCenter			paintformat18;
1214   Variable<PaintScaleAroundCenter>		paintformat19;
1215   PaintScaleUniform				paintformat20;
1216   Variable<PaintScaleUniform>			paintformat21;
1217   PaintScaleUniformAroundCenter			paintformat22;
1218   Variable<PaintScaleUniformAroundCenter>	paintformat23;
1219   PaintRotate					paintformat24;
1220   Variable<PaintRotate>				paintformat25;
1221   PaintRotateAroundCenter			paintformat26;
1222   Variable<PaintRotateAroundCenter>		paintformat27;
1223   PaintSkew					paintformat28;
1224   Variable<PaintSkew>				paintformat29;
1225   PaintSkewAroundCenter				paintformat30;
1226   Variable<PaintSkewAroundCenter>		paintformat31;
1227   PaintComposite				paintformat32;
1228   } u;
1229   public:
1230   DEFINE_SIZE_MIN (2);
1231 };
1232 
1233 struct BaseGlyphPaintRecord
1234 {
cmpOT::BaseGlyphPaintRecord1235   int cmp (hb_codepoint_t g) const
1236   { return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
1237 
serializeOT::BaseGlyphPaintRecord1238   bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map,
1239                   const void* src_base, hb_subset_context_t *c) const
1240   {
1241     TRACE_SERIALIZE (this);
1242     auto *out = s->embed (this);
1243     if (unlikely (!out)) return_trace (false);
1244     if (!s->check_assign (out->glyphId, glyph_map->get (glyphId),
1245                           HB_SERIALIZE_ERROR_INT_OVERFLOW))
1246       return_trace (false);
1247 
1248     return_trace (out->paint.serialize_subset (c, paint, src_base));
1249   }
1250 
sanitizeOT::BaseGlyphPaintRecord1251   bool sanitize (hb_sanitize_context_t *c, const void *base) const
1252   {
1253     TRACE_SANITIZE (this);
1254     return_trace (likely (c->check_struct (this) && paint.sanitize (c, base)));
1255   }
1256 
1257   public:
1258   HBGlyphID16		glyphId;    /* Glyph ID of reference glyph */
1259   Offset32To<Paint>	paint;      /* Offset (from beginning of BaseGlyphPaintRecord array) to Paint,
1260                                      * Typically PaintColrLayers */
1261   public:
1262   DEFINE_SIZE_STATIC (6);
1263 };
1264 
1265 struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
1266 {
subsetOT::BaseGlyphList1267   bool subset (hb_subset_context_t *c) const
1268   {
1269     TRACE_SUBSET (this);
1270     auto *out = c->serializer->start_embed (this);
1271     if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
1272     const hb_set_t* glyphset = c->plan->_glyphset_colred;
1273 
1274     for (const auto& _ : as_array ())
1275     {
1276       unsigned gid = _.glyphId;
1277       if (!glyphset->has (gid)) continue;
1278 
1279       if (_.serialize (c->serializer, c->plan->glyph_map, this, c)) out->len++;
1280       else return_trace (false);
1281     }
1282 
1283     return_trace (out->len != 0);
1284   }
1285 
sanitizeOT::BaseGlyphList1286   bool sanitize (hb_sanitize_context_t *c) const
1287   {
1288     TRACE_SANITIZE (this);
1289     return_trace (SortedArray32Of<BaseGlyphPaintRecord>::sanitize (c, this));
1290   }
1291 };
1292 
1293 struct LayerList : Array32OfOffset32To<Paint>
1294 {
get_paintOT::LayerList1295   const Paint& get_paint (unsigned i) const
1296   { return this+(*this)[i]; }
1297 
subsetOT::LayerList1298   bool subset (hb_subset_context_t *c) const
1299   {
1300     TRACE_SUBSET (this);
1301     auto *out = c->serializer->start_embed (this);
1302     if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
1303 
1304     for (const auto& _ : + hb_enumerate (*this)
1305                          | hb_filter (c->plan->colrv1_layers, hb_first))
1306 
1307     {
1308       auto *o = out->serialize_append (c->serializer);
1309       if (unlikely (!o) || !o->serialize_subset (c, _.second, this))
1310         return_trace (false);
1311     }
1312     return_trace (true);
1313   }
1314 
sanitizeOT::LayerList1315   bool sanitize (hb_sanitize_context_t *c) const
1316   {
1317     TRACE_SANITIZE (this);
1318     return_trace (Array32OfOffset32To<Paint>::sanitize (c, this));
1319   }
1320 };
1321 
1322 struct COLR
1323 {
1324   static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
1325 
has_dataOT::COLR1326   bool has_data () const { return numBaseGlyphs; }
1327 
get_glyph_layersOT::COLR1328   unsigned int get_glyph_layers (hb_codepoint_t       glyph,
1329 				 unsigned int         start_offset,
1330 				 unsigned int        *count, /* IN/OUT.  May be NULL. */
1331 				 hb_ot_color_layer_t *layers /* OUT.     May be NULL. */) const
1332   {
1333     const BaseGlyphRecord &record = (this+baseGlyphsZ).bsearch (numBaseGlyphs, glyph);
1334 
1335     hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
1336     hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
1337 								       record.numLayers);
1338     if (count)
1339     {
1340       + glyph_layers.sub_array (start_offset, count)
1341       | hb_sink (hb_array (layers, *count))
1342       ;
1343     }
1344     return glyph_layers.length;
1345   }
1346 
1347   struct accelerator_t
1348   {
accelerator_tOT::COLR::accelerator_t1349     accelerator_t (hb_face_t *face)
1350     { colr = hb_sanitize_context_t ().reference_table<COLR> (face); }
~accelerator_tOT::COLR::accelerator_t1351     ~accelerator_t () { this->colr.destroy (); }
1352 
is_validOT::COLR::accelerator_t1353     bool is_valid () { return colr.get_blob ()->length; }
1354 
closure_glyphsOT::COLR::accelerator_t1355     void closure_glyphs (hb_codepoint_t glyph,
1356 			 hb_set_t *related_ids /* OUT */) const
1357     { colr->closure_glyphs (glyph, related_ids); }
1358 
closure_V0palette_indicesOT::COLR::accelerator_t1359     void closure_V0palette_indices (const hb_set_t *glyphs,
1360 				    hb_set_t *palettes /* OUT */) const
1361     { colr->closure_V0palette_indices (glyphs, palettes); }
1362 
closure_forV1OT::COLR::accelerator_t1363     void closure_forV1 (hb_set_t *glyphset,
1364                         hb_set_t *layer_indices,
1365                         hb_set_t *palette_indices) const
1366     { colr->closure_forV1 (glyphset, layer_indices, palette_indices); }
1367 
1368     private:
1369     hb_blob_ptr_t<COLR> colr;
1370   };
1371 
closure_glyphsOT::COLR1372   void closure_glyphs (hb_codepoint_t glyph,
1373 		       hb_set_t *related_ids /* OUT */) const
1374   {
1375     const BaseGlyphRecord *record = get_base_glyph_record (glyph);
1376     if (!record) return;
1377 
1378     auto glyph_layers = (this+layersZ).as_array (numLayers).sub_array (record->firstLayerIdx,
1379 								       record->numLayers);
1380     if (!glyph_layers.length) return;
1381     related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size);
1382   }
1383 
closure_V0palette_indicesOT::COLR1384   void closure_V0palette_indices (const hb_set_t *glyphs,
1385 				  hb_set_t *palettes /* OUT */) const
1386   {
1387     if (!numBaseGlyphs || !numLayers) return;
1388     hb_array_t<const BaseGlyphRecord> baseGlyphs = (this+baseGlyphsZ).as_array (numBaseGlyphs);
1389     hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
1390 
1391     for (const BaseGlyphRecord record : baseGlyphs)
1392     {
1393       if (!glyphs->has (record.glyphId)) continue;
1394       hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
1395                                                                    record.numLayers);
1396       for (const LayerRecord layer : glyph_layers)
1397         palettes->add (layer.colorIdx);
1398     }
1399   }
1400 
closure_forV1OT::COLR1401   void closure_forV1 (hb_set_t *glyphset,
1402                       hb_set_t *layer_indices,
1403                       hb_set_t *palette_indices) const
1404   {
1405     if (version != 1) return;
1406     hb_set_t visited_glyphs;
1407 
1408     hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices);
1409     const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList;
1410 
1411     for (const BaseGlyphPaintRecord &baseglyph_paintrecord: baseglyph_paintrecords.iter ())
1412     {
1413       unsigned gid = baseglyph_paintrecord.glyphId;
1414       if (!glyphset->has (gid)) continue;
1415 
1416       const Paint &paint = &baseglyph_paintrecords+baseglyph_paintrecord.paint;
1417       paint.dispatch (&c);
1418     }
1419     hb_set_union (glyphset, &visited_glyphs);
1420   }
1421 
get_layerListOT::COLR1422   const LayerList& get_layerList () const
1423   { return (this+layerList); }
1424 
get_baseglyphListOT::COLR1425   const BaseGlyphList& get_baseglyphList () const
1426   { return (this+baseGlyphList); }
1427 
sanitizeOT::COLR1428   bool sanitize (hb_sanitize_context_t *c) const
1429   {
1430     TRACE_SANITIZE (this);
1431     return_trace (c->check_struct (this) &&
1432                   (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
1433                   (this+layersZ).sanitize (c, numLayers) &&
1434                   (version == 0 ||
1435 		   (version == 1 &&
1436 		    baseGlyphList.sanitize (c, this) &&
1437 		    layerList.sanitize (c, this) &&
1438 		    clipList.sanitize (c, this) &&
1439 		    varIdxMap.sanitize (c, this) &&
1440 		    varStore.sanitize (c, this))));
1441   }
1442 
1443   template<typename BaseIterator, typename LayerIterator,
1444 	   hb_requires (hb_is_iterator (BaseIterator)),
1445 	   hb_requires (hb_is_iterator (LayerIterator))>
serialize_V0OT::COLR1446   bool serialize_V0 (hb_serialize_context_t *c,
1447 		     unsigned version,
1448 		     BaseIterator base_it,
1449 		     LayerIterator layer_it)
1450   {
1451     TRACE_SERIALIZE (this);
1452     if (unlikely (base_it.len () != layer_it.len ()))
1453       return_trace (false);
1454 
1455     this->version = version;
1456     numLayers = 0;
1457     numBaseGlyphs = base_it.len ();
1458     if (numBaseGlyphs == 0)
1459     {
1460       baseGlyphsZ = 0;
1461       layersZ = 0;
1462       return_trace (true);
1463     }
1464 
1465     c->push ();
1466     for (const hb_item_type<BaseIterator> _ : + base_it.iter ())
1467     {
1468       auto* record = c->embed (_);
1469       if (unlikely (!record)) return_trace (false);
1470       record->firstLayerIdx = numLayers;
1471       numLayers += record->numLayers;
1472     }
1473     c->add_link (baseGlyphsZ, c->pop_pack ());
1474 
1475     c->push ();
1476     for (const hb_item_type<LayerIterator>& _ : + layer_it.iter ())
1477       _.as_array ().copy (c);
1478 
1479     c->add_link (layersZ, c->pop_pack ());
1480 
1481     return_trace (true);
1482   }
1483 
get_base_glyph_recordOT::COLR1484   const BaseGlyphRecord* get_base_glyph_record (hb_codepoint_t gid) const
1485   {
1486     const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, (unsigned int) gid);
1487     if (record == &Null (BaseGlyphRecord) ||
1488         (record && (hb_codepoint_t) record->glyphId != gid))
1489       record = nullptr;
1490     return record;
1491   }
1492 
get_base_glyph_paintrecordOT::COLR1493   const BaseGlyphPaintRecord* get_base_glyph_paintrecord (hb_codepoint_t gid) const
1494   {
1495     const BaseGlyphPaintRecord* record = &(this+baseGlyphList).bsearch ((unsigned) gid);
1496     if ((record && (hb_codepoint_t) record->glyphId != gid))
1497       record = nullptr;
1498     return record;
1499   }
1500 
subsetOT::COLR1501   bool subset (hb_subset_context_t *c) const
1502   {
1503     TRACE_SUBSET (this);
1504 
1505     const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
1506     const hb_set_t& glyphset = *c->plan->_glyphset_colred;
1507 
1508     auto base_it =
1509     + hb_range (c->plan->num_output_glyphs ())
1510     | hb_filter ([&](hb_codepoint_t new_gid)
1511 		 {
1512 		    hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
1513 		    if (glyphset.has (old_gid)) return true;
1514 		    return false;
1515 		 })
1516     | hb_map_retains_sorting ([&](hb_codepoint_t new_gid)
1517 			      {
1518 				hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
1519 
1520 				const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
1521 				if (unlikely (!old_record))
1522 				  return hb_pair_t<bool, BaseGlyphRecord> (false, Null (BaseGlyphRecord));
1523 				BaseGlyphRecord new_record = {};
1524 				new_record.glyphId = new_gid;
1525 				new_record.numLayers = old_record->numLayers;
1526 				return hb_pair_t<bool, BaseGlyphRecord> (true, new_record);
1527 			      })
1528     | hb_filter (hb_first)
1529     | hb_map_retains_sorting (hb_second)
1530     ;
1531 
1532     auto layer_it =
1533     + hb_range (c->plan->num_output_glyphs ())
1534     | hb_map (reverse_glyph_map)
1535     | hb_filter (glyphset)
1536     | hb_map_retains_sorting ([&](hb_codepoint_t old_gid)
1537 			      {
1538 				const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
1539 				hb_vector_t<LayerRecord> out_layers;
1540 
1541 				if (unlikely (!old_record ||
1542 					      old_record->firstLayerIdx >= numLayers ||
1543 					      old_record->firstLayerIdx + old_record->numLayers > numLayers))
1544 				  return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
1545 
1546 				auto layers = (this+layersZ).as_array (numLayers).sub_array (old_record->firstLayerIdx,
1547 											     old_record->numLayers);
1548 				out_layers.resize (layers.length);
1549 				for (unsigned int i = 0; i < layers.length; i++) {
1550 				  out_layers[i] = layers[i];
1551 				  hb_codepoint_t new_gid = 0;
1552 				  if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid)))
1553 				    return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
1554 				  out_layers[i].glyphId = new_gid;
1555 				  out_layers[i].colorIdx = c->plan->colr_palettes->get (layers[i].colorIdx);
1556 				}
1557 
1558 				return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers);
1559 			      })
1560     | hb_filter (hb_first)
1561     | hb_map_retains_sorting (hb_second)
1562     ;
1563 
1564     if (version == 0 && (!base_it || !layer_it))
1565       return_trace (false);
1566 
1567     COLR *colr_prime = c->serializer->start_embed<COLR> ();
1568     if (unlikely (!c->serializer->extend_min (colr_prime)))  return_trace (false);
1569 
1570     if (version == 0)
1571     return_trace (colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it));
1572 
1573     auto snap = c->serializer->snapshot ();
1574     if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false);
1575     if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this))
1576     {
1577       if (c->serializer->in_error ()) return_trace (false);
1578       //no more COLRv1 glyphs: downgrade to version 0
1579       c->serializer->revert (snap);
1580       return_trace (colr_prime->serialize_V0 (c->serializer, 0, base_it, layer_it));
1581     }
1582 
1583     if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false);
1584 
1585     colr_prime->layerList.serialize_subset (c, layerList, this);
1586     colr_prime->clipList.serialize_subset (c, clipList, this);
1587     colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this);
1588     //TODO: subset varStore once it's implemented in fonttools
1589     return_trace (true);
1590   }
1591 
1592   bool
get_extentsOT::COLR1593   get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
1594   {
1595     if (version != 1)
1596       return false;
1597 
1598     VarStoreInstancer instancer (this+varStore,
1599 				 this+varIdxMap,
1600 				 hb_array (font->coords, font->num_coords));
1601 
1602     if ((this+clipList).get_extents (glyph,
1603 				     extents,
1604 				     instancer))
1605     {
1606       extents->x_bearing = font->em_scale_x (extents->x_bearing);
1607       extents->y_bearing = font->em_scale_x (extents->y_bearing);
1608       extents->width = font->em_scale_x (extents->width);
1609       extents->height = font->em_scale_x (extents->height);
1610       return true;
1611     }
1612 
1613     return false;
1614   }
1615 
1616   protected:
1617   HBUINT16	version;	/* Table version number (starts at 0). */
1618   HBUINT16	numBaseGlyphs;	/* Number of Base Glyph Records. */
1619   NNOffset32To<SortedUnsizedArrayOf<BaseGlyphRecord>>
1620 		baseGlyphsZ;	/* Offset to Base Glyph records. */
1621   NNOffset32To<UnsizedArrayOf<LayerRecord>>
1622 		layersZ;	/* Offset to Layer Records. */
1623   HBUINT16	numLayers;	/* Number of Layer Records. */
1624   // Version-1 additions
1625   Offset32To<BaseGlyphList>		baseGlyphList;
1626   Offset32To<LayerList>			layerList;
1627   Offset32To<ClipList>			clipList;   // Offset to ClipList table (may be NULL)
1628   Offset32To<DeltaSetIndexMap>		varIdxMap;  // Offset to DeltaSetIndexMap table (may be NULL)
1629   Offset32To<VariationStore>		varStore;
1630   public:
1631   DEFINE_SIZE_MIN (14);
1632 };
1633 
1634 struct COLR_accelerator_t : COLR::accelerator_t {
COLR_accelerator_tOT::COLR_accelerator_t1635   COLR_accelerator_t (hb_face_t *face) : COLR::accelerator_t (face) {}
1636 };
1637 
1638 } /* namespace OT */
1639 
1640 
1641 #endif /* HB_OT_COLOR_COLR_TABLE_HH */
1642