/src/harfbuzz/src/OT/glyf/SimpleGlyph.hh
Line | Count | Source |
1 | | #ifndef OT_GLYF_SIMPLEGLYPH_HH |
2 | | #define OT_GLYF_SIMPLEGLYPH_HH |
3 | | |
4 | | |
5 | | #include "../../hb-open-type.hh" |
6 | | |
7 | | |
8 | | namespace OT { |
9 | | namespace glyf_impl { |
10 | | |
11 | | |
12 | | struct SimpleGlyph |
13 | | { |
14 | | enum simple_glyph_flag_t |
15 | | { |
16 | | FLAG_ON_CURVE = 0x01, |
17 | | FLAG_X_SHORT = 0x02, |
18 | | FLAG_Y_SHORT = 0x04, |
19 | | FLAG_REPEAT = 0x08, |
20 | | FLAG_X_SAME = 0x10, |
21 | | FLAG_Y_SAME = 0x20, |
22 | | FLAG_OVERLAP_SIMPLE = 0x40, |
23 | | FLAG_CUBIC = 0x80 |
24 | | }; |
25 | | |
26 | | const GlyphHeader &header; |
27 | | hb_bytes_t bytes; |
28 | | SimpleGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) : |
29 | 0 | header (header_), bytes (bytes_) {} |
30 | | |
31 | | unsigned int instruction_len_offset () const |
32 | 0 | { return GlyphHeader::static_size + 2 * header.numberOfContours; } |
33 | | |
34 | | unsigned int length (unsigned int instruction_len) const |
35 | 0 | { return instruction_len_offset () + 2 + instruction_len; } |
36 | | |
37 | | bool has_instructions_length () const |
38 | 0 | { |
39 | 0 | return instruction_len_offset () + 2 <= bytes.length; |
40 | 0 | } |
41 | | |
42 | | unsigned int instructions_length () const |
43 | 0 | { |
44 | 0 | unsigned int instruction_length_offset = instruction_len_offset (); |
45 | 0 | if (unlikely (instruction_length_offset + 2 > bytes.length)) return 0; |
46 | | |
47 | 0 | const HBUINT16 &instructionLength = StructAtOffset<HBUINT16> (&bytes, instruction_length_offset); |
48 | | /* Out of bounds of the current glyph */ |
49 | 0 | if (unlikely (length (instructionLength) > bytes.length)) return 0; |
50 | 0 | return instructionLength; |
51 | 0 | } |
52 | | |
53 | | const hb_bytes_t trim_padding () const |
54 | 0 | { |
55 | | /* based on FontTools _g_l_y_f.py::trim */ |
56 | 0 | const uint8_t *glyph = (uint8_t*) bytes.arrayZ; |
57 | 0 | const uint8_t *glyph_end = glyph + bytes.length; |
58 | | /* simple glyph w/contours, possibly trimmable */ |
59 | 0 | glyph += instruction_len_offset (); |
60 | |
|
61 | 0 | if (unlikely (glyph + 2 >= glyph_end)) return hb_bytes_t (); |
62 | 0 | unsigned int num_coordinates = StructAtOffset<HBUINT16> (glyph - 2, 0) + 1; |
63 | 0 | unsigned int num_instructions = StructAtOffset<HBUINT16> (glyph, 0); |
64 | |
|
65 | 0 | glyph += 2 + num_instructions; |
66 | |
|
67 | 0 | unsigned int coord_bytes = 0; |
68 | 0 | unsigned int coords_with_flags = 0; |
69 | 0 | while (glyph < glyph_end) |
70 | 0 | { |
71 | 0 | uint8_t flag = *glyph; |
72 | 0 | glyph++; |
73 | |
|
74 | 0 | unsigned int repeat = 1; |
75 | 0 | if (flag & FLAG_REPEAT) |
76 | 0 | { |
77 | 0 | if (unlikely (glyph >= glyph_end)) return hb_bytes_t (); |
78 | 0 | repeat = *glyph + 1; |
79 | 0 | glyph++; |
80 | 0 | } |
81 | | |
82 | 0 | unsigned int xBytes, yBytes; |
83 | 0 | xBytes = yBytes = 0; |
84 | 0 | if (flag & FLAG_X_SHORT) xBytes = 1; |
85 | 0 | else if ((flag & FLAG_X_SAME) == 0) xBytes = 2; |
86 | |
|
87 | 0 | if (flag & FLAG_Y_SHORT) yBytes = 1; |
88 | 0 | else if ((flag & FLAG_Y_SAME) == 0) yBytes = 2; |
89 | |
|
90 | 0 | coord_bytes += (xBytes + yBytes) * repeat; |
91 | 0 | coords_with_flags += repeat; |
92 | 0 | if (coords_with_flags >= num_coordinates) break; |
93 | 0 | } |
94 | | |
95 | 0 | if (unlikely (coords_with_flags != num_coordinates)) return hb_bytes_t (); |
96 | 0 | return bytes.sub_array (0, bytes.length + coord_bytes - (glyph_end - glyph)); |
97 | 0 | } |
98 | | |
99 | | /* zero instruction length */ |
100 | | void drop_hints () |
101 | 0 | { |
102 | 0 | if (!has_instructions_length ()) return; |
103 | 0 | GlyphHeader &glyph_header = const_cast<GlyphHeader &> (header); |
104 | 0 | (HBUINT16 &) StructAtOffset<HBUINT16> (&glyph_header, instruction_len_offset ()) = 0; |
105 | 0 | } |
106 | | |
107 | | void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const |
108 | 0 | { |
109 | 0 | unsigned int instructions_len = instructions_length (); |
110 | 0 | unsigned int glyph_length = length (instructions_len); |
111 | 0 | dest_start = bytes.sub_array (0, glyph_length - instructions_len); |
112 | 0 | dest_end = bytes.sub_array (glyph_length, bytes.length - glyph_length); |
113 | 0 | } |
114 | | |
115 | | void set_overlaps_flag () |
116 | 0 | { |
117 | 0 | if (unlikely (!header.numberOfContours)) return; |
118 | | |
119 | 0 | unsigned flags_offset = length (instructions_length ()); |
120 | 0 | if (unlikely (flags_offset + 1 > bytes.length)) return; |
121 | | |
122 | 0 | HBUINT8 &first_flag = (HBUINT8 &) StructAtOffset<HBUINT16> (&bytes, flags_offset); |
123 | 0 | first_flag = (uint8_t) first_flag | FLAG_OVERLAP_SIMPLE; |
124 | 0 | } |
125 | | |
126 | | static bool read_flags (const HBUINT8 *&p /* IN/OUT */, |
127 | | hb_array_t<contour_point_t> points_ /* IN/OUT */, |
128 | | const HBUINT8 *end, |
129 | | bool extended) |
130 | 0 | { |
131 | 0 | auto *points = points_.arrayZ; |
132 | 0 | unsigned count = points_.length; |
133 | 0 | for (unsigned int i = 0; i < count;) |
134 | 0 | { |
135 | 0 | if (unlikely (p + 1 > end)) return false; |
136 | 0 | uint8_t flag = *p++; |
137 | 0 | if (!extended) |
138 | 0 | flag &= ~FLAG_CUBIC; |
139 | 0 | points[i++].flag = flag; |
140 | 0 | if (flag & FLAG_REPEAT) |
141 | 0 | { |
142 | 0 | if (unlikely (p + 1 > end)) return false; |
143 | 0 | unsigned int repeat_count = *p++; |
144 | 0 | unsigned stop = hb_min (i + repeat_count, count); |
145 | 0 | for (; i < stop; i++) |
146 | 0 | points[i].flag = flag; |
147 | 0 | } |
148 | 0 | } |
149 | 0 | return true; |
150 | 0 | } |
151 | | |
152 | | static bool read_points (const HBUINT8 *&p /* IN/OUT */, |
153 | | hb_array_t<contour_point_t> points_ /* IN/OUT */, |
154 | | const HBUINT8 *end, |
155 | | float contour_point_t::*m, |
156 | | const simple_glyph_flag_t short_flag, |
157 | | const simple_glyph_flag_t same_flag) |
158 | 0 | { |
159 | 0 | int v = 0; |
160 | |
|
161 | 0 | for (auto &point : points_) |
162 | 0 | { |
163 | 0 | unsigned flag = point.flag; |
164 | 0 | if (flag & short_flag) |
165 | 0 | { |
166 | 0 | if (unlikely (p + 1 > end)) return false; |
167 | 0 | v += (bool(flag & same_flag) * 2 - 1) * *p++; |
168 | 0 | } |
169 | 0 | else |
170 | 0 | { |
171 | 0 | if (!(flag & same_flag)) |
172 | 0 | { |
173 | 0 | if (unlikely (p + HBINT16::static_size > end)) return false; |
174 | 0 | v += *(const HBINT16 *) p; |
175 | 0 | p += HBINT16::static_size; |
176 | 0 | } |
177 | 0 | } |
178 | 0 | point.*m = v; |
179 | 0 | } |
180 | 0 | return true; |
181 | 0 | } |
182 | | |
183 | | bool get_contour_points (contour_point_vector_t &points /* OUT */, |
184 | | bool extended, |
185 | | bool phantom_only = false, |
186 | | int64_t *budget = nullptr) const |
187 | 0 | { |
188 | 0 | const HBUINT16 *endPtsOfContours = &StructAfter<HBUINT16> (header); |
189 | 0 | int num_contours = header.numberOfContours; |
190 | 0 | assert (num_contours > 0); |
191 | | /* One extra item at the end, for the instruction-count below. */ |
192 | 0 | if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours]))) return false; |
193 | 0 | unsigned int num_points = endPtsOfContours[num_contours - 1] + 1; |
194 | 0 | if (unlikely (num_points < (unsigned) num_contours)) return false; |
195 | | |
196 | | /* Charge before allocating and reading, so that glyphs that fail |
197 | | * later (truncated data, composite caps) still pay for this work. */ |
198 | 0 | if (budget && unlikely (!hb_budget_spend (*budget, HB_BUDGET_1, num_points))) return false; |
199 | | |
200 | 0 | unsigned old_length = points.length; |
201 | 0 | points.alloc (points.length + num_points + 4); // Allocate for phantom points, to avoid a possible copy |
202 | 0 | if (unlikely (!points.resize_dirty (points.length + num_points))) return false; |
203 | 0 | auto points_ = points.as_array ().sub_array (old_length); |
204 | 0 | if (!phantom_only) |
205 | 0 | hb_memset (points_.arrayZ, 0, sizeof (contour_point_t) * num_points); |
206 | 0 | if (phantom_only) return true; |
207 | | |
208 | 0 | for (int i = 0; i < num_contours; i++) |
209 | 0 | points_[endPtsOfContours[i]].is_end_point = true; |
210 | | |
211 | | /* Skip instructions */ |
212 | 0 | const HBUINT8 *p = &StructAtOffset<HBUINT8> (&endPtsOfContours[num_contours + 1], |
213 | 0 | endPtsOfContours[num_contours]); |
214 | |
|
215 | 0 | if (unlikely ((const char *) p < bytes.arrayZ)) return false; /* Unlikely overflow */ |
216 | 0 | const HBUINT8 *end = (const HBUINT8 *) (bytes.arrayZ + bytes.length); |
217 | 0 | if (unlikely (p >= end)) return false; |
218 | | |
219 | | /* Read x & y coordinates */ |
220 | 0 | return read_flags (p, points_, end, extended) |
221 | 0 | && read_points (p, points_, end, &contour_point_t::x, |
222 | 0 | FLAG_X_SHORT, FLAG_X_SAME) |
223 | 0 | && read_points (p, points_, end, &contour_point_t::y, |
224 | 0 | FLAG_Y_SHORT, FLAG_Y_SAME); |
225 | 0 | } |
226 | | |
227 | | static void encode_coord (int value, |
228 | | unsigned &flag, |
229 | | const simple_glyph_flag_t short_flag, |
230 | | const simple_glyph_flag_t same_flag, |
231 | | hb_vector_t<uint8_t> &coords /* OUT */) |
232 | 0 | { |
233 | 0 | if (value == 0) |
234 | 0 | { |
235 | 0 | flag |= same_flag; |
236 | 0 | } |
237 | 0 | else if (value >= -255 && value <= 255) |
238 | 0 | { |
239 | 0 | flag |= short_flag; |
240 | 0 | if (value > 0) flag |= same_flag; |
241 | 0 | else value = -value; |
242 | |
|
243 | 0 | coords.arrayZ[coords.length++] = (uint8_t) value; |
244 | 0 | } |
245 | 0 | else |
246 | 0 | { |
247 | 0 | int16_t val = value; |
248 | 0 | coords.arrayZ[coords.length++] = val >> 8; |
249 | 0 | coords.arrayZ[coords.length++] = val & 0xff; |
250 | 0 | } |
251 | 0 | } |
252 | | |
253 | | static void encode_flag (unsigned flag, |
254 | | unsigned &repeat, |
255 | | unsigned lastflag, |
256 | | hb_vector_t<uint8_t> &flags /* OUT */) |
257 | 0 | { |
258 | 0 | if (flag == lastflag && repeat != 255) |
259 | 0 | { |
260 | 0 | repeat++; |
261 | 0 | if (repeat == 1) |
262 | 0 | { |
263 | | /* We know there's room. */ |
264 | 0 | flags.arrayZ[flags.length++] = flag; |
265 | 0 | } |
266 | 0 | else |
267 | 0 | { |
268 | 0 | unsigned len = flags.length; |
269 | 0 | flags.arrayZ[len-2] = flag | FLAG_REPEAT; |
270 | 0 | flags.arrayZ[len-1] = repeat; |
271 | 0 | } |
272 | 0 | } |
273 | 0 | else |
274 | 0 | { |
275 | 0 | repeat = 0; |
276 | 0 | flags.arrayZ[flags.length++] = flag; |
277 | 0 | } |
278 | 0 | } |
279 | | |
280 | | bool compile_bytes_with_deltas (const contour_point_vector_t &all_points, |
281 | | bool no_hinting, |
282 | | hb_bytes_t &dest_bytes /* OUT */) |
283 | 0 | { |
284 | 0 | if (header.numberOfContours == 0 || all_points.length <= 4) |
285 | 0 | { |
286 | 0 | dest_bytes = hb_bytes_t (); |
287 | 0 | return true; |
288 | 0 | } |
289 | 0 | unsigned num_points = all_points.length - 4; |
290 | |
|
291 | 0 | hb_vector_t<uint8_t> flags, x_coords, y_coords; |
292 | 0 | if (unlikely (!flags.alloc_exact (num_points))) return false; |
293 | 0 | if (unlikely (!x_coords.alloc_exact (2*num_points))) return false; |
294 | 0 | if (unlikely (!y_coords.alloc_exact (2*num_points))) return false; |
295 | | |
296 | 0 | unsigned lastflag = 255, repeat = 0; |
297 | 0 | int prev_x = 0, prev_y = 0; |
298 | |
|
299 | 0 | for (unsigned i = 0; i < num_points; i++) |
300 | 0 | { |
301 | 0 | unsigned flag = all_points.arrayZ[i].flag; |
302 | 0 | flag &= FLAG_ON_CURVE | FLAG_OVERLAP_SIMPLE | FLAG_CUBIC; |
303 | |
|
304 | 0 | int cur_x = roundf (all_points.arrayZ[i].x); |
305 | 0 | int cur_y = roundf (all_points.arrayZ[i].y); |
306 | 0 | encode_coord (cur_x - prev_x, flag, FLAG_X_SHORT, FLAG_X_SAME, x_coords); |
307 | 0 | encode_coord (cur_y - prev_y, flag, FLAG_Y_SHORT, FLAG_Y_SAME, y_coords); |
308 | 0 | encode_flag (flag, repeat, lastflag, flags); |
309 | |
|
310 | 0 | prev_x = cur_x; |
311 | 0 | prev_y = cur_y; |
312 | 0 | lastflag = flag; |
313 | 0 | } |
314 | |
|
315 | 0 | unsigned len_before_instrs = 2 * header.numberOfContours + 2; |
316 | 0 | unsigned len_instrs = instructions_length (); |
317 | 0 | unsigned total_len = len_before_instrs + flags.length + x_coords.length + y_coords.length; |
318 | |
|
319 | 0 | if (!no_hinting) |
320 | 0 | total_len += len_instrs; |
321 | |
|
322 | 0 | char *p = (char *) hb_malloc (total_len); |
323 | 0 | if (unlikely (!p)) return false; |
324 | | |
325 | 0 | const char *src = bytes.arrayZ + GlyphHeader::static_size; |
326 | 0 | char *cur = p; |
327 | 0 | hb_memcpy (p, src, len_before_instrs); |
328 | |
|
329 | 0 | cur += len_before_instrs; |
330 | 0 | src += len_before_instrs; |
331 | |
|
332 | 0 | if (!no_hinting) |
333 | 0 | { |
334 | 0 | hb_memcpy (cur, src, len_instrs); |
335 | 0 | cur += len_instrs; |
336 | 0 | } |
337 | |
|
338 | 0 | hb_memcpy (cur, flags.arrayZ, flags.length); |
339 | 0 | cur += flags.length; |
340 | |
|
341 | 0 | hb_memcpy (cur, x_coords.arrayZ, x_coords.length); |
342 | 0 | cur += x_coords.length; |
343 | |
|
344 | 0 | hb_memcpy (cur, y_coords.arrayZ, y_coords.length); |
345 | |
|
346 | 0 | dest_bytes = hb_bytes_t (p, total_len); |
347 | 0 | return true; |
348 | 0 | } |
349 | | }; |
350 | | |
351 | | |
352 | | } /* namespace glyf_impl */ |
353 | | } /* namespace OT */ |
354 | | |
355 | | |
356 | | #endif /* OT_GLYF_SIMPLEGLYPH_HH */ |