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