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