/src/harfbuzz/src/OT/glyf/SimpleGlyph.hh
Line | Count | Source (jump to first uncovered line) |
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 | 0 |
|
47 | 0 | const HBUINT16 &instructionLength = StructAtOffset<HBUINT16> (&bytes, instruction_length_offset); |
48 | 0 | /* 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 | 0 |
|
119 | 0 | unsigned flags_offset = length (instructions_length ()); |
120 | 0 | if (unlikely (flags_offset + 1 > bytes.length)) return; |
121 | 0 |
|
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 | 0 | { |
130 | 0 | auto *points = points_.arrayZ; |
131 | 0 | unsigned count = points_.length; |
132 | 0 | for (unsigned int i = 0; i < count;) |
133 | 0 | { |
134 | 0 | if (unlikely (p + 1 > end)) return false; |
135 | 0 | uint8_t flag = *p++; |
136 | 0 | points[i++].flag = flag; |
137 | 0 | if (flag & FLAG_REPEAT) |
138 | 0 | { |
139 | 0 | if (unlikely (p + 1 > end)) return false; |
140 | 0 | unsigned int repeat_count = *p++; |
141 | 0 | unsigned stop = hb_min (i + repeat_count, count); |
142 | 0 | for (; i < stop; i++) |
143 | 0 | points[i].flag = flag; |
144 | 0 | } |
145 | 0 | } |
146 | 0 | return true; |
147 | 0 | } |
148 | | |
149 | | static bool read_points (const HBUINT8 *&p /* IN/OUT */, |
150 | | hb_array_t<contour_point_t> points_ /* IN/OUT */, |
151 | | const HBUINT8 *end, |
152 | | float contour_point_t::*m, |
153 | | const simple_glyph_flag_t short_flag, |
154 | | const simple_glyph_flag_t same_flag) |
155 | 0 | { |
156 | 0 | int v = 0; |
157 | |
|
158 | 0 | for (auto &point : points_) |
159 | 0 | { |
160 | 0 | unsigned flag = point.flag; |
161 | 0 | if (flag & short_flag) |
162 | 0 | { |
163 | 0 | if (unlikely (p + 1 > end)) return false; |
164 | 0 | v += (bool(flag & same_flag) * 2 - 1) * *p++; |
165 | 0 | } |
166 | 0 | else |
167 | 0 | { |
168 | 0 | if (!(flag & same_flag)) |
169 | 0 | { |
170 | 0 | if (unlikely (p + HBINT16::static_size > end)) return false; |
171 | 0 | v += *(const HBINT16 *) p; |
172 | 0 | p += HBINT16::static_size; |
173 | 0 | } |
174 | 0 | } |
175 | 0 | point.*m = v; |
176 | 0 | } |
177 | 0 | return true; |
178 | 0 | } |
179 | | |
180 | | bool get_contour_points (contour_point_vector_t &points /* OUT */, |
181 | | bool phantom_only = false) const |
182 | 0 | { |
183 | 0 | const HBUINT16 *endPtsOfContours = &StructAfter<HBUINT16> (header); |
184 | 0 | int num_contours = header.numberOfContours; |
185 | 0 | assert (num_contours > 0); |
186 | | /* One extra item at the end, for the instruction-count below. */ |
187 | 0 | if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours]))) return false; |
188 | 0 | unsigned int num_points = endPtsOfContours[num_contours - 1] + 1; |
189 | |
|
190 | 0 | unsigned old_length = points.length; |
191 | 0 | points.alloc (points.length + num_points + 4); // Allocate for phantom points, to avoid a possible copy |
192 | 0 | if (unlikely (!points.resize (points.length + num_points, false))) return false; |
193 | 0 | auto points_ = points.as_array ().sub_array (old_length); |
194 | 0 | if (!phantom_only) |
195 | 0 | hb_memset (points_.arrayZ, 0, sizeof (contour_point_t) * num_points); |
196 | 0 | if (phantom_only) return true; |
197 | | |
198 | 0 | for (int i = 0; i < num_contours; i++) |
199 | 0 | points_[endPtsOfContours[i]].is_end_point = true; |
200 | | |
201 | | /* Skip instructions */ |
202 | 0 | const HBUINT8 *p = &StructAtOffset<HBUINT8> (&endPtsOfContours[num_contours + 1], |
203 | 0 | endPtsOfContours[num_contours]); |
204 | |
|
205 | 0 | if (unlikely ((const char *) p < bytes.arrayZ)) return false; /* Unlikely overflow */ |
206 | 0 | const HBUINT8 *end = (const HBUINT8 *) (bytes.arrayZ + bytes.length); |
207 | 0 | if (unlikely (p >= end)) return false; |
208 | | |
209 | | /* Read x & y coordinates */ |
210 | 0 | return read_flags (p, points_, end) |
211 | 0 | && read_points (p, points_, end, &contour_point_t::x, |
212 | 0 | FLAG_X_SHORT, FLAG_X_SAME) |
213 | 0 | && read_points (p, points_, end, &contour_point_t::y, |
214 | 0 | FLAG_Y_SHORT, FLAG_Y_SAME); |
215 | 0 | } |
216 | | |
217 | | static void encode_coord (int value, |
218 | | unsigned &flag, |
219 | | const simple_glyph_flag_t short_flag, |
220 | | const simple_glyph_flag_t same_flag, |
221 | | hb_vector_t<uint8_t> &coords /* OUT */) |
222 | 0 | { |
223 | 0 | if (value == 0) |
224 | 0 | { |
225 | 0 | flag |= same_flag; |
226 | 0 | } |
227 | 0 | else if (value >= -255 && value <= 255) |
228 | 0 | { |
229 | 0 | flag |= short_flag; |
230 | 0 | if (value > 0) flag |= same_flag; |
231 | 0 | else value = -value; |
232 | 0 |
|
233 | 0 | coords.arrayZ[coords.length++] = (uint8_t) value; |
234 | 0 | } |
235 | 0 | else |
236 | 0 | { |
237 | 0 | int16_t val = value; |
238 | 0 | coords.arrayZ[coords.length++] = val >> 8; |
239 | 0 | coords.arrayZ[coords.length++] = val & 0xff; |
240 | 0 | } |
241 | 0 | } |
242 | | |
243 | | static void encode_flag (unsigned flag, |
244 | | unsigned &repeat, |
245 | | unsigned lastflag, |
246 | | hb_vector_t<uint8_t> &flags /* OUT */) |
247 | 0 | { |
248 | 0 | if (flag == lastflag && repeat != 255) |
249 | 0 | { |
250 | 0 | repeat++; |
251 | 0 | if (repeat == 1) |
252 | 0 | { |
253 | 0 | /* We know there's room. */ |
254 | 0 | flags.arrayZ[flags.length++] = flag; |
255 | 0 | } |
256 | 0 | else |
257 | 0 | { |
258 | 0 | unsigned len = flags.length; |
259 | 0 | flags.arrayZ[len-2] = flag | FLAG_REPEAT; |
260 | 0 | flags.arrayZ[len-1] = repeat; |
261 | 0 | } |
262 | 0 | } |
263 | 0 | else |
264 | 0 | { |
265 | 0 | repeat = 0; |
266 | 0 | flags.arrayZ[flags.length++] = flag; |
267 | 0 | } |
268 | 0 | } |
269 | | |
270 | | bool compile_bytes_with_deltas (const contour_point_vector_t &all_points, |
271 | | bool no_hinting, |
272 | | hb_bytes_t &dest_bytes /* OUT */) |
273 | 0 | { |
274 | 0 | if (header.numberOfContours == 0 || all_points.length <= 4) |
275 | 0 | { |
276 | 0 | dest_bytes = hb_bytes_t (); |
277 | 0 | return true; |
278 | 0 | } |
279 | 0 | unsigned num_points = all_points.length - 4; |
280 | 0 |
|
281 | 0 | hb_vector_t<uint8_t> flags, x_coords, y_coords; |
282 | 0 | if (unlikely (!flags.alloc_exact (num_points))) return false; |
283 | 0 | if (unlikely (!x_coords.alloc_exact (2*num_points))) return false; |
284 | 0 | if (unlikely (!y_coords.alloc_exact (2*num_points))) return false; |
285 | 0 |
|
286 | 0 | unsigned lastflag = 255, repeat = 0; |
287 | 0 | int prev_x = 0, prev_y = 0; |
288 | 0 |
|
289 | 0 | for (unsigned i = 0; i < num_points; i++) |
290 | 0 | { |
291 | 0 | unsigned flag = all_points.arrayZ[i].flag; |
292 | 0 | flag &= FLAG_ON_CURVE | FLAG_OVERLAP_SIMPLE | FLAG_CUBIC; |
293 | 0 |
|
294 | 0 | int cur_x = roundf (all_points.arrayZ[i].x); |
295 | 0 | int cur_y = roundf (all_points.arrayZ[i].y); |
296 | 0 | encode_coord (cur_x - prev_x, flag, FLAG_X_SHORT, FLAG_X_SAME, x_coords); |
297 | 0 | encode_coord (cur_y - prev_y, flag, FLAG_Y_SHORT, FLAG_Y_SAME, y_coords); |
298 | 0 | encode_flag (flag, repeat, lastflag, flags); |
299 | 0 |
|
300 | 0 | prev_x = cur_x; |
301 | 0 | prev_y = cur_y; |
302 | 0 | lastflag = flag; |
303 | 0 | } |
304 | 0 |
|
305 | 0 | unsigned len_before_instrs = 2 * header.numberOfContours + 2; |
306 | 0 | unsigned len_instrs = instructions_length (); |
307 | 0 | unsigned total_len = len_before_instrs + flags.length + x_coords.length + y_coords.length; |
308 | 0 |
|
309 | 0 | if (!no_hinting) |
310 | 0 | total_len += len_instrs; |
311 | 0 |
|
312 | 0 | char *p = (char *) hb_malloc (total_len); |
313 | 0 | if (unlikely (!p)) return false; |
314 | 0 |
|
315 | 0 | const char *src = bytes.arrayZ + GlyphHeader::static_size; |
316 | 0 | char *cur = p; |
317 | 0 | hb_memcpy (p, src, len_before_instrs); |
318 | 0 |
|
319 | 0 | cur += len_before_instrs; |
320 | 0 | src += len_before_instrs; |
321 | 0 |
|
322 | 0 | if (!no_hinting) |
323 | 0 | { |
324 | 0 | hb_memcpy (cur, src, len_instrs); |
325 | 0 | cur += len_instrs; |
326 | 0 | } |
327 | 0 |
|
328 | 0 | hb_memcpy (cur, flags.arrayZ, flags.length); |
329 | 0 | cur += flags.length; |
330 | 0 |
|
331 | 0 | hb_memcpy (cur, x_coords.arrayZ, x_coords.length); |
332 | 0 | cur += x_coords.length; |
333 | 0 |
|
334 | 0 | hb_memcpy (cur, y_coords.arrayZ, y_coords.length); |
335 | 0 |
|
336 | 0 | dest_bytes = hb_bytes_t (p, total_len); |
337 | 0 | return true; |
338 | 0 | } |
339 | | }; |
340 | | |
341 | | |
342 | | } /* namespace glyf_impl */ |
343 | | } /* namespace OT */ |
344 | | |
345 | | |
346 | | #endif /* OT_GLYF_SIMPLEGLYPH_HH */ |