• 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 COLRV1_MAX_NESTING_LEVEL
42 #define 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.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_ = 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;
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   template <typename context_t, typename ...Ts>
dispatchOT::Paint1066   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1067   {
1068     TRACE_DISPATCH (this, u.format);
1069     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1070     switch (u.format) {
1071     case 1: return_trace (c->dispatch (u.paintformat1, std::forward<Ts> (ds)...));
1072     case 2: return_trace (c->dispatch (u.paintformat2, std::forward<Ts> (ds)...));
1073     case 3: return_trace (c->dispatch (u.paintformat3, std::forward<Ts> (ds)...));
1074     case 4: return_trace (c->dispatch (u.paintformat4, std::forward<Ts> (ds)...));
1075     case 5: return_trace (c->dispatch (u.paintformat5, std::forward<Ts> (ds)...));
1076     case 6: return_trace (c->dispatch (u.paintformat6, std::forward<Ts> (ds)...));
1077     case 7: return_trace (c->dispatch (u.paintformat7, std::forward<Ts> (ds)...));
1078     case 8: return_trace (c->dispatch (u.paintformat8, std::forward<Ts> (ds)...));
1079     case 9: return_trace (c->dispatch (u.paintformat9, std::forward<Ts> (ds)...));
1080     case 10: return_trace (c->dispatch (u.paintformat10, std::forward<Ts> (ds)...));
1081     case 11: return_trace (c->dispatch (u.paintformat11, std::forward<Ts> (ds)...));
1082     case 12: return_trace (c->dispatch (u.paintformat12, std::forward<Ts> (ds)...));
1083     case 13: return_trace (c->dispatch (u.paintformat13, std::forward<Ts> (ds)...));
1084     case 14: return_trace (c->dispatch (u.paintformat14, std::forward<Ts> (ds)...));
1085     case 15: return_trace (c->dispatch (u.paintformat15, std::forward<Ts> (ds)...));
1086     case 16: return_trace (c->dispatch (u.paintformat16, std::forward<Ts> (ds)...));
1087     case 17: return_trace (c->dispatch (u.paintformat17, std::forward<Ts> (ds)...));
1088     case 18: return_trace (c->dispatch (u.paintformat18, std::forward<Ts> (ds)...));
1089     case 19: return_trace (c->dispatch (u.paintformat19, std::forward<Ts> (ds)...));
1090     case 20: return_trace (c->dispatch (u.paintformat20, std::forward<Ts> (ds)...));
1091     case 21: return_trace (c->dispatch (u.paintformat21, std::forward<Ts> (ds)...));
1092     case 22: return_trace (c->dispatch (u.paintformat22, std::forward<Ts> (ds)...));
1093     case 23: return_trace (c->dispatch (u.paintformat23, std::forward<Ts> (ds)...));
1094     case 24: return_trace (c->dispatch (u.paintformat24, std::forward<Ts> (ds)...));
1095     case 25: return_trace (c->dispatch (u.paintformat25, std::forward<Ts> (ds)...));
1096     case 26: return_trace (c->dispatch (u.paintformat26, std::forward<Ts> (ds)...));
1097     case 27: return_trace (c->dispatch (u.paintformat27, std::forward<Ts> (ds)...));
1098     case 28: return_trace (c->dispatch (u.paintformat28, std::forward<Ts> (ds)...));
1099     case 29: return_trace (c->dispatch (u.paintformat29, std::forward<Ts> (ds)...));
1100     case 30: return_trace (c->dispatch (u.paintformat30, std::forward<Ts> (ds)...));
1101     case 31: return_trace (c->dispatch (u.paintformat31, std::forward<Ts> (ds)...));
1102     case 32: return_trace (c->dispatch (u.paintformat32, std::forward<Ts> (ds)...));
1103     default:return_trace (c->default_return_value ());
1104     }
1105   }
1106 
1107   protected:
1108   union {
1109   HBUINT8					format;
1110   PaintColrLayers				paintformat1;
1111   PaintSolid					paintformat2;
1112   Variable<PaintSolid>				paintformat3;
1113   PaintLinearGradient<NoVariable>		paintformat4;
1114   Variable<PaintLinearGradient<Variable>>	paintformat5;
1115   PaintRadialGradient<NoVariable>		paintformat6;
1116   Variable<PaintRadialGradient<Variable>>	paintformat7;
1117   PaintSweepGradient<NoVariable>		paintformat8;
1118   Variable<PaintSweepGradient<Variable>>	paintformat9;
1119   PaintGlyph					paintformat10;
1120   PaintColrGlyph				paintformat11;
1121   PaintTransform<NoVariable>			paintformat12;
1122   PaintTransform<Variable>			paintformat13;
1123   PaintTranslate				paintformat14;
1124   Variable<PaintTranslate>			paintformat15;
1125   PaintScale					paintformat16;
1126   Variable<PaintScale>				paintformat17;
1127   PaintScaleAroundCenter			paintformat18;
1128   Variable<PaintScaleAroundCenter>		paintformat19;
1129   PaintScaleUniform				paintformat20;
1130   Variable<PaintScaleUniform>			paintformat21;
1131   PaintScaleUniformAroundCenter			paintformat22;
1132   Variable<PaintScaleUniformAroundCenter>	paintformat23;
1133   PaintRotate					paintformat24;
1134   Variable<PaintRotate>				paintformat25;
1135   PaintRotateAroundCenter			paintformat26;
1136   Variable<PaintRotateAroundCenter>		paintformat27;
1137   PaintSkew					paintformat28;
1138   Variable<PaintSkew>				paintformat29;
1139   PaintSkewAroundCenter				paintformat30;
1140   Variable<PaintSkewAroundCenter>		paintformat31;
1141   PaintComposite				paintformat32;
1142   } u;
1143 };
1144 
1145 struct BaseGlyphPaintRecord
1146 {
cmpOT::BaseGlyphPaintRecord1147   int cmp (hb_codepoint_t g) const
1148   { return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
1149 
serializeOT::BaseGlyphPaintRecord1150   bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map,
1151                   const void* src_base, hb_subset_context_t *c) const
1152   {
1153     TRACE_SERIALIZE (this);
1154     auto *out = s->embed (this);
1155     if (unlikely (!out)) return_trace (false);
1156     if (!s->check_assign (out->glyphId, glyph_map->get (glyphId),
1157                           HB_SERIALIZE_ERROR_INT_OVERFLOW))
1158       return_trace (false);
1159 
1160     return_trace (out->paint.serialize_subset (c, paint, src_base));
1161   }
1162 
sanitizeOT::BaseGlyphPaintRecord1163   bool sanitize (hb_sanitize_context_t *c, const void *base) const
1164   {
1165     TRACE_SANITIZE (this);
1166     return_trace (likely (c->check_struct (this) && paint.sanitize (c, base)));
1167   }
1168 
1169   public:
1170   HBGlyphID16		glyphId;    /* Glyph ID of reference glyph */
1171   Offset32To<Paint>	paint;      /* Offset (from beginning of BaseGlyphPaintRecord array) to Paint,
1172                                      * Typically PaintColrLayers */
1173   public:
1174   DEFINE_SIZE_STATIC (6);
1175 };
1176 
1177 struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
1178 {
subsetOT::BaseGlyphList1179   bool subset (hb_subset_context_t *c) const
1180   {
1181     TRACE_SUBSET (this);
1182     auto *out = c->serializer->start_embed (this);
1183     if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
1184     const hb_set_t* glyphset = c->plan->_glyphset;
1185 
1186     for (const auto& _ : as_array ())
1187     {
1188       unsigned gid = _.glyphId;
1189       if (!glyphset->has (gid)) continue;
1190 
1191       if (_.serialize (c->serializer, c->plan->glyph_map, this, c)) out->len++;
1192       else return_trace (false);
1193     }
1194 
1195     return_trace (out->len != 0);
1196   }
1197 
sanitizeOT::BaseGlyphList1198   bool sanitize (hb_sanitize_context_t *c) const
1199   {
1200     TRACE_SANITIZE (this);
1201     return_trace (SortedArray32Of<BaseGlyphPaintRecord>::sanitize (c, this));
1202   }
1203 };
1204 
1205 struct LayerList : Array32OfOffset32To<Paint>
1206 {
get_paintOT::LayerList1207   const Paint& get_paint (unsigned i) const
1208   { return this+(*this)[i]; }
1209 
subsetOT::LayerList1210   bool subset (hb_subset_context_t *c) const
1211   {
1212     TRACE_SUBSET (this);
1213     auto *out = c->serializer->start_embed (this);
1214     if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
1215 
1216     for (const auto& _ : + hb_enumerate (*this)
1217                          | hb_filter (c->plan->colrv1_layers, hb_first))
1218 
1219     {
1220       auto *o = out->serialize_append (c->serializer);
1221       if (unlikely (!o) || !o->serialize_subset (c, _.second, this))
1222         return_trace (false);
1223     }
1224     return_trace (true);
1225   }
1226 
sanitizeOT::LayerList1227   bool sanitize (hb_sanitize_context_t *c) const
1228   {
1229     TRACE_SANITIZE (this);
1230     return_trace (Array32OfOffset32To<Paint>::sanitize (c, this));
1231   }
1232 };
1233 
1234 struct COLR
1235 {
1236   static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
1237 
has_dataOT::COLR1238   bool has_data () const { return numBaseGlyphs; }
1239 
get_glyph_layersOT::COLR1240   unsigned int get_glyph_layers (hb_codepoint_t       glyph,
1241 				 unsigned int         start_offset,
1242 				 unsigned int        *count, /* IN/OUT.  May be NULL. */
1243 				 hb_ot_color_layer_t *layers /* OUT.     May be NULL. */) const
1244   {
1245     const BaseGlyphRecord &record = (this+baseGlyphsZ).bsearch (numBaseGlyphs, glyph);
1246 
1247     hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
1248     hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
1249 								       record.numLayers);
1250     if (count)
1251     {
1252       + glyph_layers.sub_array (start_offset, count)
1253       | hb_sink (hb_array (layers, *count))
1254       ;
1255     }
1256     return glyph_layers.length;
1257   }
1258 
1259   struct accelerator_t
1260   {
accelerator_tOT::COLR::accelerator_t1261     accelerator_t () {}
~accelerator_tOT::COLR::accelerator_t1262     ~accelerator_t () { fini (); }
1263 
initOT::COLR::accelerator_t1264     void init (hb_face_t *face)
1265     { colr = hb_sanitize_context_t ().reference_table<COLR> (face); }
1266 
finiOT::COLR::accelerator_t1267     void fini () { this->colr.destroy (); }
1268 
is_validOT::COLR::accelerator_t1269     bool is_valid () { return colr.get_blob ()->length; }
1270 
closure_glyphsOT::COLR::accelerator_t1271     void closure_glyphs (hb_codepoint_t glyph,
1272 			 hb_set_t *related_ids /* OUT */) const
1273     { colr->closure_glyphs (glyph, related_ids); }
1274 
closure_V0palette_indicesOT::COLR::accelerator_t1275     void closure_V0palette_indices (const hb_set_t *glyphs,
1276 				    hb_set_t *palettes /* OUT */) const
1277     { colr->closure_V0palette_indices (glyphs, palettes); }
1278 
closure_forV1OT::COLR::accelerator_t1279     void closure_forV1 (hb_set_t *glyphset,
1280                         hb_set_t *layer_indices,
1281                         hb_set_t *palette_indices) const
1282     { colr->closure_forV1 (glyphset, layer_indices, palette_indices); }
1283 
1284     private:
1285     hb_blob_ptr_t<COLR> colr;
1286   };
1287 
closure_glyphsOT::COLR1288   void closure_glyphs (hb_codepoint_t glyph,
1289 		       hb_set_t *related_ids /* OUT */) const
1290   {
1291     const BaseGlyphRecord *record = get_base_glyph_record (glyph);
1292     if (!record) return;
1293 
1294     auto glyph_layers = (this+layersZ).as_array (numLayers).sub_array (record->firstLayerIdx,
1295 								       record->numLayers);
1296     if (!glyph_layers.length) return;
1297     related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size);
1298   }
1299 
closure_V0palette_indicesOT::COLR1300   void closure_V0palette_indices (const hb_set_t *glyphs,
1301 				  hb_set_t *palettes /* OUT */) const
1302   {
1303     if (!numBaseGlyphs || !numLayers) return;
1304     hb_array_t<const BaseGlyphRecord> baseGlyphs = (this+baseGlyphsZ).as_array (numBaseGlyphs);
1305     hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
1306 
1307     for (const BaseGlyphRecord record : baseGlyphs)
1308     {
1309       if (!glyphs->has (record.glyphId)) continue;
1310       hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
1311                                                                    record.numLayers);
1312       for (const LayerRecord layer : glyph_layers)
1313         palettes->add (layer.colorIdx);
1314     }
1315   }
1316 
closure_forV1OT::COLR1317   void closure_forV1 (hb_set_t *glyphset,
1318                       hb_set_t *layer_indices,
1319                       hb_set_t *palette_indices) const
1320   {
1321     if (version != 1) return;
1322     hb_set_t visited_glyphs;
1323 
1324     hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices);
1325     const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList;
1326 
1327     for (const BaseGlyphPaintRecord &baseglyph_paintrecord: baseglyph_paintrecords.iter ())
1328     {
1329       unsigned gid = baseglyph_paintrecord.glyphId;
1330       if (!glyphset->has (gid)) continue;
1331 
1332       const Paint &paint = &baseglyph_paintrecords+baseglyph_paintrecord.paint;
1333       paint.dispatch (&c);
1334     }
1335     hb_set_union (glyphset, &visited_glyphs);
1336   }
1337 
get_layerListOT::COLR1338   const LayerList& get_layerList () const
1339   { return (this+layerList); }
1340 
get_baseglyphListOT::COLR1341   const BaseGlyphList& get_baseglyphList () const
1342   { return (this+baseGlyphList); }
1343 
sanitizeOT::COLR1344   bool sanitize (hb_sanitize_context_t *c) const
1345   {
1346     TRACE_SANITIZE (this);
1347     return_trace (c->check_struct (this) &&
1348                   (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
1349                   (this+layersZ).sanitize (c, numLayers) &&
1350                   (version == 0 ||
1351 		   (COLRV1_ENABLE_SUBSETTING && version == 1 &&
1352 		    baseGlyphList.sanitize (c, this) &&
1353 		    layerList.sanitize (c, this) &&
1354 		    clipList.sanitize (c, this) &&
1355 		    varIdxMap.sanitize (c, this) &&
1356 		    varStore.sanitize (c, this))));
1357   }
1358 
1359   template<typename BaseIterator, typename LayerIterator,
1360 	   hb_requires (hb_is_iterator (BaseIterator)),
1361 	   hb_requires (hb_is_iterator (LayerIterator))>
serialize_V0OT::COLR1362   bool serialize_V0 (hb_serialize_context_t *c,
1363 		     unsigned version,
1364 		     BaseIterator base_it,
1365 		     LayerIterator layer_it)
1366   {
1367     TRACE_SERIALIZE (this);
1368     if (unlikely (base_it.len () != layer_it.len ()))
1369       return_trace (false);
1370 
1371     this->version = version;
1372     numLayers = 0;
1373     numBaseGlyphs = base_it.len ();
1374     if (numBaseGlyphs == 0)
1375     {
1376       baseGlyphsZ = 0;
1377       layersZ = 0;
1378       return_trace (true);
1379     }
1380 
1381     c->push ();
1382     for (const hb_item_type<BaseIterator> _ : + base_it.iter ())
1383     {
1384       auto* record = c->embed (_);
1385       if (unlikely (!record)) return_trace (false);
1386       record->firstLayerIdx = numLayers;
1387       numLayers += record->numLayers;
1388     }
1389     c->add_link (baseGlyphsZ, c->pop_pack ());
1390 
1391     c->push ();
1392     for (const hb_item_type<LayerIterator>& _ : + layer_it.iter ())
1393       _.as_array ().copy (c);
1394 
1395     c->add_link (layersZ, c->pop_pack ());
1396 
1397     return_trace (true);
1398   }
1399 
get_base_glyph_recordOT::COLR1400   const BaseGlyphRecord* get_base_glyph_record (hb_codepoint_t gid) const
1401   {
1402     if ((unsigned int) gid == 0) // Ignore notdef.
1403       return nullptr;
1404     const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, (unsigned int) gid);
1405     if ((record && (hb_codepoint_t) record->glyphId != gid))
1406       record = nullptr;
1407     return record;
1408   }
1409 
get_base_glyph_paintrecordOT::COLR1410   const BaseGlyphPaintRecord* get_base_glyph_paintrecord (hb_codepoint_t gid) const
1411   {
1412     const BaseGlyphPaintRecord* record = &(this+baseGlyphList).bsearch ((unsigned) gid);
1413     if ((record && (hb_codepoint_t) record->glyphId != gid))
1414       record = nullptr;
1415     return record;
1416   }
1417 
subsetOT::COLR1418   bool subset (hb_subset_context_t *c) const
1419   {
1420     TRACE_SUBSET (this);
1421 
1422     const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
1423 
1424     auto base_it =
1425     + hb_range (c->plan->num_output_glyphs ())
1426     | hb_map_retains_sorting ([&](hb_codepoint_t new_gid)
1427 			      {
1428 				hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
1429 
1430 				const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
1431 				if (unlikely (!old_record))
1432 				  return hb_pair_t<bool, BaseGlyphRecord> (false, Null (BaseGlyphRecord));
1433 
1434 				BaseGlyphRecord new_record = {};
1435 				new_record.glyphId = new_gid;
1436 				new_record.numLayers = old_record->numLayers;
1437 				return hb_pair_t<bool, BaseGlyphRecord> (true, new_record);
1438 			      })
1439     | hb_filter (hb_first)
1440     | hb_map_retains_sorting (hb_second)
1441     ;
1442 
1443     auto layer_it =
1444     + hb_range (c->plan->num_output_glyphs ())
1445     | hb_map (reverse_glyph_map)
1446     | hb_map_retains_sorting ([&](hb_codepoint_t old_gid)
1447 			      {
1448 				const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
1449 				hb_vector_t<LayerRecord> out_layers;
1450 
1451 				if (unlikely (!old_record ||
1452 					      old_record->firstLayerIdx >= numLayers ||
1453 					      old_record->firstLayerIdx + old_record->numLayers > numLayers))
1454 				  return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
1455 
1456 				auto layers = (this+layersZ).as_array (numLayers).sub_array (old_record->firstLayerIdx,
1457 											     old_record->numLayers);
1458 				out_layers.resize (layers.length);
1459 				for (unsigned int i = 0; i < layers.length; i++) {
1460 				  out_layers[i] = layers[i];
1461 				  hb_codepoint_t new_gid = 0;
1462 				  if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid)))
1463 				    return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
1464 				  out_layers[i].glyphId = new_gid;
1465 				  out_layers[i].colorIdx = c->plan->colr_palettes->get (layers[i].colorIdx);
1466 				}
1467 
1468 				return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers);
1469 			      })
1470     | hb_filter (hb_first)
1471     | hb_map_retains_sorting (hb_second)
1472     ;
1473 
1474     if (version == 0 && (!base_it || !layer_it))
1475       return_trace (false);
1476 
1477     COLR *colr_prime = c->serializer->start_embed<COLR> ();
1478     if (unlikely (!c->serializer->extend_min (colr_prime)))  return_trace (false);
1479 
1480     if (version == 0)
1481     return_trace (colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it));
1482 
1483     auto snap = c->serializer->snapshot ();
1484     if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false);
1485     if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this))
1486     {
1487       if (c->serializer->in_error ()) return_trace (false);
1488       //no more COLRv1 glyphs: downgrade to version 0
1489       c->serializer->revert (snap);
1490       return_trace (colr_prime->serialize_V0 (c->serializer, 0, base_it, layer_it));
1491     }
1492 
1493     if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false);
1494 
1495     colr_prime->layerList.serialize_subset (c, layerList, this);
1496     colr_prime->clipList.serialize_subset (c, clipList, this);
1497     colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this);
1498     //TODO: subset varStore once it's implemented in fonttools
1499     return_trace (true);
1500   }
1501 
1502   protected:
1503   HBUINT16	version;	/* Table version number (starts at 0). */
1504   HBUINT16	numBaseGlyphs;	/* Number of Base Glyph Records. */
1505   NNOffset32To<SortedUnsizedArrayOf<BaseGlyphRecord>>
1506 		baseGlyphsZ;	/* Offset to Base Glyph records. */
1507   NNOffset32To<UnsizedArrayOf<LayerRecord>>
1508 		layersZ;	/* Offset to Layer Records. */
1509   HBUINT16	numLayers;	/* Number of Layer Records. */
1510   // Version-1 additions
1511   Offset32To<BaseGlyphList>		baseGlyphList;
1512   Offset32To<LayerList>			layerList;
1513   Offset32To<ClipList>			clipList;   // Offset to ClipList table (may be NULL)
1514   Offset32To<DeltaSetIndexMap>		varIdxMap;  // Offset to DeltaSetIndexMap table (may be NULL)
1515   Offset32To<VariationStore>		varStore;
1516   public:
1517   DEFINE_SIZE_MIN (14);
1518 };
1519 
1520 } /* namespace OT */
1521 
1522 
1523 #endif /* HB_OT_COLOR_COLR_TABLE_HH */
1524