1 | /* |
2 | * Copyright © 2015 Google, Inc. |
3 | * Copyright © 2019 Adobe Inc. |
4 | * Copyright © 2019 Ebrahim Byagowi |
5 | * |
6 | * This is part of HarfBuzz, a text shaping library. |
7 | * |
8 | * Permission is hereby granted, without written agreement and without |
9 | * license or royalty fees, to use, copy, modify, and distribute this |
10 | * software and its documentation for any purpose, provided that the |
11 | * above copyright notice and the following two paragraphs appear in |
12 | * all copies of this software. |
13 | * |
14 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
15 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
16 | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
17 | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
18 | * DAMAGE. |
19 | * |
20 | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
21 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
22 | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
23 | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
24 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
25 | * |
26 | * Google Author(s): Behdad Esfahbod, Garret Rieger, Roderick Sheeter |
27 | * Adobe Author(s): Michiharu Ariza |
28 | */ |
29 | |
30 | #ifndef HB_OT_GLYF_TABLE_HH |
31 | #define HB_OT_GLYF_TABLE_HH |
32 | |
33 | #include "hb-open-type.hh" |
34 | #include "hb-ot-head-table.hh" |
35 | #include "hb-ot-hmtx-table.hh" |
36 | #include "hb-ot-var-gvar-table.hh" |
37 | #include "hb-draw.hh" |
38 | |
39 | namespace OT { |
40 | |
41 | |
42 | /* |
43 | * loca -- Index to Location |
44 | * https://docs.microsoft.com/en-us/typography/opentype/spec/loca |
45 | */ |
46 | #define HB_OT_TAG_loca HB_TAG('l','o','c','a') |
47 | |
48 | |
49 | struct loca |
50 | { |
51 | friend struct glyf; |
52 | |
53 | static constexpr hb_tag_t tableTag = HB_OT_TAG_loca; |
54 | |
55 | bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const |
56 | { |
57 | TRACE_SANITIZE (this); |
58 | return_trace (true); |
59 | } |
60 | |
61 | protected: |
62 | UnsizedArrayOf<HBUINT8> |
63 | dataZ; /* Location data. */ |
64 | public: |
65 | DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always |
66 | * check the size externally, allow Null() object of it by |
67 | * defining it _MIN instead. */ |
68 | }; |
69 | |
70 | |
71 | /* |
72 | * glyf -- TrueType Glyph Data |
73 | * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf |
74 | */ |
75 | #define HB_OT_TAG_glyf HB_TAG('g','l','y','f') |
76 | |
77 | |
78 | struct glyf |
79 | { |
80 | static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf; |
81 | |
82 | bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const |
83 | { |
84 | TRACE_SANITIZE (this); |
85 | /* Runtime checks as eager sanitizing each glyph is costy */ |
86 | return_trace (true); |
87 | } |
88 | |
89 | template<typename Iterator, |
90 | hb_requires (hb_is_source_of (Iterator, unsigned int))> |
91 | static bool |
92 | _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets) |
93 | { |
94 | unsigned max_offset = + padded_offsets | hb_reduce(hb_add, 0); |
95 | unsigned num_offsets = padded_offsets.len () + 1; |
96 | bool use_short_loca = max_offset < 0x1FFFF; |
97 | unsigned entry_size = use_short_loca ? 2 : 4; |
98 | char *loca_prime_data = (char *) calloc (entry_size, num_offsets); |
99 | |
100 | if (unlikely (!loca_prime_data)) return false; |
101 | |
102 | DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d " |
103 | "max_offset %d size %d" , |
104 | entry_size, num_offsets, max_offset, entry_size * num_offsets); |
105 | |
106 | if (use_short_loca) |
107 | _write_loca (padded_offsets, 1, hb_array ((HBUINT16*) loca_prime_data, num_offsets)); |
108 | else |
109 | _write_loca (padded_offsets, 0, hb_array ((HBUINT32*) loca_prime_data, num_offsets)); |
110 | |
111 | hb_blob_t * loca_blob = hb_blob_create (loca_prime_data, |
112 | entry_size * num_offsets, |
113 | HB_MEMORY_MODE_WRITABLE, |
114 | loca_prime_data, |
115 | free); |
116 | |
117 | bool result = plan->add_table (HB_OT_TAG_loca, loca_blob) |
118 | && _add_head_and_set_loca_version (plan, use_short_loca); |
119 | |
120 | hb_blob_destroy (loca_blob); |
121 | return result; |
122 | } |
123 | |
124 | template<typename IteratorIn, typename IteratorOut, |
125 | hb_requires (hb_is_source_of (IteratorIn, unsigned int)), |
126 | hb_requires (hb_is_sink_of (IteratorOut, unsigned))> |
127 | static void |
128 | _write_loca (IteratorIn it, unsigned right_shift, IteratorOut dest) |
129 | { |
130 | unsigned int offset = 0; |
131 | dest << 0; |
132 | + it |
133 | | hb_map ([=, &offset] (unsigned int padded_size) |
134 | { |
135 | offset += padded_size; |
136 | DEBUG_MSG (SUBSET, nullptr, "loca entry offset %d" , offset); |
137 | return offset >> right_shift; |
138 | }) |
139 | | hb_sink (dest) |
140 | ; |
141 | } |
142 | |
143 | /* requires source of SubsetGlyph complains the identifier isn't declared */ |
144 | template <typename Iterator> |
145 | bool serialize (hb_serialize_context_t *c, |
146 | Iterator it, |
147 | const hb_subset_plan_t *plan) |
148 | { |
149 | TRACE_SERIALIZE (this); |
150 | unsigned init_len = c->length (); |
151 | for (const auto &_ : it) _.serialize (c, plan); |
152 | |
153 | /* As a special case when all glyph in the font are empty, add a zero byte |
154 | * to the table, so that OTS doesn’t reject it, and to make the table work |
155 | * on Windows as well. |
156 | * See https://github.com/khaledhosny/ots/issues/52 */ |
157 | if (init_len == c->length ()) |
158 | { |
159 | HBUINT8 empty_byte; |
160 | empty_byte = 0; |
161 | c->copy (empty_byte); |
162 | } |
163 | return_trace (true); |
164 | } |
165 | |
166 | /* Byte region(s) per glyph to output |
167 | unpadded, hints removed if so requested |
168 | If we fail to process a glyph we produce an empty (0-length) glyph */ |
169 | bool subset (hb_subset_context_t *c) const |
170 | { |
171 | TRACE_SUBSET (this); |
172 | |
173 | glyf *glyf_prime = c->serializer->start_embed <glyf> (); |
174 | if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false); |
175 | |
176 | hb_vector_t<SubsetGlyph> glyphs; |
177 | _populate_subset_glyphs (c->plan, &glyphs); |
178 | |
179 | glyf_prime->serialize (c->serializer, hb_iter (glyphs), c->plan); |
180 | |
181 | auto padded_offsets = |
182 | + hb_iter (glyphs) |
183 | | hb_map (&SubsetGlyph::padded_size) |
184 | ; |
185 | |
186 | if (c->serializer->in_error ()) return_trace (false); |
187 | return_trace (c->serializer->check_success (_add_loca_and_head (c->plan, |
188 | padded_offsets))); |
189 | } |
190 | |
191 | template <typename SubsetGlyph> |
192 | void |
193 | _populate_subset_glyphs (const hb_subset_plan_t *plan, |
194 | hb_vector_t<SubsetGlyph> *glyphs /* OUT */) const |
195 | { |
196 | OT::glyf::accelerator_t glyf; |
197 | glyf.init (plan->source); |
198 | |
199 | + hb_range (plan->num_output_glyphs ()) |
200 | | hb_map ([&] (hb_codepoint_t new_gid) |
201 | { |
202 | SubsetGlyph subset_glyph = {0}; |
203 | subset_glyph.new_gid = new_gid; |
204 | |
205 | /* should never fail: all old gids should be mapped */ |
206 | if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid)) |
207 | return subset_glyph; |
208 | |
209 | subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true); |
210 | if (plan->drop_hints) subset_glyph.drop_hints_bytes (); |
211 | else subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes (); |
212 | |
213 | return subset_glyph; |
214 | }) |
215 | | hb_sink (glyphs) |
216 | ; |
217 | |
218 | glyf.fini (); |
219 | } |
220 | |
221 | static bool |
222 | _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca) |
223 | { |
224 | hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table<head> (plan->source); |
225 | hb_blob_t *head_prime_blob = hb_blob_copy_writable_or_fail (head_blob); |
226 | hb_blob_destroy (head_blob); |
227 | |
228 | if (unlikely (!head_prime_blob)) |
229 | return false; |
230 | |
231 | head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr); |
232 | head_prime->indexToLocFormat = use_short_loca ? 0 : 1; |
233 | bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob); |
234 | |
235 | hb_blob_destroy (head_prime_blob); |
236 | return success; |
237 | } |
238 | |
239 | struct CompositeGlyphChain |
240 | { |
241 | enum composite_glyph_flag_t |
242 | { |
243 | ARG_1_AND_2_ARE_WORDS = 0x0001, |
244 | ARGS_ARE_XY_VALUES = 0x0002, |
245 | ROUND_XY_TO_GRID = 0x0004, |
246 | WE_HAVE_A_SCALE = 0x0008, |
247 | MORE_COMPONENTS = 0x0020, |
248 | WE_HAVE_AN_X_AND_Y_SCALE = 0x0040, |
249 | WE_HAVE_A_TWO_BY_TWO = 0x0080, |
250 | WE_HAVE_INSTRUCTIONS = 0x0100, |
251 | USE_MY_METRICS = 0x0200, |
252 | OVERLAP_COMPOUND = 0x0400, |
253 | SCALED_COMPONENT_OFFSET = 0x0800, |
254 | UNSCALED_COMPONENT_OFFSET = 0x1000 |
255 | }; |
256 | |
257 | unsigned int get_size () const |
258 | { |
259 | unsigned int size = min_size; |
260 | /* arg1 and 2 are int16 */ |
261 | if (flags & ARG_1_AND_2_ARE_WORDS) size += 4; |
262 | /* arg1 and 2 are int8 */ |
263 | else size += 2; |
264 | |
265 | /* One x 16 bit (scale) */ |
266 | if (flags & WE_HAVE_A_SCALE) size += 2; |
267 | /* Two x 16 bit (xscale, yscale) */ |
268 | else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) size += 4; |
269 | /* Four x 16 bit (xscale, scale01, scale10, yscale) */ |
270 | else if (flags & WE_HAVE_A_TWO_BY_TWO) size += 8; |
271 | |
272 | return size; |
273 | } |
274 | |
275 | bool is_use_my_metrics () const { return flags & USE_MY_METRICS; } |
276 | bool is_anchored () const { return !(flags & ARGS_ARE_XY_VALUES); } |
277 | void get_anchor_points (unsigned int &point1, unsigned int &point2) const |
278 | { |
279 | const HBUINT8 *p = &StructAfter<const HBUINT8> (glyphIndex); |
280 | if (flags & ARG_1_AND_2_ARE_WORDS) |
281 | { |
282 | point1 = ((const HBUINT16 *) p)[0]; |
283 | point2 = ((const HBUINT16 *) p)[1]; |
284 | } |
285 | else |
286 | { |
287 | point1 = p[0]; |
288 | point2 = p[1]; |
289 | } |
290 | } |
291 | |
292 | void transform_points (contour_point_vector_t &points) const |
293 | { |
294 | float matrix[4]; |
295 | contour_point_t trans; |
296 | if (get_transformation (matrix, trans)) |
297 | { |
298 | if (scaled_offsets ()) |
299 | { |
300 | points.translate (trans); |
301 | points.transform (matrix); |
302 | } |
303 | else |
304 | { |
305 | points.transform (matrix); |
306 | points.translate (trans); |
307 | } |
308 | } |
309 | } |
310 | |
311 | protected: |
312 | bool scaled_offsets () const |
313 | { return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; } |
314 | |
315 | bool get_transformation (float (&matrix)[4], contour_point_t &trans) const |
316 | { |
317 | matrix[0] = matrix[3] = 1.f; |
318 | matrix[1] = matrix[2] = 0.f; |
319 | |
320 | int tx, ty; |
321 | const HBINT8 *p = &StructAfter<const HBINT8> (glyphIndex); |
322 | if (flags & ARG_1_AND_2_ARE_WORDS) |
323 | { |
324 | tx = *(const HBINT16 *) p; |
325 | p += HBINT16::static_size; |
326 | ty = *(const HBINT16 *) p; |
327 | p += HBINT16::static_size; |
328 | } |
329 | else |
330 | { |
331 | tx = *p++; |
332 | ty = *p++; |
333 | } |
334 | if (is_anchored ()) tx = ty = 0; |
335 | |
336 | trans.init ((float) tx, (float) ty); |
337 | |
338 | { |
339 | const F2DOT14 *points = (const F2DOT14 *) p; |
340 | if (flags & WE_HAVE_A_SCALE) |
341 | { |
342 | matrix[0] = matrix[3] = points[0].to_float (); |
343 | return true; |
344 | } |
345 | else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) |
346 | { |
347 | matrix[0] = points[0].to_float (); |
348 | matrix[3] = points[1].to_float (); |
349 | return true; |
350 | } |
351 | else if (flags & WE_HAVE_A_TWO_BY_TWO) |
352 | { |
353 | matrix[0] = points[0].to_float (); |
354 | matrix[1] = points[1].to_float (); |
355 | matrix[2] = points[2].to_float (); |
356 | matrix[3] = points[3].to_float (); |
357 | return true; |
358 | } |
359 | } |
360 | return tx || ty; |
361 | } |
362 | |
363 | public: |
364 | HBUINT16 flags; |
365 | HBGlyphID glyphIndex; |
366 | public: |
367 | DEFINE_SIZE_MIN (4); |
368 | }; |
369 | |
370 | struct composite_iter_t : hb_iter_with_fallback_t<composite_iter_t, const CompositeGlyphChain &> |
371 | { |
372 | typedef const CompositeGlyphChain *__item_t__; |
373 | composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) : |
374 | glyph (glyph_), current (current_) |
375 | { if (!check_range (current)) current = nullptr; } |
376 | composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr) {} |
377 | |
378 | const CompositeGlyphChain &__item__ () const { return *current; } |
379 | bool __more__ () const { return current; } |
380 | void __next__ () |
381 | { |
382 | if (!(current->flags & CompositeGlyphChain::MORE_COMPONENTS)) { current = nullptr; return; } |
383 | |
384 | const CompositeGlyphChain *possible = &StructAfter<CompositeGlyphChain, |
385 | CompositeGlyphChain> (*current); |
386 | if (!check_range (possible)) { current = nullptr; return; } |
387 | current = possible; |
388 | } |
389 | bool operator != (const composite_iter_t& o) const |
390 | { return glyph != o.glyph || current != o.current; } |
391 | |
392 | bool check_range (const CompositeGlyphChain *composite) const |
393 | { |
394 | return glyph.check_range (composite, CompositeGlyphChain::min_size) |
395 | && glyph.check_range (composite, composite->get_size ()); |
396 | } |
397 | |
398 | private: |
399 | hb_bytes_t glyph; |
400 | __item_t__ current; |
401 | }; |
402 | |
403 | enum phantom_point_index_t |
404 | { |
405 | PHANTOM_LEFT = 0, |
406 | PHANTOM_RIGHT = 1, |
407 | PHANTOM_TOP = 2, |
408 | PHANTOM_BOTTOM = 3, |
409 | PHANTOM_COUNT = 4 |
410 | }; |
411 | |
412 | struct Glyph |
413 | { |
414 | enum simple_glyph_flag_t |
415 | { |
416 | FLAG_ON_CURVE = 0x01, |
417 | FLAG_X_SHORT = 0x02, |
418 | FLAG_Y_SHORT = 0x04, |
419 | FLAG_REPEAT = 0x08, |
420 | FLAG_X_SAME = 0x10, |
421 | FLAG_Y_SAME = 0x20, |
422 | FLAG_RESERVED1 = 0x40, |
423 | FLAG_RESERVED2 = 0x80 |
424 | }; |
425 | |
426 | private: |
427 | struct |
428 | { |
429 | bool () const { return numberOfContours; } |
430 | |
431 | bool (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const |
432 | { |
433 | /* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */ |
434 | /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */ |
435 | extents->x_bearing = font->em_scale_x (font->face->table.hmtx->get_side_bearing (gid)); |
436 | extents->y_bearing = font->em_scale_y (hb_max (yMin, yMax)); |
437 | extents->width = font->em_scale_x (hb_max (xMin, xMax) - hb_min (xMin, xMax)); |
438 | extents->height = font->em_scale_y (hb_min (yMin, yMax) - hb_max (yMin, yMax)); |
439 | |
440 | return true; |
441 | } |
442 | |
443 | HBINT16 ; |
444 | /* If the number of contours is |
445 | * greater than or equal to zero, |
446 | * this is a simple glyph; if negative, |
447 | * this is a composite glyph. */ |
448 | FWORD ; /* Minimum x for coordinate data. */ |
449 | FWORD ; /* Minimum y for coordinate data. */ |
450 | FWORD ; /* Maximum x for coordinate data. */ |
451 | FWORD ; /* Maximum y for coordinate data. */ |
452 | public: |
453 | DEFINE_SIZE_STATIC (10); |
454 | }; |
455 | |
456 | struct SimpleGlyph |
457 | { |
458 | const GlyphHeader &; |
459 | hb_bytes_t bytes; |
460 | (const GlyphHeader &, hb_bytes_t bytes_) : |
461 | header (header_), bytes (bytes_) {} |
462 | |
463 | unsigned int instruction_len_offset () const |
464 | { return GlyphHeader::static_size + 2 * header.numberOfContours; } |
465 | |
466 | unsigned int length (unsigned int instruction_len) const |
467 | { return instruction_len_offset () + 2 + instruction_len; } |
468 | |
469 | unsigned int instructions_length () const |
470 | { |
471 | unsigned int instruction_length_offset = instruction_len_offset (); |
472 | if (unlikely (instruction_length_offset + 2 > bytes.length)) return 0; |
473 | |
474 | const HBUINT16 &instructionLength = StructAtOffset<HBUINT16> (&bytes, instruction_length_offset); |
475 | /* Out of bounds of the current glyph */ |
476 | if (unlikely (length (instructionLength) > bytes.length)) return 0; |
477 | return instructionLength; |
478 | } |
479 | |
480 | const Glyph trim_padding () const |
481 | { |
482 | /* based on FontTools _g_l_y_f.py::trim */ |
483 | const char *glyph = bytes.arrayZ; |
484 | const char *glyph_end = glyph + bytes.length; |
485 | /* simple glyph w/contours, possibly trimmable */ |
486 | glyph += instruction_len_offset (); |
487 | |
488 | if (unlikely (glyph + 2 >= glyph_end)) return Glyph (); |
489 | unsigned int num_coordinates = StructAtOffset<HBUINT16> (glyph - 2, 0) + 1; |
490 | unsigned int num_instructions = StructAtOffset<HBUINT16> (glyph, 0); |
491 | |
492 | glyph += 2 + num_instructions; |
493 | |
494 | unsigned int coord_bytes = 0; |
495 | unsigned int coords_with_flags = 0; |
496 | while (glyph < glyph_end) |
497 | { |
498 | uint8_t flag = *glyph; |
499 | glyph++; |
500 | |
501 | unsigned int repeat = 1; |
502 | if (flag & FLAG_REPEAT) |
503 | { |
504 | if (unlikely (glyph >= glyph_end)) return Glyph (); |
505 | repeat = *glyph + 1; |
506 | glyph++; |
507 | } |
508 | |
509 | unsigned int xBytes, yBytes; |
510 | xBytes = yBytes = 0; |
511 | if (flag & FLAG_X_SHORT) xBytes = 1; |
512 | else if ((flag & FLAG_X_SAME) == 0) xBytes = 2; |
513 | |
514 | if (flag & FLAG_Y_SHORT) yBytes = 1; |
515 | else if ((flag & FLAG_Y_SAME) == 0) yBytes = 2; |
516 | |
517 | coord_bytes += (xBytes + yBytes) * repeat; |
518 | coords_with_flags += repeat; |
519 | if (coords_with_flags >= num_coordinates) break; |
520 | } |
521 | |
522 | if (unlikely (coords_with_flags != num_coordinates)) return Glyph (); |
523 | return Glyph (bytes.sub_array (0, bytes.length + coord_bytes - (glyph_end - glyph))); |
524 | } |
525 | |
526 | /* zero instruction length */ |
527 | void drop_hints () |
528 | { |
529 | GlyphHeader & = const_cast<GlyphHeader &> (header); |
530 | (HBUINT16 &) StructAtOffset<HBUINT16> (&glyph_header, instruction_len_offset ()) = 0; |
531 | } |
532 | |
533 | void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const |
534 | { |
535 | unsigned int instructions_len = instructions_length (); |
536 | unsigned int glyph_length = length (instructions_len); |
537 | dest_start = bytes.sub_array (0, glyph_length - instructions_len); |
538 | dest_end = bytes.sub_array (glyph_length, bytes.length - glyph_length); |
539 | } |
540 | |
541 | static bool read_points (const HBUINT8 *&p /* IN/OUT */, |
542 | contour_point_vector_t &points_ /* IN/OUT */, |
543 | const hb_bytes_t &bytes, |
544 | void (* setter) (contour_point_t &_, float v), |
545 | const simple_glyph_flag_t short_flag, |
546 | const simple_glyph_flag_t same_flag) |
547 | { |
548 | float v = 0; |
549 | for (unsigned i = 0; i < points_.length; i++) |
550 | { |
551 | uint8_t flag = points_[i].flag; |
552 | if (flag & short_flag) |
553 | { |
554 | if (unlikely (!bytes.check_range (p))) return false; |
555 | if (flag & same_flag) |
556 | v += *p++; |
557 | else |
558 | v -= *p++; |
559 | } |
560 | else |
561 | { |
562 | if (!(flag & same_flag)) |
563 | { |
564 | if (unlikely (!bytes.check_range ((const HBUINT16 *) p))) return false; |
565 | v += *(const HBINT16 *) p; |
566 | p += HBINT16::static_size; |
567 | } |
568 | } |
569 | setter (points_[i], v); |
570 | } |
571 | return true; |
572 | } |
573 | |
574 | bool get_contour_points (contour_point_vector_t &points_ /* OUT */, |
575 | bool phantom_only = false) const |
576 | { |
577 | const HBUINT16 *endPtsOfContours = &StructAfter<HBUINT16> (header); |
578 | int num_contours = header.numberOfContours; |
579 | if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours + 1]))) return false; |
580 | unsigned int num_points = endPtsOfContours[num_contours - 1] + 1; |
581 | |
582 | points_.resize (num_points); |
583 | for (unsigned int i = 0; i < points_.length; i++) points_[i].init (); |
584 | if (phantom_only) return true; |
585 | |
586 | for (int i = 0; i < num_contours; i++) |
587 | points_[endPtsOfContours[i]].is_end_point = true; |
588 | |
589 | /* Skip instructions */ |
590 | const HBUINT8 *p = &StructAtOffset<HBUINT8> (&endPtsOfContours[num_contours + 1], |
591 | endPtsOfContours[num_contours]); |
592 | |
593 | /* Read flags */ |
594 | for (unsigned int i = 0; i < num_points; i++) |
595 | { |
596 | if (unlikely (!bytes.check_range (p))) return false; |
597 | uint8_t flag = *p++; |
598 | points_[i].flag = flag; |
599 | if (flag & FLAG_REPEAT) |
600 | { |
601 | if (unlikely (!bytes.check_range (p))) return false; |
602 | unsigned int repeat_count = *p++; |
603 | while ((repeat_count-- > 0) && (++i < num_points)) |
604 | points_[i].flag = flag; |
605 | } |
606 | } |
607 | |
608 | /* Read x & y coordinates */ |
609 | return (read_points (p, points_, bytes, |
610 | [] (contour_point_t &p, float v) { p.x = v; }, FLAG_X_SHORT, FLAG_X_SAME) && |
611 | read_points (p, points_, bytes, |
612 | [] (contour_point_t &p, float v) { p.y = v; }, FLAG_Y_SHORT, FLAG_Y_SAME)); |
613 | } |
614 | }; |
615 | |
616 | struct CompositeGlyph |
617 | { |
618 | const GlyphHeader &; |
619 | hb_bytes_t bytes; |
620 | (const GlyphHeader &, hb_bytes_t bytes_) : |
621 | header (header_), bytes (bytes_) {} |
622 | |
623 | composite_iter_t get_iterator () const |
624 | { return composite_iter_t (bytes, &StructAfter<CompositeGlyphChain, GlyphHeader> (header)); } |
625 | |
626 | unsigned int instructions_length (hb_bytes_t bytes) const |
627 | { |
628 | unsigned int start = bytes.length; |
629 | unsigned int end = bytes.length; |
630 | const CompositeGlyphChain *last = nullptr; |
631 | for (auto &item : get_iterator ()) |
632 | last = &item; |
633 | if (unlikely (!last)) return 0; |
634 | |
635 | if ((uint16_t) last->flags & CompositeGlyphChain::WE_HAVE_INSTRUCTIONS) |
636 | start = (char *) last - &bytes + last->get_size (); |
637 | if (unlikely (start > end)) return 0; |
638 | return end - start; |
639 | } |
640 | |
641 | /* Trimming for composites not implemented. |
642 | * If removing hints it falls out of that. */ |
643 | const Glyph trim_padding () const { return Glyph (bytes); } |
644 | |
645 | /* remove WE_HAVE_INSTRUCTIONS flag from composite glyph */ |
646 | void drop_hints () |
647 | { |
648 | for (const auto &_ : get_iterator ()) |
649 | *const_cast<OT::HBUINT16 *> (&_.flags) = (uint16_t) _.flags & ~OT::glyf::CompositeGlyphChain::WE_HAVE_INSTRUCTIONS; |
650 | } |
651 | |
652 | /* Chop instructions off the end */ |
653 | void drop_hints_bytes (hb_bytes_t &dest_start) const |
654 | { dest_start = bytes.sub_array (0, bytes.length - instructions_length (bytes)); } |
655 | }; |
656 | |
657 | enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE }; |
658 | |
659 | public: |
660 | composite_iter_t get_composite_iterator () const |
661 | { |
662 | if (type != COMPOSITE) return composite_iter_t (); |
663 | return CompositeGlyph (*header, bytes).get_iterator (); |
664 | } |
665 | |
666 | const Glyph trim_padding () const |
667 | { |
668 | switch (type) { |
669 | case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding (); |
670 | case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding (); |
671 | default: return bytes; |
672 | } |
673 | } |
674 | |
675 | void drop_hints () |
676 | { |
677 | switch (type) { |
678 | case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return; |
679 | case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return; |
680 | default: return; |
681 | } |
682 | } |
683 | |
684 | void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const |
685 | { |
686 | switch (type) { |
687 | case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return; |
688 | case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return; |
689 | default: return; |
690 | } |
691 | } |
692 | |
693 | /* Note: Recursively calls itself. |
694 | * all_points includes phantom points |
695 | */ |
696 | template<typename T> |
697 | bool get_points (T glyph_for_gid, hb_font_t *font, |
698 | contour_point_vector_t &all_points /* OUT */, |
699 | bool phantom_only = false, |
700 | unsigned int depth = 0) const |
701 | { |
702 | if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false; |
703 | contour_point_vector_t points; |
704 | |
705 | switch (type) { |
706 | case COMPOSITE: |
707 | { |
708 | /* pseudo component points for each component in composite glyph */ |
709 | unsigned num_points = hb_len (CompositeGlyph (*header, bytes).get_iterator ()); |
710 | if (unlikely (!points.resize (num_points))) return false; |
711 | for (unsigned i = 0; i < points.length; i++) |
712 | points[i].init (); |
713 | break; |
714 | } |
715 | case SIMPLE: |
716 | if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only))) |
717 | return false; |
718 | break; |
719 | default: return false; /* empty glyph */ |
720 | } |
721 | |
722 | hb_face_t *face = font->face; |
723 | |
724 | /* Init phantom points */ |
725 | if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false; |
726 | hb_array_t<contour_point_t> phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); |
727 | { |
728 | for (unsigned i = 0; i < PHANTOM_COUNT; ++i) phantoms[i].init (); |
729 | int h_delta = (int) header->xMin - face->table.hmtx->get_side_bearing (gid); |
730 | int v_orig = (int) header->yMax + face->table.vmtx->get_side_bearing (gid); |
731 | unsigned h_adv = face->table.hmtx->get_advance (gid); |
732 | unsigned v_adv = face->table.vmtx->get_advance (gid); |
733 | phantoms[PHANTOM_LEFT].x = h_delta; |
734 | phantoms[PHANTOM_RIGHT].x = h_adv + h_delta; |
735 | phantoms[PHANTOM_TOP].y = v_orig; |
736 | phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv; |
737 | } |
738 | |
739 | #ifndef HB_NO_VAR |
740 | if (unlikely (!face->table.gvar->apply_deltas_to_points (gid, font, points.as_array ()))) |
741 | return false; |
742 | #endif |
743 | |
744 | switch (type) { |
745 | case SIMPLE: |
746 | all_points.extend (points.as_array ()); |
747 | break; |
748 | case COMPOSITE: |
749 | { |
750 | unsigned int comp_index = 0; |
751 | for (auto &item : get_composite_iterator ()) |
752 | { |
753 | contour_point_vector_t comp_points; |
754 | if (unlikely (!glyph_for_gid (item.glyphIndex).get_points (glyph_for_gid, font, comp_points, phantom_only, depth + 1)) |
755 | || comp_points.length < PHANTOM_COUNT) |
756 | return false; |
757 | |
758 | /* Copy phantom points from component if USE_MY_METRICS flag set */ |
759 | if (item.is_use_my_metrics ()) |
760 | for (unsigned int i = 0; i < PHANTOM_COUNT; i++) |
761 | phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; |
762 | |
763 | /* Apply component transformation & translation */ |
764 | item.transform_points (comp_points); |
765 | |
766 | /* Apply translation from gvar */ |
767 | comp_points.translate (points[comp_index]); |
768 | |
769 | if (item.is_anchored ()) |
770 | { |
771 | unsigned int p1, p2; |
772 | item.get_anchor_points (p1, p2); |
773 | if (likely (p1 < all_points.length && p2 < comp_points.length)) |
774 | { |
775 | contour_point_t delta; |
776 | delta.init (all_points[p1].x - comp_points[p2].x, |
777 | all_points[p1].y - comp_points[p2].y); |
778 | |
779 | comp_points.translate (delta); |
780 | } |
781 | } |
782 | |
783 | all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT)); |
784 | |
785 | comp_index++; |
786 | } |
787 | |
788 | all_points.extend (phantoms); |
789 | } break; |
790 | default: return false; |
791 | } |
792 | |
793 | if (depth == 0) /* Apply at top level */ |
794 | { |
795 | /* Undocumented rasterizer behavior: |
796 | * Shift points horizontally by the updated left side bearing |
797 | */ |
798 | contour_point_t delta; |
799 | delta.init (-phantoms[PHANTOM_LEFT].x, 0.f); |
800 | if (delta.x) all_points.translate (delta); |
801 | } |
802 | |
803 | return true; |
804 | } |
805 | |
806 | bool get_extents (hb_font_t *font, hb_glyph_extents_t *extents) const |
807 | { |
808 | if (type == EMPTY) return true; /* Empty glyph; zero extents. */ |
809 | return header->get_extents (font, gid, extents); |
810 | } |
811 | |
812 | hb_bytes_t get_bytes () const { return bytes; } |
813 | |
814 | Glyph (hb_bytes_t bytes_ = hb_bytes_t (), |
815 | hb_codepoint_t gid_ = (hb_codepoint_t) -1) : bytes (bytes_), gid (gid_), |
816 | header (bytes.as<GlyphHeader> ()) |
817 | { |
818 | int num_contours = header->numberOfContours; |
819 | if (unlikely (num_contours == 0)) type = EMPTY; |
820 | else if (num_contours > 0) type = SIMPLE; |
821 | else type = COMPOSITE; /* negative numbers */ |
822 | } |
823 | |
824 | protected: |
825 | hb_bytes_t bytes; |
826 | hb_codepoint_t gid; |
827 | const GlyphHeader *; |
828 | unsigned type; |
829 | }; |
830 | |
831 | struct accelerator_t |
832 | { |
833 | void init (hb_face_t *face_) |
834 | { |
835 | short_offset = false; |
836 | num_glyphs = 0; |
837 | loca_table = nullptr; |
838 | glyf_table = nullptr; |
839 | face = face_; |
840 | const OT::head &head = *face->table.head; |
841 | if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0) |
842 | /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ |
843 | return; |
844 | short_offset = 0 == head.indexToLocFormat; |
845 | |
846 | loca_table = hb_sanitize_context_t ().reference_table<loca> (face); |
847 | glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face); |
848 | |
849 | num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1; |
850 | num_glyphs = hb_min (num_glyphs, face->get_num_glyphs ()); |
851 | } |
852 | |
853 | void fini () |
854 | { |
855 | loca_table.destroy (); |
856 | glyf_table.destroy (); |
857 | } |
858 | |
859 | protected: |
860 | template<typename T> |
861 | bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer) const |
862 | { |
863 | /* Making this alloc free is not that easy |
864 | https://github.com/harfbuzz/harfbuzz/issues/2095 |
865 | mostly because of gvar handling in VF fonts, |
866 | perhaps a separate path for non-VF fonts can be considered */ |
867 | contour_point_vector_t all_points; |
868 | |
869 | bool phantom_only = !consumer.is_consuming_contour_points (); |
870 | if (unlikely (!glyph_for_gid (gid).get_points ([this] (hb_codepoint_t gid) -> const Glyph { return this->glyph_for_gid (gid); }, |
871 | font, all_points, phantom_only))) |
872 | return false; |
873 | |
874 | if (consumer.is_consuming_contour_points ()) |
875 | { |
876 | for (unsigned point_index = 0; point_index + 4 < all_points.length; ++point_index) |
877 | consumer.consume_point (all_points[point_index]); |
878 | consumer.points_end (); |
879 | } |
880 | |
881 | /* Where to write phantoms, nullptr if not requested */ |
882 | contour_point_t *phantoms = consumer.get_phantoms_sink (); |
883 | if (phantoms) |
884 | for (unsigned i = 0; i < PHANTOM_COUNT; ++i) |
885 | phantoms[i] = all_points[all_points.length - PHANTOM_COUNT + i]; |
886 | |
887 | return true; |
888 | } |
889 | |
890 | public: |
891 | #ifndef HB_NO_VAR |
892 | struct points_aggregator_t |
893 | { |
894 | hb_font_t *font; |
895 | hb_glyph_extents_t *extents; |
896 | contour_point_t *phantoms; |
897 | |
898 | struct contour_bounds_t |
899 | { |
900 | contour_bounds_t () { min_x = min_y = FLT_MAX; max_x = max_y = -FLT_MAX; } |
901 | |
902 | void add (const contour_point_t &p) |
903 | { |
904 | min_x = hb_min (min_x, p.x); |
905 | min_y = hb_min (min_y, p.y); |
906 | max_x = hb_max (max_x, p.x); |
907 | max_y = hb_max (max_y, p.y); |
908 | } |
909 | |
910 | bool empty () const { return (min_x >= max_x) || (min_y >= max_y); } |
911 | |
912 | void get_extents (hb_font_t *font, hb_glyph_extents_t *extents) |
913 | { |
914 | if (unlikely (empty ())) |
915 | { |
916 | extents->width = 0; |
917 | extents->x_bearing = 0; |
918 | extents->height = 0; |
919 | extents->y_bearing = 0; |
920 | return; |
921 | } |
922 | extents->x_bearing = font->em_scalef_x (min_x); |
923 | extents->width = font->em_scalef_x (max_x - min_x); |
924 | extents->y_bearing = font->em_scalef_y (max_y); |
925 | extents->height = font->em_scalef_y (min_y - max_y); |
926 | } |
927 | |
928 | protected: |
929 | float min_x, min_y, max_x, max_y; |
930 | } bounds; |
931 | |
932 | points_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_t *phantoms_) |
933 | { |
934 | font = font_; |
935 | extents = extents_; |
936 | phantoms = phantoms_; |
937 | if (extents) bounds = contour_bounds_t (); |
938 | } |
939 | |
940 | void consume_point (const contour_point_t &point) { bounds.add (point); } |
941 | void points_end () { bounds.get_extents (font, extents); } |
942 | |
943 | bool is_consuming_contour_points () { return extents; } |
944 | contour_point_t *get_phantoms_sink () { return phantoms; } |
945 | }; |
946 | |
947 | unsigned int |
948 | get_advance_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const |
949 | { |
950 | bool success = false; |
951 | |
952 | contour_point_t phantoms[PHANTOM_COUNT]; |
953 | if (likely (font->num_coords == face->table.gvar->get_axis_count ())) |
954 | success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms)); |
955 | |
956 | if (unlikely (!success)) |
957 | return is_vertical |
958 | ? face->table.vmtx->get_advance (gid) |
959 | : face->table.hmtx->get_advance (gid); |
960 | |
961 | return is_vertical |
962 | ? roundf (phantoms[PHANTOM_TOP].y - phantoms[PHANTOM_BOTTOM].y) |
963 | : roundf (phantoms[PHANTOM_RIGHT].x - phantoms[PHANTOM_LEFT].x); |
964 | } |
965 | |
966 | int get_side_bearing_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const |
967 | { |
968 | hb_glyph_extents_t extents; |
969 | |
970 | contour_point_t phantoms[PHANTOM_COUNT]; |
971 | if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms)))) |
972 | return is_vertical |
973 | ? face->table.vmtx->get_side_bearing (gid) |
974 | : face->table.hmtx->get_side_bearing (gid); |
975 | |
976 | return is_vertical |
977 | ? ceilf (phantoms[PHANTOM_TOP].y) - extents.y_bearing |
978 | : floorf (phantoms[PHANTOM_LEFT].x); |
979 | } |
980 | #endif |
981 | |
982 | bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const |
983 | { |
984 | if (unlikely (gid >= num_glyphs)) return false; |
985 | #ifndef HB_NO_VAR |
986 | if (font->num_coords && font->num_coords == face->table.gvar->get_axis_count ()) |
987 | return get_points (font, gid, points_aggregator_t (font, extents, nullptr)); |
988 | #endif |
989 | return glyph_for_gid (gid).get_extents (font, extents); |
990 | } |
991 | |
992 | const Glyph |
993 | glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const |
994 | { |
995 | unsigned int start_offset, end_offset; |
996 | if (unlikely (gid >= num_glyphs)) return Glyph (); |
997 | |
998 | if (short_offset) |
999 | { |
1000 | const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ; |
1001 | start_offset = 2 * offsets[gid]; |
1002 | end_offset = 2 * offsets[gid + 1]; |
1003 | } |
1004 | else |
1005 | { |
1006 | const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ; |
1007 | start_offset = offsets[gid]; |
1008 | end_offset = offsets[gid + 1]; |
1009 | } |
1010 | |
1011 | if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ())) |
1012 | return Glyph (); |
1013 | |
1014 | Glyph glyph (hb_bytes_t ((const char *) this->glyf_table + start_offset, |
1015 | end_offset - start_offset), gid); |
1016 | return needs_padding_removal ? glyph.trim_padding () : glyph; |
1017 | } |
1018 | |
1019 | void |
1020 | add_gid_and_children (hb_codepoint_t gid, hb_set_t *gids_to_retain, |
1021 | unsigned int depth = 0) const |
1022 | { |
1023 | if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return; |
1024 | /* Check if is already visited */ |
1025 | if (gids_to_retain->has (gid)) return; |
1026 | |
1027 | gids_to_retain->add (gid); |
1028 | |
1029 | for (auto &item : glyph_for_gid (gid).get_composite_iterator ()) |
1030 | add_gid_and_children (item.glyphIndex, gids_to_retain, depth); |
1031 | } |
1032 | |
1033 | #ifdef HB_EXPERIMENTAL_API |
1034 | struct path_builder_t |
1035 | { |
1036 | hb_font_t *font; |
1037 | draw_helper_t *draw_helper; |
1038 | |
1039 | struct optional_point_t |
1040 | { |
1041 | optional_point_t () { has_data = false; } |
1042 | optional_point_t (float x_, float y_) { x = x_; y = y_; has_data = true; } |
1043 | |
1044 | bool has_data; |
1045 | float x; |
1046 | float y; |
1047 | |
1048 | optional_point_t lerp (optional_point_t p, float t) |
1049 | { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); } |
1050 | } first_oncurve, first_offcurve, last_offcurve; |
1051 | |
1052 | path_builder_t (hb_font_t *font_, draw_helper_t &draw_helper_) |
1053 | { |
1054 | font = font_; |
1055 | draw_helper = &draw_helper_; |
1056 | first_oncurve = first_offcurve = last_offcurve = optional_point_t (); |
1057 | } |
1058 | |
1059 | /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287 |
1060 | See also: |
1061 | * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html |
1062 | * https://stackoverflow.com/a/20772557 */ |
1063 | void consume_point (const contour_point_t &point) |
1064 | { |
1065 | /* Skip empty contours */ |
1066 | if (unlikely (point.is_end_point && !first_oncurve.has_data && !first_offcurve.has_data)) |
1067 | return; |
1068 | |
1069 | bool is_on_curve = point.flag & Glyph::FLAG_ON_CURVE; |
1070 | optional_point_t p (point.x, point.y); |
1071 | if (!first_oncurve.has_data) |
1072 | { |
1073 | if (is_on_curve) |
1074 | { |
1075 | first_oncurve = p; |
1076 | draw_helper->move_to (font->em_scalef_x (p.x), font->em_scalef_y (p.y)); |
1077 | } |
1078 | else |
1079 | { |
1080 | if (first_offcurve.has_data) |
1081 | { |
1082 | optional_point_t mid = first_offcurve.lerp (p, .5f); |
1083 | first_oncurve = mid; |
1084 | last_offcurve = p; |
1085 | draw_helper->move_to (font->em_scalef_x (mid.x), font->em_scalef_y (mid.y)); |
1086 | } |
1087 | else |
1088 | first_offcurve = p; |
1089 | } |
1090 | } |
1091 | else |
1092 | { |
1093 | if (last_offcurve.has_data) |
1094 | { |
1095 | if (is_on_curve) |
1096 | { |
1097 | draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), |
1098 | font->em_scalef_x (p.x), font->em_scalef_y (p.y)); |
1099 | last_offcurve = optional_point_t (); |
1100 | } |
1101 | else |
1102 | { |
1103 | optional_point_t mid = last_offcurve.lerp (p, .5f); |
1104 | draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), |
1105 | font->em_scalef_x (mid.x), font->em_scalef_y (mid.y)); |
1106 | last_offcurve = p; |
1107 | } |
1108 | } |
1109 | else |
1110 | { |
1111 | if (is_on_curve) |
1112 | draw_helper->line_to (font->em_scalef_x (p.x), font->em_scalef_y (p.y)); |
1113 | else |
1114 | last_offcurve = p; |
1115 | } |
1116 | } |
1117 | |
1118 | if (point.is_end_point) |
1119 | { |
1120 | if (first_offcurve.has_data && last_offcurve.has_data) |
1121 | { |
1122 | optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f); |
1123 | draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), |
1124 | font->em_scalef_x (mid.x), font->em_scalef_y (mid.y)); |
1125 | last_offcurve = optional_point_t (); |
1126 | /* now check the rest */ |
1127 | } |
1128 | |
1129 | if (first_offcurve.has_data && first_oncurve.has_data) |
1130 | draw_helper->quadratic_to (font->em_scalef_x (first_offcurve.x), font->em_scalef_y (first_offcurve.y), |
1131 | font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y)); |
1132 | else if (last_offcurve.has_data && first_oncurve.has_data) |
1133 | draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), |
1134 | font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y)); |
1135 | else if (first_oncurve.has_data) |
1136 | draw_helper->line_to (font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y)); |
1137 | |
1138 | /* Getting ready for the next contour */ |
1139 | first_oncurve = first_offcurve = last_offcurve = optional_point_t (); |
1140 | draw_helper->end_path (); |
1141 | } |
1142 | } |
1143 | void points_end () {} |
1144 | |
1145 | bool is_consuming_contour_points () { return true; } |
1146 | contour_point_t *get_phantoms_sink () { return nullptr; } |
1147 | }; |
1148 | |
1149 | bool |
1150 | get_path (hb_font_t *font, hb_codepoint_t gid, draw_helper_t &draw_helper) const |
1151 | { return get_points (font, gid, path_builder_t (font, draw_helper)); } |
1152 | #endif |
1153 | |
1154 | private: |
1155 | bool short_offset; |
1156 | unsigned int num_glyphs; |
1157 | hb_blob_ptr_t<loca> loca_table; |
1158 | hb_blob_ptr_t<glyf> glyf_table; |
1159 | hb_face_t *face; |
1160 | }; |
1161 | |
1162 | struct SubsetGlyph |
1163 | { |
1164 | hb_codepoint_t new_gid; |
1165 | hb_codepoint_t old_gid; |
1166 | Glyph source_glyph; |
1167 | hb_bytes_t dest_start; /* region of source_glyph to copy first */ |
1168 | hb_bytes_t dest_end; /* region of source_glyph to copy second */ |
1169 | |
1170 | bool serialize (hb_serialize_context_t *c, |
1171 | const hb_subset_plan_t *plan) const |
1172 | { |
1173 | TRACE_SERIALIZE (this); |
1174 | |
1175 | hb_bytes_t dest_glyph = dest_start.copy (c); |
1176 | dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length); |
1177 | unsigned int pad_length = padding (); |
1178 | DEBUG_MSG (SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d" , dest_glyph.length, dest_glyph.length + pad_length, pad_length); |
1179 | |
1180 | HBUINT8 pad; |
1181 | pad = 0; |
1182 | while (pad_length > 0) |
1183 | { |
1184 | c->embed (pad); |
1185 | pad_length--; |
1186 | } |
1187 | |
1188 | if (unlikely (!dest_glyph.length)) return_trace (true); |
1189 | |
1190 | /* update components gids */ |
1191 | for (auto &_ : Glyph (dest_glyph).get_composite_iterator ()) |
1192 | { |
1193 | hb_codepoint_t new_gid; |
1194 | if (plan->new_gid_for_old_gid (_.glyphIndex, &new_gid)) |
1195 | ((OT::glyf::CompositeGlyphChain *) &_)->glyphIndex = new_gid; |
1196 | } |
1197 | |
1198 | if (plan->drop_hints) Glyph (dest_glyph).drop_hints (); |
1199 | |
1200 | return_trace (true); |
1201 | } |
1202 | |
1203 | void drop_hints_bytes () |
1204 | { source_glyph.drop_hints_bytes (dest_start, dest_end); } |
1205 | |
1206 | unsigned int length () const { return dest_start.length + dest_end.length; } |
1207 | /* pad to 2 to ensure 2-byte loca will be ok */ |
1208 | unsigned int padding () const { return length () % 2; } |
1209 | unsigned int padded_size () const { return length () + padding (); } |
1210 | }; |
1211 | |
1212 | protected: |
1213 | UnsizedArrayOf<HBUINT8> |
1214 | dataZ; /* Glyphs data. */ |
1215 | public: |
1216 | DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always |
1217 | * check the size externally, allow Null() object of it by |
1218 | * defining it _MIN instead. */ |
1219 | }; |
1220 | |
1221 | struct glyf_accelerator_t : glyf::accelerator_t {}; |
1222 | |
1223 | } /* namespace OT */ |
1224 | |
1225 | |
1226 | #endif /* HB_OT_GLYF_TABLE_HH */ |
1227 | |