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 const hb_tag_t tableTag = HB_OT_TAG_loca; |
49 | |
50 | inline bool sanitize (hb_sanitize_context_t *c) const |
51 | { |
52 | TRACE_SANITIZE (this); |
53 | return_trace (true); |
54 | } |
55 | |
56 | protected: |
57 | HBUINT8 dataZ[VAR]; /* Location data. */ |
58 | DEFINE_SIZE_ARRAY (0, dataZ); |
59 | }; |
60 | |
61 | |
62 | /* |
63 | * glyf -- TrueType Glyph Data |
64 | * https://docs.microsoft.com/en-us/typography/opentype/spec/glyf |
65 | */ |
66 | #define HB_OT_TAG_glyf HB_TAG('g','l','y','f') |
67 | |
68 | |
69 | struct glyf |
70 | { |
71 | static const hb_tag_t tableTag = HB_OT_TAG_glyf; |
72 | |
73 | inline bool sanitize (hb_sanitize_context_t *c) const |
74 | { |
75 | TRACE_SANITIZE (this); |
76 | /* We don't check for anything specific here. The users of the |
77 | * struct do all the hard work... */ |
78 | return_trace (true); |
79 | } |
80 | |
81 | inline bool subset (hb_subset_plan_t *plan) const |
82 | { |
83 | hb_blob_t *glyf_prime = nullptr; |
84 | hb_blob_t *loca_prime = nullptr; |
85 | |
86 | bool success = true; |
87 | bool use_short_loca = false; |
88 | if (hb_subset_glyf_and_loca (plan, &use_short_loca, &glyf_prime, &loca_prime)) { |
89 | success = success && plan->add_table (HB_OT_TAG_glyf, glyf_prime); |
90 | success = success && plan->add_table (HB_OT_TAG_loca, loca_prime); |
91 | success = success && _add_head_and_set_loca_version (plan, use_short_loca); |
92 | } else { |
93 | success = false; |
94 | } |
95 | hb_blob_destroy (loca_prime); |
96 | hb_blob_destroy (glyf_prime); |
97 | |
98 | return success; |
99 | } |
100 | |
101 | static bool |
102 | _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca) |
103 | { |
104 | hb_blob_t *head_blob = hb_sanitize_context_t().reference_table<head> (plan->source); |
105 | hb_blob_t *head_prime_blob = hb_blob_copy_writable_or_fail (head_blob); |
106 | hb_blob_destroy (head_blob); |
107 | |
108 | if (unlikely (!head_prime_blob)) |
109 | return false; |
110 | |
111 | head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr); |
112 | head_prime->indexToLocFormat.set (use_short_loca ? 0 : 1); |
113 | bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob); |
114 | |
115 | hb_blob_destroy (head_prime_blob); |
116 | return success; |
117 | } |
118 | |
119 | struct |
120 | { |
121 | HBINT16 ; /* If the number of contours is |
122 | * greater than or equal to zero, |
123 | * this is a simple glyph; if negative, |
124 | * this is a composite glyph. */ |
125 | FWORD ; /* Minimum x for coordinate data. */ |
126 | FWORD ; /* Minimum y for coordinate data. */ |
127 | FWORD ; /* Maximum x for coordinate data. */ |
128 | FWORD ; /* Maximum y for coordinate data. */ |
129 | |
130 | DEFINE_SIZE_STATIC (10); |
131 | }; |
132 | |
133 | struct |
134 | { |
135 | enum { |
136 | ARG_1_AND_2_ARE_WORDS = 0x0001, |
137 | = 0x0002, |
138 | = 0x0004, |
139 | = 0x0008, |
140 | = 0x0020, |
141 | WE_HAVE_AN_X_AND_Y_SCALE = 0x0040, |
142 | = 0x0080, |
143 | = 0x0100, |
144 | = 0x0200, |
145 | = 0x0400, |
146 | = 0x0800, |
147 | = 0x1000 |
148 | }; |
149 | |
150 | HBUINT16 ; |
151 | HBUINT16 ; |
152 | |
153 | inline unsigned int (void) const |
154 | { |
155 | unsigned int size = min_size; |
156 | if (flags & ARG_1_AND_2_ARE_WORDS) { |
157 | // arg1 and 2 are int16 |
158 | size += 4; |
159 | } else { |
160 | // arg1 and 2 are int8 |
161 | size += 2; |
162 | } |
163 | if (flags & WE_HAVE_A_SCALE) { |
164 | // One x 16 bit (scale) |
165 | size += 2; |
166 | } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) { |
167 | // Two x 16 bit (xscale, yscale) |
168 | size += 4; |
169 | } else if (flags & WE_HAVE_A_TWO_BY_TWO) { |
170 | // Four x 16 bit (xscale, scale01, scale10, yscale) |
171 | size += 8; |
172 | } |
173 | return size; |
174 | } |
175 | |
176 | struct |
177 | { |
178 | const char *; |
179 | const char *; |
180 | const CompositeGlyphHeader *; |
181 | |
182 | inline bool () |
183 | { |
184 | if (current->flags & CompositeGlyphHeader::MORE_COMPONENTS) |
185 | { |
186 | const CompositeGlyphHeader *possible = |
187 | &StructAfter<CompositeGlyphHeader, CompositeGlyphHeader> (*current); |
188 | if (!in_range (possible)) |
189 | return false; |
190 | current = possible; |
191 | return true; |
192 | } |
193 | return false; |
194 | } |
195 | |
196 | inline bool (const CompositeGlyphHeader *composite) const |
197 | { |
198 | return (const char *) composite >= glyph_start |
199 | && ((const char *) composite + CompositeGlyphHeader::min_size) <= glyph_end |
200 | && ((const char *) composite + composite->get_size()) <= glyph_end; |
201 | } |
202 | }; |
203 | |
204 | static inline bool (const char * glyph_data, |
205 | unsigned int length, |
206 | CompositeGlyphHeader::Iterator *iterator /* OUT */) |
207 | { |
208 | if (length < GlyphHeader::static_size) |
209 | return false; /* Empty glyph; zero extents. */ |
210 | |
211 | const GlyphHeader & = StructAtOffset<GlyphHeader> (glyph_data, 0); |
212 | if (glyph_header.numberOfContours < 0) |
213 | { |
214 | const CompositeGlyphHeader *possible = |
215 | &StructAfter<CompositeGlyphHeader, GlyphHeader> (glyph_header); |
216 | |
217 | iterator->glyph_start = glyph_data; |
218 | iterator->glyph_end = (const char *) glyph_data + length; |
219 | if (!iterator->in_range (possible)) |
220 | return false; |
221 | iterator->current = possible; |
222 | return true; |
223 | } |
224 | |
225 | return false; |
226 | } |
227 | |
228 | DEFINE_SIZE_MIN (4); |
229 | }; |
230 | |
231 | struct accelerator_t |
232 | { |
233 | inline void init (hb_face_t *face) |
234 | { |
235 | memset (this, 0, sizeof (accelerator_t)); |
236 | |
237 | hb_blob_t *head_blob = hb_sanitize_context_t().reference_table<head> (face); |
238 | const head *head_table = head_blob->as<head> (); |
239 | if (head_table->indexToLocFormat > 1 || head_table->glyphDataFormat != 0) |
240 | { |
241 | /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ |
242 | hb_blob_destroy (head_blob); |
243 | return; |
244 | } |
245 | short_offset = 0 == head_table->indexToLocFormat; |
246 | hb_blob_destroy (head_blob); |
247 | |
248 | loca_blob = hb_sanitize_context_t().reference_table<loca> (face); |
249 | loca_table = loca_blob->as<loca> (); |
250 | glyf_blob = hb_sanitize_context_t().reference_table<glyf> (face); |
251 | glyf_table = glyf_blob->as<glyf> (); |
252 | |
253 | num_glyphs = MAX (1u, hb_blob_get_length (loca_blob) / (short_offset ? 2 : 4)) - 1; |
254 | glyf_len = hb_blob_get_length (glyf_blob); |
255 | } |
256 | |
257 | inline void fini (void) |
258 | { |
259 | hb_blob_destroy (loca_blob); |
260 | hb_blob_destroy (glyf_blob); |
261 | } |
262 | |
263 | /* |
264 | * Returns true if the referenced glyph is a valid glyph and a composite glyph. |
265 | * If true is returned a pointer to the composite glyph will be written into |
266 | * composite. |
267 | */ |
268 | inline bool (hb_codepoint_t glyph, |
269 | CompositeGlyphHeader::Iterator *composite /* OUT */) const |
270 | { |
271 | if (unlikely (!num_glyphs)) |
272 | return false; |
273 | |
274 | unsigned int start_offset, end_offset; |
275 | if (!get_offsets (glyph, &start_offset, &end_offset)) |
276 | return false; /* glyph not found */ |
277 | |
278 | return CompositeGlyphHeader::get_iterator ((const char*) this->glyf_table + start_offset, |
279 | end_offset - start_offset, |
280 | composite); |
281 | } |
282 | |
283 | enum simple_glyph_flag_t { |
284 | FLAG_X_SHORT = 0x02, |
285 | FLAG_Y_SHORT = 0x04, |
286 | FLAG_REPEAT = 0x08, |
287 | FLAG_X_SAME = 0x10, |
288 | FLAG_Y_SAME = 0x20 |
289 | }; |
290 | |
291 | /* based on FontTools _g_l_y_f.py::trim */ |
292 | inline bool remove_padding(unsigned int start_offset, |
293 | unsigned int *end_offset) const |
294 | { |
295 | if (*end_offset - start_offset < GlyphHeader::static_size) |
296 | return true; |
297 | |
298 | const char *glyph = ((const char *) glyf_table) + start_offset; |
299 | const char * const glyph_end = glyph + (*end_offset - start_offset); |
300 | const GlyphHeader & = StructAtOffset<GlyphHeader> (glyph, 0); |
301 | int16_t num_contours = (int16_t) glyph_header.numberOfContours; |
302 | |
303 | if (num_contours < 0) |
304 | /* Trimming for composites not implemented. |
305 | * If removing hints it falls out of that. */ |
306 | return true; |
307 | else if (num_contours > 0) |
308 | { |
309 | /* simple glyph w/contours, possibly trimmable */ |
310 | glyph += GlyphHeader::static_size + 2 * num_contours; |
311 | |
312 | if (unlikely (glyph + 2 >= glyph_end)) return false; |
313 | uint16_t nCoordinates = (uint16_t) StructAtOffset<HBUINT16>(glyph - 2, 0) + 1; |
314 | uint16_t nInstructions = (uint16_t) StructAtOffset<HBUINT16>(glyph, 0); |
315 | |
316 | glyph += 2 + nInstructions; |
317 | if (unlikely (glyph + 2 >= glyph_end)) return false; |
318 | |
319 | unsigned int coordBytes = 0; |
320 | unsigned int coordsWithFlags = 0; |
321 | while (glyph < glyph_end) |
322 | { |
323 | uint8_t flag = (uint8_t) *glyph; |
324 | glyph++; |
325 | |
326 | unsigned int repeat = 1; |
327 | if (flag & FLAG_REPEAT) |
328 | { |
329 | if (glyph >= glyph_end) |
330 | { |
331 | DEBUG_MSG(SUBSET, nullptr, "Bad flag" ); |
332 | return false; |
333 | } |
334 | repeat = ((uint8_t) *glyph) + 1; |
335 | glyph++; |
336 | } |
337 | |
338 | unsigned int xBytes, yBytes; |
339 | xBytes = yBytes = 0; |
340 | if (flag & FLAG_X_SHORT) |
341 | xBytes = 1; |
342 | else if ((flag & FLAG_X_SAME) == 0) |
343 | xBytes = 2; |
344 | |
345 | if (flag & FLAG_Y_SHORT) |
346 | yBytes = 1; |
347 | else if ((flag & FLAG_Y_SAME) == 0) |
348 | yBytes = 2; |
349 | |
350 | coordBytes += (xBytes + yBytes) * repeat; |
351 | coordsWithFlags += repeat; |
352 | if (coordsWithFlags >= nCoordinates) |
353 | break; |
354 | } |
355 | |
356 | if (coordsWithFlags != nCoordinates) |
357 | { |
358 | DEBUG_MSG(SUBSET, nullptr, "Expect %d coords to have flags, got flags for %d" , nCoordinates, coordsWithFlags); |
359 | return false; |
360 | } |
361 | glyph += coordBytes; |
362 | |
363 | if (glyph < glyph_end) |
364 | *end_offset -= glyph_end - glyph; |
365 | } |
366 | return true; |
367 | } |
368 | |
369 | inline bool get_offsets (hb_codepoint_t glyph, |
370 | unsigned int *start_offset /* OUT */, |
371 | unsigned int *end_offset /* OUT */) const |
372 | { |
373 | if (unlikely (glyph >= num_glyphs)) |
374 | return false; |
375 | |
376 | if (short_offset) |
377 | { |
378 | const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ; |
379 | *start_offset = 2 * offsets[glyph]; |
380 | *end_offset = 2 * offsets[glyph + 1]; |
381 | } |
382 | else |
383 | { |
384 | const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ; |
385 | |
386 | *start_offset = offsets[glyph]; |
387 | *end_offset = offsets[glyph + 1]; |
388 | } |
389 | |
390 | if (*start_offset > *end_offset || *end_offset > glyf_len) |
391 | return false; |
392 | |
393 | return true; |
394 | } |
395 | |
396 | inline bool get_instruction_offsets(unsigned int start_offset, |
397 | unsigned int end_offset, |
398 | unsigned int *instruction_start /* OUT */, |
399 | unsigned int *instruction_end /* OUT */) const |
400 | { |
401 | if (end_offset - start_offset < GlyphHeader::static_size) |
402 | { |
403 | *instruction_start = 0; |
404 | *instruction_end = 0; |
405 | return true; /* Empty glyph; no instructions. */ |
406 | } |
407 | const GlyphHeader & = StructAtOffset<GlyphHeader> (glyf_table, start_offset); |
408 | int16_t num_contours = (int16_t) glyph_header.numberOfContours; |
409 | if (num_contours < 0) |
410 | { |
411 | CompositeGlyphHeader::Iterator composite_it; |
412 | if (unlikely (!CompositeGlyphHeader::get_iterator ( |
413 | (const char*) this->glyf_table + start_offset, |
414 | end_offset - start_offset, &composite_it))) return false; |
415 | const CompositeGlyphHeader *last; |
416 | do { |
417 | last = composite_it.current; |
418 | } while (composite_it.move_to_next()); |
419 | |
420 | if ( (uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS) |
421 | *instruction_start = ((char *) last - (char *) glyf_table->dataZ) + last->get_size(); |
422 | else |
423 | *instruction_start = end_offset; |
424 | *instruction_end = end_offset; |
425 | if (unlikely (*instruction_start > *instruction_end)) |
426 | { |
427 | DEBUG_MSG(SUBSET, nullptr, "Invalid instruction offset, %d is outside [%d, %d]" , *instruction_start, start_offset, end_offset); |
428 | return false; |
429 | } |
430 | } |
431 | else |
432 | { |
433 | unsigned int instruction_length_offset = start_offset + GlyphHeader::static_size + 2 * num_contours; |
434 | if (unlikely (instruction_length_offset + 2 > end_offset)) |
435 | { |
436 | DEBUG_MSG(SUBSET, nullptr, "Glyph size is too short, missing field instructionLength." ); |
437 | return false; |
438 | } |
439 | |
440 | const HBUINT16 &instruction_length = StructAtOffset<HBUINT16> (glyf_table, instruction_length_offset); |
441 | unsigned int start = instruction_length_offset + 2; |
442 | unsigned int end = start + (uint16_t) instruction_length; |
443 | if (unlikely (end > end_offset)) // Out of bounds of the current glyph |
444 | { |
445 | DEBUG_MSG(SUBSET, nullptr, "The instructions array overruns the glyph's boundaries." ); |
446 | return false; |
447 | } |
448 | |
449 | *instruction_start = start; |
450 | *instruction_end = end; |
451 | } |
452 | return true; |
453 | } |
454 | |
455 | inline bool get_extents (hb_codepoint_t glyph, |
456 | hb_glyph_extents_t *extents) const |
457 | { |
458 | unsigned int start_offset, end_offset; |
459 | if (!get_offsets (glyph, &start_offset, &end_offset)) |
460 | return false; |
461 | |
462 | if (end_offset - start_offset < GlyphHeader::static_size) |
463 | return true; /* Empty glyph; zero extents. */ |
464 | |
465 | const GlyphHeader & = StructAtOffset<GlyphHeader> (glyf_table, start_offset); |
466 | |
467 | extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax); |
468 | extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax); |
469 | extents->width = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing; |
470 | extents->height = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing; |
471 | |
472 | return true; |
473 | } |
474 | |
475 | private: |
476 | bool short_offset; |
477 | unsigned int num_glyphs; |
478 | const loca *loca_table; |
479 | const glyf *glyf_table; |
480 | hb_blob_t *loca_blob; |
481 | hb_blob_t *glyf_blob; |
482 | unsigned int glyf_len; |
483 | }; |
484 | |
485 | protected: |
486 | HBUINT8 dataZ[VAR]; /* Glyphs data. */ |
487 | |
488 | DEFINE_SIZE_ARRAY (0, dataZ); |
489 | }; |
490 | |
491 | struct glyf_accelerator_t : glyf::accelerator_t {}; |
492 | |
493 | } /* namespace OT */ |
494 | |
495 | |
496 | #endif /* HB_OT_GLYF_TABLE_HH */ |
497 | |