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 
34 /*
35  * COLR -- Color
36  * https://docs.microsoft.com/en-us/typography/opentype/spec/colr
37  */
38 #define HB_OT_TAG_COLR HB_TAG('C','O','L','R')
39 
40 
41 namespace OT {
42 
43 struct LayerRecord
44 {
operator hb_ot_color_layer_tOT::LayerRecord45   operator hb_ot_color_layer_t () const { return {glyphId, colorIdx}; }
46 
sanitizeOT::LayerRecord47   bool sanitize (hb_sanitize_context_t *c) const
48   {
49     TRACE_SANITIZE (this);
50     return_trace (c->check_struct (this));
51   }
52 
53   public:
54   HBGlyphID	glyphId;	/* Glyph ID of layer glyph */
55   Index		colorIdx;	/* Index value to use with a
56 				 * selected color palette.
57 				 * An index value of 0xFFFF
58 				 * is a special case indicating
59 				 * that the text foreground
60 				 * color (defined by a
61 				 * higher-level client) should
62 				 * be used and shall not be
63 				 * treated as actual index
64 				 * into CPAL ColorRecord array. */
65   public:
66   DEFINE_SIZE_STATIC (4);
67 };
68 
69 struct BaseGlyphRecord
70 {
cmpOT::BaseGlyphRecord71   int cmp (hb_codepoint_t g) const
72   { return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
73 
sanitizeOT::BaseGlyphRecord74   bool sanitize (hb_sanitize_context_t *c) const
75   {
76     TRACE_SANITIZE (this);
77     return_trace (likely (c->check_struct (this)));
78   }
79 
80   public:
81   HBGlyphID	glyphId;	/* Glyph ID of reference glyph */
82   HBUINT16	firstLayerIdx;	/* Index (from beginning of
83 				 * the Layer Records) to the
84 				 * layer record. There will be
85 				 * numLayers consecutive entries
86 				 * for this base glyph. */
87   HBUINT16	numLayers;	/* Number of color layers
88 				 * associated with this glyph */
89   public:
90   DEFINE_SIZE_STATIC (6);
91 };
92 
93 template <typename T>
94 struct Variable
95 {
sanitizeOT::Variable96   bool sanitize (hb_sanitize_context_t *c) const
97   {
98     TRACE_SANITIZE (this);
99     return_trace (c->check_struct (this));
100   }
101 
102   protected:
103   T      value;
104   VarIdx varIdx;
105   public:
106   DEFINE_SIZE_STATIC (4 + T::static_size);
107 };
108 
109 template <typename T>
110 struct NoVariable
111 {
sanitizeOT::NoVariable112   bool sanitize (hb_sanitize_context_t *c) const
113   {
114     TRACE_SANITIZE (this);
115     return_trace (c->check_struct (this));
116   }
117 
118   T      value;
119   public:
120   DEFINE_SIZE_STATIC (T::static_size);
121 };
122 
123 // Color structures
124 
125 template <template<typename> class Var>
126 struct ColorIndex
127 {
sanitizeOT::ColorIndex128   bool sanitize (hb_sanitize_context_t *c) const
129   {
130     TRACE_SANITIZE (this);
131     return_trace (c->check_struct (this));
132   }
133 
134   HBUINT16	paletteIndex;
135   Var<F2DOT14>	alpha;
136   public:
137   DEFINE_SIZE_STATIC (2 + Var<F2DOT14>::static_size);
138 };
139 
140 template <template<typename> class Var>
141 struct ColorStop
142 {
sanitizeOT::ColorStop143   bool sanitize (hb_sanitize_context_t *c) const
144   {
145     TRACE_SANITIZE (this);
146     return_trace (c->check_struct (this));
147   }
148 
149   Var<F2DOT14>		stopOffset;
150   ColorIndex<Var>		color;
151   public:
152   DEFINE_SIZE_STATIC (Var<F2DOT14>::static_size + ColorIndex<Var>::static_size);
153 };
154 
155 struct Extend : HBUINT8
156 {
157   enum {
158     EXTEND_PAD     = 0,
159     EXTEND_REPEAT  = 1,
160     EXTEND_REFLECT = 2,
161   };
162   public:
163   DEFINE_SIZE_STATIC (1);
164 };
165 
166 template <template<typename> class Var>
167 struct ColorLine
168 {
sanitizeOT::ColorLine169   bool sanitize (hb_sanitize_context_t *c) const
170   {
171     TRACE_SANITIZE (this);
172     return_trace (c->check_struct (this) &&
173                   stops.sanitize (c));
174   }
175 
176   Extend			extend;
177   Array16Of<ColorStop<Var>>	stops;
178   public:
179   DEFINE_SIZE_ARRAY_SIZED (3, stops);
180 };
181 
182 // Composition modes
183 
184 // Compositing modes are taken from https://www.w3.org/TR/compositing-1/
185 // NOTE: a brief audit of major implementations suggests most support most
186 // or all of the specified modes.
187 struct CompositeMode : HBUINT8
188 {
189   enum {
190     // Porter-Duff modes
191     // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators
192     COMPOSITE_CLEAR          =  0,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_clear
193     COMPOSITE_SRC            =  1,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_src
194     COMPOSITE_DEST           =  2,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dst
195     COMPOSITE_SRC_OVER       =  3,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcover
196     COMPOSITE_DEST_OVER      =  4,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstover
197     COMPOSITE_SRC_IN         =  5,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcin
198     COMPOSITE_DEST_IN        =  6,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstin
199     COMPOSITE_SRC_OUT        =  7,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcout
200     COMPOSITE_DEST_OUT       =  8,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstout
201     COMPOSITE_SRC_ATOP       =  9,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcatop
202     COMPOSITE_DEST_ATOP      = 10,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstatop
203     COMPOSITE_XOR            = 11,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_xor
204     COMPOSITE_PLUS           = 12,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_plus
205 
206     // Blend modes
207     // https://www.w3.org/TR/compositing-1/#blending
208     COMPOSITE_SCREEN         = 13,  // https://www.w3.org/TR/compositing-1/#blendingscreen
209     COMPOSITE_OVERLAY        = 14,  // https://www.w3.org/TR/compositing-1/#blendingoverlay
210     COMPOSITE_DARKEN         = 15,  // https://www.w3.org/TR/compositing-1/#blendingdarken
211     COMPOSITE_LIGHTEN        = 16,  // https://www.w3.org/TR/compositing-1/#blendinglighten
212     COMPOSITE_COLOR_DODGE    = 17,  // https://www.w3.org/TR/compositing-1/#blendingcolordodge
213     COMPOSITE_COLOR_BURN     = 18,  // https://www.w3.org/TR/compositing-1/#blendingcolorburn
214     COMPOSITE_HARD_LIGHT     = 19,  // https://www.w3.org/TR/compositing-1/#blendinghardlight
215     COMPOSITE_SOFT_LIGHT     = 20,  // https://www.w3.org/TR/compositing-1/#blendingsoftlight
216     COMPOSITE_DIFFERENCE     = 21,  // https://www.w3.org/TR/compositing-1/#blendingdifference
217     COMPOSITE_EXCLUSION      = 22,  // https://www.w3.org/TR/compositing-1/#blendingexclusion
218     COMPOSITE_MULTIPLY       = 23,  // https://www.w3.org/TR/compositing-1/#blendingmultiply
219 
220     // Modes that, uniquely, do not operate on components
221     // https://www.w3.org/TR/compositing-1/#blendingnonseparable
222     COMPOSITE_HSL_HUE        = 24,  // https://www.w3.org/TR/compositing-1/#blendinghue
223     COMPOSITE_HSL_SATURATION = 25,  // https://www.w3.org/TR/compositing-1/#blendingsaturation
224     COMPOSITE_HSL_COLOR      = 26,  // https://www.w3.org/TR/compositing-1/#blendingcolor
225     COMPOSITE_HSL_LUMINOSITY = 27,  // https://www.w3.org/TR/compositing-1/#blendingluminosity
226   };
227   public:
228   DEFINE_SIZE_STATIC (1);
229 };
230 
231 template <template<typename> class Var>
232 struct Affine2x3
233 {
sanitizeOT::Affine2x3234   bool sanitize (hb_sanitize_context_t *c) const
235   {
236     TRACE_SANITIZE (this);
237     return_trace (c->check_struct (this));
238   }
239 
240   Var<HBFixed> xx;
241   Var<HBFixed> yx;
242   Var<HBFixed> xy;
243   Var<HBFixed> yy;
244   Var<HBFixed> dx;
245   Var<HBFixed> dy;
246   public:
247   DEFINE_SIZE_STATIC (6 * Var<HBFixed>::static_size);
248 };
249 
250 struct PaintColrLayers
251 {
sanitizeOT::PaintColrLayers252   bool sanitize (hb_sanitize_context_t *c) const
253   {
254     TRACE_SANITIZE (this);
255     return_trace (c->check_struct (this));
256   }
257 
258   HBUINT8	format; /* format = 1 */
259   HBUINT8	numLayers;
260   HBUINT32	firstLayerIndex;  /* index into COLRv1::layersV1 */
261   public:
262   DEFINE_SIZE_STATIC (6);
263 };
264 
265 template <template<typename> class Var>
266 struct PaintSolid
267 {
sanitizeOT::PaintSolid268   bool sanitize (hb_sanitize_context_t *c) const
269   {
270     TRACE_SANITIZE (this);
271     return_trace (c->check_struct (this));
272   }
273 
274   HBUINT8		format; /* format = 2(noVar) or 3(Var)*/
275   ColorIndex<Var>	color;
276   public:
277   DEFINE_SIZE_STATIC (1 + ColorIndex<Var>::static_size);
278 };
279 
280 template <template<typename> class Var>
281 struct PaintLinearGradient
282 {
sanitizeOT::PaintLinearGradient283   bool sanitize (hb_sanitize_context_t *c) const
284   {
285     TRACE_SANITIZE (this);
286     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
287   }
288 
289   HBUINT8			format; /* format = 4(noVar) or 5 (Var) */
290   Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintLinearGradient
291                                             * table) to ColorLine subtable. */
292   Var<FWORD>			x0;
293   Var<FWORD>			y0;
294   Var<FWORD>			x1;
295   Var<FWORD>			y1;
296   Var<FWORD>			x2;
297   Var<FWORD>			y2;
298   public:
299   DEFINE_SIZE_STATIC (4 + 6 * Var<FWORD>::static_size);
300 };
301 
302 template <template<typename> class Var>
303 struct PaintRadialGradient
304 {
sanitizeOT::PaintRadialGradient305   bool sanitize (hb_sanitize_context_t *c) const
306   {
307     TRACE_SANITIZE (this);
308     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
309   }
310 
311   HBUINT8			format; /* format = 6(noVar) or 7 (Var) */
312   Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintRadialGradient
313                                             * table) to ColorLine subtable. */
314   Var<FWORD>			x0;
315   Var<FWORD>			y0;
316   Var<UFWORD>			radius0;
317   Var<FWORD>			x1;
318   Var<FWORD>			y1;
319   Var<UFWORD>			radius1;
320   public:
321   DEFINE_SIZE_STATIC (4 + 6 * Var<FWORD>::static_size);
322 };
323 
324 template <template<typename> class Var>
325 struct PaintSweepGradient
326 {
sanitizeOT::PaintSweepGradient327   bool sanitize (hb_sanitize_context_t *c) const
328   {
329     TRACE_SANITIZE (this);
330     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
331   }
332 
333   HBUINT8			format; /* format = 8(noVar) or 9 (Var) */
334   Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintSweepGradient
335                                             * table) to ColorLine subtable. */
336   Var<FWORD>			centerX;
337   Var<FWORD>			centerY;
338   Var<HBFixed>			startAngle;
339   Var<HBFixed>			endAngle;
340   public:
341   DEFINE_SIZE_STATIC (2 * Var<FWORD>::static_size + 2 * Var<HBFixed>::static_size);
342 };
343 
344 struct Paint;
345 // Paint a non-COLR glyph, filled as indicated by paint.
346 struct PaintGlyph
347 {
sanitizeOT::PaintGlyph348   bool sanitize (hb_sanitize_context_t *c) const
349   {
350     TRACE_SANITIZE (this);
351     return_trace (c->check_struct (this) && paint.sanitize (c, this));
352   }
353 
354   HBUINT8		format; /* format = 10 */
355   Offset24To<Paint>	paint;  /* Offset (from beginning of PaintGlyph table) to Paint subtable. */
356   HBUINT16		gid;
357   public:
358   DEFINE_SIZE_STATIC (6);
359 };
360 
361 struct PaintColrGlyph
362 {
sanitizeOT::PaintColrGlyph363   bool sanitize (hb_sanitize_context_t *c) const
364   {
365     TRACE_SANITIZE (this);
366     return_trace (c->check_struct (this));
367   }
368 
369   HBUINT8	format; /* format = 11 */
370   HBUINT16	gid;
371   public:
372   DEFINE_SIZE_STATIC (3);
373 };
374 
375 template <template<typename> class Var>
376 struct PaintTransform
377 {
sanitizeOT::PaintTransform378   bool sanitize (hb_sanitize_context_t *c) const
379   {
380     TRACE_SANITIZE (this);
381     return_trace (c->check_struct (this) && src.sanitize (c, this));
382   }
383 
384   HBUINT8		format; /* format = 12(noVar) or 13 (Var) */
385   Offset24To<Paint>	src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */
386   Affine2x3<Var>	transform;
387   public:
388   DEFINE_SIZE_STATIC (4 + Affine2x3<Var>::static_size);
389 };
390 
391 template <template<typename> class Var>
392 struct PaintTranslate
393 {
sanitizeOT::PaintTranslate394   bool sanitize (hb_sanitize_context_t *c) const
395   {
396     TRACE_SANITIZE (this);
397     return_trace (c->check_struct (this) && src.sanitize (c, this));
398   }
399 
400   HBUINT8		format; /* format = 14(noVar) or 15 (Var) */
401   Offset24To<Paint>	src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */
402   Var<HBFixed>		dx;
403   Var<HBFixed>		dy;
404   public:
405   DEFINE_SIZE_STATIC (4 + Var<HBFixed>::static_size);
406 };
407 
408 template <template<typename> class Var>
409 struct PaintRotate
410 {
sanitizeOT::PaintRotate411   bool sanitize (hb_sanitize_context_t *c) const
412   {
413     TRACE_SANITIZE (this);
414     return_trace (c->check_struct (this) && src.sanitize (c, this));
415   }
416 
417   HBUINT8		format; /* format = 16 (noVar) or 17(Var) */
418   Offset24To<Paint>	src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */
419   Var<HBFixed>		angle;
420   Var<HBFixed>		centerX;
421   Var<HBFixed>		centerY;
422   public:
423   DEFINE_SIZE_STATIC (4 + 3 * Var<HBFixed>::static_size);
424 };
425 
426 template <template<typename> class Var>
427 struct PaintSkew
428 {
sanitizeOT::PaintSkew429   bool sanitize (hb_sanitize_context_t *c) const
430   {
431     TRACE_SANITIZE (this);
432     return_trace (c->check_struct (this) && src.sanitize (c, this));
433   }
434 
435   HBUINT8		format; /* format = 18(noVar) or 19 (Var) */
436   Offset24To<Paint>	src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */
437   Var<HBFixed>		xSkewAngle;
438   Var<HBFixed>		ySkewAngle;
439   Var<HBFixed>		centerX;
440   Var<HBFixed>		centerY;
441   public:
442   DEFINE_SIZE_STATIC (4 + 4 * Var<HBFixed>::static_size);
443 };
444 
445 struct PaintComposite
446 {
sanitizeOT::PaintComposite447   bool sanitize (hb_sanitize_context_t *c) const
448   {
449     TRACE_SANITIZE (this);
450     return_trace (c->check_struct (this) &&
451                   src.sanitize (c, this) &&
452                   backdrop.sanitize (c, this));
453   }
454 
455   HBUINT8		format; /* format = 20 */
456   Offset24To<Paint>	src; /* Offset (from beginning of PaintComposite table) to source Paint subtable. */
457   CompositeMode		mode;   /* If mode is unrecognized use COMPOSITE_CLEAR */
458   Offset24To<Paint>	backdrop; /* Offset (from beginning of PaintComposite table) to backdrop Paint subtable. */
459   public:
460   DEFINE_SIZE_STATIC (8);
461 };
462 
463 struct Paint
464 {
465   template <typename context_t, typename ...Ts>
dispatchOT::Paint466   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
467   {
468     TRACE_DISPATCH (this, u.format);
469     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
470     switch (u.format) {
471     case 1: return_trace (c->dispatch (u.paintformat1, hb_forward<Ts> (ds)...));
472     case 2: return_trace (c->dispatch (u.paintformat2, hb_forward<Ts> (ds)...));
473     case 3: return_trace (c->dispatch (u.paintformat3, hb_forward<Ts> (ds)...));
474     case 4: return_trace (c->dispatch (u.paintformat4, hb_forward<Ts> (ds)...));
475     case 5: return_trace (c->dispatch (u.paintformat5, hb_forward<Ts> (ds)...));
476     case 6: return_trace (c->dispatch (u.paintformat6, hb_forward<Ts> (ds)...));
477     case 7: return_trace (c->dispatch (u.paintformat7, hb_forward<Ts> (ds)...));
478     case 8: return_trace (c->dispatch (u.paintformat8, hb_forward<Ts> (ds)...));
479     case 9: return_trace (c->dispatch (u.paintformat9, hb_forward<Ts> (ds)...));
480     case 10: return_trace (c->dispatch (u.paintformat10, hb_forward<Ts> (ds)...));
481     case 11: return_trace (c->dispatch (u.paintformat11, hb_forward<Ts> (ds)...));
482     case 12: return_trace (c->dispatch (u.paintformat12, hb_forward<Ts> (ds)...));
483     case 13: return_trace (c->dispatch (u.paintformat13, hb_forward<Ts> (ds)...));
484     case 14: return_trace (c->dispatch (u.paintformat14, hb_forward<Ts> (ds)...));
485     case 15: return_trace (c->dispatch (u.paintformat15, hb_forward<Ts> (ds)...));
486     case 16: return_trace (c->dispatch (u.paintformat16, hb_forward<Ts> (ds)...));
487     case 17: return_trace (c->dispatch (u.paintformat17, hb_forward<Ts> (ds)...));
488     case 18: return_trace (c->dispatch (u.paintformat18, hb_forward<Ts> (ds)...));
489     case 19: return_trace (c->dispatch (u.paintformat19, hb_forward<Ts> (ds)...));
490     case 20: return_trace (c->dispatch (u.paintformat20, hb_forward<Ts> (ds)...));
491     default:return_trace (c->default_return_value ());
492     }
493   }
494 
495   protected:
496   union {
497   HBUINT8				format;
498   PaintColrLayers			paintformat1;
499   PaintSolid<NoVariable>		paintformat2;
500   PaintSolid<Variable>			paintformat3;
501   PaintLinearGradient<NoVariable>	paintformat4;
502   PaintLinearGradient<Variable>		paintformat5;
503   PaintRadialGradient<NoVariable>	paintformat6;
504   PaintRadialGradient<Variable>		paintformat7;
505   PaintSweepGradient<NoVariable>	paintformat8;
506   PaintSweepGradient<Variable>		paintformat9;
507   PaintGlyph				paintformat10;
508   PaintColrGlyph			paintformat11;
509   PaintTransform<NoVariable>		paintformat12;
510   PaintTransform<Variable>		paintformat13;
511   PaintTranslate<NoVariable>		paintformat14;
512   PaintTranslate<Variable>		paintformat15;
513   PaintRotate<NoVariable>		paintformat16;
514   PaintRotate<Variable>			paintformat17;
515   PaintSkew<NoVariable>			paintformat18;
516   PaintSkew<Variable>			paintformat19;
517   PaintComposite			paintformat20;
518   } u;
519 };
520 
521 struct BaseGlyphV1Record
522 {
cmpOT::BaseGlyphV1Record523   int cmp (hb_codepoint_t g) const
524   { return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
525 
sanitizeOT::BaseGlyphV1Record526   bool sanitize (hb_sanitize_context_t *c) const
527   {
528     TRACE_SANITIZE (this);
529     return_trace (likely (c->check_struct (this) && paint.sanitize (c, this)));
530   }
531 
532   public:
533   HBGlyphID		glyphId;    /* Glyph ID of reference glyph */
534   Offset32To<Paint>	paint;      /* Offset (from beginning of BaseGlyphV1Record) to Paint,
535                                      * Typically PaintColrLayers */
536   public:
537   DEFINE_SIZE_STATIC (6);
538 };
539 
540 typedef SortedArray32Of<BaseGlyphV1Record> BaseGlyphV1List;
541 
542 struct LayerV1List : Array32OfOffset32To<Paint>
543 {
get_paintOT::LayerV1List544   const Paint& get_paint (unsigned i) const
545   { return this+(*this)[i]; }
546 
sanitizeOT::LayerV1List547   bool sanitize (hb_sanitize_context_t *c) const
548   {
549     TRACE_SANITIZE (this);
550     return_trace (Array32OfOffset32To<Paint>::sanitize (c, this));
551   }
552 };
553 
554 struct COLR
555 {
556   static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
557 
has_dataOT::COLR558   bool has_data () const { return numBaseGlyphs; }
559 
get_glyph_layersOT::COLR560   unsigned int get_glyph_layers (hb_codepoint_t       glyph,
561 				 unsigned int         start_offset,
562 				 unsigned int        *count, /* IN/OUT.  May be NULL. */
563 				 hb_ot_color_layer_t *layers /* OUT.     May be NULL. */) const
564   {
565     const BaseGlyphRecord &record = (this+baseGlyphsZ).bsearch (numBaseGlyphs, glyph);
566 
567     hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
568     hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
569 								       record.numLayers);
570     if (count)
571     {
572       + glyph_layers.sub_array (start_offset, count)
573       | hb_sink (hb_array (layers, *count))
574       ;
575     }
576     return glyph_layers.length;
577   }
578 
579   struct accelerator_t
580   {
accelerator_tOT::COLR::accelerator_t581     accelerator_t () {}
~accelerator_tOT::COLR::accelerator_t582     ~accelerator_t () { fini (); }
583 
initOT::COLR::accelerator_t584     void init (hb_face_t *face)
585     { colr = hb_sanitize_context_t ().reference_table<COLR> (face); }
586 
finiOT::COLR::accelerator_t587     void fini () { this->colr.destroy (); }
588 
is_validOT::COLR::accelerator_t589     bool is_valid () { return colr.get_blob ()->length; }
590 
closure_glyphsOT::COLR::accelerator_t591     void closure_glyphs (hb_codepoint_t glyph,
592 			 hb_set_t *related_ids /* OUT */) const
593     { colr->closure_glyphs (glyph, related_ids); }
594 
595     private:
596     hb_blob_ptr_t<COLR> colr;
597   };
598 
closure_glyphsOT::COLR599   void closure_glyphs (hb_codepoint_t glyph,
600 		       hb_set_t *related_ids /* OUT */) const
601   {
602     const BaseGlyphRecord *record = get_base_glyph_record (glyph);
603     if (!record) return;
604 
605     auto glyph_layers = (this+layersZ).as_array (numLayers).sub_array (record->firstLayerIdx,
606 								       record->numLayers);
607     if (!glyph_layers.length) return;
608     related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size);
609   }
610 
sanitizeOT::COLR611   bool sanitize (hb_sanitize_context_t *c) const
612   {
613     TRACE_SANITIZE (this);
614     return_trace (c->check_struct (this) &&
615                   (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
616                   (this+layersZ).sanitize (c, numLayers) &&
617                   (version == 0 || (version == 1 &&
618                                     baseGlyphsV1List.sanitize (c, this) &&
619                                     layersV1.sanitize (c, this) &&
620                                     varStore.sanitize (c, this))));
621   }
622 
623   template<typename BaseIterator, typename LayerIterator,
624 	   hb_requires (hb_is_iterator (BaseIterator)),
625 	   hb_requires (hb_is_iterator (LayerIterator))>
serializeOT::COLR626   bool serialize (hb_serialize_context_t *c,
627 		  unsigned version,
628 		  BaseIterator base_it,
629 		  LayerIterator layer_it)
630   {
631     TRACE_SERIALIZE (this);
632     if (unlikely (base_it.len () != layer_it.len ()))
633       return_trace (false);
634 
635     if (unlikely (!c->extend_min (this))) return_trace (false);
636     this->version = version;
637     numLayers = 0;
638     numBaseGlyphs = base_it.len ();
639     baseGlyphsZ = COLR::min_size;
640     layersZ = COLR::min_size + numBaseGlyphs * BaseGlyphRecord::min_size;
641 
642     for (const hb_item_type<BaseIterator> _ : + base_it.iter ())
643     {
644       auto* record = c->embed (_);
645       if (unlikely (!record)) return_trace (false);
646       record->firstLayerIdx = numLayers;
647       numLayers += record->numLayers;
648     }
649 
650     for (const hb_item_type<LayerIterator>& _ : + layer_it.iter ())
651       _.as_array ().copy (c);
652 
653     return_trace (true);
654   }
655 
get_base_glyph_recordOT::COLR656   const BaseGlyphRecord* get_base_glyph_record (hb_codepoint_t gid) const
657   {
658     if ((unsigned int) gid == 0) // Ignore notdef.
659       return nullptr;
660     const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, (unsigned int) gid);
661     if ((record && (hb_codepoint_t) record->glyphId != gid))
662       record = nullptr;
663     return record;
664   }
665 
subsetOT::COLR666   bool subset (hb_subset_context_t *c) const
667   {
668     TRACE_SUBSET (this);
669 
670     const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
671 
672     auto base_it =
673     + hb_range (c->plan->num_output_glyphs ())
674     | hb_map_retains_sorting ([&](hb_codepoint_t new_gid)
675 			      {
676 				hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
677 
678 				const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
679 				if (unlikely (!old_record))
680 				  return hb_pair_t<bool, BaseGlyphRecord> (false, Null (BaseGlyphRecord));
681 
682 				BaseGlyphRecord new_record = {};
683 				new_record.glyphId = new_gid;
684 				new_record.numLayers = old_record->numLayers;
685 				return hb_pair_t<bool, BaseGlyphRecord> (true, new_record);
686 			      })
687     | hb_filter (hb_first)
688     | hb_map_retains_sorting (hb_second)
689     ;
690 
691     auto layer_it =
692     + hb_range (c->plan->num_output_glyphs ())
693     | hb_map (reverse_glyph_map)
694     | hb_map_retains_sorting ([&](hb_codepoint_t old_gid)
695 			      {
696 				const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
697 				hb_vector_t<LayerRecord> out_layers;
698 
699 				if (unlikely (!old_record ||
700 					      old_record->firstLayerIdx >= numLayers ||
701 					      old_record->firstLayerIdx + old_record->numLayers > numLayers))
702 				  return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
703 
704 				auto layers = (this+layersZ).as_array (numLayers).sub_array (old_record->firstLayerIdx,
705 											     old_record->numLayers);
706 				out_layers.resize (layers.length);
707 				for (unsigned int i = 0; i < layers.length; i++) {
708 				  out_layers[i] = layers[i];
709 				  hb_codepoint_t new_gid = 0;
710 				  if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid)))
711 				    return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
712 				  out_layers[i].glyphId = new_gid;
713 				}
714 
715 				return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers);
716 			      })
717     | hb_filter (hb_first)
718     | hb_map_retains_sorting (hb_second)
719     ;
720 
721     if (unlikely (!base_it || !layer_it || base_it.len () != layer_it.len ()))
722       return_trace (false);
723 
724     COLR *colr_prime = c->serializer->start_embed<COLR> ();
725     return_trace (colr_prime->serialize (c->serializer, version, base_it, layer_it));
726   }
727 
728   protected:
729   HBUINT16	version;	/* Table version number (starts at 0). */
730   HBUINT16	numBaseGlyphs;	/* Number of Base Glyph Records. */
731   NNOffset32To<SortedUnsizedArrayOf<BaseGlyphRecord>>
732 		baseGlyphsZ;	/* Offset to Base Glyph records. */
733   NNOffset32To<UnsizedArrayOf<LayerRecord>>
734 		layersZ;	/* Offset to Layer Records. */
735   HBUINT16	numLayers;	/* Number of Layer Records. */
736   // Version-1 additions
737   Offset32To<BaseGlyphV1List>		baseGlyphsV1List;
738   Offset32To<LayerV1List>		layersV1;
739   Offset32To<VariationStore>		varStore;
740   public:
741   DEFINE_SIZE_MIN (14);
742 };
743 
744 } /* namespace OT */
745 
746 
747 #endif /* HB_OT_COLOR_COLR_TABLE_HH */
748