1 #include "VARC.hh"
2
3 #ifndef HB_NO_VAR_COMPOSITES
4
5 #include "../../../hb-draw.hh"
6 #include "../../../hb-geometry.hh"
7 #include "../../../hb-ot-layout-common.hh"
8 #include "../../../hb-ot-layout-gdef-table.hh"
9
10 namespace OT {
11
12 //namespace Var {
13
14
15 struct hb_transforming_pen_context_t
16 {
17 hb_transform_t transform;
18 hb_draw_funcs_t *dfuncs;
19 void *data;
20 hb_draw_state_t *st;
21 };
22
23 static void
hb_transforming_pen_move_to(hb_draw_funcs_t * dfuncs HB_UNUSED,void * data,hb_draw_state_t * st,float to_x,float to_y,void * user_data HB_UNUSED)24 hb_transforming_pen_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
25 void *data,
26 hb_draw_state_t *st,
27 float to_x, float to_y,
28 void *user_data HB_UNUSED)
29 {
30 hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
31
32 c->transform.transform_point (to_x, to_y);
33
34 c->dfuncs->move_to (c->data, *c->st, to_x, to_y);
35 }
36
37 static void
hb_transforming_pen_line_to(hb_draw_funcs_t * dfuncs HB_UNUSED,void * data,hb_draw_state_t * st,float to_x,float to_y,void * user_data HB_UNUSED)38 hb_transforming_pen_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
39 void *data,
40 hb_draw_state_t *st,
41 float to_x, float to_y,
42 void *user_data HB_UNUSED)
43 {
44 hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
45
46 c->transform.transform_point (to_x, to_y);
47
48 c->dfuncs->line_to (c->data, *c->st, to_x, to_y);
49 }
50
51 static void
hb_transforming_pen_quadratic_to(hb_draw_funcs_t * dfuncs HB_UNUSED,void * data,hb_draw_state_t * st,float control_x,float control_y,float to_x,float to_y,void * user_data HB_UNUSED)52 hb_transforming_pen_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
53 void *data,
54 hb_draw_state_t *st,
55 float control_x, float control_y,
56 float to_x, float to_y,
57 void *user_data HB_UNUSED)
58 {
59 hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
60
61 c->transform.transform_point (control_x, control_y);
62 c->transform.transform_point (to_x, to_y);
63
64 c->dfuncs->quadratic_to (c->data, *c->st, control_x, control_y, to_x, to_y);
65 }
66
67 static void
hb_transforming_pen_cubic_to(hb_draw_funcs_t * dfuncs HB_UNUSED,void * data,hb_draw_state_t * st,float control1_x,float control1_y,float control2_x,float control2_y,float to_x,float to_y,void * user_data HB_UNUSED)68 hb_transforming_pen_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
69 void *data,
70 hb_draw_state_t *st,
71 float control1_x, float control1_y,
72 float control2_x, float control2_y,
73 float to_x, float to_y,
74 void *user_data HB_UNUSED)
75 {
76 hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
77
78 c->transform.transform_point (control1_x, control1_y);
79 c->transform.transform_point (control2_x, control2_y);
80 c->transform.transform_point (to_x, to_y);
81
82 c->dfuncs->cubic_to (c->data, *c->st, control1_x, control1_y, control2_x, control2_y, to_x, to_y);
83 }
84
85 static void
hb_transforming_pen_close_path(hb_draw_funcs_t * dfuncs HB_UNUSED,void * data,hb_draw_state_t * st,void * user_data HB_UNUSED)86 hb_transforming_pen_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED,
87 void *data,
88 hb_draw_state_t *st,
89 void *user_data HB_UNUSED)
90 {
91 hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
92
93 c->dfuncs->close_path (c->data, *c->st);
94 }
95
96 static inline void free_static_transforming_pen_funcs ();
97
98 static struct hb_transforming_pen_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_transforming_pen_funcs_lazy_loader_t>
99 {
createOT::hb_transforming_pen_funcs_lazy_loader_t100 static hb_draw_funcs_t *create ()
101 {
102 hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
103
104 hb_draw_funcs_set_move_to_func (funcs, hb_transforming_pen_move_to, nullptr, nullptr);
105 hb_draw_funcs_set_line_to_func (funcs, hb_transforming_pen_line_to, nullptr, nullptr);
106 hb_draw_funcs_set_quadratic_to_func (funcs, hb_transforming_pen_quadratic_to, nullptr, nullptr);
107 hb_draw_funcs_set_cubic_to_func (funcs, hb_transforming_pen_cubic_to, nullptr, nullptr);
108 hb_draw_funcs_set_close_path_func (funcs, hb_transforming_pen_close_path, nullptr, nullptr);
109
110 hb_draw_funcs_make_immutable (funcs);
111
112 hb_atexit (free_static_transforming_pen_funcs);
113
114 return funcs;
115 }
116 } static_transforming_pen_funcs;
117
118 static inline
free_static_transforming_pen_funcs()119 void free_static_transforming_pen_funcs ()
120 {
121 static_transforming_pen_funcs.free_instance ();
122 }
123
124 static hb_draw_funcs_t *
hb_transforming_pen_get_funcs()125 hb_transforming_pen_get_funcs ()
126 {
127 return static_transforming_pen_funcs.get_unconst ();
128 }
129
130
131 hb_ubytes_t
get_path_at(hb_font_t * font,hb_codepoint_t parent_gid,hb_draw_session_t & draw_session,hb_array_t<const int> coords,hb_ubytes_t total_record,hb_set_t * visited,signed * edges_left,signed depth_left,VarRegionList::cache_t * cache) const132 VarComponent::get_path_at (hb_font_t *font,
133 hb_codepoint_t parent_gid,
134 hb_draw_session_t &draw_session,
135 hb_array_t<const int> coords,
136 hb_ubytes_t total_record,
137 hb_set_t *visited,
138 signed *edges_left,
139 signed depth_left,
140 VarRegionList::cache_t *cache) const
141 {
142 const unsigned char *end = total_record.arrayZ + total_record.length;
143 const unsigned char *record = total_record.arrayZ;
144
145 auto &VARC = *font->face->table.VARC;
146 auto &varStore = &VARC+VARC.varStore;
147 auto instancer = MultiItemVarStoreInstancer(&varStore, nullptr, coords, cache);
148
149 #define READ_UINT32VAR(name) \
150 HB_STMT_START { \
151 if (unlikely (unsigned (end - record) < HBUINT32VAR::min_size)) return hb_ubytes_t (); \
152 hb_barrier (); \
153 auto &varint = * (const HBUINT32VAR *) record; \
154 unsigned size = varint.get_size (); \
155 if (unlikely (unsigned (end - record) < size)) return hb_ubytes_t (); \
156 name = (uint32_t) varint; \
157 record += size; \
158 } HB_STMT_END
159
160 uint32_t flags;
161 READ_UINT32VAR (flags);
162
163 // gid
164
165 hb_codepoint_t gid = 0;
166 if (flags & (unsigned) flags_t::GID_IS_24BIT)
167 {
168 if (unlikely (unsigned (end - record) < HBGlyphID24::static_size))
169 return hb_ubytes_t ();
170 hb_barrier ();
171 gid = * (const HBGlyphID24 *) record;
172 record += HBGlyphID24::static_size;
173 }
174 else
175 {
176 if (unlikely (unsigned (end - record) < HBGlyphID16::static_size))
177 return hb_ubytes_t ();
178 hb_barrier ();
179 gid = * (const HBGlyphID16 *) record;
180 record += HBGlyphID16::static_size;
181 }
182
183 // Condition
184 bool show = true;
185 if (flags & (unsigned) flags_t::HAVE_CONDITION)
186 {
187 unsigned conditionIndex;
188 READ_UINT32VAR (conditionIndex);
189 const auto &condition = (&VARC+VARC.conditionList)[conditionIndex];
190 show = condition.evaluate (coords.arrayZ, coords.length, &instancer);
191 }
192
193 // Axis values
194
195 hb_vector_t<unsigned> axisIndices;
196 hb_vector_t<float> axisValues;
197 if (flags & (unsigned) flags_t::HAVE_AXES)
198 {
199 unsigned axisIndicesIndex;
200 READ_UINT32VAR (axisIndicesIndex);
201 axisIndices = (&VARC+VARC.axisIndicesList)[axisIndicesIndex];
202 axisValues.resize (axisIndices.length);
203 const HBUINT8 *p = (const HBUINT8 *) record;
204 TupleValues::decompile (p, axisValues, (const HBUINT8 *) end);
205 record += (const unsigned char *) p - record;
206 }
207
208 // Apply variations if any
209 if (flags & (unsigned) flags_t::AXIS_VALUES_HAVE_VARIATION)
210 {
211 uint32_t axisValuesVarIdx;
212 READ_UINT32VAR (axisValuesVarIdx);
213 if (show && coords && !axisValues.in_error ())
214 varStore.get_delta (axisValuesVarIdx, coords, axisValues.as_array (), cache);
215 }
216
217 auto component_coords = coords;
218 /* Copying coords is expensive; so we have put an arbitrary
219 * limit on the max number of coords for now. */
220 if ((flags & (unsigned) flags_t::RESET_UNSPECIFIED_AXES) ||
221 coords.length > HB_VAR_COMPOSITE_MAX_AXES)
222 component_coords = hb_array<int> (font->coords, font->num_coords);
223
224 // Transform
225
226 uint32_t transformVarIdx = VarIdx::NO_VARIATION;
227 if (flags & (unsigned) flags_t::TRANSFORM_HAS_VARIATION)
228 READ_UINT32VAR (transformVarIdx);
229
230 #define PROCESS_TRANSFORM_COMPONENTS \
231 HB_STMT_START { \
232 PROCESS_TRANSFORM_COMPONENT (FWORD, HAVE_TRANSLATE_X, translateX); \
233 PROCESS_TRANSFORM_COMPONENT (FWORD, HAVE_TRANSLATE_Y, translateY); \
234 PROCESS_TRANSFORM_COMPONENT (F4DOT12, HAVE_ROTATION, rotation); \
235 PROCESS_TRANSFORM_COMPONENT (F6DOT10, HAVE_SCALE_X, scaleX); \
236 PROCESS_TRANSFORM_COMPONENT (F6DOT10, HAVE_SCALE_Y, scaleY); \
237 PROCESS_TRANSFORM_COMPONENT (F4DOT12, HAVE_SKEW_X, skewX); \
238 PROCESS_TRANSFORM_COMPONENT (F4DOT12, HAVE_SKEW_Y, skewY); \
239 PROCESS_TRANSFORM_COMPONENT (FWORD, HAVE_TCENTER_X, tCenterX); \
240 PROCESS_TRANSFORM_COMPONENT (FWORD, HAVE_TCENTER_Y, tCenterY); \
241 } HB_STMT_END
242
243 hb_transform_decomposed_t transform;
244
245 // Read transform components
246 #define PROCESS_TRANSFORM_COMPONENT(type, flag, name) \
247 if (flags & (unsigned) flags_t::flag) \
248 { \
249 static_assert (type::static_size == HBINT16::static_size, ""); \
250 if (unlikely (unsigned (end - record) < HBINT16::static_size)) \
251 return hb_ubytes_t (); \
252 hb_barrier (); \
253 transform.name = * (const HBINT16 *) record; \
254 record += HBINT16::static_size; \
255 }
256 PROCESS_TRANSFORM_COMPONENTS;
257 #undef PROCESS_TRANSFORM_COMPONENT
258
259 // Read reserved records
260 unsigned i = flags & (unsigned) flags_t::RESERVED_MASK;
261 while (i)
262 {
263 HB_UNUSED uint32_t discard;
264 READ_UINT32VAR (discard);
265 i &= i - 1;
266 }
267
268 /* Parsing is over now. */
269
270 if (show)
271 {
272 // Only use coord_setter if there's actually any axis overrides.
273 coord_setter_t coord_setter (axisIndices ? component_coords : hb_array<int> ());
274 // Go backwards, to reduce coord_setter vector reallocations.
275 for (unsigned i = axisIndices.length; i; i--)
276 coord_setter[axisIndices[i - 1]] = axisValues[i - 1];
277 if (axisIndices)
278 component_coords = coord_setter.get_coords ();
279
280 // Apply transform variations if any
281 if (transformVarIdx != VarIdx::NO_VARIATION && coords)
282 {
283 float transformValues[9];
284 unsigned numTransformValues = 0;
285 #define PROCESS_TRANSFORM_COMPONENT(type, flag, name) \
286 if (flags & (unsigned) flags_t::flag) \
287 transformValues[numTransformValues++] = transform.name;
288 PROCESS_TRANSFORM_COMPONENTS;
289 #undef PROCESS_TRANSFORM_COMPONENT
290 varStore.get_delta (transformVarIdx, coords, hb_array (transformValues, numTransformValues), cache);
291 numTransformValues = 0;
292 #define PROCESS_TRANSFORM_COMPONENT(type, flag, name) \
293 if (flags & (unsigned) flags_t::flag) \
294 transform.name = transformValues[numTransformValues++];
295 PROCESS_TRANSFORM_COMPONENTS;
296 #undef PROCESS_TRANSFORM_COMPONENT
297 }
298
299 // Divide them by their divisors
300 #define PROCESS_TRANSFORM_COMPONENT(type, flag, name) \
301 if (flags & (unsigned) flags_t::flag) \
302 { \
303 HBINT16 int_v; \
304 int_v = roundf (transform.name); \
305 type typed_v = * (const type *) &int_v; \
306 float float_v = (float) typed_v; \
307 transform.name = float_v; \
308 }
309 PROCESS_TRANSFORM_COMPONENTS;
310 #undef PROCESS_TRANSFORM_COMPONENT
311
312 if (!(flags & (unsigned) flags_t::HAVE_SCALE_Y))
313 transform.scaleY = transform.scaleX;
314
315 // Scale the transform by the font's scale
316 float x_scale = font->x_multf;
317 float y_scale = font->y_multf;
318 transform.translateX *= x_scale;
319 transform.translateY *= y_scale;
320 transform.tCenterX *= x_scale;
321 transform.tCenterY *= y_scale;
322
323 // Build a transforming pen to apply the transform.
324 hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs ();
325 hb_transforming_pen_context_t context {transform.to_transform (),
326 draw_session.funcs,
327 draw_session.draw_data,
328 &draw_session.st};
329 hb_draw_session_t transformer_session {transformer_funcs, &context};
330
331 VARC.get_path_at (font, gid,
332 transformer_session, component_coords,
333 parent_gid,
334 visited, edges_left, depth_left - 1);
335 }
336
337 #undef PROCESS_TRANSFORM_COMPONENTS
338 #undef READ_UINT32VAR
339
340 return hb_ubytes_t (record, end - record);
341 }
342
343 //} // namespace Var
344 } // namespace OT
345
346 #endif
347