/src/harfbuzz/src/OT/Var/VARC/VARC.cc
Line | Count | Source |
1 | | #ifndef HB_OT_VAR_VARC_CC |
2 | | #define HB_OT_VAR_VARC_CC |
3 | | #ifdef HB_OT_VAR_VARC_CC /* Pacify -Wunused-macros. */ |
4 | | |
5 | | #include "VARC.hh" |
6 | | |
7 | | #ifndef HB_NO_VAR_COMPOSITES |
8 | | |
9 | | #include "../../../hb-draw.hh" |
10 | | #include "../../../hb-depend-data.hh" |
11 | | #include "../../../hb-ot-layout-common.hh" |
12 | | #include "../../../hb-ot-layout-gdef-table.hh" |
13 | | |
14 | | namespace OT { |
15 | | |
16 | | //namespace Var { |
17 | | |
18 | | #define VARC_PROCESS_TRANSFORM_COMPONENTS \ |
19 | 0 | HB_STMT_START { \ |
20 | 0 | PROCESS_TRANSFORM_COMPONENT ( 0, FWORD, HAVE_TRANSLATE_X, translateX); \ |
21 | 0 | PROCESS_TRANSFORM_COMPONENT ( 0, FWORD, HAVE_TRANSLATE_Y, translateY); \ |
22 | 0 | PROCESS_TRANSFORM_COMPONENT (12, F4DOT12, HAVE_ROTATION, rotation); \ |
23 | 0 | PROCESS_TRANSFORM_COMPONENT (10, F6DOT10, HAVE_SCALE_X, scaleX); \ |
24 | 0 | PROCESS_TRANSFORM_COMPONENT (10, F6DOT10, HAVE_SCALE_Y, scaleY); \ |
25 | 0 | PROCESS_TRANSFORM_COMPONENT (12, F4DOT12, HAVE_SKEW_X, skewX); \ |
26 | 0 | PROCESS_TRANSFORM_COMPONENT (12, F4DOT12, HAVE_SKEW_Y, skewY); \ |
27 | 0 | PROCESS_TRANSFORM_COMPONENT ( 0, FWORD, HAVE_TCENTER_X, tCenterX); \ |
28 | 0 | PROCESS_TRANSFORM_COMPONENT ( 0, FWORD, HAVE_TCENTER_Y, tCenterY); \ |
29 | 0 | } HB_STMT_END |
30 | | |
31 | | bool |
32 | | VarComponent::decompile_record (const VARC &varc, |
33 | | hb_ubytes_t total_record, |
34 | | hb_vector_t<unsigned> *axis_indices, |
35 | | hb_vector_t<double> *axis_values, |
36 | | record_t *decoded, |
37 | | int64_t *budget) |
38 | 0 | { |
39 | 0 | const unsigned char *start = total_record.arrayZ; |
40 | 0 | const unsigned char *record = start; |
41 | 0 | const unsigned char *end = start + total_record.length; |
42 | |
|
43 | 0 | if (axis_indices) axis_indices->clear (); |
44 | 0 | if (axis_values) axis_values->clear (); |
45 | |
|
46 | 0 | #define READ_UINT32VAR(name) \ |
47 | 0 | HB_STMT_START { \ |
48 | 0 | if (unlikely (unsigned (end - record) < HBUINT32VAR::min_size)) return false; \ |
49 | 0 | hb_barrier (); \ |
50 | 0 | auto &varint = * (const HBUINT32VAR *) record; \ |
51 | 0 | unsigned size = varint.get_size (); \ |
52 | 0 | if (unlikely (unsigned (end - record) < size)) return false; \ |
53 | 0 | name = (uint32_t) varint; \ |
54 | 0 | record += size; \ |
55 | 0 | } HB_STMT_END |
56 | 0 | #define READ_UINT32VAR_FIELD(name, field) \ |
57 | 0 | HB_STMT_START { \ |
58 | 0 | decoded->field##_offset = record - start; \ |
59 | 0 | READ_UINT32VAR (name); \ |
60 | 0 | decoded->field##_size = record - start - decoded->field##_offset; \ |
61 | 0 | } HB_STMT_END |
62 | |
|
63 | 0 | READ_UINT32VAR (decoded->flags); |
64 | | |
65 | 0 | decoded->gid_offset = record - start; |
66 | 0 | if (decoded->flags & (unsigned) flags_t::GID_IS_24BIT) |
67 | 0 | { |
68 | 0 | decoded->gid_size = HBGlyphID24::static_size; |
69 | 0 | if (unlikely (unsigned (end - record) < HBGlyphID24::static_size)) return false; |
70 | 0 | hb_barrier (); |
71 | 0 | decoded->gid = * (const HBGlyphID24 *) record; |
72 | 0 | record += HBGlyphID24::static_size; |
73 | 0 | } |
74 | 0 | else |
75 | 0 | { |
76 | 0 | decoded->gid_size = HBGlyphID16::static_size; |
77 | 0 | if (unlikely (unsigned (end - record) < HBGlyphID16::static_size)) return false; |
78 | 0 | hb_barrier (); |
79 | 0 | decoded->gid = * (const HBGlyphID16 *) record; |
80 | 0 | record += HBGlyphID16::static_size; |
81 | 0 | } |
82 | | |
83 | 0 | if (decoded->flags & (unsigned) flags_t::HAVE_CONDITION) |
84 | 0 | READ_UINT32VAR_FIELD (decoded->condition_index, condition); |
85 | | |
86 | 0 | if (decoded->flags & (unsigned) flags_t::HAVE_AXES) |
87 | 0 | { |
88 | 0 | READ_UINT32VAR_FIELD (decoded->axis_indices_index, axis_indices); |
89 | 0 | unsigned axis_count; |
90 | 0 | if (axis_indices) |
91 | 0 | { |
92 | 0 | axis_indices->extend ((&varc+varc.axisIndicesList)[decoded->axis_indices_index]); |
93 | 0 | if (unlikely (axis_indices->in_error ())) return false; |
94 | 0 | axis_count = axis_indices->length; |
95 | 0 | } |
96 | 0 | else |
97 | 0 | axis_count = hb_len ((&varc+varc.axisIndicesList)[decoded->axis_indices_index]); |
98 | 0 | if (unlikely (budget && axis_count && |
99 | 0 | !hb_budget_spend (*budget, HB_BUDGET_1, axis_count))) |
100 | 0 | return false; |
101 | 0 | if (axis_values) |
102 | 0 | { |
103 | 0 | if (unlikely (!axis_values->resize (axis_count))) return false; |
104 | 0 | const HBUINT8 *p = (const HBUINT8 *) record; |
105 | 0 | if (unlikely (!TupleValues::decompile (p, *axis_values, |
106 | 0 | (const HBUINT8 *) end))) |
107 | 0 | return false; |
108 | 0 | record = (const unsigned char *) p; |
109 | 0 | } |
110 | 0 | else if (unlikely (!TupleValues::skip (record, end, axis_count))) |
111 | 0 | return false; |
112 | 0 | } |
113 | | |
114 | 0 | decoded->axis_values_var_idx = VarIdx::NO_VARIATION; |
115 | 0 | if (decoded->flags & (unsigned) flags_t::AXIS_VALUES_HAVE_VARIATION) |
116 | 0 | READ_UINT32VAR_FIELD (decoded->axis_values_var_idx, axis_values_var); |
117 | | |
118 | 0 | decoded->transform_var_idx = VarIdx::NO_VARIATION; |
119 | 0 | if (decoded->flags & (unsigned) flags_t::TRANSFORM_HAS_VARIATION) |
120 | 0 | READ_UINT32VAR_FIELD (decoded->transform_var_idx, transform_var); |
121 | | |
122 | 0 | #define PROCESS_TRANSFORM_COMPONENT(shift, type, flag, name) \ |
123 | 0 | if (decoded->flags & (unsigned) flags_t::flag) \ |
124 | 0 | { \ |
125 | 0 | static_assert (type::static_size == HBINT16::static_size, ""); \ |
126 | 0 | if (unlikely (unsigned (end - record) < HBINT16::static_size)) return false; \ |
127 | 0 | hb_barrier (); \ |
128 | 0 | decoded->transform.name = * (const HBINT16 *) record; \ |
129 | 0 | record += HBINT16::static_size; \ |
130 | 0 | } |
131 | 0 | VARC_PROCESS_TRANSFORM_COMPONENTS; |
132 | 0 | #undef PROCESS_TRANSFORM_COMPONENT |
133 | | |
134 | 0 | unsigned reserved = decoded->flags & (unsigned) flags_t::RESERVED_MASK; |
135 | 0 | while (reserved) |
136 | 0 | { |
137 | 0 | uint32_t discard HB_UNUSED; |
138 | 0 | READ_UINT32VAR (discard); |
139 | 0 | reserved &= reserved - 1; |
140 | 0 | } |
141 | | |
142 | 0 | decoded->size = record - start; |
143 | 0 | #undef READ_UINT32VAR_FIELD |
144 | 0 | #undef READ_UINT32VAR |
145 | 0 | return true; |
146 | 0 | } |
147 | | |
148 | | bool |
149 | | VARC::closure_glyphs (hb_set_t *glyphset) const |
150 | 0 | { |
151 | 0 | if (unlikely (glyphset->in_error ())) |
152 | 0 | return false; |
153 | | |
154 | 0 | hb_set_t pending = *glyphset; |
155 | 0 | if (unlikely (pending.in_error ())) |
156 | 0 | return false; |
157 | | |
158 | 0 | while (pending) |
159 | 0 | { |
160 | 0 | hb_codepoint_t gid = pending.get_min (); |
161 | 0 | pending.del (gid); |
162 | |
|
163 | 0 | unsigned index = (this+coverage).get_coverage (gid); |
164 | 0 | if (index == NOT_COVERED) continue; |
165 | | |
166 | 0 | hb_ubytes_t record = (this+glyphRecords)[index]; |
167 | 0 | while (record) |
168 | 0 | { |
169 | 0 | VarComponent::record_t component; |
170 | 0 | if (unlikely (!VarComponent::decompile_record (*this, record, |
171 | 0 | nullptr, nullptr, &component))) |
172 | 0 | return false; |
173 | 0 | if (!glyphset->has (component.gid)) |
174 | 0 | { |
175 | 0 | glyphset->add (component.gid); |
176 | 0 | if (unlikely (glyphset->in_error ())) |
177 | 0 | return false; |
178 | 0 | pending.add (component.gid); |
179 | 0 | if (unlikely (pending.in_error ())) |
180 | 0 | return false; |
181 | 0 | } |
182 | 0 | record = record.sub_array (component.size); |
183 | 0 | } |
184 | 0 | } |
185 | 0 | return true; |
186 | 0 | } |
187 | | |
188 | | void |
189 | | VARC::depend (hb_depend_data_builder_t *depend_data) const |
190 | 0 | { |
191 | 0 | const CFF2Index &records = this+glyphRecords; |
192 | 0 | for (auto _ : + hb_zip (this+coverage, |
193 | 0 | hb_range ((unsigned) records.count))) |
194 | 0 | { |
195 | 0 | hb_codepoint_t gid = _.first; |
196 | 0 | hb_ubytes_t record = records[_.second]; |
197 | 0 | while (record) |
198 | 0 | { |
199 | 0 | VarComponent::record_t component; |
200 | 0 | if (unlikely (!VarComponent::decompile_record (*this, record, |
201 | 0 | nullptr, nullptr, &component))) |
202 | 0 | { |
203 | 0 | depend_data->fail (); |
204 | 0 | return; |
205 | 0 | } |
206 | 0 | depend_data->add_depend (gid, tableTag, component.gid); |
207 | 0 | record = record.sub_array (component.size); |
208 | 0 | } |
209 | 0 | } |
210 | 0 | } |
211 | | |
212 | | |
213 | | #ifndef HB_NO_DRAW |
214 | | |
215 | | struct hb_transforming_pen_context_t |
216 | | { |
217 | | hb_transform_t<> transform; |
218 | | hb_draw_funcs_t *dfuncs; |
219 | | void *data; |
220 | | hb_draw_state_t *st; |
221 | | int64_t *budget_remaining; |
222 | | }; |
223 | | |
224 | | static void |
225 | | hb_transforming_pen_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED, |
226 | | void *data, |
227 | | hb_draw_state_t *st, |
228 | | float to_x, float to_y, |
229 | | void *user_data HB_UNUSED) |
230 | 0 | { |
231 | 0 | hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; |
232 | |
|
233 | 0 | c->transform.transform_point (to_x, to_y); |
234 | |
|
235 | 0 | c->dfuncs->move_to (c->data, *c->st, to_x, to_y); |
236 | 0 | } |
237 | | |
238 | | static void |
239 | | hb_transforming_pen_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED, |
240 | | void *data, |
241 | | hb_draw_state_t *st, |
242 | | float to_x, float to_y, |
243 | | void *user_data HB_UNUSED) |
244 | 0 | { |
245 | 0 | hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; |
246 | |
|
247 | 0 | c->transform.transform_point (to_x, to_y); |
248 | |
|
249 | 0 | c->dfuncs->line_to (c->data, *c->st, to_x, to_y); |
250 | 0 | } |
251 | | |
252 | | static void |
253 | | hb_transforming_pen_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, |
254 | | void *data, |
255 | | hb_draw_state_t *st, |
256 | | float control_x, float control_y, |
257 | | float to_x, float to_y, |
258 | | void *user_data HB_UNUSED) |
259 | 0 | { |
260 | 0 | hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; |
261 | |
|
262 | 0 | c->transform.transform_point (control_x, control_y); |
263 | 0 | c->transform.transform_point (to_x, to_y); |
264 | |
|
265 | 0 | c->dfuncs->quadratic_to (c->data, *c->st, control_x, control_y, to_x, to_y); |
266 | 0 | } |
267 | | |
268 | | static void |
269 | | hb_transforming_pen_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, |
270 | | void *data, |
271 | | hb_draw_state_t *st, |
272 | | float control1_x, float control1_y, |
273 | | float control2_x, float control2_y, |
274 | | float to_x, float to_y, |
275 | | void *user_data HB_UNUSED) |
276 | 0 | { |
277 | 0 | hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; |
278 | |
|
279 | 0 | c->transform.transform_point (control1_x, control1_y); |
280 | 0 | c->transform.transform_point (control2_x, control2_y); |
281 | 0 | c->transform.transform_point (to_x, to_y); |
282 | |
|
283 | 0 | c->dfuncs->cubic_to (c->data, *c->st, control1_x, control1_y, control2_x, control2_y, to_x, to_y); |
284 | 0 | } |
285 | | |
286 | | static void |
287 | | hb_transforming_pen_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED, |
288 | | void *data, |
289 | | hb_draw_state_t *st, |
290 | | void *user_data HB_UNUSED) |
291 | 0 | { |
292 | 0 | hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; |
293 | |
|
294 | 0 | c->dfuncs->close_path (c->data, *c->st); |
295 | 0 | } |
296 | | |
297 | | static int64_t * |
298 | | hb_transforming_pen_get_budget_remaining (hb_draw_funcs_t *, void *draw_data, void *) |
299 | 0 | { |
300 | 0 | return ((hb_transforming_pen_context_t *) draw_data)->budget_remaining; |
301 | 0 | } |
302 | | |
303 | | static inline void free_static_transforming_pen_funcs (); |
304 | | |
305 | | static struct hb_transforming_pen_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_transforming_pen_funcs_lazy_loader_t> |
306 | | { |
307 | | static hb_draw_funcs_t *create () |
308 | 0 | { |
309 | 0 | hb_draw_funcs_t *funcs = hb_draw_funcs_create (); |
310 | |
|
311 | 0 | hb_draw_funcs_set_move_to_func (funcs, hb_transforming_pen_move_to, nullptr, nullptr); |
312 | 0 | hb_draw_funcs_set_line_to_func (funcs, hb_transforming_pen_line_to, nullptr, nullptr); |
313 | 0 | hb_draw_funcs_set_quadratic_to_func (funcs, hb_transforming_pen_quadratic_to, nullptr, nullptr); |
314 | 0 | hb_draw_funcs_set_cubic_to_func (funcs, hb_transforming_pen_cubic_to, nullptr, nullptr); |
315 | 0 | hb_draw_funcs_set_close_path_func (funcs, hb_transforming_pen_close_path, nullptr, nullptr); |
316 | 0 | hb_draw_funcs_set_get_budget_remaining_func (funcs, hb_transforming_pen_get_budget_remaining, nullptr, nullptr); |
317 | |
|
318 | 0 | hb_draw_funcs_make_immutable (funcs); |
319 | |
|
320 | 0 | hb_atexit (free_static_transforming_pen_funcs); |
321 | |
|
322 | 0 | return funcs; |
323 | 0 | } |
324 | | } static_transforming_pen_funcs; |
325 | | |
326 | | static inline |
327 | | void free_static_transforming_pen_funcs () |
328 | 0 | { |
329 | 0 | static_transforming_pen_funcs.free_instance (); |
330 | 0 | } |
331 | | |
332 | | static hb_draw_funcs_t * |
333 | | hb_transforming_pen_get_funcs () |
334 | 0 | { |
335 | 0 | return static_transforming_pen_funcs.get_unconst (); |
336 | 0 | } |
337 | | |
338 | | hb_ubytes_t |
339 | | VarComponent::get_path_at (const hb_varc_context_t &c, |
340 | | hb_codepoint_t parent_gid, |
341 | | hb_array_t<const int> coords, |
342 | | hb_transform_t<> total_transform, |
343 | | hb_ubytes_t total_record, |
344 | | hb_scalar_cache_t *cache) const |
345 | 0 | { |
346 | 0 | if (unlikely (!hb_budget_spend (c.budget, HB_BUDGET_4))) |
347 | 0 | return hb_ubytes_t (); |
348 | | |
349 | 0 | const unsigned char *end = total_record.arrayZ + total_record.length; |
350 | 0 | auto &VARC = *c.font->face->table.VARC->table; |
351 | 0 | auto &varStore = &VARC+VARC.varStore; |
352 | |
|
353 | 0 | auto &axisIndices = c.scratch.axisIndices; |
354 | 0 | auto &axisValues = c.scratch.axisValues; |
355 | 0 | record_t component; |
356 | 0 | if (unlikely (!decompile_record (VARC, total_record, |
357 | 0 | &axisIndices, &axisValues, &component, |
358 | 0 | &c.budget))) |
359 | 0 | return hb_ubytes_t (); |
360 | | |
361 | 0 | uint32_t flags = component.flags; |
362 | 0 | hb_codepoint_t gid = component.gid; |
363 | 0 | const unsigned char *record = total_record.arrayZ + component.size; |
364 | | |
365 | | // Condition |
366 | 0 | bool show = true; |
367 | 0 | if (flags & (unsigned) flags_t::HAVE_CONDITION) |
368 | 0 | { |
369 | 0 | const auto &condition = (&VARC+VARC.conditionList)[component.condition_index]; |
370 | 0 | auto instancer = MultiItemVarStoreInstancer(&varStore, nullptr, coords, cache); |
371 | 0 | show = condition.evaluate (coords.arrayZ, coords.length, &instancer); |
372 | 0 | } |
373 | | |
374 | | // Axis values |
375 | | |
376 | | // Apply variations if any |
377 | 0 | if ((flags & (unsigned) flags_t::AXIS_VALUES_HAVE_VARIATION) && |
378 | 0 | show && !axisValues.in_error ()) |
379 | 0 | { |
380 | 0 | if (unlikely (!hb_budget_spend (c.budget, axisValues.length, |
381 | 0 | coords.length))) |
382 | 0 | return hb_ubytes_t (); |
383 | 0 | varStore.get_delta (component.axis_values_var_idx, coords, |
384 | 0 | axisValues.as_array (), cache); |
385 | 0 | } |
386 | | |
387 | 0 | auto component_coords = coords; |
388 | | /* Copying coords is expensive; so we have put an arbitrary |
389 | | * limit on the max number of coords for now. */ |
390 | 0 | if ((flags & (unsigned) flags_t::RESET_UNSPECIFIED_AXES) || |
391 | 0 | coords.length > HB_VAR_COMPOSITE_MAX_AXES) |
392 | 0 | component_coords = hb_array (c.font->coords, c.font->num_coords); |
393 | |
|
394 | 0 | uint32_t transformVarIdx = component.transform_var_idx; |
395 | 0 | hb_transform_decomposed_t<> transform = component.transform; |
396 | |
|
397 | 0 | if (show) |
398 | 0 | { |
399 | | // Only use coord_setter if there's actually any axis overrides. |
400 | 0 | if (unlikely (axisIndices && |
401 | 0 | !hb_budget_spend (c.budget, HB_BUDGET_1, |
402 | 0 | component_coords.length))) |
403 | 0 | return hb_ubytes_t (); |
404 | 0 | coord_setter_t coord_setter (axisIndices ? component_coords : hb_array<int> ()); |
405 | 0 | for (unsigned i = 0; i < axisIndices.length; i++) |
406 | 0 | coord_setter[axisIndices[i]] = hb_clamp_to<int> (round (axisValues[i])); |
407 | 0 | if (axisIndices) |
408 | 0 | component_coords = coord_setter.get_coords (); |
409 | | |
410 | | // Apply transform variations if any |
411 | 0 | if (transformVarIdx != VarIdx::NO_VARIATION) |
412 | 0 | { |
413 | 0 | double transformValues[9]; |
414 | 0 | unsigned numTransformValues = 0; |
415 | 0 | #define PROCESS_TRANSFORM_COMPONENT(shift, type, flag, name) \ |
416 | 0 | if (flags & (unsigned) flags_t::flag) \ |
417 | 0 | transformValues[numTransformValues++] = (double) transform.name; |
418 | 0 | VARC_PROCESS_TRANSFORM_COMPONENTS; |
419 | 0 | #undef PROCESS_TRANSFORM_COMPONENT |
420 | 0 | if (unlikely (!hb_budget_spend (c.budget, numTransformValues, |
421 | 0 | coords.length))) |
422 | 0 | return hb_ubytes_t (); |
423 | 0 | varStore.get_delta (transformVarIdx, coords, hb_array (transformValues, numTransformValues), cache); |
424 | 0 | numTransformValues = 0; |
425 | 0 | #define PROCESS_TRANSFORM_COMPONENT(shift, type, flag, name) \ |
426 | 0 | if (flags & (unsigned) flags_t::flag) \ |
427 | 0 | transform.name = (float) transformValues[numTransformValues++]; |
428 | 0 | VARC_PROCESS_TRANSFORM_COMPONENTS; |
429 | 0 | #undef PROCESS_TRANSFORM_COMPONENT |
430 | 0 | } |
431 | | |
432 | | // Divide them by their divisors |
433 | 0 | #define PROCESS_TRANSFORM_COMPONENT(shift, type, flag, name) \ |
434 | 0 | if (shift && (flags & (unsigned) flags_t::flag)) \ |
435 | 0 | transform.name *= 1.f / (1 << shift); |
436 | 0 | VARC_PROCESS_TRANSFORM_COMPONENTS; |
437 | 0 | #undef PROCESS_TRANSFORM_COMPONENT |
438 | |
|
439 | 0 | if (!(flags & (unsigned) flags_t::HAVE_SCALE_Y)) |
440 | 0 | transform.scaleY = transform.scaleX; |
441 | |
|
442 | 0 | transform.rotation *= HB_PI; |
443 | 0 | transform.skewX *= HB_PI; |
444 | 0 | transform.skewY *= HB_PI; |
445 | |
|
446 | 0 | total_transform.transform (transform.to_transform ()); |
447 | |
|
448 | 0 | bool same_coords = component_coords.length == coords.length && |
449 | 0 | component_coords.arrayZ == coords.arrayZ; |
450 | |
|
451 | 0 | c.depth_left--; |
452 | 0 | VARC.get_path_at (c, gid, |
453 | 0 | component_coords, total_transform, |
454 | 0 | parent_gid, |
455 | 0 | same_coords ? cache : nullptr); |
456 | 0 | c.depth_left++; |
457 | 0 | } |
458 | | |
459 | 0 | return hb_ubytes_t (record, end - record); |
460 | 0 | } |
461 | | |
462 | | bool |
463 | | VARC::get_path_at (const hb_varc_context_t &c, |
464 | | hb_codepoint_t glyph, |
465 | | hb_array_t<const int> coords, |
466 | | hb_transform_t<> transform, |
467 | | hb_codepoint_t parent_glyph, |
468 | | hb_scalar_cache_t *parent_cache) const |
469 | 0 | { |
470 | | // Don't recurse on the same glyph. |
471 | 0 | unsigned idx = glyph == parent_glyph ? |
472 | 0 | NOT_COVERED : |
473 | 0 | (this+coverage).get_coverage (glyph); |
474 | 0 | if (idx == NOT_COVERED) |
475 | 0 | { |
476 | 0 | if (c.draw_session) |
477 | 0 | { |
478 | | /* Out of budget: draw nothing, but signal success so remaining |
479 | | * leaves are skipped instead of falling back per-glyph. */ |
480 | 0 | if (unlikely (!hb_budget_spend (c.budget, HB_BUDGET_1))) return true; |
481 | | |
482 | 0 | hb_transform_t<> leaf_transform = transform; |
483 | 0 | leaf_transform.x0 *= c.font->x_multf; |
484 | 0 | leaf_transform.y0 *= c.font->y_multf; |
485 | | |
486 | | // Build a transforming pen to apply the transform. |
487 | 0 | hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs (); |
488 | 0 | hb_transforming_pen_context_t context {leaf_transform, |
489 | 0 | c.draw_session->funcs, |
490 | 0 | c.draw_session->draw_data, |
491 | 0 | &c.draw_session->st, |
492 | 0 | &c.budget}; |
493 | 0 | hb_draw_session_t transformer_session {transformer_funcs, &context}; |
494 | 0 | hb_draw_session_t &shape_draw_session = leaf_transform.is_identity () ? *c.draw_session : transformer_session; |
495 | |
|
496 | 0 | if (c.font->face->table.glyf->get_path_at (c.font, glyph, shape_draw_session, coords, c.scratch.glyf_scratch, nullptr, &shape_draw_session.get_budget ())) return true; |
497 | 0 | #ifndef HB_NO_CFF |
498 | 0 | if (c.font->face->table.cff2->get_path_at (c.font, glyph, shape_draw_session, coords, &shape_draw_session.get_budget ())) return true; |
499 | 0 | if (c.font->face->table.cff1->get_path (c.font, glyph, shape_draw_session, &shape_draw_session.get_budget ())) return true; // Doesn't have variations |
500 | 0 | #endif |
501 | 0 | return false; |
502 | 0 | } |
503 | 0 | else if (c.extents) |
504 | 0 | { |
505 | 0 | if (unlikely (!hb_budget_spend (c.budget, HB_BUDGET_1))) return true; |
506 | | |
507 | 0 | hb_glyph_extents_t glyph_extents; |
508 | 0 | if (!c.font->face->table.glyf->get_extents_at (c.font, glyph, &glyph_extents, coords, &c.budget)) |
509 | 0 | #ifndef HB_NO_CFF |
510 | 0 | if (!c.font->face->table.cff2->get_extents_at (c.font, glyph, &glyph_extents, coords, &c.budget)) |
511 | 0 | if (!c.font->face->table.cff1->get_extents (c.font, glyph, &glyph_extents, &c.budget)) // Doesn't have variations |
512 | 0 | #endif |
513 | 0 | return false; |
514 | | |
515 | 0 | hb_extents_t<> comp_extents (glyph_extents); |
516 | 0 | hb_transform_t<> leaf_transform = transform; |
517 | 0 | leaf_transform.x0 *= c.font->x_multf; |
518 | 0 | leaf_transform.y0 *= c.font->y_multf; |
519 | 0 | leaf_transform.transform_extents (comp_extents); |
520 | 0 | c.extents->union_ (comp_extents); |
521 | 0 | } |
522 | 0 | return true; |
523 | 0 | } |
524 | | |
525 | 0 | if (c.depth_left <= 0) |
526 | 0 | return true; |
527 | | |
528 | 0 | if (c.edges_left <= 0) |
529 | 0 | return true; |
530 | 0 | (c.edges_left)--; |
531 | |
|
532 | 0 | hb_decycler_node_t node (c.decycler); |
533 | 0 | if (unlikely (!node.visit (glyph))) |
534 | 0 | return true; |
535 | | |
536 | 0 | hb_ubytes_t record = (this+glyphRecords)[idx]; |
537 | |
|
538 | 0 | hb_scalar_cache_t static_cache; |
539 | 0 | hb_scalar_cache_t *cache = parent_cache ? |
540 | 0 | parent_cache : |
541 | 0 | (this+varStore).create_cache (&static_cache); |
542 | |
|
543 | 0 | VarCompositeGlyph::get_path_at (c, |
544 | 0 | glyph, |
545 | 0 | coords, transform, |
546 | 0 | record, |
547 | 0 | cache); |
548 | |
|
549 | 0 | if (cache != parent_cache) |
550 | 0 | (this+varStore).destroy_cache (cache, &static_cache); |
551 | |
|
552 | 0 | return true; |
553 | 0 | } |
554 | | |
555 | | #endif |
556 | | |
557 | | #undef VARC_PROCESS_TRANSFORM_COMPONENTS |
558 | | |
559 | | //} // namespace Var |
560 | | } // namespace OT |
561 | | |
562 | | #endif |
563 | | |
564 | | #endif /* HB_OT_VAR_VARC_CC (pacify clang) */ |
565 | | #endif /* HB_OT_VAR_VARC_CC */ |