/src/harfbuzz/src/OT/glyf/glyf.hh
Line | Count | Source |
1 | | #ifndef OT_GLYF_GLYF_HH |
2 | | #define OT_GLYF_GLYF_HH |
3 | | |
4 | | |
5 | | #include "../../hb-open-type.hh" |
6 | | #include "../../hb-ot-head-table.hh" |
7 | | #include "../../hb-ot-hmtx-table.hh" |
8 | | #include "../../hb-ot-var-gvar-table.hh" |
9 | | #include "../../hb-draw.hh" |
10 | | #include "../../hb-paint.hh" |
11 | | |
12 | | #include "glyf-helpers.hh" |
13 | | #include "Glyph.hh" |
14 | | #include "SubsetGlyph.hh" |
15 | | #include "loca.hh" |
16 | | #include "path-builder.hh" |
17 | | |
18 | | |
19 | | namespace OT { |
20 | | |
21 | | |
22 | | /* |
23 | | * glyf -- TrueType Glyph Data |
24 | | * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf |
25 | | */ |
26 | | #define HB_OT_TAG_glyf HB_TAG('g','l','y','f') |
27 | | |
28 | | struct glyf |
29 | | { |
30 | | friend struct glyf_accelerator_t; |
31 | | |
32 | | static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf; |
33 | | |
34 | | static bool has_valid_glyf_format(const hb_face_t* face) |
35 | 0 | { |
36 | 0 | const OT::head &head = *face->table.head; |
37 | 0 | return head.indexToLocFormat <= 1 && head.glyphDataFormat <= 1; |
38 | 0 | } |
39 | | |
40 | | bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const |
41 | 0 | { |
42 | 0 | TRACE_SANITIZE (this); |
43 | | /* Runtime checks as eager sanitizing each glyph is costy */ |
44 | 0 | return_trace (true); |
45 | 0 | } |
46 | | |
47 | | /* requires source of SubsetGlyph complains the identifier isn't declared */ |
48 | | template <typename Iterator> |
49 | | bool serialize (hb_serialize_context_t *c, |
50 | | Iterator it, |
51 | | bool use_short_loca, |
52 | | const hb_subset_plan_t *plan) |
53 | 0 | { |
54 | 0 | TRACE_SERIALIZE (this); |
55 | 0 |
|
56 | 0 | unsigned init_len = c->length (); |
57 | 0 | for (auto &_ : it) |
58 | 0 | if (unlikely (!_.serialize (c, use_short_loca, plan))) |
59 | 0 | return false; |
60 | 0 |
|
61 | 0 | /* As a special case when all glyph in the font are empty, add a zero byte |
62 | 0 | * to the table, so that OTS doesn’t reject it, and to make the table work |
63 | 0 | * on Windows as well. |
64 | 0 | * See https://github.com/khaledhosny/ots/issues/52 */ |
65 | 0 | if (init_len == c->length ()) |
66 | 0 | { |
67 | 0 | HBUINT8 empty_byte; |
68 | 0 | empty_byte = 0; |
69 | 0 | c->copy (empty_byte); |
70 | 0 | } |
71 | 0 | return_trace (true); |
72 | 0 | } |
73 | | |
74 | | /* Byte region(s) per glyph to output |
75 | | unpadded, hints removed if so requested |
76 | | If we fail to process a glyph we produce an empty (0-length) glyph */ |
77 | | bool subset (hb_subset_context_t *c) const |
78 | 0 | { |
79 | 0 | TRACE_SUBSET (this); |
80 | 0 |
|
81 | 0 | if (!has_valid_glyf_format (c->plan->source)) { |
82 | 0 | // glyf format is unknown don't attempt to subset it. |
83 | 0 | DEBUG_MSG (SUBSET, nullptr, |
84 | 0 | "unkown glyf format, dropping from subset."); |
85 | 0 | return_trace (false); |
86 | 0 | } |
87 | 0 |
|
88 | 0 | hb_font_t *font = nullptr; |
89 | 0 | if (c->plan->normalized_coords) |
90 | 0 | { |
91 | 0 | font = _create_font_for_instancing (c->plan); |
92 | 0 | if (unlikely (!font)) |
93 | 0 | return_trace (false); |
94 | 0 | } |
95 | 0 |
|
96 | 0 | hb_vector_t<unsigned> padded_offsets; |
97 | 0 | if (unlikely (!padded_offsets.alloc_exact (c->plan->new_to_old_gid_list.length))) |
98 | 0 | return_trace (false); |
99 | 0 |
|
100 | 0 | hb_vector_t<glyf_impl::SubsetGlyph> glyphs; |
101 | 0 | if (!_populate_subset_glyphs (c->plan, font, glyphs)) |
102 | 0 | { |
103 | 0 | hb_font_destroy (font); |
104 | 0 | return_trace (false); |
105 | 0 | } |
106 | 0 |
|
107 | 0 | if (font) |
108 | 0 | hb_font_destroy (font); |
109 | 0 |
|
110 | 0 | unsigned max_offset = 0; |
111 | 0 | for (auto &g : glyphs) |
112 | 0 | { |
113 | 0 | unsigned size = g.padded_size (); |
114 | 0 | padded_offsets.push (size); |
115 | 0 | max_offset += size; |
116 | 0 | } |
117 | 0 |
|
118 | 0 | bool use_short_loca = false; |
119 | 0 | if (likely (!c->plan->force_long_loca)) |
120 | 0 | use_short_loca = max_offset < 0x1FFFF; |
121 | 0 |
|
122 | 0 | if (!use_short_loca) |
123 | 0 | { |
124 | 0 | padded_offsets.resize (0); |
125 | 0 | for (auto &g : glyphs) |
126 | 0 | padded_offsets.push (g.length ()); |
127 | 0 | } |
128 | 0 |
|
129 | 0 | auto *glyf_prime = c->serializer->start_embed <glyf> (); |
130 | 0 | bool result = glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan); |
131 | 0 | if (c->plan->normalized_coords && !c->plan->pinned_at_default) |
132 | 0 | _free_compiled_subset_glyphs (glyphs); |
133 | 0 |
|
134 | 0 | if (unlikely (!c->serializer->check_success (glyf_impl::_add_loca_and_head (c, |
135 | 0 | padded_offsets.iter (), |
136 | 0 | use_short_loca)))) |
137 | 0 | return_trace (false); |
138 | 0 |
|
139 | 0 | return result; |
140 | 0 | } |
141 | | |
142 | | bool |
143 | | _populate_subset_glyphs (const hb_subset_plan_t *plan, |
144 | | hb_font_t *font, |
145 | | hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const; |
146 | | |
147 | | hb_font_t * |
148 | | _create_font_for_instancing (const hb_subset_plan_t *plan) const; |
149 | | |
150 | | void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> &glyphs) const |
151 | 0 | { |
152 | 0 | for (auto &g : glyphs) |
153 | 0 | g.free_compiled_bytes (); |
154 | 0 | } |
155 | | |
156 | | protected: |
157 | | UnsizedArrayOf<HBUINT8> |
158 | | dataZ; /* Glyphs data. */ |
159 | | public: |
160 | | DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always |
161 | | * check the size externally, allow Null() object of it by |
162 | | * defining it _MIN instead. */ |
163 | | }; |
164 | | |
165 | | struct glyf_accelerator_t |
166 | | { |
167 | | glyf_accelerator_t (hb_face_t *face) |
168 | 0 | { |
169 | 0 | short_offset = false; |
170 | 0 | num_glyphs = 0; |
171 | 0 | loca_table = nullptr; |
172 | 0 | glyf_table = nullptr; |
173 | 0 | #ifndef HB_NO_VAR |
174 | 0 | gvar = nullptr; |
175 | | #ifndef HB_NO_BEYOND_64K |
176 | | GVAR = nullptr; |
177 | | #endif |
178 | 0 | #endif |
179 | 0 | hmtx = nullptr; |
180 | 0 | #ifndef HB_NO_VERTICAL |
181 | 0 | vmtx = nullptr; |
182 | 0 | #endif |
183 | 0 | const OT::head &head = *face->table.head; |
184 | 0 | if (!glyf::has_valid_glyf_format (face)) |
185 | | /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ |
186 | 0 | return; |
187 | 0 | short_offset = 0 == head.indexToLocFormat; |
188 | |
|
189 | 0 | loca_table = face->table.loca.get_blob (); // Needs no destruct! |
190 | 0 | glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face); |
191 | 0 | #ifndef HB_NO_VAR |
192 | 0 | gvar = face->table.gvar; |
193 | | #ifndef HB_NO_BEYOND_64K |
194 | | GVAR = face->table.GVAR; |
195 | | #endif |
196 | 0 | #endif |
197 | 0 | hmtx = face->table.hmtx; |
198 | 0 | #ifndef HB_NO_VERTICAL |
199 | 0 | vmtx = face->table.vmtx; |
200 | 0 | #endif |
201 | |
|
202 | 0 | num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1; |
203 | 0 | num_glyphs = hb_min (num_glyphs, face->get_num_glyphs ()); |
204 | 0 | } |
205 | | ~glyf_accelerator_t () |
206 | 0 | { |
207 | 0 | auto *scratch = cached_scratch.get_relaxed (); |
208 | 0 | if (scratch) |
209 | 0 | { |
210 | 0 | scratch->~hb_glyf_scratch_t (); |
211 | 0 | hb_free (scratch); |
212 | 0 | } |
213 | |
|
214 | 0 | glyf_table.destroy (); |
215 | 0 | } |
216 | | |
217 | 0 | bool has_data () const { return num_glyphs; } |
218 | | |
219 | | protected: |
220 | | template<typename T> |
221 | | bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer, |
222 | | hb_array_t<const int> coords, |
223 | | hb_glyf_scratch_t &scratch, |
224 | | hb_scalar_cache_t *gvar_cache = nullptr) const |
225 | 0 | { |
226 | 0 | if (gid >= num_glyphs) return false; |
227 | | |
228 | 0 | auto &all_points = scratch.all_points; |
229 | 0 | all_points.resize (0); |
230 | |
|
231 | 0 | bool phantom_only = !consumer.is_consuming_contour_points (); |
232 | 0 | if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, scratch, nullptr, nullptr, nullptr, true, true, phantom_only, coords, gvar_cache))) |
233 | 0 | return false; |
234 | | |
235 | 0 | unsigned count = all_points.length; |
236 | 0 | assert (count >= glyf_impl::PHANTOM_COUNT); |
237 | 0 | count -= glyf_impl::PHANTOM_COUNT; |
238 | |
|
239 | 0 | if (consumer.is_consuming_contour_points ()) |
240 | 0 | { |
241 | 0 | auto *points = all_points.arrayZ; |
242 | |
|
243 | 0 | if (false) |
244 | 0 | { |
245 | | /* Our path-builder was designed to work with this simple loop. |
246 | | * But FreeType and CoreText do it differently, so we match those |
247 | | * with the other, more complicated, code branch below. */ |
248 | 0 | for (unsigned i = 0; i < count; i++) |
249 | 0 | { |
250 | 0 | consumer.consume_point (points[i]); |
251 | 0 | if (points[i].is_end_point) |
252 | 0 | consumer.contour_end (); |
253 | 0 | } |
254 | 0 | } |
255 | 0 | else |
256 | 0 | { |
257 | 0 | for (unsigned i = 0; i < count; i++) |
258 | 0 | { |
259 | | // Start of a contour. |
260 | 0 | if (points[i].flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE) |
261 | 0 | { |
262 | | // First point is on-curve. Draw the contour. |
263 | 0 | for (; i < count; i++) |
264 | 0 | { |
265 | 0 | consumer.consume_point (points[i]); |
266 | 0 | if (points[i].is_end_point) |
267 | 0 | { |
268 | 0 | consumer.contour_end (); |
269 | 0 | break; |
270 | 0 | } |
271 | 0 | } |
272 | 0 | } |
273 | 0 | else |
274 | 0 | { |
275 | 0 | unsigned start = i; |
276 | | |
277 | | // Find end of the contour. |
278 | 0 | for (; i < count; i++) |
279 | 0 | if (points[i].is_end_point) |
280 | 0 | break; |
281 | |
|
282 | 0 | unsigned end = i; |
283 | | |
284 | | // Enough to start from the end. Our path-builder takes care of the rest. |
285 | 0 | if (likely (end < count)) // Can only fail in case of alloc failure *maybe*. |
286 | 0 | consumer.consume_point (points[end]); |
287 | |
|
288 | 0 | for (i = start; i < end; i++) |
289 | 0 | consumer.consume_point (points[i]); |
290 | |
|
291 | 0 | consumer.contour_end (); |
292 | 0 | } |
293 | 0 | } |
294 | 0 | } |
295 | |
|
296 | 0 | consumer.points_end (); |
297 | 0 | } |
298 | | |
299 | | /* Where to write phantoms, nullptr if not requested */ |
300 | 0 | contour_point_t *phantoms = consumer.get_phantoms_sink (); |
301 | 0 | if (phantoms) |
302 | 0 | for (unsigned i = 0; i < glyf_impl::PHANTOM_COUNT; ++i) |
303 | 0 | phantoms[i] = all_points.arrayZ[count + i]; |
304 | |
|
305 | 0 | return true; |
306 | 0 | } Unexecuted instantiation: bool OT::glyf_accelerator_t::get_points<OT::glyf_accelerator_t::points_aggregator_t>(hb_font_t*, unsigned int, OT::glyf_accelerator_t::points_aggregator_t, hb_array_t<int const>, hb_glyf_scratch_t&, OT::hb_scalar_cache_t*) const Unexecuted instantiation: bool OT::glyf_accelerator_t::get_points<OT::glyf_impl::path_builder_t>(hb_font_t*, unsigned int, OT::glyf_impl::path_builder_t, hb_array_t<int const>, hb_glyf_scratch_t&, OT::hb_scalar_cache_t*) const |
307 | | |
308 | | public: |
309 | | |
310 | | #ifndef HB_NO_VAR |
311 | | struct points_aggregator_t |
312 | | { |
313 | | hb_font_t *font; |
314 | | hb_glyph_extents_t *extents; |
315 | | contour_point_t *phantoms; |
316 | | bool scaled; |
317 | | |
318 | | struct contour_bounds_t |
319 | | { |
320 | 0 | contour_bounds_t () { min_x = min_y = FLT_MAX; max_x = max_y = -FLT_MAX; } |
321 | | |
322 | | void add (const contour_point_t &p) |
323 | 0 | { |
324 | 0 | min_x = hb_min (min_x, p.x); |
325 | 0 | min_y = hb_min (min_y, p.y); |
326 | 0 | max_x = hb_max (max_x, p.x); |
327 | 0 | max_y = hb_max (max_y, p.y); |
328 | 0 | } |
329 | | |
330 | 0 | bool empty () const { return (min_x >= max_x) || (min_y >= max_y); } |
331 | | |
332 | | void get_extents (hb_font_t *font, hb_glyph_extents_t *extents, bool scaled) |
333 | 0 | { |
334 | 0 | if (unlikely (empty ())) |
335 | 0 | { |
336 | 0 | extents->width = 0; |
337 | 0 | extents->x_bearing = 0; |
338 | 0 | extents->height = 0; |
339 | 0 | extents->y_bearing = 0; |
340 | 0 | return; |
341 | 0 | } |
342 | 0 | { |
343 | 0 | extents->x_bearing = roundf (min_x); |
344 | 0 | extents->width = roundf (max_x - extents->x_bearing); |
345 | 0 | extents->y_bearing = roundf (max_y); |
346 | 0 | extents->height = roundf (min_y - extents->y_bearing); |
347 | |
|
348 | 0 | if (scaled) |
349 | 0 | font->scale_glyph_extents (extents); |
350 | 0 | } |
351 | 0 | } |
352 | | |
353 | | protected: |
354 | | float min_x, min_y, max_x, max_y; |
355 | | } bounds; |
356 | | |
357 | | points_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_t *phantoms_, bool scaled_) |
358 | 0 | { |
359 | 0 | font = font_; |
360 | 0 | extents = extents_; |
361 | 0 | phantoms = phantoms_; |
362 | 0 | scaled = scaled_; |
363 | 0 | if (extents) bounds = contour_bounds_t (); |
364 | 0 | } |
365 | | |
366 | | HB_ALWAYS_INLINE |
367 | 0 | void consume_point (const contour_point_t &point) { bounds.add (point); } |
368 | 0 | void contour_end () {} |
369 | 0 | void points_end () { bounds.get_extents (font, extents, scaled); } |
370 | | |
371 | 0 | bool is_consuming_contour_points () { return extents; } |
372 | 0 | contour_point_t *get_phantoms_sink () { return phantoms; } |
373 | | }; |
374 | | |
375 | | #ifndef HB_NO_VAR |
376 | | unsigned |
377 | | get_advance_with_var_unscaled (hb_codepoint_t gid, |
378 | | hb_font_t *font, |
379 | | bool is_vertical, |
380 | | hb_glyf_scratch_t &scratch, |
381 | | hb_scalar_cache_t *gvar_cache = nullptr) const |
382 | 0 | { |
383 | 0 | if (unlikely (gid >= num_glyphs)) return 0; |
384 | | |
385 | 0 | bool success = false; |
386 | |
|
387 | 0 | contour_point_t phantoms[glyf_impl::PHANTOM_COUNT]; |
388 | 0 | success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false), |
389 | 0 | hb_array (font->coords, |
390 | 0 | font->has_nonzero_coords ? font->num_coords : 0), |
391 | 0 | scratch, gvar_cache); |
392 | 0 | if (unlikely (!success)) |
393 | 0 | { |
394 | 0 | unsigned upem = font->face->get_upem (); |
395 | 0 | return is_vertical ? upem : upem / 2; |
396 | 0 | } |
397 | | |
398 | 0 | float result = is_vertical |
399 | 0 | ? phantoms[glyf_impl::PHANTOM_TOP].y - phantoms[glyf_impl::PHANTOM_BOTTOM].y |
400 | 0 | : phantoms[glyf_impl::PHANTOM_RIGHT].x - phantoms[glyf_impl::PHANTOM_LEFT].x; |
401 | 0 | return hb_clamp (roundf (result), 0.f, (float) UINT_MAX / 2); |
402 | 0 | } |
403 | | |
404 | | float |
405 | | get_v_origin_with_var_unscaled (hb_codepoint_t gid, |
406 | | hb_font_t *font, |
407 | | hb_glyf_scratch_t &scratch, |
408 | | hb_scalar_cache_t *gvar_cache = nullptr) const |
409 | 0 | { |
410 | 0 | if (unlikely (gid >= num_glyphs)) return 0; |
411 | | |
412 | 0 | bool success = false; |
413 | |
|
414 | 0 | contour_point_t phantoms[glyf_impl::PHANTOM_COUNT]; |
415 | 0 | success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false), |
416 | 0 | hb_array (font->coords, |
417 | 0 | font->has_nonzero_coords ? font->num_coords : 0), |
418 | 0 | scratch, gvar_cache); |
419 | 0 | if (unlikely (!success)) |
420 | 0 | { |
421 | 0 | return font->face->get_upem (); |
422 | 0 | } |
423 | | |
424 | 0 | return phantoms[glyf_impl::PHANTOM_TOP].y; |
425 | 0 | } |
426 | | #endif |
427 | | #endif |
428 | | |
429 | | public: |
430 | | |
431 | | bool get_extents (hb_font_t *font, |
432 | | hb_codepoint_t gid, |
433 | | hb_glyph_extents_t *extents) const |
434 | 0 | { return get_extents_at (font, gid, extents, hb_array (font->coords, |
435 | 0 | font->has_nonzero_coords ? font->num_coords : 0)); } |
436 | | |
437 | | bool get_extents_at (hb_font_t *font, |
438 | | hb_codepoint_t gid, |
439 | | hb_glyph_extents_t *extents, |
440 | | hb_array_t<const int> coords) const |
441 | 0 | { |
442 | 0 | if (unlikely (gid >= num_glyphs)) return false; |
443 | | |
444 | 0 | #ifndef HB_NO_VAR |
445 | 0 | if (coords) |
446 | 0 | { |
447 | 0 | hb_glyf_scratch_t *scratch = acquire_scratch (); |
448 | 0 | if (unlikely (!scratch)) return false; |
449 | 0 | bool ret = get_points (font, |
450 | 0 | gid, |
451 | 0 | points_aggregator_t (font, extents, nullptr, true), |
452 | 0 | coords, |
453 | 0 | *scratch); |
454 | 0 | release_scratch (scratch); |
455 | 0 | return ret; |
456 | 0 | } |
457 | 0 | #endif |
458 | 0 | return glyph_for_gid (gid).get_extents_without_var_scaled (font, *this, extents); |
459 | 0 | } |
460 | | |
461 | | const glyf_impl::Glyph |
462 | | glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const |
463 | 0 | { |
464 | 0 | if (unlikely (gid >= num_glyphs)) return glyf_impl::Glyph (); |
465 | | |
466 | 0 | unsigned int start_offset, end_offset; |
467 | |
|
468 | 0 | if (short_offset) |
469 | 0 | { |
470 | 0 | const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ; |
471 | 0 | start_offset = 2 * offsets[gid]; |
472 | 0 | end_offset = 2 * offsets[gid + 1]; |
473 | 0 | } |
474 | 0 | else |
475 | 0 | { |
476 | 0 | const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ; |
477 | 0 | start_offset = offsets[gid]; |
478 | 0 | end_offset = offsets[gid + 1]; |
479 | 0 | } |
480 | |
|
481 | 0 | if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ())) |
482 | 0 | return glyf_impl::Glyph (); |
483 | | |
484 | 0 | glyf_impl::Glyph glyph (hb_bytes_t ((const char *) this->glyf_table + start_offset, |
485 | 0 | end_offset - start_offset), gid); |
486 | 0 | return needs_padding_removal ? glyf_impl::Glyph (glyph.trim_padding (), gid) : glyph; |
487 | 0 | } |
488 | | |
489 | | bool |
490 | | get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session, hb_scalar_cache_t *gvar_cache = nullptr) const |
491 | 0 | { |
492 | 0 | if (!has_data ()) return false; |
493 | | |
494 | 0 | hb_glyf_scratch_t *scratch = acquire_scratch (); |
495 | 0 | if (unlikely (!scratch)) return true; |
496 | | |
497 | 0 | bool ret = get_points (font, gid, glyf_impl::path_builder_t (font, draw_session), |
498 | 0 | hb_array (font->coords, |
499 | 0 | font->has_nonzero_coords ? font->num_coords : 0), |
500 | 0 | *scratch, |
501 | 0 | gvar_cache); |
502 | |
|
503 | 0 | release_scratch (scratch); |
504 | |
|
505 | 0 | return ret; |
506 | 0 | } |
507 | | |
508 | | bool |
509 | | get_path_at (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session, |
510 | | hb_array_t<const int> coords, |
511 | | hb_glyf_scratch_t &scratch, |
512 | | hb_scalar_cache_t *gvar_cache = nullptr) const |
513 | 0 | { |
514 | 0 | if (!has_data ()) return false; |
515 | 0 | return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session), |
516 | 0 | coords, |
517 | 0 | scratch, |
518 | 0 | gvar_cache); |
519 | 0 | } |
520 | | |
521 | | |
522 | | hb_glyf_scratch_t *acquire_scratch () const |
523 | 0 | { |
524 | 0 | if (!has_data ()) return nullptr; |
525 | 0 | hb_glyf_scratch_t *scratch = cached_scratch.get_acquire (); |
526 | 0 | if (!scratch || unlikely (!cached_scratch.cmpexch (scratch, nullptr))) |
527 | 0 | { |
528 | 0 | scratch = (hb_glyf_scratch_t *) hb_calloc (1, sizeof (hb_glyf_scratch_t)); |
529 | 0 | if (unlikely (!scratch)) |
530 | 0 | return nullptr; |
531 | 0 | } |
532 | 0 | return scratch; |
533 | 0 | } |
534 | | void release_scratch (hb_glyf_scratch_t *scratch) const |
535 | 0 | { |
536 | 0 | if (!scratch) |
537 | 0 | return; |
538 | 0 | if (!cached_scratch.cmpexch (nullptr, scratch)) |
539 | 0 | { |
540 | 0 | scratch->~hb_glyf_scratch_t (); |
541 | 0 | hb_free (scratch); |
542 | 0 | } |
543 | 0 | } |
544 | | |
545 | | #ifndef HB_NO_VAR |
546 | | const gvar_accelerator_t *gvar; |
547 | | #ifndef HB_NO_BEYOND_64K |
548 | | const GVAR_accelerator_t *GVAR; |
549 | | #endif |
550 | | #endif |
551 | | const hmtx_accelerator_t *hmtx; |
552 | | #ifndef HB_NO_VERTICAL |
553 | | const vmtx_accelerator_t *vmtx; |
554 | | #endif |
555 | | |
556 | | private: |
557 | | bool short_offset; |
558 | | unsigned int num_glyphs; |
559 | | hb_blob_ptr_t<loca> loca_table; |
560 | | hb_blob_ptr_t<glyf> glyf_table; |
561 | | mutable hb_atomic_t<hb_glyf_scratch_t *> cached_scratch; |
562 | | }; |
563 | | |
564 | | |
565 | | inline bool |
566 | | glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan, |
567 | | hb_font_t *font, |
568 | | hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const |
569 | 0 | { |
570 | 0 | OT::glyf_accelerator_t glyf (plan->source); |
571 | 0 | if (!glyphs.alloc_exact (plan->new_to_old_gid_list.length)) return false; |
572 | 0 |
|
573 | 0 | for (const auto &pair : plan->new_to_old_gid_list) |
574 | 0 | { |
575 | 0 | hb_codepoint_t new_gid = pair.first; |
576 | 0 | hb_codepoint_t old_gid = pair.second; |
577 | 0 | glyf_impl::SubsetGlyph *p = glyphs.push (); |
578 | 0 | glyf_impl::SubsetGlyph& subset_glyph = *p; |
579 | 0 | subset_glyph.old_gid = old_gid; |
580 | 0 |
|
581 | 0 | if (unlikely (old_gid == 0 && new_gid == 0 && |
582 | 0 | !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) && |
583 | 0 | !plan->normalized_coords) |
584 | 0 | subset_glyph.source_glyph = glyf_impl::Glyph (); |
585 | 0 | else |
586 | 0 | { |
587 | 0 | /* If plan has an accelerator, the preprocessing step already trimmed glyphs. |
588 | 0 | * Don't trim them again! */ |
589 | 0 | subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, !plan->accelerator); |
590 | 0 | } |
591 | 0 |
|
592 | 0 | if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) |
593 | 0 | subset_glyph.drop_hints_bytes (); |
594 | 0 | else |
595 | 0 | subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes (); |
596 | 0 |
|
597 | 0 | if (font) |
598 | 0 | { |
599 | 0 | if (unlikely (!subset_glyph.compile_bytes_with_deltas (plan, font, glyf))) |
600 | 0 | { |
601 | 0 | // when pinned at default, only bounds are updated, thus no need to free |
602 | 0 | if (!plan->pinned_at_default) |
603 | 0 | _free_compiled_subset_glyphs (glyphs); |
604 | 0 | return false; |
605 | 0 | } |
606 | 0 | } |
607 | 0 | } |
608 | 0 | return true; |
609 | 0 | } |
610 | | |
611 | | inline hb_font_t * |
612 | | glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const |
613 | 0 | { |
614 | 0 | hb_font_t *font = hb_font_create (plan->source); |
615 | 0 | if (unlikely (font == hb_font_get_empty ())) return nullptr; |
616 | 0 |
|
617 | 0 | hb_vector_t<hb_variation_t> vars; |
618 | 0 | if (unlikely (!vars.alloc (plan->user_axes_location.get_population (), true))) |
619 | 0 | { |
620 | 0 | hb_font_destroy (font); |
621 | 0 | return nullptr; |
622 | 0 | } |
623 | 0 |
|
624 | 0 | for (auto _ : plan->user_axes_location) |
625 | 0 | { |
626 | 0 | hb_variation_t var; |
627 | 0 | var.tag = _.first; |
628 | 0 | var.value = _.second.middle; |
629 | 0 | vars.push (var); |
630 | 0 | } |
631 | 0 |
|
632 | 0 | #ifndef HB_NO_VAR |
633 | 0 | hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location.get_population ()); |
634 | 0 | #endif |
635 | 0 | return font; |
636 | 0 | } |
637 | | |
638 | | |
639 | | } /* namespace OT */ |
640 | | |
641 | | |
642 | | #endif /* OT_GLYF_GLYF_HH */ |