1 | /* |
2 | * Copyright © 2015 Google, Inc. |
3 | * |
4 | * This is part of HarfBuzz, a text shaping library. |
5 | * |
6 | * Permission is hereby granted, without written agreement and without |
7 | * license or royalty fees, to use, copy, modify, and distribute this |
8 | * software and its documentation for any purpose, provided that the |
9 | * above copyright notice and the following two paragraphs appear in |
10 | * all copies of this software. |
11 | * |
12 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
13 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
14 | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
15 | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
16 | * DAMAGE. |
17 | * |
18 | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
19 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
20 | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
21 | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
22 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
23 | * |
24 | * Google Author(s): Behdad Esfahbod |
25 | */ |
26 | |
27 | #ifndef HB_OT_GLYF_TABLE_HH |
28 | #define HB_OT_GLYF_TABLE_HH |
29 | |
30 | #include "hb-open-type.hh" |
31 | #include "hb-ot-head-table.hh" |
32 | #include "hb-subset-glyf.hh" |
33 | |
34 | namespace OT { |
35 | |
36 | |
37 | /* |
38 | * loca -- Index to Location |
39 | * https://docs.microsoft.com/en-us/typography/opentype/spec/loca |
40 | */ |
41 | #define HB_OT_TAG_loca HB_TAG('l','o','c','a') |
42 | |
43 | |
44 | struct loca |
45 | { |
46 | friend struct glyf; |
47 | |
48 | static constexpr hb_tag_t tableTag = HB_OT_TAG_loca; |
49 | |
50 | bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const |
51 | { |
52 | TRACE_SANITIZE (this); |
53 | return_trace (true); |
54 | } |
55 | |
56 | protected: |
57 | UnsizedArrayOf<HBUINT8> dataZ; /* Location data. */ |
58 | public: |
59 | DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always |
60 | * check the size externally, allow Null() object of it by |
61 | * defining it MIN() instead. */ |
62 | }; |
63 | |
64 | |
65 | /* |
66 | * glyf -- TrueType Glyph Data |
67 | * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf |
68 | */ |
69 | #define HB_OT_TAG_glyf HB_TAG('g','l','y','f') |
70 | |
71 | |
72 | struct glyf |
73 | { |
74 | static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf; |
75 | |
76 | bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const |
77 | { |
78 | TRACE_SANITIZE (this); |
79 | /* We don't check for anything specific here. The users of the |
80 | * struct do all the hard work... */ |
81 | return_trace (true); |
82 | } |
83 | |
84 | bool subset (hb_subset_plan_t *plan) const |
85 | { |
86 | hb_blob_t *glyf_prime = nullptr; |
87 | hb_blob_t *loca_prime = nullptr; |
88 | |
89 | bool success = true; |
90 | bool use_short_loca = false; |
91 | if (hb_subset_glyf_and_loca (plan, &use_short_loca, &glyf_prime, &loca_prime)) { |
92 | success = success && plan->add_table (HB_OT_TAG_glyf, glyf_prime); |
93 | success = success && plan->add_table (HB_OT_TAG_loca, loca_prime); |
94 | success = success && _add_head_and_set_loca_version (plan, use_short_loca); |
95 | } else { |
96 | success = false; |
97 | } |
98 | hb_blob_destroy (loca_prime); |
99 | hb_blob_destroy (glyf_prime); |
100 | |
101 | return success; |
102 | } |
103 | |
104 | static bool |
105 | _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca) |
106 | { |
107 | hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table<head> (plan->source); |
108 | hb_blob_t *head_prime_blob = hb_blob_copy_writable_or_fail (head_blob); |
109 | hb_blob_destroy (head_blob); |
110 | |
111 | if (unlikely (!head_prime_blob)) |
112 | return false; |
113 | |
114 | head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr); |
115 | head_prime->indexToLocFormat.set (use_short_loca ? 0 : 1); |
116 | bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob); |
117 | |
118 | hb_blob_destroy (head_prime_blob); |
119 | return success; |
120 | } |
121 | |
122 | struct |
123 | { |
124 | HBINT16 ; /* If the number of contours is |
125 | * greater than or equal to zero, |
126 | * this is a simple glyph; if negative, |
127 | * this is a composite glyph. */ |
128 | FWORD ; /* Minimum x for coordinate data. */ |
129 | FWORD ; /* Minimum y for coordinate data. */ |
130 | FWORD ; /* Maximum x for coordinate data. */ |
131 | FWORD ; /* Maximum y for coordinate data. */ |
132 | |
133 | DEFINE_SIZE_STATIC (10); |
134 | }; |
135 | |
136 | struct |
137 | { |
138 | enum { |
139 | ARG_1_AND_2_ARE_WORDS = 0x0001, |
140 | = 0x0002, |
141 | = 0x0004, |
142 | = 0x0008, |
143 | = 0x0020, |
144 | WE_HAVE_AN_X_AND_Y_SCALE = 0x0040, |
145 | = 0x0080, |
146 | = 0x0100, |
147 | = 0x0200, |
148 | = 0x0400, |
149 | = 0x0800, |
150 | = 0x1000 |
151 | }; |
152 | |
153 | HBUINT16 ; |
154 | GlyphID ; |
155 | |
156 | unsigned int () const |
157 | { |
158 | unsigned int size = min_size; |
159 | // arg1 and 2 are int16 |
160 | if (flags & ARG_1_AND_2_ARE_WORDS) size += 4; |
161 | // arg1 and 2 are int8 |
162 | else size += 2; |
163 | |
164 | // One x 16 bit (scale) |
165 | if (flags & WE_HAVE_A_SCALE) size += 2; |
166 | // Two x 16 bit (xscale, yscale) |
167 | else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) size += 4; |
168 | // Four x 16 bit (xscale, scale01, scale10, yscale) |
169 | else if (flags & WE_HAVE_A_TWO_BY_TWO) size += 8; |
170 | |
171 | return size; |
172 | } |
173 | |
174 | struct |
175 | { |
176 | const char *; |
177 | const char *; |
178 | const CompositeGlyphHeader *; |
179 | |
180 | bool () |
181 | { |
182 | if (current->flags & CompositeGlyphHeader::MORE_COMPONENTS) |
183 | { |
184 | const CompositeGlyphHeader *possible = |
185 | &StructAfter<CompositeGlyphHeader, CompositeGlyphHeader> (*current); |
186 | if (!in_range (possible)) |
187 | return false; |
188 | current = possible; |
189 | return true; |
190 | } |
191 | return false; |
192 | } |
193 | |
194 | bool (const CompositeGlyphHeader *composite) const |
195 | { |
196 | return (const char *) composite >= glyph_start |
197 | && ((const char *) composite + CompositeGlyphHeader::min_size) <= glyph_end |
198 | && ((const char *) composite + composite->get_size ()) <= glyph_end; |
199 | } |
200 | }; |
201 | |
202 | static bool (const char * glyph_data, |
203 | unsigned int length, |
204 | CompositeGlyphHeader::Iterator *iterator /* OUT */) |
205 | { |
206 | if (length < GlyphHeader::static_size) |
207 | return false; /* Empty glyph; zero extents. */ |
208 | |
209 | const GlyphHeader & = StructAtOffset<GlyphHeader> (glyph_data, 0); |
210 | if (glyph_header.numberOfContours < 0) |
211 | { |
212 | const CompositeGlyphHeader *possible = |
213 | &StructAfter<CompositeGlyphHeader, GlyphHeader> (glyph_header); |
214 | |
215 | iterator->glyph_start = glyph_data; |
216 | iterator->glyph_end = (const char *) glyph_data + length; |
217 | if (!iterator->in_range (possible)) |
218 | return false; |
219 | iterator->current = possible; |
220 | return true; |
221 | } |
222 | |
223 | return false; |
224 | } |
225 | |
226 | DEFINE_SIZE_MIN (4); |
227 | }; |
228 | |
229 | struct accelerator_t |
230 | { |
231 | void init (hb_face_t *face) |
232 | { |
233 | memset (this, 0, sizeof (accelerator_t)); |
234 | |
235 | const OT::head &head = *face->table.head; |
236 | if (head.indexToLocFormat > 1 || head.glyphDataFormat != 0) |
237 | /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ |
238 | return; |
239 | short_offset = 0 == head.indexToLocFormat; |
240 | |
241 | loca_table = hb_sanitize_context_t ().reference_table<loca> (face); |
242 | glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face); |
243 | |
244 | num_glyphs = MAX (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1; |
245 | } |
246 | |
247 | void fini () |
248 | { |
249 | loca_table.destroy (); |
250 | glyf_table.destroy (); |
251 | } |
252 | |
253 | /* |
254 | * Returns true if the referenced glyph is a valid glyph and a composite glyph. |
255 | * If true is returned a pointer to the composite glyph will be written into |
256 | * composite. |
257 | */ |
258 | bool (hb_codepoint_t glyph, |
259 | CompositeGlyphHeader::Iterator *composite /* OUT */) const |
260 | { |
261 | if (unlikely (!num_glyphs)) |
262 | return false; |
263 | |
264 | unsigned int start_offset, end_offset; |
265 | if (!get_offsets (glyph, &start_offset, &end_offset)) |
266 | return false; /* glyph not found */ |
267 | |
268 | return CompositeGlyphHeader::get_iterator ((const char *) this->glyf_table + start_offset, |
269 | end_offset - start_offset, |
270 | composite); |
271 | } |
272 | |
273 | enum simple_glyph_flag_t { |
274 | FLAG_ON_CURVE = 0x01, |
275 | FLAG_X_SHORT = 0x02, |
276 | FLAG_Y_SHORT = 0x04, |
277 | FLAG_REPEAT = 0x08, |
278 | FLAG_X_SAME = 0x10, |
279 | FLAG_Y_SAME = 0x20, |
280 | FLAG_RESERVED1 = 0x40, |
281 | FLAG_RESERVED2 = 0x80 |
282 | }; |
283 | |
284 | /* based on FontTools _g_l_y_f.py::trim */ |
285 | bool remove_padding (unsigned int start_offset, |
286 | unsigned int *end_offset) const |
287 | { |
288 | if (*end_offset - start_offset < GlyphHeader::static_size) return true; |
289 | |
290 | const char *glyph = ((const char *) glyf_table) + start_offset; |
291 | const char * const glyph_end = glyph + (*end_offset - start_offset); |
292 | const GlyphHeader & = StructAtOffset<GlyphHeader> (glyph, 0); |
293 | int16_t num_contours = (int16_t) glyph_header.numberOfContours; |
294 | |
295 | if (num_contours < 0) |
296 | /* Trimming for composites not implemented. |
297 | * If removing hints it falls out of that. */ |
298 | return true; |
299 | else if (num_contours > 0) |
300 | { |
301 | /* simple glyph w/contours, possibly trimmable */ |
302 | glyph += GlyphHeader::static_size + 2 * num_contours; |
303 | |
304 | if (unlikely (glyph + 2 >= glyph_end)) return false; |
305 | uint16_t nCoordinates = (uint16_t) StructAtOffset<HBUINT16> (glyph - 2, 0) + 1; |
306 | uint16_t nInstructions = (uint16_t) StructAtOffset<HBUINT16> (glyph, 0); |
307 | |
308 | glyph += 2 + nInstructions; |
309 | if (unlikely (glyph + 2 >= glyph_end)) return false; |
310 | |
311 | unsigned int coordBytes = 0; |
312 | unsigned int coordsWithFlags = 0; |
313 | while (glyph < glyph_end) |
314 | { |
315 | uint8_t flag = (uint8_t) *glyph; |
316 | glyph++; |
317 | |
318 | unsigned int repeat = 1; |
319 | if (flag & FLAG_REPEAT) |
320 | { |
321 | if (glyph >= glyph_end) |
322 | { |
323 | DEBUG_MSG(SUBSET, nullptr, "Bad flag" ); |
324 | return false; |
325 | } |
326 | repeat = ((uint8_t) *glyph) + 1; |
327 | glyph++; |
328 | } |
329 | |
330 | unsigned int xBytes, yBytes; |
331 | xBytes = yBytes = 0; |
332 | if (flag & FLAG_X_SHORT) xBytes = 1; |
333 | else if ((flag & FLAG_X_SAME) == 0) xBytes = 2; |
334 | |
335 | if (flag & FLAG_Y_SHORT) yBytes = 1; |
336 | else if ((flag & FLAG_Y_SAME) == 0) yBytes = 2; |
337 | |
338 | coordBytes += (xBytes + yBytes) * repeat; |
339 | coordsWithFlags += repeat; |
340 | if (coordsWithFlags >= nCoordinates) |
341 | break; |
342 | } |
343 | |
344 | if (coordsWithFlags != nCoordinates) |
345 | { |
346 | DEBUG_MSG(SUBSET, nullptr, "Expect %d coords to have flags, got flags for %d" , nCoordinates, coordsWithFlags); |
347 | return false; |
348 | } |
349 | glyph += coordBytes; |
350 | |
351 | if (glyph < glyph_end) |
352 | *end_offset -= glyph_end - glyph; |
353 | } |
354 | return true; |
355 | } |
356 | |
357 | bool get_offsets (hb_codepoint_t glyph, |
358 | unsigned int *start_offset /* OUT */, |
359 | unsigned int *end_offset /* OUT */) const |
360 | { |
361 | if (unlikely (glyph >= num_glyphs)) |
362 | return false; |
363 | |
364 | if (short_offset) |
365 | { |
366 | const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ; |
367 | *start_offset = 2 * offsets[glyph]; |
368 | *end_offset = 2 * offsets[glyph + 1]; |
369 | } |
370 | else |
371 | { |
372 | const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ; |
373 | |
374 | *start_offset = offsets[glyph]; |
375 | *end_offset = offsets[glyph + 1]; |
376 | } |
377 | |
378 | if (*start_offset > *end_offset || *end_offset > glyf_table.get_length ()) |
379 | return false; |
380 | |
381 | return true; |
382 | } |
383 | |
384 | bool get_instruction_offsets (unsigned int start_offset, |
385 | unsigned int end_offset, |
386 | unsigned int *instruction_start /* OUT */, |
387 | unsigned int *instruction_end /* OUT */) const |
388 | { |
389 | if (end_offset - start_offset < GlyphHeader::static_size) |
390 | { |
391 | *instruction_start = 0; |
392 | *instruction_end = 0; |
393 | return true; /* Empty glyph; no instructions. */ |
394 | } |
395 | const GlyphHeader & = StructAtOffset<GlyphHeader> (glyf_table, start_offset); |
396 | int16_t num_contours = (int16_t) glyph_header.numberOfContours; |
397 | if (num_contours < 0) |
398 | { |
399 | CompositeGlyphHeader::Iterator composite_it; |
400 | if (unlikely (!CompositeGlyphHeader::get_iterator ( |
401 | (const char*) this->glyf_table + start_offset, |
402 | end_offset - start_offset, &composite_it))) return false; |
403 | const CompositeGlyphHeader *last; |
404 | do { |
405 | last = composite_it.current; |
406 | } while (composite_it.move_to_next ()); |
407 | |
408 | if ((uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS) |
409 | *instruction_start = ((char *) last - (char *) glyf_table->dataZ.arrayZ) + last->get_size (); |
410 | else |
411 | *instruction_start = end_offset; |
412 | *instruction_end = end_offset; |
413 | if (unlikely (*instruction_start > *instruction_end)) |
414 | { |
415 | DEBUG_MSG(SUBSET, nullptr, "Invalid instruction offset, %d is outside [%d, %d]" , *instruction_start, start_offset, end_offset); |
416 | return false; |
417 | } |
418 | } |
419 | else |
420 | { |
421 | unsigned int instruction_length_offset = start_offset + GlyphHeader::static_size + 2 * num_contours; |
422 | if (unlikely (instruction_length_offset + 2 > end_offset)) |
423 | { |
424 | DEBUG_MSG(SUBSET, nullptr, "Glyph size is too short, missing field instructionLength." ); |
425 | return false; |
426 | } |
427 | |
428 | const HBUINT16 &instruction_length = StructAtOffset<HBUINT16> (glyf_table, instruction_length_offset); |
429 | unsigned int start = instruction_length_offset + 2; |
430 | unsigned int end = start + (uint16_t) instruction_length; |
431 | if (unlikely (end > end_offset)) // Out of bounds of the current glyph |
432 | { |
433 | DEBUG_MSG(SUBSET, nullptr, "The instructions array overruns the glyph's boundaries." ); |
434 | return false; |
435 | } |
436 | |
437 | *instruction_start = start; |
438 | *instruction_end = end; |
439 | } |
440 | return true; |
441 | } |
442 | |
443 | bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const |
444 | { |
445 | unsigned int start_offset, end_offset; |
446 | if (!get_offsets (glyph, &start_offset, &end_offset)) |
447 | return false; |
448 | |
449 | if (end_offset - start_offset < GlyphHeader::static_size) |
450 | return true; /* Empty glyph; zero extents. */ |
451 | |
452 | const GlyphHeader & = StructAtOffset<GlyphHeader> (glyf_table, start_offset); |
453 | |
454 | extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax); |
455 | extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax); |
456 | extents->width = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing; |
457 | extents->height = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing; |
458 | |
459 | return true; |
460 | } |
461 | |
462 | private: |
463 | bool short_offset; |
464 | unsigned int num_glyphs; |
465 | hb_blob_ptr_t<loca> loca_table; |
466 | hb_blob_ptr_t<glyf> glyf_table; |
467 | }; |
468 | |
469 | protected: |
470 | UnsizedArrayOf<HBUINT8> dataZ; /* Glyphs data. */ |
471 | public: |
472 | DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always |
473 | * check the size externally, allow Null() object of it by |
474 | * defining it MIN() instead. */ |
475 | }; |
476 | |
477 | struct glyf_accelerator_t : glyf::accelerator_t {}; |
478 | |
479 | } /* namespace OT */ |
480 | |
481 | |
482 | #endif /* HB_OT_GLYF_TABLE_HH */ |
483 | |