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 ItemVarStoreInstancer &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_MAX_GRAPH_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 ItemVarStoreInstancer &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
add_var_idxesOT::hb_colrv1_closure_context_t162 void add_var_idxes (unsigned first_var_idx, unsigned num_idxes)
163 {
164 if (!num_idxes || first_var_idx == VarIdx::NO_VARIATION) return;
165 variation_indices->add_range (first_var_idx, first_var_idx + num_idxes - 1);
166 }
167
168 public:
169 const void *base;
170 hb_set_t visited_paint;
171 hb_set_t *glyphs;
172 hb_set_t *layer_indices;
173 hb_set_t *palette_indices;
174 hb_set_t *variation_indices;
175 unsigned num_var_idxes;
176 unsigned nesting_level_left;
177
hb_colrv1_closure_context_tOT::hb_colrv1_closure_context_t178 hb_colrv1_closure_context_t (const void *base_,
179 hb_set_t *glyphs_,
180 hb_set_t *layer_indices_,
181 hb_set_t *palette_indices_,
182 hb_set_t *variation_indices_,
183 unsigned num_var_idxes_ = 1,
184 unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
185 base (base_),
186 glyphs (glyphs_),
187 layer_indices (layer_indices_),
188 palette_indices (palette_indices_),
189 variation_indices (variation_indices_),
190 num_var_idxes (num_var_idxes_),
191 nesting_level_left (nesting_level_left_)
192 {}
193 };
194
195 struct LayerRecord
196 {
operator hb_ot_color_layer_tOT::LayerRecord197 operator hb_ot_color_layer_t () const { return {glyphId, colorIdx}; }
198
sanitizeOT::LayerRecord199 bool sanitize (hb_sanitize_context_t *c) const
200 {
201 TRACE_SANITIZE (this);
202 return_trace (c->check_struct (this));
203 }
204
205 public:
206 HBGlyphID16 glyphId; /* Glyph ID of layer glyph */
207 Index colorIdx; /* Index value to use with a
208 * selected color palette.
209 * An index value of 0xFFFF
210 * is a special case indicating
211 * that the text foreground
212 * color (defined by a
213 * higher-level client) should
214 * be used and shall not be
215 * treated as actual index
216 * into CPAL ColorRecord array. */
217 public:
218 DEFINE_SIZE_STATIC (4);
219 };
220
221 struct BaseGlyphRecord
222 {
cmpOT::BaseGlyphRecord223 int cmp (hb_codepoint_t g) const
224 { return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
225
sanitizeOT::BaseGlyphRecord226 bool sanitize (hb_sanitize_context_t *c) const
227 {
228 TRACE_SANITIZE (this);
229 return_trace (c->check_struct (this));
230 }
231
232 public:
233 HBGlyphID16 glyphId; /* Glyph ID of reference glyph */
234 HBUINT16 firstLayerIdx; /* Index (from beginning of
235 * the Layer Records) to the
236 * layer record. There will be
237 * numLayers consecutive entries
238 * for this base glyph. */
239 HBUINT16 numLayers; /* Number of color layers
240 * associated with this glyph */
241 public:
242 DEFINE_SIZE_STATIC (6);
243 };
244
245 template <typename T>
246 struct Variable
247 {
248 static constexpr bool is_variable = true;
249
copyOT::Variable250 Variable<T>* copy (hb_serialize_context_t *c) const
251 {
252 TRACE_SERIALIZE (this);
253 return_trace (c->embed (this));
254 }
255
closurev1OT::Variable256 void closurev1 (hb_colrv1_closure_context_t* c) const
257 {
258 c->num_var_idxes = 0;
259 // update c->num_var_idxes during value closure
260 value.closurev1 (c);
261 c->add_var_idxes (varIdxBase, c->num_var_idxes);
262 }
263
subsetOT::Variable264 bool subset (hb_subset_context_t *c,
265 const ItemVarStoreInstancer &instancer) const
266 {
267 TRACE_SUBSET (this);
268 if (!value.subset (c, instancer, varIdxBase)) return_trace (false);
269 if (c->plan->all_axes_pinned)
270 return_trace (true);
271
272 VarIdx new_varidx;
273 new_varidx = varIdxBase;
274 if (varIdxBase != VarIdx::NO_VARIATION)
275 {
276 hb_pair_t<unsigned, int> *new_varidx_delta;
277 if (!c->plan->colrv1_variation_idx_delta_map.has (varIdxBase, &new_varidx_delta))
278 return_trace (false);
279
280 new_varidx = hb_first (*new_varidx_delta);
281 }
282
283 return_trace (c->serializer->embed (new_varidx));
284 }
285
sanitizeOT::Variable286 bool sanitize (hb_sanitize_context_t *c) const
287 {
288 TRACE_SANITIZE (this);
289 return_trace (c->check_struct (this) && value.sanitize (c));
290 }
291
paint_glyphOT::Variable292 void paint_glyph (hb_paint_context_t *c) const
293 {
294 TRACE_PAINT (this);
295 value.paint_glyph (c, varIdxBase);
296 }
297
get_color_stopOT::Variable298 void get_color_stop (hb_paint_context_t *c,
299 hb_color_stop_t *stop,
300 const ItemVarStoreInstancer &instancer) const
301 {
302 value.get_color_stop (c, stop, varIdxBase, instancer);
303 }
304
get_extendOT::Variable305 hb_paint_extend_t get_extend () const
306 {
307 return value.get_extend ();
308 }
309
310 protected:
311 T value;
312 public:
313 VarIdx varIdxBase;
314 public:
315 DEFINE_SIZE_MIN (VarIdx::static_size + T::min_size);
316 };
317
318 template <typename T>
319 struct NoVariable
320 {
321 static constexpr bool is_variable = false;
322
323 static constexpr uint32_t varIdxBase = VarIdx::NO_VARIATION;
324
copyOT::NoVariable325 NoVariable<T>* copy (hb_serialize_context_t *c) const
326 {
327 TRACE_SERIALIZE (this);
328 return_trace (c->embed (this));
329 }
330
closurev1OT::NoVariable331 void closurev1 (hb_colrv1_closure_context_t* c) const
332 { value.closurev1 (c); }
333
subsetOT::NoVariable334 bool subset (hb_subset_context_t *c,
335 const ItemVarStoreInstancer &instancer) const
336 {
337 TRACE_SUBSET (this);
338 return_trace (value.subset (c, instancer, varIdxBase));
339 }
340
sanitizeOT::NoVariable341 bool sanitize (hb_sanitize_context_t *c) const
342 {
343 TRACE_SANITIZE (this);
344 return_trace (c->check_struct (this) && value.sanitize (c));
345 }
346
paint_glyphOT::NoVariable347 void paint_glyph (hb_paint_context_t *c) const
348 {
349 TRACE_PAINT (this);
350 value.paint_glyph (c, varIdxBase);
351 }
352
get_color_stopOT::NoVariable353 void get_color_stop (hb_paint_context_t *c,
354 hb_color_stop_t *stop,
355 const ItemVarStoreInstancer &instancer) const
356 {
357 value.get_color_stop (c, stop, VarIdx::NO_VARIATION, instancer);
358 }
359
get_extendOT::NoVariable360 hb_paint_extend_t get_extend () const
361 {
362 return value.get_extend ();
363 }
364
365 T value;
366 public:
367 DEFINE_SIZE_MIN (T::min_size);
368 };
369
370 // Color structures
371
372 struct ColorStop
373 {
closurev1OT::ColorStop374 void closurev1 (hb_colrv1_closure_context_t* c) const
375 {
376 c->add_palette_index (paletteIndex);
377 c->num_var_idxes = 2;
378 }
379
subsetOT::ColorStop380 bool subset (hb_subset_context_t *c,
381 const ItemVarStoreInstancer &instancer,
382 uint32_t varIdxBase) const
383 {
384 TRACE_SUBSET (this);
385 auto *out = c->serializer->embed (*this);
386 if (unlikely (!out)) return_trace (false);
387
388 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
389 {
390 out->stopOffset.set_float (stopOffset.to_float(instancer (varIdxBase, 0)));
391 out->alpha.set_float (alpha.to_float (instancer (varIdxBase, 1)));
392 }
393
394 return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex),
395 HB_SERIALIZE_ERROR_INT_OVERFLOW));
396 }
397
sanitizeOT::ColorStop398 bool sanitize (hb_sanitize_context_t *c) const
399 {
400 TRACE_SANITIZE (this);
401 return_trace (c->check_struct (this));
402 }
403
get_color_stopOT::ColorStop404 void get_color_stop (hb_paint_context_t *c,
405 hb_color_stop_t *out,
406 uint32_t varIdx,
407 const ItemVarStoreInstancer &instancer) const
408 {
409 out->offset = stopOffset.to_float(instancer (varIdx, 0));
410 out->color = c->get_color (paletteIndex,
411 alpha.to_float (instancer (varIdx, 1)),
412 &out->is_foreground);
413 }
414
415 F2DOT14 stopOffset;
416 HBUINT16 paletteIndex;
417 F2DOT14 alpha;
418 public:
419 DEFINE_SIZE_STATIC (2 + 2 * F2DOT14::static_size);
420 };
421
422 struct Extend : HBUINT8
423 {
424 enum {
425 EXTEND_PAD = 0,
426 EXTEND_REPEAT = 1,
427 EXTEND_REFLECT = 2,
428 };
429 public:
430 DEFINE_SIZE_STATIC (1);
431 };
432
433 template <template<typename> class Var>
434 struct ColorLine
435 {
closurev1OT::ColorLine436 void closurev1 (hb_colrv1_closure_context_t* c) const
437 {
438 for (const auto &stop : stops.iter ())
439 stop.closurev1 (c);
440 }
441
subsetOT::ColorLine442 bool subset (hb_subset_context_t *c,
443 const ItemVarStoreInstancer &instancer) const
444 {
445 TRACE_SUBSET (this);
446 auto *out = c->serializer->start_embed (this);
447 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
448
449 if (!c->serializer->check_assign (out->extend, extend, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
450 if (!c->serializer->check_assign (out->stops.len, stops.len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)) return_trace (false);
451
452 for (const auto& stop : stops.iter ())
453 {
454 if (!stop.subset (c, instancer)) return_trace (false);
455 }
456 return_trace (true);
457 }
458
sanitizeOT::ColorLine459 bool sanitize (hb_sanitize_context_t *c) const
460 {
461 TRACE_SANITIZE (this);
462 return_trace (c->check_struct (this) &&
463 stops.sanitize (c));
464 }
465
466 /* get up to count stops from start */
467 unsigned int
get_color_stopsOT::ColorLine468 get_color_stops (hb_paint_context_t *c,
469 unsigned int start,
470 unsigned int *count,
471 hb_color_stop_t *color_stops,
472 const ItemVarStoreInstancer &instancer) const
473 {
474 unsigned int len = stops.len;
475
476 if (count && color_stops)
477 {
478 unsigned int i;
479 for (i = 0; i < *count && start + i < len; i++)
480 stops[start + i].get_color_stop (c, &color_stops[i], instancer);
481 *count = i;
482 }
483
484 return len;
485 }
486
static_get_color_stopsOT::ColorLine487 HB_INTERNAL static unsigned int static_get_color_stops (hb_color_line_t *color_line,
488 void *color_line_data,
489 unsigned int start,
490 unsigned int *count,
491 hb_color_stop_t *color_stops,
492 void *user_data)
493 {
494 const ColorLine *thiz = (const ColorLine *) color_line_data;
495 hb_paint_context_t *c = (hb_paint_context_t *) user_data;
496 return thiz->get_color_stops (c, start, count, color_stops, c->instancer);
497 }
498
get_extendOT::ColorLine499 hb_paint_extend_t get_extend () const
500 {
501 return (hb_paint_extend_t) (unsigned int) extend;
502 }
503
static_get_extendOT::ColorLine504 HB_INTERNAL static hb_paint_extend_t static_get_extend (hb_color_line_t *color_line,
505 void *color_line_data,
506 void *user_data)
507 {
508 const ColorLine *thiz = (const ColorLine *) color_line_data;
509 return thiz->get_extend ();
510 }
511
512 Extend extend;
513 Array16Of<Var<ColorStop>> stops;
514 public:
515 DEFINE_SIZE_ARRAY_SIZED (3, stops);
516 };
517
518 // Composition modes
519
520 // Compositing modes are taken from https://www.w3.org/TR/compositing-1/
521 // NOTE: a brief audit of major implementations suggests most support most
522 // or all of the specified modes.
523 struct CompositeMode : HBUINT8
524 {
525 enum {
526 // Porter-Duff modes
527 // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators
528 COMPOSITE_CLEAR = 0, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_clear
529 COMPOSITE_SRC = 1, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_src
530 COMPOSITE_DEST = 2, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dst
531 COMPOSITE_SRC_OVER = 3, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcover
532 COMPOSITE_DEST_OVER = 4, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstover
533 COMPOSITE_SRC_IN = 5, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcin
534 COMPOSITE_DEST_IN = 6, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstin
535 COMPOSITE_SRC_OUT = 7, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcout
536 COMPOSITE_DEST_OUT = 8, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstout
537 COMPOSITE_SRC_ATOP = 9, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcatop
538 COMPOSITE_DEST_ATOP = 10, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstatop
539 COMPOSITE_XOR = 11, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_xor
540 COMPOSITE_PLUS = 12, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_plus
541
542 // Blend modes
543 // https://www.w3.org/TR/compositing-1/#blending
544 COMPOSITE_SCREEN = 13, // https://www.w3.org/TR/compositing-1/#blendingscreen
545 COMPOSITE_OVERLAY = 14, // https://www.w3.org/TR/compositing-1/#blendingoverlay
546 COMPOSITE_DARKEN = 15, // https://www.w3.org/TR/compositing-1/#blendingdarken
547 COMPOSITE_LIGHTEN = 16, // https://www.w3.org/TR/compositing-1/#blendinglighten
548 COMPOSITE_COLOR_DODGE = 17, // https://www.w3.org/TR/compositing-1/#blendingcolordodge
549 COMPOSITE_COLOR_BURN = 18, // https://www.w3.org/TR/compositing-1/#blendingcolorburn
550 COMPOSITE_HARD_LIGHT = 19, // https://www.w3.org/TR/compositing-1/#blendinghardlight
551 COMPOSITE_SOFT_LIGHT = 20, // https://www.w3.org/TR/compositing-1/#blendingsoftlight
552 COMPOSITE_DIFFERENCE = 21, // https://www.w3.org/TR/compositing-1/#blendingdifference
553 COMPOSITE_EXCLUSION = 22, // https://www.w3.org/TR/compositing-1/#blendingexclusion
554 COMPOSITE_MULTIPLY = 23, // https://www.w3.org/TR/compositing-1/#blendingmultiply
555
556 // Modes that, uniquely, do not operate on components
557 // https://www.w3.org/TR/compositing-1/#blendingnonseparable
558 COMPOSITE_HSL_HUE = 24, // https://www.w3.org/TR/compositing-1/#blendinghue
559 COMPOSITE_HSL_SATURATION = 25, // https://www.w3.org/TR/compositing-1/#blendingsaturation
560 COMPOSITE_HSL_COLOR = 26, // https://www.w3.org/TR/compositing-1/#blendingcolor
561 COMPOSITE_HSL_LUMINOSITY = 27, // https://www.w3.org/TR/compositing-1/#blendingluminosity
562 };
563 public:
564 DEFINE_SIZE_STATIC (1);
565 };
566
567 struct Affine2x3
568 {
sanitizeOT::Affine2x3569 bool sanitize (hb_sanitize_context_t *c) const
570 {
571 TRACE_SANITIZE (this);
572 return_trace (c->check_struct (this));
573 }
574
closurev1OT::Affine2x3575 void closurev1 (hb_colrv1_closure_context_t* c) const
576 { c->num_var_idxes = 6; }
577
subsetOT::Affine2x3578 bool subset (hb_subset_context_t *c,
579 const ItemVarStoreInstancer &instancer,
580 uint32_t varIdxBase) const
581 {
582 TRACE_SUBSET (this);
583 auto *out = c->serializer->embed (*this);
584 if (unlikely (!out)) return_trace (false);
585 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
586 {
587 out->xx.set_float (xx.to_float(instancer (varIdxBase, 0)));
588 out->yx.set_float (yx.to_float(instancer (varIdxBase, 1)));
589 out->xy.set_float (xy.to_float(instancer (varIdxBase, 2)));
590 out->yy.set_float (yy.to_float(instancer (varIdxBase, 3)));
591 out->dx.set_float (dx.to_float(instancer (varIdxBase, 4)));
592 out->dy.set_float (dy.to_float(instancer (varIdxBase, 5)));
593 }
594 return_trace (true);
595 }
596
paint_glyphOT::Affine2x3597 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
598 {
599 TRACE_PAINT (this);
600 c->funcs->push_transform (c->data,
601 xx.to_float (c->instancer (varIdxBase, 0)),
602 yx.to_float (c->instancer (varIdxBase, 1)),
603 xy.to_float (c->instancer (varIdxBase, 2)),
604 yy.to_float (c->instancer (varIdxBase, 3)),
605 dx.to_float (c->instancer (varIdxBase, 4)),
606 dy.to_float (c->instancer (varIdxBase, 5)));
607 }
608
609 F16DOT16 xx;
610 F16DOT16 yx;
611 F16DOT16 xy;
612 F16DOT16 yy;
613 F16DOT16 dx;
614 F16DOT16 dy;
615 public:
616 DEFINE_SIZE_STATIC (6 * F16DOT16::static_size);
617 };
618
619 struct PaintColrLayers
620 {
621 void closurev1 (hb_colrv1_closure_context_t* c) const;
622
subsetOT::PaintColrLayers623 bool subset (hb_subset_context_t *c,
624 const ItemVarStoreInstancer &instancer HB_UNUSED) const
625 {
626 TRACE_SUBSET (this);
627 auto *out = c->serializer->embed (this);
628 if (unlikely (!out)) return_trace (false);
629 return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers.get (firstLayerIndex),
630 HB_SERIALIZE_ERROR_INT_OVERFLOW));
631
632 return_trace (true);
633 }
634
sanitizeOT::PaintColrLayers635 bool sanitize (hb_sanitize_context_t *c) const
636 {
637 TRACE_SANITIZE (this);
638 return_trace (c->check_struct (this));
639 }
640
641 inline void paint_glyph (hb_paint_context_t *c) const;
642
643 HBUINT8 format; /* format = 1 */
644 HBUINT8 numLayers;
645 HBUINT32 firstLayerIndex; /* index into COLRv1::layerList */
646 public:
647 DEFINE_SIZE_STATIC (6);
648 };
649
650 struct PaintSolid
651 {
closurev1OT::PaintSolid652 void closurev1 (hb_colrv1_closure_context_t* c) const
653 {
654 c->add_palette_index (paletteIndex);
655 c->num_var_idxes = 1;
656 }
657
subsetOT::PaintSolid658 bool subset (hb_subset_context_t *c,
659 const ItemVarStoreInstancer &instancer,
660 uint32_t varIdxBase) const
661 {
662 TRACE_SUBSET (this);
663 auto *out = c->serializer->embed (*this);
664 if (unlikely (!out)) return_trace (false);
665
666 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
667 out->alpha.set_float (alpha.to_float (instancer (varIdxBase, 0)));
668
669 if (format == 3 && c->plan->all_axes_pinned)
670 out->format = 2;
671
672 return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex),
673 HB_SERIALIZE_ERROR_INT_OVERFLOW));
674 }
675
sanitizeOT::PaintSolid676 bool sanitize (hb_sanitize_context_t *c) const
677 {
678 TRACE_SANITIZE (this);
679 return_trace (c->check_struct (this));
680 }
681
paint_glyphOT::PaintSolid682 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
683 {
684 TRACE_PAINT (this);
685 hb_bool_t is_foreground;
686 hb_color_t color;
687
688 color = c->get_color (paletteIndex,
689 alpha.to_float (c->instancer (varIdxBase, 0)),
690 &is_foreground);
691 c->funcs->color (c->data, is_foreground, color);
692 }
693
694 HBUINT8 format; /* format = 2(noVar) or 3(Var)*/
695 HBUINT16 paletteIndex;
696 F2DOT14 alpha;
697 public:
698 DEFINE_SIZE_STATIC (3 + F2DOT14::static_size);
699 };
700
701 template <template<typename> class Var>
702 struct PaintLinearGradient
703 {
closurev1OT::PaintLinearGradient704 void closurev1 (hb_colrv1_closure_context_t* c) const
705 {
706 (this+colorLine).closurev1 (c);
707 c->num_var_idxes = 6;
708 }
709
subsetOT::PaintLinearGradient710 bool subset (hb_subset_context_t *c,
711 const ItemVarStoreInstancer &instancer,
712 uint32_t varIdxBase) const
713 {
714 TRACE_SUBSET (this);
715 auto *out = c->serializer->embed (this);
716 if (unlikely (!out)) return_trace (false);
717
718 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
719 {
720 out->x0 = x0 + (int) roundf (instancer (varIdxBase, 0));
721 out->y0 = y0 + (int) roundf (instancer (varIdxBase, 1));
722 out->x1 = x1 + (int) roundf (instancer (varIdxBase, 2));
723 out->y1 = y1 + (int) roundf (instancer (varIdxBase, 3));
724 out->x2 = x2 + (int) roundf (instancer (varIdxBase, 4));
725 out->y2 = y2 + (int) roundf (instancer (varIdxBase, 5));
726 }
727
728 if (format == 5 && c->plan->all_axes_pinned)
729 out->format = 4;
730
731 return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer));
732 }
733
sanitizeOT::PaintLinearGradient734 bool sanitize (hb_sanitize_context_t *c) const
735 {
736 TRACE_SANITIZE (this);
737 return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
738 }
739
paint_glyphOT::PaintLinearGradient740 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
741 {
742 TRACE_PAINT (this);
743 hb_color_line_t cl = {
744 (void *) &(this+colorLine),
745 (this+colorLine).static_get_color_stops, c,
746 (this+colorLine).static_get_extend, nullptr
747 };
748
749 c->funcs->linear_gradient (c->data, &cl,
750 x0 + c->instancer (varIdxBase, 0),
751 y0 + c->instancer (varIdxBase, 1),
752 x1 + c->instancer (varIdxBase, 2),
753 y1 + c->instancer (varIdxBase, 3),
754 x2 + c->instancer (varIdxBase, 4),
755 y2 + c->instancer (varIdxBase, 5));
756 }
757
758 HBUINT8 format; /* format = 4(noVar) or 5 (Var) */
759 Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintLinearGradient
760 * table) to ColorLine subtable. */
761 FWORD x0;
762 FWORD y0;
763 FWORD x1;
764 FWORD y1;
765 FWORD x2;
766 FWORD y2;
767 public:
768 DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size);
769 };
770
771 template <template<typename> class Var>
772 struct PaintRadialGradient
773 {
closurev1OT::PaintRadialGradient774 void closurev1 (hb_colrv1_closure_context_t* c) const
775 {
776 (this+colorLine).closurev1 (c);
777 c->num_var_idxes = 6;
778 }
779
subsetOT::PaintRadialGradient780 bool subset (hb_subset_context_t *c,
781 const ItemVarStoreInstancer &instancer,
782 uint32_t varIdxBase) const
783 {
784 TRACE_SUBSET (this);
785 auto *out = c->serializer->embed (this);
786 if (unlikely (!out)) return_trace (false);
787
788 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
789 {
790 out->x0 = x0 + (int) roundf (instancer (varIdxBase, 0));
791 out->y0 = y0 + (int) roundf (instancer (varIdxBase, 1));
792 out->radius0 = radius0 + (unsigned) roundf (instancer (varIdxBase, 2));
793 out->x1 = x1 + (int) roundf (instancer (varIdxBase, 3));
794 out->y1 = y1 + (int) roundf (instancer (varIdxBase, 4));
795 out->radius1 = radius1 + (unsigned) roundf (instancer (varIdxBase, 5));
796 }
797
798 if (format == 7 && c->plan->all_axes_pinned)
799 out->format = 6;
800
801 return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer));
802 }
803
sanitizeOT::PaintRadialGradient804 bool sanitize (hb_sanitize_context_t *c) const
805 {
806 TRACE_SANITIZE (this);
807 return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
808 }
809
paint_glyphOT::PaintRadialGradient810 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
811 {
812 TRACE_PAINT (this);
813 hb_color_line_t cl = {
814 (void *) &(this+colorLine),
815 (this+colorLine).static_get_color_stops, c,
816 (this+colorLine).static_get_extend, nullptr
817 };
818
819 c->funcs->radial_gradient (c->data, &cl,
820 x0 + c->instancer (varIdxBase, 0),
821 y0 + c->instancer (varIdxBase, 1),
822 radius0 + c->instancer (varIdxBase, 2),
823 x1 + c->instancer (varIdxBase, 3),
824 y1 + c->instancer (varIdxBase, 4),
825 radius1 + c->instancer (varIdxBase, 5));
826 }
827
828 HBUINT8 format; /* format = 6(noVar) or 7 (Var) */
829 Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintRadialGradient
830 * table) to ColorLine subtable. */
831 FWORD x0;
832 FWORD y0;
833 UFWORD radius0;
834 FWORD x1;
835 FWORD y1;
836 UFWORD radius1;
837 public:
838 DEFINE_SIZE_STATIC (4 + 6 * FWORD::static_size);
839 };
840
841 template <template<typename> class Var>
842 struct PaintSweepGradient
843 {
closurev1OT::PaintSweepGradient844 void closurev1 (hb_colrv1_closure_context_t* c) const
845 {
846 (this+colorLine).closurev1 (c);
847 c->num_var_idxes = 4;
848 }
849
subsetOT::PaintSweepGradient850 bool subset (hb_subset_context_t *c,
851 const ItemVarStoreInstancer &instancer,
852 uint32_t varIdxBase) const
853 {
854 TRACE_SUBSET (this);
855 auto *out = c->serializer->embed (this);
856 if (unlikely (!out)) return_trace (false);
857
858 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
859 {
860 out->centerX = centerX + (int) roundf (instancer (varIdxBase, 0));
861 out->centerY = centerY + (int) roundf (instancer (varIdxBase, 1));
862 out->startAngle.set_float (startAngle.to_float (instancer (varIdxBase, 2)));
863 out->endAngle.set_float (endAngle.to_float (instancer (varIdxBase, 3)));
864 }
865
866 if (format == 9 && c->plan->all_axes_pinned)
867 out->format = 8;
868
869 return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer));
870 }
871
sanitizeOT::PaintSweepGradient872 bool sanitize (hb_sanitize_context_t *c) const
873 {
874 TRACE_SANITIZE (this);
875 return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
876 }
877
paint_glyphOT::PaintSweepGradient878 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
879 {
880 TRACE_PAINT (this);
881 hb_color_line_t cl = {
882 (void *) &(this+colorLine),
883 (this+colorLine).static_get_color_stops, c,
884 (this+colorLine).static_get_extend, nullptr
885 };
886
887 c->funcs->sweep_gradient (c->data, &cl,
888 centerX + c->instancer (varIdxBase, 0),
889 centerY + c->instancer (varIdxBase, 1),
890 (startAngle.to_float (c->instancer (varIdxBase, 2)) + 1) * HB_PI,
891 (endAngle.to_float (c->instancer (varIdxBase, 3)) + 1) * HB_PI);
892 }
893
894 HBUINT8 format; /* format = 8(noVar) or 9 (Var) */
895 Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintSweepGradient
896 * table) to ColorLine subtable. */
897 FWORD centerX;
898 FWORD centerY;
899 F2DOT14 startAngle;
900 F2DOT14 endAngle;
901 public:
902 DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size + 2 * F2DOT14::static_size);
903 };
904
905 // Paint a non-COLR glyph, filled as indicated by paint.
906 struct PaintGlyph
907 {
908 void closurev1 (hb_colrv1_closure_context_t* c) const;
909
subsetOT::PaintGlyph910 bool subset (hb_subset_context_t *c,
911 const ItemVarStoreInstancer &instancer) const
912 {
913 TRACE_SUBSET (this);
914 auto *out = c->serializer->embed (this);
915 if (unlikely (!out)) return_trace (false);
916
917 if (! c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid),
918 HB_SERIALIZE_ERROR_INT_OVERFLOW))
919 return_trace (false);
920
921 return_trace (out->paint.serialize_subset (c, paint, this, instancer));
922 }
923
sanitizeOT::PaintGlyph924 bool sanitize (hb_sanitize_context_t *c) const
925 {
926 TRACE_SANITIZE (this);
927 return_trace (c->check_struct (this) && paint.sanitize (c, this));
928 }
929
paint_glyphOT::PaintGlyph930 void paint_glyph (hb_paint_context_t *c) const
931 {
932 TRACE_PAINT (this);
933 c->funcs->push_inverse_root_transform (c->data, c->font);
934 c->funcs->push_clip_glyph (c->data, gid, c->font);
935 c->funcs->push_root_transform (c->data, c->font);
936 c->recurse (this+paint);
937 c->funcs->pop_transform (c->data);
938 c->funcs->pop_clip (c->data);
939 c->funcs->pop_transform (c->data);
940 }
941
942 HBUINT8 format; /* format = 10 */
943 Offset24To<Paint> paint; /* Offset (from beginning of PaintGlyph table) to Paint subtable. */
944 HBUINT16 gid;
945 public:
946 DEFINE_SIZE_STATIC (6);
947 };
948
949 struct PaintColrGlyph
950 {
951 void closurev1 (hb_colrv1_closure_context_t* c) const;
952
subsetOT::PaintColrGlyph953 bool subset (hb_subset_context_t *c,
954 const ItemVarStoreInstancer &instancer HB_UNUSED) const
955 {
956 TRACE_SUBSET (this);
957 auto *out = c->serializer->embed (this);
958 if (unlikely (!out)) return_trace (false);
959
960 return_trace (c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid),
961 HB_SERIALIZE_ERROR_INT_OVERFLOW));
962 }
963
sanitizeOT::PaintColrGlyph964 bool sanitize (hb_sanitize_context_t *c) const
965 {
966 TRACE_SANITIZE (this);
967 return_trace (c->check_struct (this));
968 }
969
970 inline void paint_glyph (hb_paint_context_t *c) const;
971
972 HBUINT8 format; /* format = 11 */
973 HBUINT16 gid;
974 public:
975 DEFINE_SIZE_STATIC (3);
976 };
977
978 template <template<typename> class Var>
979 struct PaintTransform
980 {
981 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
982
subsetOT::PaintTransform983 bool subset (hb_subset_context_t *c,
984 const ItemVarStoreInstancer &instancer) const
985 {
986 TRACE_SUBSET (this);
987 auto *out = c->serializer->embed (this);
988 if (unlikely (!out)) return_trace (false);
989 if (!out->transform.serialize_subset (c, transform, this, instancer)) return_trace (false);
990 if (format == 13 && c->plan->all_axes_pinned)
991 out->format = 12;
992 return_trace (out->src.serialize_subset (c, src, this, instancer));
993 }
994
sanitizeOT::PaintTransform995 bool sanitize (hb_sanitize_context_t *c) const
996 {
997 TRACE_SANITIZE (this);
998 return_trace (c->check_struct (this) &&
999 src.sanitize (c, this) &&
1000 transform.sanitize (c, this));
1001 }
1002
paint_glyphOT::PaintTransform1003 void paint_glyph (hb_paint_context_t *c) const
1004 {
1005 TRACE_PAINT (this);
1006 (this+transform).paint_glyph (c);
1007 c->recurse (this+src);
1008 c->funcs->pop_transform (c->data);
1009 }
1010
1011 HBUINT8 format; /* format = 12(noVar) or 13 (Var) */
1012 Offset24To<Paint> src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */
1013 Offset24To<Var<Affine2x3>> transform;
1014 public:
1015 DEFINE_SIZE_STATIC (7);
1016 };
1017
1018 struct PaintTranslate
1019 {
1020 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1021
subsetOT::PaintTranslate1022 bool subset (hb_subset_context_t *c,
1023 const ItemVarStoreInstancer &instancer,
1024 uint32_t varIdxBase) const
1025 {
1026 TRACE_SUBSET (this);
1027 auto *out = c->serializer->embed (this);
1028 if (unlikely (!out)) return_trace (false);
1029
1030 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1031 {
1032 out->dx = dx + (int) roundf (instancer (varIdxBase, 0));
1033 out->dy = dy + (int) roundf (instancer (varIdxBase, 1));
1034 }
1035
1036 if (format == 15 && c->plan->all_axes_pinned)
1037 out->format = 14;
1038
1039 return_trace (out->src.serialize_subset (c, src, this, instancer));
1040 }
1041
sanitizeOT::PaintTranslate1042 bool sanitize (hb_sanitize_context_t *c) const
1043 {
1044 TRACE_SANITIZE (this);
1045 return_trace (c->check_struct (this) && src.sanitize (c, this));
1046 }
1047
paint_glyphOT::PaintTranslate1048 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1049 {
1050 TRACE_PAINT (this);
1051 float ddx = dx + c->instancer (varIdxBase, 0);
1052 float ddy = dy + c->instancer (varIdxBase, 1);
1053
1054 bool p1 = c->funcs->push_translate (c->data, ddx, ddy);
1055 c->recurse (this+src);
1056 if (p1) c->funcs->pop_transform (c->data);
1057 }
1058
1059 HBUINT8 format; /* format = 14(noVar) or 15 (Var) */
1060 Offset24To<Paint> src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */
1061 FWORD dx;
1062 FWORD dy;
1063 public:
1064 DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size);
1065 };
1066
1067 struct PaintScale
1068 {
1069 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1070
subsetOT::PaintScale1071 bool subset (hb_subset_context_t *c,
1072 const ItemVarStoreInstancer &instancer,
1073 uint32_t varIdxBase) const
1074 {
1075 TRACE_SUBSET (this);
1076 auto *out = c->serializer->embed (this);
1077 if (unlikely (!out)) return_trace (false);
1078
1079 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1080 {
1081 out->scaleX.set_float (scaleX.to_float (instancer (varIdxBase, 0)));
1082 out->scaleY.set_float (scaleY.to_float (instancer (varIdxBase, 1)));
1083 }
1084
1085 if (format == 17 && c->plan->all_axes_pinned)
1086 out->format = 16;
1087
1088 return_trace (out->src.serialize_subset (c, src, this, instancer));
1089 }
1090
sanitizeOT::PaintScale1091 bool sanitize (hb_sanitize_context_t *c) const
1092 {
1093 TRACE_SANITIZE (this);
1094 return_trace (c->check_struct (this) && src.sanitize (c, this));
1095 }
1096
paint_glyphOT::PaintScale1097 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1098 {
1099 TRACE_PAINT (this);
1100 float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
1101 float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
1102
1103 bool p1 = c->funcs->push_scale (c->data, sx, sy);
1104 c->recurse (this+src);
1105 if (p1) c->funcs->pop_transform (c->data);
1106 }
1107
1108 HBUINT8 format; /* format = 16 (noVar) or 17(Var) */
1109 Offset24To<Paint> src; /* Offset (from beginning of PaintScale table) to Paint subtable. */
1110 F2DOT14 scaleX;
1111 F2DOT14 scaleY;
1112 public:
1113 DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size);
1114 };
1115
1116 struct PaintScaleAroundCenter
1117 {
1118 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1119
subsetOT::PaintScaleAroundCenter1120 bool subset (hb_subset_context_t *c,
1121 const ItemVarStoreInstancer &instancer,
1122 uint32_t varIdxBase) const
1123 {
1124 TRACE_SUBSET (this);
1125 auto *out = c->serializer->embed (this);
1126 if (unlikely (!out)) return_trace (false);
1127
1128 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1129 {
1130 out->scaleX.set_float (scaleX.to_float (instancer (varIdxBase, 0)));
1131 out->scaleY.set_float (scaleY.to_float (instancer (varIdxBase, 1)));
1132 out->centerX = centerX + (int) roundf (instancer (varIdxBase, 2));
1133 out->centerY = centerY + (int) roundf (instancer (varIdxBase, 3));
1134 }
1135
1136 if (format == 19 && c->plan->all_axes_pinned)
1137 out->format = 18;
1138
1139 return_trace (out->src.serialize_subset (c, src, this, instancer));
1140 }
1141
sanitizeOT::PaintScaleAroundCenter1142 bool sanitize (hb_sanitize_context_t *c) const
1143 {
1144 TRACE_SANITIZE (this);
1145 return_trace (c->check_struct (this) && src.sanitize (c, this));
1146 }
1147
paint_glyphOT::PaintScaleAroundCenter1148 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1149 {
1150 TRACE_PAINT (this);
1151 float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
1152 float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
1153 float tCenterX = centerX + c->instancer (varIdxBase, 2);
1154 float tCenterY = centerY + c->instancer (varIdxBase, 3);
1155
1156 bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
1157 bool p2 = c->funcs->push_scale (c->data, sx, sy);
1158 bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
1159 c->recurse (this+src);
1160 if (p3) c->funcs->pop_transform (c->data);
1161 if (p2) c->funcs->pop_transform (c->data);
1162 if (p1) c->funcs->pop_transform (c->data);
1163 }
1164
1165 HBUINT8 format; /* format = 18 (noVar) or 19(Var) */
1166 Offset24To<Paint> src; /* Offset (from beginning of PaintScaleAroundCenter table) to Paint subtable. */
1167 F2DOT14 scaleX;
1168 F2DOT14 scaleY;
1169 FWORD centerX;
1170 FWORD centerY;
1171 public:
1172 DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size + 2 * FWORD::static_size);
1173 };
1174
1175 struct PaintScaleUniform
1176 {
1177 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1178
subsetOT::PaintScaleUniform1179 bool subset (hb_subset_context_t *c,
1180 const ItemVarStoreInstancer &instancer,
1181 uint32_t varIdxBase) const
1182 {
1183 TRACE_SUBSET (this);
1184 auto *out = c->serializer->embed (this);
1185 if (unlikely (!out)) return_trace (false);
1186
1187 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1188 out->scale.set_float (scale.to_float (instancer (varIdxBase, 0)));
1189
1190 if (format == 21 && c->plan->all_axes_pinned)
1191 out->format = 20;
1192
1193 return_trace (out->src.serialize_subset (c, src, this, instancer));
1194 }
1195
sanitizeOT::PaintScaleUniform1196 bool sanitize (hb_sanitize_context_t *c) const
1197 {
1198 TRACE_SANITIZE (this);
1199 return_trace (c->check_struct (this) && src.sanitize (c, this));
1200 }
1201
paint_glyphOT::PaintScaleUniform1202 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1203 {
1204 TRACE_PAINT (this);
1205 float s = scale.to_float (c->instancer (varIdxBase, 0));
1206
1207 bool p1 = c->funcs->push_scale (c->data, s, s);
1208 c->recurse (this+src);
1209 if (p1) c->funcs->pop_transform (c->data);
1210 }
1211
1212 HBUINT8 format; /* format = 20 (noVar) or 21(Var) */
1213 Offset24To<Paint> src; /* Offset (from beginning of PaintScaleUniform table) to Paint subtable. */
1214 F2DOT14 scale;
1215 public:
1216 DEFINE_SIZE_STATIC (4 + F2DOT14::static_size);
1217 };
1218
1219 struct PaintScaleUniformAroundCenter
1220 {
1221 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1222
subsetOT::PaintScaleUniformAroundCenter1223 bool subset (hb_subset_context_t *c,
1224 const ItemVarStoreInstancer &instancer,
1225 uint32_t varIdxBase) const
1226 {
1227 TRACE_SUBSET (this);
1228 auto *out = c->serializer->embed (this);
1229 if (unlikely (!out)) return_trace (false);
1230
1231 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1232 {
1233 out->scale.set_float (scale.to_float (instancer (varIdxBase, 0)));
1234 out->centerX = centerX + (int) roundf (instancer (varIdxBase, 1));
1235 out->centerY = centerY + (int) roundf (instancer (varIdxBase, 2));
1236 }
1237
1238 if (format == 23 && c->plan->all_axes_pinned)
1239 out->format = 22;
1240
1241 return_trace (out->src.serialize_subset (c, src, this, instancer));
1242 }
1243
sanitizeOT::PaintScaleUniformAroundCenter1244 bool sanitize (hb_sanitize_context_t *c) const
1245 {
1246 TRACE_SANITIZE (this);
1247 return_trace (c->check_struct (this) && src.sanitize (c, this));
1248 }
1249
paint_glyphOT::PaintScaleUniformAroundCenter1250 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1251 {
1252 TRACE_PAINT (this);
1253 float s = scale.to_float (c->instancer (varIdxBase, 0));
1254 float tCenterX = centerX + c->instancer (varIdxBase, 1);
1255 float tCenterY = centerY + c->instancer (varIdxBase, 2);
1256
1257 bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
1258 bool p2 = c->funcs->push_scale (c->data, s, s);
1259 bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
1260 c->recurse (this+src);
1261 if (p3) c->funcs->pop_transform (c->data);
1262 if (p2) c->funcs->pop_transform (c->data);
1263 if (p1) c->funcs->pop_transform (c->data);
1264 }
1265
1266 HBUINT8 format; /* format = 22 (noVar) or 23(Var) */
1267 Offset24To<Paint> src; /* Offset (from beginning of PaintScaleUniformAroundCenter table) to Paint subtable. */
1268 F2DOT14 scale;
1269 FWORD centerX;
1270 FWORD centerY;
1271 public:
1272 DEFINE_SIZE_STATIC (4 + F2DOT14::static_size + 2 * FWORD::static_size);
1273 };
1274
1275 struct PaintRotate
1276 {
1277 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1278
subsetOT::PaintRotate1279 bool subset (hb_subset_context_t *c,
1280 const ItemVarStoreInstancer &instancer,
1281 uint32_t varIdxBase) const
1282 {
1283 TRACE_SUBSET (this);
1284 auto *out = c->serializer->embed (this);
1285 if (unlikely (!out)) return_trace (false);
1286
1287 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1288 out->angle.set_float (angle.to_float (instancer (varIdxBase, 0)));
1289
1290 if (format == 25 && c->plan->all_axes_pinned)
1291 out->format = 24;
1292
1293 return_trace (out->src.serialize_subset (c, src, this, instancer));
1294 }
1295
sanitizeOT::PaintRotate1296 bool sanitize (hb_sanitize_context_t *c) const
1297 {
1298 TRACE_SANITIZE (this);
1299 return_trace (c->check_struct (this) && src.sanitize (c, this));
1300 }
1301
paint_glyphOT::PaintRotate1302 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1303 {
1304 TRACE_PAINT (this);
1305 float a = angle.to_float (c->instancer (varIdxBase, 0));
1306
1307 bool p1 = c->funcs->push_rotate (c->data, a);
1308 c->recurse (this+src);
1309 if (p1) c->funcs->pop_transform (c->data);
1310 }
1311
1312 HBUINT8 format; /* format = 24 (noVar) or 25(Var) */
1313 Offset24To<Paint> src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */
1314 F2DOT14 angle;
1315 public:
1316 DEFINE_SIZE_STATIC (4 + F2DOT14::static_size);
1317 };
1318
1319 struct PaintRotateAroundCenter
1320 {
1321 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1322
subsetOT::PaintRotateAroundCenter1323 bool subset (hb_subset_context_t *c,
1324 const ItemVarStoreInstancer &instancer,
1325 uint32_t varIdxBase) const
1326 {
1327 TRACE_SUBSET (this);
1328 auto *out = c->serializer->embed (this);
1329 if (unlikely (!out)) return_trace (false);
1330
1331 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1332 {
1333 out->angle.set_float (angle.to_float (instancer (varIdxBase, 0)));
1334 out->centerX = centerX + (int) roundf (instancer (varIdxBase, 1));
1335 out->centerY = centerY + (int) roundf (instancer (varIdxBase, 2));
1336 }
1337
1338 if (format ==27 && c->plan->all_axes_pinned)
1339 out->format = 26;
1340
1341 return_trace (out->src.serialize_subset (c, src, this, instancer));
1342 }
1343
sanitizeOT::PaintRotateAroundCenter1344 bool sanitize (hb_sanitize_context_t *c) const
1345 {
1346 TRACE_SANITIZE (this);
1347 return_trace (c->check_struct (this) && src.sanitize (c, this));
1348 }
1349
paint_glyphOT::PaintRotateAroundCenter1350 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1351 {
1352 TRACE_PAINT (this);
1353 float a = angle.to_float (c->instancer (varIdxBase, 0));
1354 float tCenterX = centerX + c->instancer (varIdxBase, 1);
1355 float tCenterY = centerY + c->instancer (varIdxBase, 2);
1356
1357 bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
1358 bool p2 = c->funcs->push_rotate (c->data, a);
1359 bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
1360 c->recurse (this+src);
1361 if (p3) c->funcs->pop_transform (c->data);
1362 if (p2) c->funcs->pop_transform (c->data);
1363 if (p1) c->funcs->pop_transform (c->data);
1364 }
1365
1366 HBUINT8 format; /* format = 26 (noVar) or 27(Var) */
1367 Offset24To<Paint> src; /* Offset (from beginning of PaintRotateAroundCenter table) to Paint subtable. */
1368 F2DOT14 angle;
1369 FWORD centerX;
1370 FWORD centerY;
1371 public:
1372 DEFINE_SIZE_STATIC (4 + F2DOT14::static_size + 2 * FWORD::static_size);
1373 };
1374
1375 struct PaintSkew
1376 {
1377 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1378
subsetOT::PaintSkew1379 bool subset (hb_subset_context_t *c,
1380 const ItemVarStoreInstancer &instancer,
1381 uint32_t varIdxBase) const
1382 {
1383 TRACE_SUBSET (this);
1384 auto *out = c->serializer->embed (this);
1385 if (unlikely (!out)) return_trace (false);
1386
1387 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1388 {
1389 out->xSkewAngle.set_float (xSkewAngle.to_float (instancer (varIdxBase, 0)));
1390 out->ySkewAngle.set_float (ySkewAngle.to_float (instancer (varIdxBase, 1)));
1391 }
1392
1393 if (format == 29 && c->plan->all_axes_pinned)
1394 out->format = 28;
1395
1396 return_trace (out->src.serialize_subset (c, src, this, instancer));
1397 }
1398
sanitizeOT::PaintSkew1399 bool sanitize (hb_sanitize_context_t *c) const
1400 {
1401 TRACE_SANITIZE (this);
1402 return_trace (c->check_struct (this) && src.sanitize (c, this));
1403 }
1404
paint_glyphOT::PaintSkew1405 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1406 {
1407 TRACE_PAINT (this);
1408 float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
1409 float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
1410
1411 bool p1 = c->funcs->push_skew (c->data, sx, sy);
1412 c->recurse (this+src);
1413 if (p1) c->funcs->pop_transform (c->data);
1414 }
1415
1416 HBUINT8 format; /* format = 28(noVar) or 29 (Var) */
1417 Offset24To<Paint> src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */
1418 F2DOT14 xSkewAngle;
1419 F2DOT14 ySkewAngle;
1420 public:
1421 DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size);
1422 };
1423
1424 struct PaintSkewAroundCenter
1425 {
1426 HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
1427
subsetOT::PaintSkewAroundCenter1428 bool subset (hb_subset_context_t *c,
1429 const ItemVarStoreInstancer &instancer,
1430 uint32_t varIdxBase) const
1431 {
1432 TRACE_SUBSET (this);
1433 auto *out = c->serializer->embed (this);
1434 if (unlikely (!out)) return_trace (false);
1435
1436 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1437 {
1438 out->xSkewAngle.set_float (xSkewAngle.to_float (instancer (varIdxBase, 0)));
1439 out->ySkewAngle.set_float (ySkewAngle.to_float (instancer (varIdxBase, 1)));
1440 out->centerX = centerX + (int) roundf (instancer (varIdxBase, 2));
1441 out->centerY = centerY + (int) roundf (instancer (varIdxBase, 3));
1442 }
1443
1444 if (format == 31 && c->plan->all_axes_pinned)
1445 out->format = 30;
1446
1447 return_trace (out->src.serialize_subset (c, src, this, instancer));
1448 }
1449
sanitizeOT::PaintSkewAroundCenter1450 bool sanitize (hb_sanitize_context_t *c) const
1451 {
1452 TRACE_SANITIZE (this);
1453 return_trace (c->check_struct (this) && src.sanitize (c, this));
1454 }
1455
paint_glyphOT::PaintSkewAroundCenter1456 void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
1457 {
1458 TRACE_PAINT (this);
1459 float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
1460 float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
1461 float tCenterX = centerX + c->instancer (varIdxBase, 2);
1462 float tCenterY = centerY + c->instancer (varIdxBase, 3);
1463
1464 bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
1465 bool p2 = c->funcs->push_skew (c->data, sx, sy);
1466 bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
1467 c->recurse (this+src);
1468 if (p3) c->funcs->pop_transform (c->data);
1469 if (p2) c->funcs->pop_transform (c->data);
1470 if (p1) c->funcs->pop_transform (c->data);
1471 }
1472
1473 HBUINT8 format; /* format = 30(noVar) or 31 (Var) */
1474 Offset24To<Paint> src; /* Offset (from beginning of PaintSkewAroundCenter table) to Paint subtable. */
1475 F2DOT14 xSkewAngle;
1476 F2DOT14 ySkewAngle;
1477 FWORD centerX;
1478 FWORD centerY;
1479 public:
1480 DEFINE_SIZE_STATIC (4 + 2 * F2DOT14::static_size + 2 * FWORD::static_size);
1481 };
1482
1483 struct PaintComposite
1484 {
1485 void closurev1 (hb_colrv1_closure_context_t* c) const;
1486
subsetOT::PaintComposite1487 bool subset (hb_subset_context_t *c,
1488 const ItemVarStoreInstancer &instancer) const
1489 {
1490 TRACE_SUBSET (this);
1491 auto *out = c->serializer->embed (this);
1492 if (unlikely (!out)) return_trace (false);
1493
1494 bool ret = false;
1495 ret |= out->src.serialize_subset (c, src, this, instancer);
1496 ret |= out->backdrop.serialize_subset (c, backdrop, this, instancer);
1497 return_trace (ret);
1498 }
1499
sanitizeOT::PaintComposite1500 bool sanitize (hb_sanitize_context_t *c) const
1501 {
1502 TRACE_SANITIZE (this);
1503 return_trace (c->check_struct (this) &&
1504 c->check_ops (this->min_size) && // PainComposite can get exponential
1505 src.sanitize (c, this) &&
1506 backdrop.sanitize (c, this));
1507 }
1508
paint_glyphOT::PaintComposite1509 void paint_glyph (hb_paint_context_t *c) const
1510 {
1511 TRACE_PAINT (this);
1512 c->recurse (this+backdrop);
1513 c->funcs->push_group (c->data);
1514 c->recurse (this+src);
1515 c->funcs->pop_group (c->data, (hb_paint_composite_mode_t) (int) mode);
1516 }
1517
1518 HBUINT8 format; /* format = 32 */
1519 Offset24To<Paint> src; /* Offset (from beginning of PaintComposite table) to source Paint subtable. */
1520 CompositeMode mode; /* If mode is unrecognized use COMPOSITE_CLEAR */
1521 Offset24To<Paint> backdrop; /* Offset (from beginning of PaintComposite table) to backdrop Paint subtable. */
1522 public:
1523 DEFINE_SIZE_STATIC (8);
1524 };
1525
1526 struct ClipBoxData
1527 {
1528 int xMin, yMin, xMax, yMax;
1529 };
1530
1531 struct ClipBoxFormat1
1532 {
sanitizeOT::ClipBoxFormat11533 bool sanitize (hb_sanitize_context_t *c) const
1534 {
1535 TRACE_SANITIZE (this);
1536 return_trace (c->check_struct (this));
1537 }
1538
get_clip_boxOT::ClipBoxFormat11539 void get_clip_box (ClipBoxData &clip_box, const ItemVarStoreInstancer &instancer HB_UNUSED) const
1540 {
1541 clip_box.xMin = xMin;
1542 clip_box.yMin = yMin;
1543 clip_box.xMax = xMax;
1544 clip_box.yMax = yMax;
1545 }
1546
subsetOT::ClipBoxFormat11547 bool subset (hb_subset_context_t *c,
1548 const ItemVarStoreInstancer &instancer,
1549 uint32_t varIdxBase) const
1550 {
1551 TRACE_SUBSET (this);
1552 auto *out = c->serializer->embed (*this);
1553 if (unlikely (!out)) return_trace (false);
1554
1555 if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION)
1556 {
1557 out->xMin = xMin + (int) roundf (instancer (varIdxBase, 0));
1558 out->yMin = yMin + (int) roundf (instancer (varIdxBase, 1));
1559 out->xMax = xMax + (int) roundf (instancer (varIdxBase, 2));
1560 out->yMax = yMax + (int) roundf (instancer (varIdxBase, 3));
1561 }
1562
1563 if (format == 2 && c->plan->all_axes_pinned)
1564 out->format = 1;
1565
1566 return_trace (true);
1567 }
1568
1569 public:
1570 HBUINT8 format; /* format = 1(noVar) or 2(Var)*/
1571 FWORD xMin;
1572 FWORD yMin;
1573 FWORD xMax;
1574 FWORD yMax;
1575 public:
1576 DEFINE_SIZE_STATIC (1 + 4 * FWORD::static_size);
1577 };
1578
1579 struct ClipBoxFormat2 : Variable<ClipBoxFormat1>
1580 {
get_clip_boxOT::ClipBoxFormat21581 void get_clip_box (ClipBoxData &clip_box, const ItemVarStoreInstancer &instancer) const
1582 {
1583 value.get_clip_box(clip_box, instancer);
1584 if (instancer)
1585 {
1586 clip_box.xMin += roundf (instancer (varIdxBase, 0));
1587 clip_box.yMin += roundf (instancer (varIdxBase, 1));
1588 clip_box.xMax += roundf (instancer (varIdxBase, 2));
1589 clip_box.yMax += roundf (instancer (varIdxBase, 3));
1590 }
1591 }
1592
closurev1OT::ClipBoxFormat21593 void closurev1 (hb_colrv1_closure_context_t* c) const
1594 { c->variation_indices->add_range (varIdxBase, varIdxBase + 3); }
1595 };
1596
1597 struct ClipBox
1598 {
subsetOT::ClipBox1599 bool subset (hb_subset_context_t *c,
1600 const ItemVarStoreInstancer &instancer) const
1601 {
1602 TRACE_SUBSET (this);
1603 switch (u.format) {
1604 case 1: return_trace (u.format1.subset (c, instancer, VarIdx::NO_VARIATION));
1605 case 2: return_trace (u.format2.subset (c, instancer));
1606 default:return_trace (c->default_return_value ());
1607 }
1608 }
1609
closurev1OT::ClipBox1610 void closurev1 (hb_colrv1_closure_context_t* c) const
1611 {
1612 switch (u.format) {
1613 case 2: u.format2.closurev1 (c);
1614 default:return;
1615 }
1616 }
1617
1618 template <typename context_t, typename ...Ts>
dispatchOT::ClipBox1619 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1620 {
1621 if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
1622 TRACE_DISPATCH (this, u.format);
1623 switch (u.format) {
1624 case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
1625 case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
1626 default:return_trace (c->default_return_value ());
1627 }
1628 }
1629
get_extentsOT::ClipBox1630 bool get_extents (hb_glyph_extents_t *extents,
1631 const ItemVarStoreInstancer &instancer) const
1632 {
1633 ClipBoxData clip_box;
1634 switch (u.format) {
1635 case 1:
1636 u.format1.get_clip_box (clip_box, instancer);
1637 break;
1638 case 2:
1639 u.format2.get_clip_box (clip_box, instancer);
1640 break;
1641 default:
1642 return false;
1643 }
1644
1645 extents->x_bearing = clip_box.xMin;
1646 extents->y_bearing = clip_box.yMax;
1647 extents->width = clip_box.xMax - clip_box.xMin;
1648 extents->height = clip_box.yMin - clip_box.yMax;
1649 return true;
1650 }
1651
1652 protected:
1653 union {
1654 HBUINT8 format; /* Format identifier */
1655 ClipBoxFormat1 format1;
1656 ClipBoxFormat2 format2;
1657 } u;
1658 };
1659
1660 struct ClipRecord
1661 {
cmpOT::ClipRecord1662 int cmp (hb_codepoint_t g) const
1663 { return g < startGlyphID ? -1 : g <= endGlyphID ? 0 : +1; }
1664
closurev1OT::ClipRecord1665 void closurev1 (hb_colrv1_closure_context_t* c, const void *base) const
1666 {
1667 if (!c->glyphs->intersects (startGlyphID, endGlyphID)) return;
1668 (base+clipBox).closurev1 (c);
1669 }
1670
subsetOT::ClipRecord1671 bool subset (hb_subset_context_t *c,
1672 const void *base,
1673 const ItemVarStoreInstancer &instancer) const
1674 {
1675 TRACE_SUBSET (this);
1676 auto *out = c->serializer->embed (*this);
1677 if (unlikely (!out)) return_trace (false);
1678
1679 return_trace (out->clipBox.serialize_subset (c, clipBox, base, instancer));
1680 }
1681
sanitizeOT::ClipRecord1682 bool sanitize (hb_sanitize_context_t *c, const void *base) const
1683 {
1684 TRACE_SANITIZE (this);
1685 return_trace (c->check_struct (this) && clipBox.sanitize (c, base));
1686 }
1687
get_extentsOT::ClipRecord1688 bool get_extents (hb_glyph_extents_t *extents,
1689 const void *base,
1690 const ItemVarStoreInstancer &instancer) const
1691 {
1692 return (base+clipBox).get_extents (extents, instancer);
1693 }
1694
1695 public:
1696 HBUINT16 startGlyphID; // first gid clip applies to
1697 HBUINT16 endGlyphID; // last gid clip applies to, inclusive
1698 Offset24To<ClipBox> clipBox; // Box or VarBox
1699 public:
1700 DEFINE_SIZE_STATIC (7);
1701 };
1702 DECLARE_NULL_NAMESPACE_BYTES (OT, ClipRecord);
1703
1704 struct ClipList
1705 {
serialize_clip_recordsOT::ClipList1706 unsigned serialize_clip_records (hb_subset_context_t *c,
1707 const ItemVarStoreInstancer &instancer,
1708 const hb_set_t& gids,
1709 const hb_map_t& gid_offset_map) const
1710 {
1711 TRACE_SERIALIZE (this);
1712 if (gids.is_empty () ||
1713 gid_offset_map.get_population () != gids.get_population ())
1714 return_trace (0);
1715
1716 unsigned count = 0;
1717
1718 hb_codepoint_t start_gid= gids.get_min ();
1719 hb_codepoint_t prev_gid = start_gid;
1720
1721 unsigned offset = gid_offset_map.get (start_gid);
1722 unsigned prev_offset = offset;
1723 for (const hb_codepoint_t _ : gids.iter ())
1724 {
1725 if (_ == start_gid) continue;
1726
1727 offset = gid_offset_map.get (_);
1728 if (_ == prev_gid + 1 && offset == prev_offset)
1729 {
1730 prev_gid = _;
1731 continue;
1732 }
1733
1734 ClipRecord record;
1735 record.startGlyphID = start_gid;
1736 record.endGlyphID = prev_gid;
1737 record.clipBox = prev_offset;
1738
1739 if (!record.subset (c, this, instancer)) return_trace (0);
1740 count++;
1741
1742 start_gid = _;
1743 prev_gid = _;
1744 prev_offset = offset;
1745 }
1746
1747 //last one
1748 {
1749 ClipRecord record;
1750 record.startGlyphID = start_gid;
1751 record.endGlyphID = prev_gid;
1752 record.clipBox = prev_offset;
1753 if (!record.subset (c, this, instancer)) return_trace (0);
1754 count++;
1755 }
1756 return_trace (count);
1757 }
1758
subsetOT::ClipList1759 bool subset (hb_subset_context_t *c,
1760 const ItemVarStoreInstancer &instancer) const
1761 {
1762 TRACE_SUBSET (this);
1763 auto *out = c->serializer->start_embed (*this);
1764 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
1765 if (!c->serializer->check_assign (out->format, format, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
1766
1767 const hb_set_t& glyphset = c->plan->_glyphset_colred;
1768 const hb_map_t &glyph_map = *c->plan->glyph_map;
1769
1770 hb_map_t new_gid_offset_map;
1771 hb_set_t new_gids;
1772 for (const ClipRecord& record : clips.iter ())
1773 {
1774 unsigned start_gid = record.startGlyphID;
1775 unsigned end_gid = record.endGlyphID;
1776 for (unsigned gid = start_gid; gid <= end_gid; gid++)
1777 {
1778 if (!glyphset.has (gid) || !glyph_map.has (gid)) continue;
1779 unsigned new_gid = glyph_map.get (gid);
1780 new_gid_offset_map.set (new_gid, record.clipBox);
1781 new_gids.add (new_gid);
1782 }
1783 }
1784
1785 unsigned count = serialize_clip_records (c, instancer, new_gids, new_gid_offset_map);
1786 if (!count) return_trace (false);
1787 return_trace (c->serializer->check_assign (out->clips.len, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
1788 }
1789
sanitizeOT::ClipList1790 bool sanitize (hb_sanitize_context_t *c) const
1791 {
1792 TRACE_SANITIZE (this);
1793 // TODO Make a formatted struct!
1794 return_trace (c->check_struct (this) && clips.sanitize (c, this));
1795 }
1796
1797 bool
get_extentsOT::ClipList1798 get_extents (hb_codepoint_t gid,
1799 hb_glyph_extents_t *extents,
1800 const ItemVarStoreInstancer &instancer) const
1801 {
1802 auto *rec = clips.as_array ().bsearch (gid);
1803 if (rec)
1804 {
1805 rec->get_extents (extents, this, instancer);
1806 return true;
1807 }
1808 return false;
1809 }
1810
1811 HBUINT8 format; // Set to 1.
1812 SortedArray32Of<ClipRecord> clips; // Clip records, sorted by startGlyphID
1813 public:
1814 DEFINE_SIZE_ARRAY_SIZED (5, clips);
1815 };
1816
1817 struct Paint
1818 {
1819
1820 template <typename ...Ts>
sanitizeOT::Paint1821 bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
1822 {
1823 TRACE_SANITIZE (this);
1824
1825 if (unlikely (!c->check_start_recursion (HB_MAX_NESTING_LEVEL)))
1826 return_trace (c->no_dispatch_return_value ());
1827
1828 return_trace (c->end_recursion (this->dispatch (c, std::forward<Ts> (ds)...)));
1829 }
1830
1831 template <typename context_t, typename ...Ts>
dispatchOT::Paint1832 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1833 {
1834 if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
1835 TRACE_DISPATCH (this, u.format);
1836 switch (u.format) {
1837 case 1: return_trace (c->dispatch (u.paintformat1, std::forward<Ts> (ds)...));
1838 case 2: return_trace (c->dispatch (u.paintformat2, std::forward<Ts> (ds)...));
1839 case 3: return_trace (c->dispatch (u.paintformat3, std::forward<Ts> (ds)...));
1840 case 4: return_trace (c->dispatch (u.paintformat4, std::forward<Ts> (ds)...));
1841 case 5: return_trace (c->dispatch (u.paintformat5, std::forward<Ts> (ds)...));
1842 case 6: return_trace (c->dispatch (u.paintformat6, std::forward<Ts> (ds)...));
1843 case 7: return_trace (c->dispatch (u.paintformat7, std::forward<Ts> (ds)...));
1844 case 8: return_trace (c->dispatch (u.paintformat8, std::forward<Ts> (ds)...));
1845 case 9: return_trace (c->dispatch (u.paintformat9, std::forward<Ts> (ds)...));
1846 case 10: return_trace (c->dispatch (u.paintformat10, std::forward<Ts> (ds)...));
1847 case 11: return_trace (c->dispatch (u.paintformat11, std::forward<Ts> (ds)...));
1848 case 12: return_trace (c->dispatch (u.paintformat12, std::forward<Ts> (ds)...));
1849 case 13: return_trace (c->dispatch (u.paintformat13, std::forward<Ts> (ds)...));
1850 case 14: return_trace (c->dispatch (u.paintformat14, std::forward<Ts> (ds)...));
1851 case 15: return_trace (c->dispatch (u.paintformat15, std::forward<Ts> (ds)...));
1852 case 16: return_trace (c->dispatch (u.paintformat16, std::forward<Ts> (ds)...));
1853 case 17: return_trace (c->dispatch (u.paintformat17, std::forward<Ts> (ds)...));
1854 case 18: return_trace (c->dispatch (u.paintformat18, std::forward<Ts> (ds)...));
1855 case 19: return_trace (c->dispatch (u.paintformat19, std::forward<Ts> (ds)...));
1856 case 20: return_trace (c->dispatch (u.paintformat20, std::forward<Ts> (ds)...));
1857 case 21: return_trace (c->dispatch (u.paintformat21, std::forward<Ts> (ds)...));
1858 case 22: return_trace (c->dispatch (u.paintformat22, std::forward<Ts> (ds)...));
1859 case 23: return_trace (c->dispatch (u.paintformat23, std::forward<Ts> (ds)...));
1860 case 24: return_trace (c->dispatch (u.paintformat24, std::forward<Ts> (ds)...));
1861 case 25: return_trace (c->dispatch (u.paintformat25, std::forward<Ts> (ds)...));
1862 case 26: return_trace (c->dispatch (u.paintformat26, std::forward<Ts> (ds)...));
1863 case 27: return_trace (c->dispatch (u.paintformat27, std::forward<Ts> (ds)...));
1864 case 28: return_trace (c->dispatch (u.paintformat28, std::forward<Ts> (ds)...));
1865 case 29: return_trace (c->dispatch (u.paintformat29, std::forward<Ts> (ds)...));
1866 case 30: return_trace (c->dispatch (u.paintformat30, std::forward<Ts> (ds)...));
1867 case 31: return_trace (c->dispatch (u.paintformat31, std::forward<Ts> (ds)...));
1868 case 32: return_trace (c->dispatch (u.paintformat32, std::forward<Ts> (ds)...));
1869 default:return_trace (c->default_return_value ());
1870 }
1871 }
1872
1873 protected:
1874 union {
1875 HBUINT8 format;
1876 PaintColrLayers paintformat1;
1877 NoVariable<PaintSolid> paintformat2;
1878 Variable<PaintSolid> paintformat3;
1879 NoVariable<PaintLinearGradient<NoVariable>> paintformat4;
1880 Variable<PaintLinearGradient<Variable>> paintformat5;
1881 NoVariable<PaintRadialGradient<NoVariable>> paintformat6;
1882 Variable<PaintRadialGradient<Variable>> paintformat7;
1883 NoVariable<PaintSweepGradient<NoVariable>> paintformat8;
1884 Variable<PaintSweepGradient<Variable>> paintformat9;
1885 PaintGlyph paintformat10;
1886 PaintColrGlyph paintformat11;
1887 PaintTransform<NoVariable> paintformat12;
1888 PaintTransform<Variable> paintformat13;
1889 NoVariable<PaintTranslate> paintformat14;
1890 Variable<PaintTranslate> paintformat15;
1891 NoVariable<PaintScale> paintformat16;
1892 Variable<PaintScale> paintformat17;
1893 NoVariable<PaintScaleAroundCenter> paintformat18;
1894 Variable<PaintScaleAroundCenter> paintformat19;
1895 NoVariable<PaintScaleUniform> paintformat20;
1896 Variable<PaintScaleUniform> paintformat21;
1897 NoVariable<PaintScaleUniformAroundCenter> paintformat22;
1898 Variable<PaintScaleUniformAroundCenter> paintformat23;
1899 NoVariable<PaintRotate> paintformat24;
1900 Variable<PaintRotate> paintformat25;
1901 NoVariable<PaintRotateAroundCenter> paintformat26;
1902 Variable<PaintRotateAroundCenter> paintformat27;
1903 NoVariable<PaintSkew> paintformat28;
1904 Variable<PaintSkew> paintformat29;
1905 NoVariable<PaintSkewAroundCenter> paintformat30;
1906 Variable<PaintSkewAroundCenter> paintformat31;
1907 PaintComposite paintformat32;
1908 } u;
1909 public:
1910 DEFINE_SIZE_MIN (2);
1911 };
1912
1913 struct BaseGlyphPaintRecord
1914 {
cmpOT::BaseGlyphPaintRecord1915 int cmp (hb_codepoint_t g) const
1916 { return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
1917
serializeOT::BaseGlyphPaintRecord1918 bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map,
1919 const void* src_base, hb_subset_context_t *c,
1920 const ItemVarStoreInstancer &instancer) const
1921 {
1922 TRACE_SERIALIZE (this);
1923 auto *out = s->embed (this);
1924 if (unlikely (!out)) return_trace (false);
1925 if (!s->check_assign (out->glyphId, glyph_map->get (glyphId),
1926 HB_SERIALIZE_ERROR_INT_OVERFLOW))
1927 return_trace (false);
1928
1929 return_trace (out->paint.serialize_subset (c, paint, src_base, instancer));
1930 }
1931
sanitizeOT::BaseGlyphPaintRecord1932 bool sanitize (hb_sanitize_context_t *c, const void *base) const
1933 {
1934 TRACE_SANITIZE (this);
1935 return_trace (likely (c->check_struct (this) && paint.sanitize (c, base)));
1936 }
1937
1938 public:
1939 HBGlyphID16 glyphId; /* Glyph ID of reference glyph */
1940 Offset32To<Paint> paint; /* Offset (from beginning of BaseGlyphPaintRecord array) to Paint,
1941 * Typically PaintColrLayers */
1942 public:
1943 DEFINE_SIZE_STATIC (6);
1944 };
1945
1946 struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
1947 {
subsetOT::BaseGlyphList1948 bool subset (hb_subset_context_t *c,
1949 const ItemVarStoreInstancer &instancer) const
1950 {
1951 TRACE_SUBSET (this);
1952 auto *out = c->serializer->start_embed (this);
1953 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
1954 const hb_set_t* glyphset = &c->plan->_glyphset_colred;
1955
1956 for (const auto& _ : as_array ())
1957 {
1958 unsigned gid = _.glyphId;
1959 if (!glyphset->has (gid)) continue;
1960
1961 if (_.serialize (c->serializer, c->plan->glyph_map, this, c, instancer)) out->len++;
1962 else return_trace (false);
1963 }
1964
1965 return_trace (out->len != 0);
1966 }
1967
sanitizeOT::BaseGlyphList1968 bool sanitize (hb_sanitize_context_t *c) const
1969 {
1970 TRACE_SANITIZE (this);
1971 return_trace (SortedArray32Of<BaseGlyphPaintRecord>::sanitize (c, this));
1972 }
1973 };
1974
1975 struct LayerList : Array32OfOffset32To<Paint>
1976 {
get_paintOT::LayerList1977 const Paint& get_paint (unsigned i) const
1978 { return this+(*this)[i]; }
1979
subsetOT::LayerList1980 bool subset (hb_subset_context_t *c,
1981 const ItemVarStoreInstancer &instancer) const
1982 {
1983 TRACE_SUBSET (this);
1984 auto *out = c->serializer->start_embed (this);
1985 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
1986
1987 bool ret = false;
1988 for (const auto& _ : + hb_enumerate (*this)
1989 | hb_filter (c->plan->colrv1_layers, hb_first))
1990
1991 {
1992 auto *o = out->serialize_append (c->serializer);
1993 if (unlikely (!o)) return_trace (false);
1994 ret |= o->serialize_subset (c, _.second, this, instancer);
1995 }
1996 return_trace (ret);
1997 }
1998
sanitizeOT::LayerList1999 bool sanitize (hb_sanitize_context_t *c) const
2000 {
2001 TRACE_SANITIZE (this);
2002 return_trace (Array32OfOffset32To<Paint>::sanitize (c, this));
2003 }
2004 };
2005
2006 struct delta_set_index_map_subset_plan_t
2007 {
get_inner_bit_countOT::delta_set_index_map_subset_plan_t2008 unsigned get_inner_bit_count () const { return inner_bit_count; }
get_widthOT::delta_set_index_map_subset_plan_t2009 unsigned get_width () const { return ((outer_bit_count + inner_bit_count + 7) / 8); }
get_output_mapOT::delta_set_index_map_subset_plan_t2010 hb_array_t<const uint32_t> get_output_map () const { return output_map.as_array (); }
2011
delta_set_index_map_subset_plan_tOT::delta_set_index_map_subset_plan_t2012 delta_set_index_map_subset_plan_t (const hb_map_t &new_deltaset_idx_varidx_map)
2013 {
2014 map_count = 0;
2015 outer_bit_count = 0;
2016 inner_bit_count = 1;
2017 output_map.init ();
2018
2019 /* search backwards */
2020 unsigned count = new_deltaset_idx_varidx_map.get_population ();
2021 if (!count) return;
2022
2023 unsigned last_idx = (unsigned)-1;
2024 unsigned last_varidx = (unsigned)-1;
2025
2026 for (unsigned i = count; i; i--)
2027 {
2028 unsigned delta_set_idx = i - 1;
2029 unsigned var_idx = new_deltaset_idx_varidx_map.get (delta_set_idx);
2030 if (i == count)
2031 {
2032 last_idx = delta_set_idx;
2033 last_varidx = var_idx;
2034 continue;
2035 }
2036 if (var_idx != last_varidx)
2037 break;
2038 last_idx = delta_set_idx;
2039 }
2040
2041 map_count = last_idx + 1;
2042 }
2043
remapOT::delta_set_index_map_subset_plan_t2044 bool remap (const hb_map_t &new_deltaset_idx_varidx_map)
2045 {
2046 /* recalculate bit_count */
2047 outer_bit_count = 1;
2048 inner_bit_count = 1;
2049
2050 if (unlikely (!output_map.resize (map_count, false))) return false;
2051
2052 for (unsigned idx = 0; idx < map_count; idx++)
2053 {
2054 uint32_t *var_idx;
2055 if (!new_deltaset_idx_varidx_map.has (idx, &var_idx)) return false;
2056 output_map.arrayZ[idx] = *var_idx;
2057
2058 unsigned outer = (*var_idx) >> 16;
2059 unsigned bit_count = (outer == 0) ? 1 : hb_bit_storage (outer);
2060 outer_bit_count = hb_max (bit_count, outer_bit_count);
2061
2062 unsigned inner = (*var_idx) & 0xFFFF;
2063 bit_count = (inner == 0) ? 1 : hb_bit_storage (inner);
2064 inner_bit_count = hb_max (bit_count, inner_bit_count);
2065 }
2066 return true;
2067 }
2068
2069 private:
2070 unsigned map_count;
2071 unsigned outer_bit_count;
2072 unsigned inner_bit_count;
2073 hb_vector_t<uint32_t> output_map;
2074 };
2075
2076 struct COLR
2077 {
2078 static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
2079
has_v0_dataOT::COLR2080 bool has_v0_data () const { return numBaseGlyphs; }
has_v1_dataOT::COLR2081 bool has_v1_data () const
2082 {
2083 if (version < 1)
2084 return false;
2085 hb_barrier ();
2086
2087 return (this+baseGlyphList).len > 0;
2088 }
2089
get_glyph_layersOT::COLR2090 unsigned int get_glyph_layers (hb_codepoint_t glyph,
2091 unsigned int start_offset,
2092 unsigned int *count, /* IN/OUT. May be NULL. */
2093 hb_ot_color_layer_t *layers /* OUT. May be NULL. */) const
2094 {
2095 const BaseGlyphRecord &record = (this+baseGlyphsZ).bsearch (numBaseGlyphs, glyph);
2096
2097 hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
2098 hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
2099 record.numLayers);
2100 if (count)
2101 {
2102 + glyph_layers.sub_array (start_offset, count)
2103 | hb_sink (hb_array (layers, *count))
2104 ;
2105 }
2106 return glyph_layers.length;
2107 }
2108
2109 struct accelerator_t
2110 {
accelerator_tOT::COLR::accelerator_t2111 accelerator_t (hb_face_t *face)
2112 { colr = hb_sanitize_context_t ().reference_table<COLR> (face); }
~accelerator_tOT::COLR::accelerator_t2113 ~accelerator_t () { this->colr.destroy (); }
2114
is_validOT::COLR::accelerator_t2115 bool is_valid () { return colr.get_blob ()->length; }
2116
closure_glyphsOT::COLR::accelerator_t2117 void closure_glyphs (hb_codepoint_t glyph,
2118 hb_set_t *related_ids /* OUT */) const
2119 { colr->closure_glyphs (glyph, related_ids); }
2120
closure_V0palette_indicesOT::COLR::accelerator_t2121 void closure_V0palette_indices (const hb_set_t *glyphs,
2122 hb_set_t *palettes /* OUT */) const
2123 { colr->closure_V0palette_indices (glyphs, palettes); }
2124
closure_forV1OT::COLR::accelerator_t2125 void closure_forV1 (hb_set_t *glyphset,
2126 hb_set_t *layer_indices,
2127 hb_set_t *palette_indices,
2128 hb_set_t *variation_indices,
2129 hb_set_t *delta_set_indices) const
2130 { colr->closure_forV1 (glyphset, layer_indices, palette_indices, variation_indices, delta_set_indices); }
2131
has_var_storeOT::COLR::accelerator_t2132 bool has_var_store () const
2133 { return colr->has_var_store (); }
2134
get_var_storeOT::COLR::accelerator_t2135 const ItemVariationStore &get_var_store () const
2136 { return colr->get_var_store (); }
2137
has_delta_set_index_mapOT::COLR::accelerator_t2138 bool has_delta_set_index_map () const
2139 { return colr->has_delta_set_index_map (); }
2140
get_delta_set_index_mapOT::COLR::accelerator_t2141 const DeltaSetIndexMap &get_delta_set_index_map () const
2142 { return colr->get_delta_set_index_map (); }
2143
2144 private:
2145 hb_blob_ptr_t<COLR> colr;
2146 };
2147
closure_glyphsOT::COLR2148 void closure_glyphs (hb_codepoint_t glyph,
2149 hb_set_t *related_ids /* OUT */) const
2150 {
2151 const BaseGlyphRecord *record = get_base_glyph_record (glyph);
2152 if (!record) return;
2153
2154 auto glyph_layers = (this+layersZ).as_array (numLayers).sub_array (record->firstLayerIdx,
2155 record->numLayers);
2156 if (!glyph_layers.length) return;
2157 related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size);
2158 }
2159
closure_V0palette_indicesOT::COLR2160 void closure_V0palette_indices (const hb_set_t *glyphs,
2161 hb_set_t *palettes /* OUT */) const
2162 {
2163 if (!numBaseGlyphs || !numLayers) return;
2164 hb_array_t<const BaseGlyphRecord> baseGlyphs = (this+baseGlyphsZ).as_array (numBaseGlyphs);
2165 hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
2166
2167 for (const BaseGlyphRecord record : baseGlyphs)
2168 {
2169 if (!glyphs->has (record.glyphId)) continue;
2170 hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
2171 record.numLayers);
2172 for (const LayerRecord layer : glyph_layers)
2173 palettes->add (layer.colorIdx);
2174 }
2175 }
2176
closure_forV1OT::COLR2177 void closure_forV1 (hb_set_t *glyphset,
2178 hb_set_t *layer_indices,
2179 hb_set_t *palette_indices,
2180 hb_set_t *variation_indices,
2181 hb_set_t *delta_set_indices) const
2182 {
2183 if (version < 1) return;
2184 hb_barrier ();
2185
2186 hb_set_t visited_glyphs;
2187
2188 hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices, variation_indices);
2189 const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList;
2190
2191 for (const BaseGlyphPaintRecord &baseglyph_paintrecord: baseglyph_paintrecords.iter ())
2192 {
2193 unsigned gid = baseglyph_paintrecord.glyphId;
2194 if (!glyphset->has (gid)) continue;
2195
2196 const Paint &paint = &baseglyph_paintrecords+baseglyph_paintrecord.paint;
2197 paint.dispatch (&c);
2198 }
2199 hb_set_union (glyphset, &visited_glyphs);
2200
2201 const ClipList &cliplist = this+clipList;
2202 c.glyphs = glyphset;
2203 for (const ClipRecord &clip_record : cliplist.clips.iter())
2204 clip_record.closurev1 (&c, &cliplist);
2205
2206 // if a DeltaSetIndexMap is included, collected variation indices are
2207 // actually delta set indices, we need to map them into variation indices
2208 if (has_delta_set_index_map ())
2209 {
2210 const DeltaSetIndexMap &var_idx_map = this+varIdxMap;
2211 delta_set_indices->set (*variation_indices);
2212 variation_indices->clear ();
2213 for (unsigned delta_set_idx : *delta_set_indices)
2214 variation_indices->add (var_idx_map.map (delta_set_idx));
2215 }
2216 }
2217
get_layerListOT::COLR2218 const LayerList& get_layerList () const
2219 { return (this+layerList); }
2220
get_baseglyphListOT::COLR2221 const BaseGlyphList& get_baseglyphList () const
2222 { return (this+baseGlyphList); }
2223
has_var_storeOT::COLR2224 bool has_var_store () const
2225 { return version >= 1 && hb_barrier () && varStore != 0; }
2226
has_delta_set_index_mapOT::COLR2227 bool has_delta_set_index_map () const
2228 { return version >= 1 && hb_barrier () && varIdxMap != 0; }
2229
has_clip_listOT::COLR2230 bool has_clip_list () const
2231 { return version >= 1 && hb_barrier () && clipList != 0; }
2232
get_delta_set_index_mapOT::COLR2233 const DeltaSetIndexMap &get_delta_set_index_map () const
2234 { return has_delta_set_index_map () && hb_barrier () ? this+varIdxMap : Null (DeltaSetIndexMap); }
2235
get_var_storeOT::COLR2236 const ItemVariationStore &get_var_store () const
2237 { return has_var_store () && hb_barrier () ? this+varStore : Null (ItemVariationStore); }
2238
get_clip_listOT::COLR2239 const ClipList &get_clip_list () const
2240 { return has_clip_list () && hb_barrier () ? this+clipList : Null (ClipList); }
2241
sanitizeOT::COLR2242 bool sanitize (hb_sanitize_context_t *c) const
2243 {
2244 TRACE_SANITIZE (this);
2245 return_trace (c->check_struct (this) &&
2246 hb_barrier () &&
2247 (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
2248 (this+layersZ).sanitize (c, numLayers) &&
2249 (version == 0 ||
2250 (hb_barrier () &&
2251 baseGlyphList.sanitize (c, this) &&
2252 layerList.sanitize (c, this) &&
2253 clipList.sanitize (c, this) &&
2254 varIdxMap.sanitize (c, this) &&
2255 varStore.sanitize (c, this))));
2256 }
2257
2258 template<typename BaseIterator, typename LayerIterator,
2259 hb_requires (hb_is_iterator (BaseIterator)),
2260 hb_requires (hb_is_iterator (LayerIterator))>
serialize_V0OT::COLR2261 bool serialize_V0 (hb_serialize_context_t *c,
2262 unsigned version,
2263 BaseIterator base_it,
2264 LayerIterator layer_it)
2265 {
2266 TRACE_SERIALIZE (this);
2267 if (unlikely (base_it.len () != layer_it.len ()))
2268 return_trace (false);
2269
2270 this->version = version;
2271 numLayers = 0;
2272 numBaseGlyphs = base_it.len ();
2273 if (numBaseGlyphs == 0)
2274 {
2275 baseGlyphsZ = 0;
2276 layersZ = 0;
2277 return_trace (true);
2278 }
2279
2280 c->push ();
2281 for (const hb_item_type<BaseIterator> _ : + base_it.iter ())
2282 {
2283 auto* record = c->embed (_);
2284 if (unlikely (!record)) return_trace (false);
2285 record->firstLayerIdx = numLayers;
2286 numLayers += record->numLayers;
2287 }
2288 c->add_link (baseGlyphsZ, c->pop_pack ());
2289
2290 c->push ();
2291 for (const hb_item_type<LayerIterator>& _ : + layer_it.iter ())
2292 _.as_array ().copy (c);
2293
2294 c->add_link (layersZ, c->pop_pack ());
2295
2296 return_trace (true);
2297 }
2298
get_base_glyph_recordOT::COLR2299 const BaseGlyphRecord* get_base_glyph_record (hb_codepoint_t gid) const
2300 {
2301 const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, (unsigned int) gid);
2302 if (record == &Null (BaseGlyphRecord) ||
2303 (record && (hb_codepoint_t) record->glyphId != gid))
2304 record = nullptr;
2305 return record;
2306 }
2307
get_base_glyph_paintrecordOT::COLR2308 const BaseGlyphPaintRecord* get_base_glyph_paintrecord (hb_codepoint_t gid) const
2309 {
2310 const BaseGlyphPaintRecord* record = &(this+baseGlyphList).bsearch ((unsigned) gid);
2311 if ((record && (hb_codepoint_t) record->glyphId != gid))
2312 record = nullptr;
2313 return record;
2314 }
2315
downgrade_to_V0OT::COLR2316 bool downgrade_to_V0 (const hb_set_t &glyphset) const
2317 {
2318 //no more COLRv1 glyphs, downgrade to version 0
2319 for (const BaseGlyphPaintRecord& _ : get_baseglyphList ())
2320 if (glyphset.has (_.glyphId))
2321 return false;
2322
2323 return true;
2324 }
2325
subset_varstoreOT::COLR2326 bool subset_varstore (hb_subset_context_t *c,
2327 COLR* out /* OUT */) const
2328 {
2329 TRACE_SUBSET (this);
2330 if (!varStore || c->plan->all_axes_pinned ||
2331 !c->plan->colrv1_variation_idx_delta_map)
2332 return_trace (true);
2333
2334 const ItemVariationStore& var_store = this+varStore;
2335 if (c->plan->normalized_coords)
2336 {
2337 item_variations_t item_vars;
2338 /* turn off varstore optimization when varIdxMap is null, so we maintain
2339 * original var_idx sequence */
2340 bool optimize = (varIdxMap != 0) ? true : false;
2341 if (!item_vars.instantiate (var_store, c->plan,
2342 optimize, /* optimization */
2343 optimize, /* use_no_variation_idx = false */
2344 c->plan->colrv1_varstore_inner_maps.as_array ()))
2345 return_trace (false);
2346
2347 /* do not serialize varStore if there's no variation data after
2348 * instancing: region_list or var_data is empty */
2349 if (item_vars.get_region_list () &&
2350 item_vars.get_vardata_encodings () &&
2351 !out->varStore.serialize_serialize (c->serializer,
2352 item_vars.has_long_word (),
2353 c->plan->axis_tags,
2354 item_vars.get_region_list (),
2355 item_vars.get_vardata_encodings ()))
2356 return_trace (false);
2357
2358 /* if varstore is optimized, update colrv1_new_deltaset_idx_varidx_map in
2359 * subset plan.
2360 * If varstore is empty after instancing, varidx_map would be empty and
2361 * all var_idxes will be updated to VarIdx::NO_VARIATION */
2362 if (optimize)
2363 {
2364 const hb_map_t &varidx_map = item_vars.get_varidx_map ();
2365 for (auto _ : c->plan->colrv1_new_deltaset_idx_varidx_map.iter_ref ())
2366 {
2367 uint32_t varidx = _.second;
2368 uint32_t *new_varidx;
2369 if (varidx_map.has (varidx, &new_varidx))
2370 _.second = *new_varidx;
2371 else
2372 _.second = VarIdx::NO_VARIATION;
2373 }
2374 }
2375 }
2376 else
2377 {
2378 if (unlikely (!out->varStore.serialize_serialize (c->serializer,
2379 &var_store,
2380 c->plan->colrv1_varstore_inner_maps.as_array ())))
2381 return_trace (false);
2382 }
2383
2384 return_trace (true);
2385 }
2386
subset_delta_set_index_mapOT::COLR2387 bool subset_delta_set_index_map (hb_subset_context_t *c,
2388 COLR* out /* OUT */) const
2389 {
2390 TRACE_SUBSET (this);
2391 if (!varIdxMap || c->plan->all_axes_pinned ||
2392 !c->plan->colrv1_new_deltaset_idx_varidx_map)
2393 return_trace (true);
2394
2395 const hb_map_t &deltaset_idx_varidx_map = c->plan->colrv1_new_deltaset_idx_varidx_map;
2396 delta_set_index_map_subset_plan_t index_map_plan (deltaset_idx_varidx_map);
2397
2398 if (unlikely (!index_map_plan.remap (deltaset_idx_varidx_map)))
2399 return_trace (false);
2400
2401 return_trace (out->varIdxMap.serialize_serialize (c->serializer, index_map_plan));
2402 }
2403
subsetOT::COLR2404 bool subset (hb_subset_context_t *c) const
2405 {
2406 TRACE_SUBSET (this);
2407 const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
2408 const hb_set_t& glyphset = c->plan->_glyphset_colred;
2409
2410 auto base_it =
2411 + hb_range (c->plan->num_output_glyphs ())
2412 | hb_filter ([&](hb_codepoint_t new_gid)
2413 {
2414 hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
2415 if (glyphset.has (old_gid)) return true;
2416 return false;
2417 })
2418 | hb_map_retains_sorting ([&](hb_codepoint_t new_gid)
2419 {
2420 hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
2421
2422 const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
2423 if (unlikely (!old_record))
2424 return hb_pair_t<bool, BaseGlyphRecord> (false, Null (BaseGlyphRecord));
2425 BaseGlyphRecord new_record = {};
2426 new_record.glyphId = new_gid;
2427 new_record.numLayers = old_record->numLayers;
2428 return hb_pair_t<bool, BaseGlyphRecord> (true, new_record);
2429 })
2430 | hb_filter (hb_first)
2431 | hb_map_retains_sorting (hb_second)
2432 ;
2433
2434 auto layer_it =
2435 + hb_range (c->plan->num_output_glyphs ())
2436 | hb_map (reverse_glyph_map)
2437 | hb_filter (glyphset)
2438 | hb_map_retains_sorting ([&](hb_codepoint_t old_gid)
2439 {
2440 const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
2441 hb_vector_t<LayerRecord> out_layers;
2442
2443 if (unlikely (!old_record ||
2444 old_record->firstLayerIdx >= numLayers ||
2445 old_record->firstLayerIdx + old_record->numLayers > numLayers))
2446 return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
2447
2448 auto layers = (this+layersZ).as_array (numLayers).sub_array (old_record->firstLayerIdx,
2449 old_record->numLayers);
2450 out_layers.resize (layers.length);
2451 for (unsigned int i = 0; i < layers.length; i++) {
2452 out_layers[i] = layers[i];
2453 hb_codepoint_t new_gid = 0;
2454 if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid)))
2455 return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
2456 out_layers[i].glyphId = new_gid;
2457 out_layers[i].colorIdx = c->plan->colr_palettes.get (layers[i].colorIdx);
2458 }
2459
2460 return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers);
2461 })
2462 | hb_filter (hb_first)
2463 | hb_map_retains_sorting (hb_second)
2464 ;
2465
2466 if (version == 0 && (!base_it || !layer_it))
2467 return_trace (false);
2468
2469 auto *colr_prime = c->serializer->start_embed<COLR> ();
2470 if (unlikely (!c->serializer->extend_min (colr_prime))) return_trace (false);
2471
2472 if (version == 0 || downgrade_to_V0 (glyphset))
2473 return_trace (colr_prime->serialize_V0 (c->serializer, 0, base_it, layer_it));
2474
2475 hb_barrier ();
2476
2477 //start version 1
2478 if (!c->serializer->allocate_size<void> (5 * HBUINT32::static_size)) return_trace (false);
2479 if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false);
2480
2481 /* subset ItemVariationStore first, cause varidx_map needs to be updated
2482 * after instancing */
2483 if (!subset_varstore (c, colr_prime)) return_trace (false);
2484
2485 ItemVarStoreInstancer instancer (&(get_var_store ()),
2486 &(get_delta_set_index_map ()),
2487 c->plan->normalized_coords.as_array ());
2488
2489 if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this, instancer))
2490 return_trace (false);
2491
2492 colr_prime->layerList.serialize_subset (c, layerList, this, instancer);
2493 colr_prime->clipList.serialize_subset (c, clipList, this, instancer);
2494
2495 return_trace (subset_delta_set_index_map (c, colr_prime));
2496 }
2497
get_base_glyph_paintOT::COLR2498 const Paint *get_base_glyph_paint (hb_codepoint_t glyph) const
2499 {
2500 const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList;
2501 const BaseGlyphPaintRecord* record = get_base_glyph_paintrecord (glyph);
2502 if (record)
2503 {
2504 const Paint &paint = &baseglyph_paintrecords+record->paint;
2505 return &paint;
2506 }
2507 else
2508 return nullptr;
2509 }
2510
2511 #ifndef HB_NO_PAINT
2512 bool
get_extentsOT::COLR2513 get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
2514 {
2515
2516 ItemVarStoreInstancer instancer (&(get_var_store ()),
2517 &(get_delta_set_index_map ()),
2518 hb_array (font->coords, font->num_coords));
2519
2520 if (get_clip (glyph, extents, instancer))
2521 {
2522 font->scale_glyph_extents (extents);
2523 return true;
2524 }
2525
2526 auto *extents_funcs = hb_paint_extents_get_funcs ();
2527 hb_paint_extents_context_t extents_data;
2528 bool ret = paint_glyph (font, glyph, extents_funcs, &extents_data, 0, HB_COLOR(0,0,0,0));
2529
2530 hb_extents_t e = extents_data.get_extents ();
2531 if (e.is_void ())
2532 {
2533 extents->x_bearing = 0;
2534 extents->y_bearing = 0;
2535 extents->width = 0;
2536 extents->height = 0;
2537 }
2538 else
2539 {
2540 extents->x_bearing = e.xmin;
2541 extents->y_bearing = e.ymax;
2542 extents->width = e.xmax - e.xmin;
2543 extents->height = e.ymin - e.ymax;
2544 }
2545
2546 return ret;
2547 }
2548 #endif
2549
2550 bool
has_paint_for_glyphOT::COLR2551 has_paint_for_glyph (hb_codepoint_t glyph) const
2552 {
2553 if (version >= 1)
2554 {
2555 hb_barrier ();
2556
2557 const Paint *paint = get_base_glyph_paint (glyph);
2558
2559 return paint != nullptr;
2560 }
2561
2562 return false;
2563 }
2564
get_clipOT::COLR2565 bool get_clip (hb_codepoint_t glyph,
2566 hb_glyph_extents_t *extents,
2567 const ItemVarStoreInstancer instancer) const
2568 {
2569 return get_clip_list ().get_extents (glyph,
2570 extents,
2571 instancer);
2572 }
2573
2574 #ifndef HB_NO_PAINT
2575 bool
paint_glyphOT::COLR2576 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
2577 {
2578 ItemVarStoreInstancer instancer (&(get_var_store ()),
2579 &(get_delta_set_index_map ()),
2580 hb_array (font->coords, font->num_coords));
2581 hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer);
2582 c.current_glyphs.add (glyph);
2583
2584 if (version >= 1)
2585 {
2586 hb_barrier ();
2587
2588 const Paint *paint = get_base_glyph_paint (glyph);
2589 if (paint)
2590 {
2591 // COLRv1 glyph
2592
2593 bool is_bounded = true;
2594 if (clip)
2595 {
2596 hb_glyph_extents_t extents;
2597 if (get_clip (glyph, &extents, instancer))
2598 {
2599 font->scale_glyph_extents (&extents);
2600 c.funcs->push_clip_rectangle (c.data,
2601 extents.x_bearing,
2602 extents.y_bearing + extents.height,
2603 extents.x_bearing + extents.width,
2604 extents.y_bearing);
2605 }
2606 else
2607 {
2608 auto *extents_funcs = hb_paint_extents_get_funcs ();
2609 hb_paint_extents_context_t extents_data;
2610
2611 paint_glyph (font, glyph,
2612 extents_funcs, &extents_data,
2613 palette_index, foreground,
2614 false);
2615
2616 hb_extents_t extents = extents_data.get_extents ();
2617 is_bounded = extents_data.is_bounded ();
2618
2619 c.funcs->push_clip_rectangle (c.data,
2620 extents.xmin,
2621 extents.ymin,
2622 extents.xmax,
2623 extents.ymax);
2624 }
2625 }
2626
2627 c.funcs->push_root_transform (c.data, font);
2628
2629 if (is_bounded)
2630 c.recurse (*paint);
2631
2632 c.funcs->pop_transform (c.data);
2633
2634 if (clip)
2635 c.funcs->pop_clip (c.data);
2636
2637 return true;
2638 }
2639 }
2640
2641 const BaseGlyphRecord *record = get_base_glyph_record (glyph);
2642 if (record && ((hb_codepoint_t) record->glyphId == glyph))
2643 {
2644 // COLRv0 glyph
2645 for (const auto &r : (this+layersZ).as_array (numLayers)
2646 .sub_array (record->firstLayerIdx, record->numLayers))
2647 {
2648 hb_bool_t is_foreground;
2649 hb_color_t color = c.get_color (r.colorIdx, 1., &is_foreground);
2650 c.funcs->push_clip_glyph (c.data, r.glyphId, c.font);
2651 c.funcs->color (c.data, is_foreground, color);
2652 c.funcs->pop_clip (c.data);
2653 }
2654
2655 return true;
2656 }
2657
2658 return false;
2659 }
2660 #endif
2661
2662 protected:
2663 HBUINT16 version; /* Table version number (starts at 0). */
2664 HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records. */
2665 NNOffset32To<SortedUnsizedArrayOf<BaseGlyphRecord>>
2666 baseGlyphsZ; /* Offset to Base Glyph records. */
2667 NNOffset32To<UnsizedArrayOf<LayerRecord>>
2668 layersZ; /* Offset to Layer Records. */
2669 HBUINT16 numLayers; /* Number of Layer Records. */
2670 // Version-1 additions
2671 Offset32To<BaseGlyphList> baseGlyphList;
2672 Offset32To<LayerList> layerList;
2673 Offset32To<ClipList> clipList; // Offset to ClipList table (may be NULL)
2674 Offset32To<DeltaSetIndexMap> varIdxMap; // Offset to DeltaSetIndexMap table (may be NULL)
2675 Offset32To<ItemVariationStore> varStore;
2676 public:
2677 DEFINE_SIZE_MIN (14);
2678 };
2679
2680 struct COLR_accelerator_t : COLR::accelerator_t {
COLR_accelerator_tOT::COLR_accelerator_t2681 COLR_accelerator_t (hb_face_t *face) : COLR::accelerator_t (face) {}
2682 };
2683
2684 void
recurse(const Paint & paint)2685 hb_paint_context_t::recurse (const Paint &paint)
2686 {
2687 if (unlikely (depth_left <= 0 || edge_count <= 0)) return;
2688 depth_left--;
2689 edge_count--;
2690 paint.dispatch (this);
2691 depth_left++;
2692 }
2693
paint_glyph(hb_paint_context_t * c) const2694 void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const
2695 {
2696 TRACE_PAINT (this);
2697 const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList ();
2698 for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++)
2699 {
2700 if (unlikely (c->current_layers.has (i)))
2701 continue;
2702
2703 c->current_layers.add (i);
2704
2705 const Paint &paint = paint_offset_lists.get_paint (i);
2706 c->funcs->push_group (c->data);
2707 c->recurse (paint);
2708 c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
2709
2710 c->current_layers.del (i);
2711 }
2712 }
2713
paint_glyph(hb_paint_context_t * c) const2714 void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
2715 {
2716 TRACE_PAINT (this);
2717
2718 if (unlikely (c->current_glyphs.has (gid)))
2719 return;
2720
2721 c->current_glyphs.add (gid);
2722
2723 c->funcs->push_inverse_root_transform (c->data, c->font);
2724 if (c->funcs->color_glyph (c->data, gid, c->font))
2725 {
2726 c->funcs->pop_transform (c->data);
2727 c->current_glyphs.del (gid);
2728 return;
2729 }
2730 c->funcs->pop_transform (c->data);
2731
2732 const COLR *colr_table = c->get_colr_table ();
2733 const Paint *paint = colr_table->get_base_glyph_paint (gid);
2734
2735 hb_glyph_extents_t extents = {0};
2736 bool has_clip_box = colr_table->get_clip (gid, &extents, c->instancer);
2737
2738 if (has_clip_box)
2739 c->funcs->push_clip_rectangle (c->data,
2740 extents.x_bearing,
2741 extents.y_bearing + extents.height,
2742 extents.x_bearing + extents.width,
2743 extents.y_bearing);
2744
2745 if (paint)
2746 c->recurse (*paint);
2747
2748 if (has_clip_box)
2749 c->funcs->pop_clip (c->data);
2750
2751 c->current_glyphs.del (gid);
2752 }
2753
2754 } /* namespace OT */
2755
2756 #endif /* OT_COLOR_COLR_COLR_HH */
2757