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