/src/harfbuzz/src/OT/Var/VARC/VARC.cc
Line | Count | Source |
1 | | #include "VARC.hh" |
2 | | |
3 | | #ifndef HB_NO_VAR_COMPOSITES |
4 | | |
5 | | #include "../../../hb-draw.hh" |
6 | | #include "../../../hb-ot-layout-common.hh" |
7 | | #include "../../../hb-ot-layout-gdef-table.hh" |
8 | | |
9 | | namespace OT { |
10 | | |
11 | | //namespace Var { |
12 | | |
13 | | |
14 | | #ifndef HB_NO_DRAW |
15 | | |
16 | | struct hb_transforming_pen_context_t |
17 | | { |
18 | | hb_transform_t<> transform; |
19 | | hb_draw_funcs_t *dfuncs; |
20 | | void *data; |
21 | | hb_draw_state_t *st; |
22 | | }; |
23 | | |
24 | | static void |
25 | | hb_transforming_pen_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED, |
26 | | void *data, |
27 | | hb_draw_state_t *st, |
28 | | float to_x, float to_y, |
29 | | void *user_data HB_UNUSED) |
30 | 0 | { |
31 | 0 | hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; |
32 | |
|
33 | 0 | c->transform.transform_point (to_x, to_y); |
34 | |
|
35 | 0 | c->dfuncs->move_to (c->data, *c->st, to_x, to_y); |
36 | 0 | } |
37 | | |
38 | | static void |
39 | | hb_transforming_pen_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED, |
40 | | void *data, |
41 | | hb_draw_state_t *st, |
42 | | float to_x, float to_y, |
43 | | void *user_data HB_UNUSED) |
44 | 0 | { |
45 | 0 | hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; |
46 | |
|
47 | 0 | c->transform.transform_point (to_x, to_y); |
48 | |
|
49 | 0 | c->dfuncs->line_to (c->data, *c->st, to_x, to_y); |
50 | 0 | } |
51 | | |
52 | | static void |
53 | | hb_transforming_pen_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, |
54 | | void *data, |
55 | | hb_draw_state_t *st, |
56 | | float control_x, float control_y, |
57 | | float to_x, float to_y, |
58 | | void *user_data HB_UNUSED) |
59 | 0 | { |
60 | 0 | hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; |
61 | |
|
62 | 0 | c->transform.transform_point (control_x, control_y); |
63 | 0 | c->transform.transform_point (to_x, to_y); |
64 | |
|
65 | 0 | c->dfuncs->quadratic_to (c->data, *c->st, control_x, control_y, to_x, to_y); |
66 | 0 | } |
67 | | |
68 | | static void |
69 | | hb_transforming_pen_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, |
70 | | void *data, |
71 | | hb_draw_state_t *st, |
72 | | float control1_x, float control1_y, |
73 | | float control2_x, float control2_y, |
74 | | float to_x, float to_y, |
75 | | void *user_data HB_UNUSED) |
76 | 0 | { |
77 | 0 | hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; |
78 | |
|
79 | 0 | c->transform.transform_point (control1_x, control1_y); |
80 | 0 | c->transform.transform_point (control2_x, control2_y); |
81 | 0 | c->transform.transform_point (to_x, to_y); |
82 | |
|
83 | 0 | c->dfuncs->cubic_to (c->data, *c->st, control1_x, control1_y, control2_x, control2_y, to_x, to_y); |
84 | 0 | } |
85 | | |
86 | | static void |
87 | | hb_transforming_pen_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED, |
88 | | void *data, |
89 | | hb_draw_state_t *st, |
90 | | void *user_data HB_UNUSED) |
91 | 0 | { |
92 | 0 | hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data; |
93 | |
|
94 | 0 | c->dfuncs->close_path (c->data, *c->st); |
95 | 0 | } |
96 | | |
97 | | static inline void free_static_transforming_pen_funcs (); |
98 | | |
99 | | static struct hb_transforming_pen_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_transforming_pen_funcs_lazy_loader_t> |
100 | | { |
101 | | static hb_draw_funcs_t *create () |
102 | 0 | { |
103 | 0 | hb_draw_funcs_t *funcs = hb_draw_funcs_create (); |
104 | |
|
105 | 0 | hb_draw_funcs_set_move_to_func (funcs, hb_transforming_pen_move_to, nullptr, nullptr); |
106 | 0 | hb_draw_funcs_set_line_to_func (funcs, hb_transforming_pen_line_to, nullptr, nullptr); |
107 | 0 | hb_draw_funcs_set_quadratic_to_func (funcs, hb_transforming_pen_quadratic_to, nullptr, nullptr); |
108 | 0 | hb_draw_funcs_set_cubic_to_func (funcs, hb_transforming_pen_cubic_to, nullptr, nullptr); |
109 | 0 | hb_draw_funcs_set_close_path_func (funcs, hb_transforming_pen_close_path, nullptr, nullptr); |
110 | |
|
111 | 0 | hb_draw_funcs_make_immutable (funcs); |
112 | |
|
113 | 0 | hb_atexit (free_static_transforming_pen_funcs); |
114 | |
|
115 | 0 | return funcs; |
116 | 0 | } |
117 | | } static_transforming_pen_funcs; |
118 | | |
119 | | static inline |
120 | | void free_static_transforming_pen_funcs () |
121 | 0 | { |
122 | 0 | static_transforming_pen_funcs.free_instance (); |
123 | 0 | } |
124 | | |
125 | | static hb_draw_funcs_t * |
126 | | hb_transforming_pen_get_funcs () |
127 | 0 | { |
128 | 0 | return static_transforming_pen_funcs.get_unconst (); |
129 | 0 | } |
130 | | |
131 | | hb_ubytes_t |
132 | | VarComponent::get_path_at (const hb_varc_context_t &c, |
133 | | hb_codepoint_t parent_gid, |
134 | | hb_array_t<const int> coords, |
135 | | hb_transform_t<> total_transform, |
136 | | hb_ubytes_t total_record, |
137 | | hb_scalar_cache_t *cache) const |
138 | 0 | { |
139 | 0 | const unsigned char *end = total_record.arrayZ + total_record.length; |
140 | 0 | const unsigned char *record = total_record.arrayZ; |
141 | |
|
142 | 0 | auto &VARC = *c.font->face->table.VARC->table; |
143 | 0 | auto &varStore = &VARC+VARC.varStore; |
144 | |
|
145 | 0 | #define READ_UINT32VAR(name) \ |
146 | 0 | HB_STMT_START { \ |
147 | 0 | if (unlikely (unsigned (end - record) < HBUINT32VAR::min_size)) return hb_ubytes_t (); \ |
148 | 0 | hb_barrier (); \ |
149 | 0 | auto &varint = * (const HBUINT32VAR *) record; \ |
150 | 0 | unsigned size = varint.get_size (); \ |
151 | 0 | if (unlikely (unsigned (end - record) < size)) return hb_ubytes_t (); \ |
152 | 0 | name = (uint32_t) varint; \ |
153 | 0 | record += size; \ |
154 | 0 | } HB_STMT_END |
155 | |
|
156 | 0 | uint32_t flags; |
157 | 0 | READ_UINT32VAR (flags); |
158 | | |
159 | | // gid |
160 | | |
161 | 0 | hb_codepoint_t gid = 0; |
162 | 0 | if (flags & (unsigned) flags_t::GID_IS_24BIT) |
163 | 0 | { |
164 | 0 | if (unlikely (unsigned (end - record) < HBGlyphID24::static_size)) |
165 | 0 | return hb_ubytes_t (); |
166 | 0 | hb_barrier (); |
167 | 0 | gid = * (const HBGlyphID24 *) record; |
168 | 0 | record += HBGlyphID24::static_size; |
169 | 0 | } |
170 | 0 | else |
171 | 0 | { |
172 | 0 | if (unlikely (unsigned (end - record) < HBGlyphID16::static_size)) |
173 | 0 | return hb_ubytes_t (); |
174 | 0 | hb_barrier (); |
175 | 0 | gid = * (const HBGlyphID16 *) record; |
176 | 0 | record += HBGlyphID16::static_size; |
177 | 0 | } |
178 | | |
179 | | // Condition |
180 | 0 | bool show = true; |
181 | 0 | if (flags & (unsigned) flags_t::HAVE_CONDITION) |
182 | 0 | { |
183 | 0 | unsigned conditionIndex; |
184 | 0 | READ_UINT32VAR (conditionIndex); |
185 | 0 | const auto &condition = (&VARC+VARC.conditionList)[conditionIndex]; |
186 | 0 | auto instancer = MultiItemVarStoreInstancer(&varStore, nullptr, coords, cache); |
187 | 0 | show = condition.evaluate (coords.arrayZ, coords.length, &instancer); |
188 | 0 | } |
189 | | |
190 | | // Axis values |
191 | | |
192 | 0 | auto &axisIndices = c.scratch.axisIndices; |
193 | 0 | axisIndices.clear (); |
194 | 0 | auto &axisValues = c.scratch.axisValues; |
195 | 0 | axisValues.clear (); |
196 | 0 | if (flags & (unsigned) flags_t::HAVE_AXES) |
197 | 0 | { |
198 | 0 | unsigned axisIndicesIndex; |
199 | 0 | READ_UINT32VAR (axisIndicesIndex); |
200 | 0 | axisIndices.extend ((&VARC+VARC.axisIndicesList)[axisIndicesIndex]); |
201 | 0 | axisValues.resize (axisIndices.length); |
202 | 0 | const HBUINT8 *p = (const HBUINT8 *) record; |
203 | 0 | TupleValues::decompile (p, axisValues, (const HBUINT8 *) end); |
204 | 0 | record = (const unsigned char *) p; |
205 | 0 | } |
206 | | |
207 | | // Apply variations if any |
208 | 0 | if (flags & (unsigned) flags_t::AXIS_VALUES_HAVE_VARIATION) |
209 | 0 | { |
210 | 0 | uint32_t axisValuesVarIdx; |
211 | 0 | READ_UINT32VAR (axisValuesVarIdx); |
212 | 0 | if (show && coords && !axisValues.in_error ()) |
213 | 0 | varStore.get_delta (axisValuesVarIdx, coords, axisValues.as_array (), cache); |
214 | 0 | } |
215 | | |
216 | 0 | auto component_coords = coords; |
217 | | /* Copying coords is expensive; so we have put an arbitrary |
218 | | * limit on the max number of coords for now. */ |
219 | 0 | if ((flags & (unsigned) flags_t::RESET_UNSPECIFIED_AXES) || |
220 | 0 | coords.length > HB_VAR_COMPOSITE_MAX_AXES) |
221 | 0 | component_coords = hb_array (c.font->coords, c.font->num_coords); |
222 | | |
223 | | // Transform |
224 | |
|
225 | 0 | uint32_t transformVarIdx = VarIdx::NO_VARIATION; |
226 | 0 | if (flags & (unsigned) flags_t::TRANSFORM_HAS_VARIATION) |
227 | 0 | READ_UINT32VAR (transformVarIdx); |
228 | | |
229 | 0 | #define PROCESS_TRANSFORM_COMPONENTS \ |
230 | 0 | HB_STMT_START { \ |
231 | 0 | PROCESS_TRANSFORM_COMPONENT ( 0, FWORD, HAVE_TRANSLATE_X, translateX); \ |
232 | 0 | PROCESS_TRANSFORM_COMPONENT ( 0, FWORD, HAVE_TRANSLATE_Y, translateY); \ |
233 | 0 | PROCESS_TRANSFORM_COMPONENT (12, F4DOT12, HAVE_ROTATION, rotation); \ |
234 | 0 | PROCESS_TRANSFORM_COMPONENT (10, F6DOT10, HAVE_SCALE_X, scaleX); \ |
235 | 0 | PROCESS_TRANSFORM_COMPONENT (10, F6DOT10, HAVE_SCALE_Y, scaleY); \ |
236 | 0 | PROCESS_TRANSFORM_COMPONENT (12, F4DOT12, HAVE_SKEW_X, skewX); \ |
237 | 0 | PROCESS_TRANSFORM_COMPONENT (12, F4DOT12, HAVE_SKEW_Y, skewY); \ |
238 | 0 | PROCESS_TRANSFORM_COMPONENT ( 0, FWORD, HAVE_TCENTER_X, tCenterX); \ |
239 | 0 | PROCESS_TRANSFORM_COMPONENT ( 0, FWORD, HAVE_TCENTER_Y, tCenterY); \ |
240 | 0 | } HB_STMT_END |
241 | | |
242 | 0 | hb_transform_decomposed_t<> transform; |
243 | | |
244 | | // Read transform components |
245 | 0 | #define PROCESS_TRANSFORM_COMPONENT(shift, type, flag, name) \ |
246 | 0 | if (flags & (unsigned) flags_t::flag) \ |
247 | 0 | { \ |
248 | 0 | static_assert (type::static_size == HBINT16::static_size, ""); \ |
249 | 0 | if (unlikely (unsigned (end - record) < HBINT16::static_size)) \ |
250 | 0 | return hb_ubytes_t (); \ |
251 | 0 | hb_barrier (); \ |
252 | 0 | transform.name = * (const HBINT16 *) record; \ |
253 | 0 | record += HBINT16::static_size; \ |
254 | 0 | } |
255 | 0 | PROCESS_TRANSFORM_COMPONENTS; |
256 | 0 | #undef PROCESS_TRANSFORM_COMPONENT |
257 | | |
258 | | // Read reserved records |
259 | 0 | unsigned i = flags & (unsigned) flags_t::RESERVED_MASK; |
260 | 0 | while (i) |
261 | 0 | { |
262 | 0 | HB_UNUSED uint32_t discard; |
263 | 0 | READ_UINT32VAR (discard); |
264 | 0 | i &= i - 1; |
265 | 0 | } |
266 | | |
267 | | /* Parsing is over now. */ |
268 | | |
269 | 0 | if (show) |
270 | 0 | { |
271 | | // Only use coord_setter if there's actually any axis overrides. |
272 | 0 | coord_setter_t coord_setter (axisIndices ? component_coords : hb_array<int> ()); |
273 | 0 | for (unsigned i = 0; i < axisIndices.length; i++) |
274 | 0 | coord_setter[axisIndices[i]] = roundf (axisValues[i]); |
275 | 0 | if (axisIndices) |
276 | 0 | component_coords = coord_setter.get_coords (); |
277 | | |
278 | | // Apply transform variations if any |
279 | 0 | if (transformVarIdx != VarIdx::NO_VARIATION && coords) |
280 | 0 | { |
281 | 0 | float transformValues[9]; |
282 | 0 | unsigned numTransformValues = 0; |
283 | 0 | #define PROCESS_TRANSFORM_COMPONENT(shift, type, flag, name) \ |
284 | 0 | if (flags & (unsigned) flags_t::flag) \ |
285 | 0 | transformValues[numTransformValues++] = transform.name; |
286 | 0 | PROCESS_TRANSFORM_COMPONENTS; |
287 | 0 | #undef PROCESS_TRANSFORM_COMPONENT |
288 | 0 | varStore.get_delta (transformVarIdx, coords, hb_array (transformValues, numTransformValues), cache); |
289 | 0 | numTransformValues = 0; |
290 | 0 | #define PROCESS_TRANSFORM_COMPONENT(shift, type, flag, name) \ |
291 | 0 | if (flags & (unsigned) flags_t::flag) \ |
292 | 0 | transform.name = transformValues[numTransformValues++]; |
293 | 0 | PROCESS_TRANSFORM_COMPONENTS; |
294 | 0 | #undef PROCESS_TRANSFORM_COMPONENT |
295 | 0 | } |
296 | | |
297 | | // Divide them by their divisors |
298 | 0 | #define PROCESS_TRANSFORM_COMPONENT(shift, type, flag, name) \ |
299 | 0 | if (shift && (flags & (unsigned) flags_t::flag)) \ |
300 | 0 | transform.name *= 1.f / (1 << shift); |
301 | 0 | PROCESS_TRANSFORM_COMPONENTS; |
302 | 0 | #undef PROCESS_TRANSFORM_COMPONENT |
303 | |
|
304 | 0 | if (!(flags & (unsigned) flags_t::HAVE_SCALE_Y)) |
305 | 0 | transform.scaleY = transform.scaleX; |
306 | |
|
307 | 0 | transform.rotation *= HB_PI; |
308 | 0 | transform.skewX *= HB_PI; |
309 | 0 | transform.skewY *= HB_PI; |
310 | |
|
311 | 0 | total_transform.transform (transform.to_transform ()); |
312 | |
|
313 | 0 | bool same_coords = component_coords.length == coords.length && |
314 | 0 | component_coords.arrayZ == coords.arrayZ; |
315 | |
|
316 | 0 | c.depth_left--; |
317 | 0 | VARC.get_path_at (c, gid, |
318 | 0 | component_coords, total_transform, |
319 | 0 | parent_gid, |
320 | 0 | same_coords ? cache : nullptr); |
321 | 0 | c.depth_left++; |
322 | 0 | } |
323 | |
|
324 | 0 | #undef PROCESS_TRANSFORM_COMPONENTS |
325 | 0 | #undef READ_UINT32VAR |
326 | |
|
327 | 0 | return hb_ubytes_t (record, end - record); |
328 | 0 | } |
329 | | |
330 | | bool |
331 | | VARC::get_path_at (const hb_varc_context_t &c, |
332 | | hb_codepoint_t glyph, |
333 | | hb_array_t<const int> coords, |
334 | | hb_transform_t<> transform, |
335 | | hb_codepoint_t parent_glyph, |
336 | | hb_scalar_cache_t *parent_cache) const |
337 | 0 | { |
338 | | // Don't recurse on the same glyph. |
339 | 0 | unsigned idx = glyph == parent_glyph ? |
340 | 0 | NOT_COVERED : |
341 | 0 | (this+coverage).get_coverage (glyph); |
342 | 0 | if (idx == NOT_COVERED) |
343 | 0 | { |
344 | 0 | if (c.draw_session) |
345 | 0 | { |
346 | 0 | hb_transform_t<> leaf_transform = transform; |
347 | 0 | leaf_transform.x0 *= c.font->x_multf; |
348 | 0 | leaf_transform.y0 *= c.font->y_multf; |
349 | | |
350 | | // Build a transforming pen to apply the transform. |
351 | 0 | hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs (); |
352 | 0 | hb_transforming_pen_context_t context {leaf_transform, |
353 | 0 | c.draw_session->funcs, |
354 | 0 | c.draw_session->draw_data, |
355 | 0 | &c.draw_session->st}; |
356 | 0 | hb_draw_session_t transformer_session {transformer_funcs, &context}; |
357 | 0 | hb_draw_session_t &shape_draw_session = leaf_transform.is_identity () ? *c.draw_session : transformer_session; |
358 | |
|
359 | 0 | if (c.font->face->table.glyf->get_path_at (c.font, glyph, shape_draw_session, coords, c.scratch.glyf_scratch)) return true; |
360 | 0 | #ifndef HB_NO_CFF |
361 | 0 | if (c.font->face->table.cff2->get_path_at (c.font, glyph, shape_draw_session, coords)) return true; |
362 | 0 | if (c.font->face->table.cff1->get_path (c.font, glyph, shape_draw_session)) return true; // Doesn't have variations |
363 | 0 | #endif |
364 | 0 | return false; |
365 | 0 | } |
366 | 0 | else if (c.extents) |
367 | 0 | { |
368 | 0 | hb_glyph_extents_t glyph_extents; |
369 | 0 | if (!c.font->face->table.glyf->get_extents_at (c.font, glyph, &glyph_extents, coords)) |
370 | 0 | #ifndef HB_NO_CFF |
371 | 0 | if (!c.font->face->table.cff2->get_extents_at (c.font, glyph, &glyph_extents, coords)) |
372 | 0 | if (!c.font->face->table.cff1->get_extents (c.font, glyph, &glyph_extents)) // Doesn't have variations |
373 | 0 | #endif |
374 | 0 | return false; |
375 | | |
376 | 0 | hb_extents_t<> comp_extents (glyph_extents); |
377 | 0 | hb_transform_t<> leaf_transform = transform; |
378 | 0 | leaf_transform.x0 *= c.font->x_multf; |
379 | 0 | leaf_transform.y0 *= c.font->y_multf; |
380 | 0 | leaf_transform.transform_extents (comp_extents); |
381 | 0 | c.extents->union_ (comp_extents); |
382 | 0 | } |
383 | 0 | return true; |
384 | 0 | } |
385 | | |
386 | 0 | if (c.depth_left <= 0) |
387 | 0 | return true; |
388 | | |
389 | 0 | if (c.edges_left <= 0) |
390 | 0 | return true; |
391 | 0 | (c.edges_left)--; |
392 | |
|
393 | 0 | hb_decycler_node_t node (c.decycler); |
394 | 0 | if (unlikely (!node.visit (glyph))) |
395 | 0 | return true; |
396 | | |
397 | 0 | hb_ubytes_t record = (this+glyphRecords)[idx]; |
398 | |
|
399 | 0 | hb_scalar_cache_t static_cache; |
400 | 0 | hb_scalar_cache_t *cache = parent_cache ? |
401 | 0 | parent_cache : |
402 | 0 | (this+varStore).create_cache (&static_cache); |
403 | |
|
404 | 0 | VarCompositeGlyph::get_path_at (c, |
405 | 0 | glyph, |
406 | 0 | coords, transform, |
407 | 0 | record, |
408 | 0 | cache); |
409 | |
|
410 | 0 | if (cache != parent_cache) |
411 | 0 | (this+varStore).destroy_cache (cache, &static_cache); |
412 | |
|
413 | 0 | return true; |
414 | 0 | } |
415 | | |
416 | | #endif |
417 | | |
418 | | //} // namespace Var |
419 | | } // namespace OT |
420 | | |
421 | | #endif |