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