OLD | NEW |
| (Empty) |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "glyf.h" | |
6 | |
7 #include <algorithm> | |
8 #include <limits> | |
9 | |
10 #include "head.h" | |
11 #include "loca.h" | |
12 #include "maxp.h" | |
13 | |
14 // glyf - Glyph Data | |
15 // http://www.microsoft.com/typography/otspec/glyf.htm | |
16 | |
17 #define TABLE_NAME "glyf" | |
18 | |
19 namespace { | |
20 | |
21 bool ParseFlagsForSimpleGlyph(ots::OpenTypeFile *file, | |
22 ots::Buffer *table, | |
23 uint32_t gly_length, | |
24 uint32_t num_flags, | |
25 uint32_t *flags_count_logical, | |
26 uint32_t *flags_count_physical, | |
27 uint32_t *xy_coordinates_length) { | |
28 uint8_t flag = 0; | |
29 if (!table->ReadU8(&flag)) { | |
30 return OTS_FAILURE_MSG("Can't read flag"); | |
31 } | |
32 | |
33 uint32_t delta = 0; | |
34 if (flag & (1u << 1)) { // x-Short | |
35 ++delta; | |
36 } else if (!(flag & (1u << 4))) { | |
37 delta += 2; | |
38 } | |
39 | |
40 if (flag & (1u << 2)) { // y-Short | |
41 ++delta; | |
42 } else if (!(flag & (1u << 5))) { | |
43 delta += 2; | |
44 } | |
45 | |
46 if (flag & (1u << 3)) { // repeat | |
47 if (*flags_count_logical + 1 >= num_flags) { | |
48 return OTS_FAILURE_MSG("Count too high (%d + 1 >= %d)", *flags_count_logic
al, num_flags); | |
49 } | |
50 uint8_t repeat = 0; | |
51 if (!table->ReadU8(&repeat)) { | |
52 return OTS_FAILURE_MSG("Can't read repeat value"); | |
53 } | |
54 if (repeat == 0) { | |
55 return OTS_FAILURE_MSG("Zero repeat"); | |
56 } | |
57 delta += (delta * repeat); | |
58 | |
59 *flags_count_logical += repeat; | |
60 if (*flags_count_logical >= num_flags) { | |
61 return OTS_FAILURE_MSG("Count too high (%d >= %d)", *flags_count_logical,
num_flags); | |
62 } | |
63 ++(*flags_count_physical); | |
64 } | |
65 | |
66 if ((flag & (1u << 6)) || (flag & (1u << 7))) { // reserved flags | |
67 return OTS_FAILURE_MSG("Bad flag value (%d)", flag); | |
68 } | |
69 | |
70 *xy_coordinates_length += delta; | |
71 if (gly_length < *xy_coordinates_length) { | |
72 return OTS_FAILURE_MSG("Glyph coordinates length too low (%d < %d)", gly_len
gth, *xy_coordinates_length); | |
73 } | |
74 | |
75 return true; | |
76 } | |
77 | |
78 bool ParseSimpleGlyph(ots::OpenTypeFile *file, const uint8_t *data, | |
79 ots::Buffer *table, int16_t num_contours, | |
80 uint32_t gly_offset, uint32_t gly_length, | |
81 uint32_t *new_size) { | |
82 ots::OpenTypeGLYF *glyf = file->glyf; | |
83 | |
84 // read the end-points array | |
85 uint16_t num_flags = 0; | |
86 for (int i = 0; i < num_contours; ++i) { | |
87 uint16_t tmp_index = 0; | |
88 if (!table->ReadU16(&tmp_index)) { | |
89 return OTS_FAILURE_MSG("Can't read contour index %d", i); | |
90 } | |
91 if (tmp_index == 0xffffu) { | |
92 return OTS_FAILURE_MSG("Bad contour index %d", i); | |
93 } | |
94 // check if the indices are monotonically increasing | |
95 if (i && (tmp_index + 1 <= num_flags)) { | |
96 return OTS_FAILURE_MSG("Decreasing contour index %d + 1 <= %d", tmp_index,
num_flags); | |
97 } | |
98 num_flags = tmp_index + 1; | |
99 } | |
100 | |
101 uint16_t bytecode_length = 0; | |
102 if (!table->ReadU16(&bytecode_length)) { | |
103 return OTS_FAILURE_MSG("Can't read bytecode length"); | |
104 } | |
105 if ((file->maxp->version_1) && | |
106 (file->maxp->max_size_glyf_instructions < bytecode_length)) { | |
107 return OTS_FAILURE_MSG("Bytecode length too high %d", bytecode_length); | |
108 } | |
109 | |
110 const uint32_t gly_header_length = 10 + num_contours * 2 + 2; | |
111 if (gly_length < (gly_header_length + bytecode_length)) { | |
112 return OTS_FAILURE_MSG("Glyph header length too high %d", gly_header_length)
; | |
113 } | |
114 | |
115 glyf->iov.push_back(std::make_pair( | |
116 data + gly_offset, | |
117 static_cast<size_t>(gly_header_length + bytecode_length))); | |
118 | |
119 if (!table->Skip(bytecode_length)) { | |
120 return OTS_FAILURE_MSG("Can't skip bytecode of length %d", bytecode_length); | |
121 } | |
122 | |
123 uint32_t flags_count_physical = 0; // on memory | |
124 uint32_t xy_coordinates_length = 0; | |
125 for (uint32_t flags_count_logical = 0; | |
126 flags_count_logical < num_flags; | |
127 ++flags_count_logical, ++flags_count_physical) { | |
128 if (!ParseFlagsForSimpleGlyph(file, | |
129 table, | |
130 gly_length, | |
131 num_flags, | |
132 &flags_count_logical, | |
133 &flags_count_physical, | |
134 &xy_coordinates_length)) { | |
135 return OTS_FAILURE_MSG("Failed to parse glyph flags %d", flags_count_logic
al); | |
136 } | |
137 } | |
138 | |
139 if (gly_length < (gly_header_length + bytecode_length + | |
140 flags_count_physical + xy_coordinates_length)) { | |
141 return OTS_FAILURE_MSG("Glyph too short %d", gly_length); | |
142 } | |
143 | |
144 if (gly_length - (gly_header_length + bytecode_length + | |
145 flags_count_physical + xy_coordinates_length) > 3) { | |
146 // We allow 0-3 bytes difference since gly_length is 4-bytes aligned, | |
147 // zero-padded length. | |
148 return OTS_FAILURE_MSG("Invalid glyph length %d", gly_length); | |
149 } | |
150 | |
151 glyf->iov.push_back(std::make_pair( | |
152 data + gly_offset + gly_header_length + bytecode_length, | |
153 static_cast<size_t>(flags_count_physical + xy_coordinates_length))); | |
154 | |
155 *new_size | |
156 = gly_header_length + flags_count_physical + xy_coordinates_length + bytec
ode_length; | |
157 | |
158 return true; | |
159 } | |
160 | |
161 } // namespace | |
162 | |
163 namespace ots { | |
164 | |
165 bool ots_glyf_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { | |
166 Buffer table(data, length); | |
167 | |
168 if (!file->maxp || !file->loca || !file->head) { | |
169 return OTS_FAILURE_MSG("Missing maxp or loca or head table needed by glyf ta
ble"); | |
170 } | |
171 | |
172 OpenTypeGLYF *glyf = new OpenTypeGLYF; | |
173 file->glyf = glyf; | |
174 | |
175 const unsigned num_glyphs = file->maxp->num_glyphs; | |
176 std::vector<uint32_t> &offsets = file->loca->offsets; | |
177 | |
178 if (offsets.size() != num_glyphs + 1) { | |
179 return OTS_FAILURE_MSG("Invalide glyph offsets size %ld != %d", offsets.size
(), num_glyphs + 1); | |
180 } | |
181 | |
182 std::vector<uint32_t> resulting_offsets(num_glyphs + 1); | |
183 uint32_t current_offset = 0; | |
184 | |
185 for (unsigned i = 0; i < num_glyphs; ++i) { | |
186 const unsigned gly_offset = offsets[i]; | |
187 // The LOCA parser checks that these values are monotonic | |
188 const unsigned gly_length = offsets[i + 1] - offsets[i]; | |
189 if (!gly_length) { | |
190 // this glyph has no outline (e.g. the space charactor) | |
191 resulting_offsets[i] = current_offset; | |
192 continue; | |
193 } | |
194 | |
195 if (gly_offset >= length) { | |
196 return OTS_FAILURE_MSG("Glyph %d offset %d too high %ld", i, gly_offset, l
ength); | |
197 } | |
198 // Since these are unsigned types, the compiler is not allowed to assume | |
199 // that they never overflow. | |
200 if (gly_offset + gly_length < gly_offset) { | |
201 return OTS_FAILURE_MSG("Glyph %d length (%d < 0)!", i, gly_length); | |
202 } | |
203 if (gly_offset + gly_length > length) { | |
204 return OTS_FAILURE_MSG("Glyph %d length %d too high", i, gly_length); | |
205 } | |
206 | |
207 table.set_offset(gly_offset); | |
208 int16_t num_contours, xmin, ymin, xmax, ymax; | |
209 if (!table.ReadS16(&num_contours) || | |
210 !table.ReadS16(&xmin) || | |
211 !table.ReadS16(&ymin) || | |
212 !table.ReadS16(&xmax) || | |
213 !table.ReadS16(&ymax)) { | |
214 return OTS_FAILURE_MSG("Can't read glyph %d header", i); | |
215 } | |
216 | |
217 if (num_contours <= -2) { | |
218 // -2, -3, -4, ... are reserved for future use. | |
219 return OTS_FAILURE_MSG("Bad number of contours %d in glyph %d", num_contou
rs, i); | |
220 } | |
221 | |
222 // workaround for fonts in http://www.princexml.com/fonts/ | |
223 if ((xmin == 32767) && | |
224 (xmax == -32767) && | |
225 (ymin == 32767) && | |
226 (ymax == -32767)) { | |
227 OTS_WARNING("bad xmin/xmax/ymin/ymax values"); | |
228 xmin = xmax = ymin = ymax = 0; | |
229 } | |
230 | |
231 if (xmin > xmax || ymin > ymax) { | |
232 return OTS_FAILURE_MSG("Bad bounding box values bl=(%d, %d), tr=(%d, %d) i
n glyph %d", xmin, ymin, xmax, ymax, i); | |
233 } | |
234 | |
235 unsigned new_size = 0; | |
236 if (num_contours >= 0) { | |
237 // this is a simple glyph and might contain bytecode | |
238 if (!ParseSimpleGlyph(file, data, &table, | |
239 num_contours, gly_offset, gly_length, &new_size)) { | |
240 return OTS_FAILURE_MSG("Failed to parse glyph %d", i); | |
241 } | |
242 } else { | |
243 // it's a composite glyph without any bytecode. Enqueue the whole thing | |
244 glyf->iov.push_back(std::make_pair(data + gly_offset, | |
245 static_cast<size_t>(gly_length))); | |
246 new_size = gly_length; | |
247 } | |
248 | |
249 resulting_offsets[i] = current_offset; | |
250 // glyphs must be four byte aligned | |
251 // TODO(yusukes): investigate whether this padding is really necessary. | |
252 // Which part of the spec requires this? | |
253 const unsigned padding = (4 - (new_size & 3)) % 4; | |
254 if (padding) { | |
255 glyf->iov.push_back(std::make_pair( | |
256 reinterpret_cast<const uint8_t*>("\x00\x00\x00\x00"), | |
257 static_cast<size_t>(padding))); | |
258 new_size += padding; | |
259 } | |
260 current_offset += new_size; | |
261 } | |
262 resulting_offsets[num_glyphs] = current_offset; | |
263 | |
264 const uint16_t max16 = std::numeric_limits<uint16_t>::max(); | |
265 if ((*std::max_element(resulting_offsets.begin(), | |
266 resulting_offsets.end()) >= (max16 * 2u)) && | |
267 (file->head->index_to_loc_format != 1)) { | |
268 OTS_WARNING("2-bytes indexing is not possible (due to the padding above)"); | |
269 file->head->index_to_loc_format = 1; | |
270 } | |
271 | |
272 file->loca->offsets = resulting_offsets; | |
273 return true; | |
274 } | |
275 | |
276 bool ots_glyf_should_serialise(OpenTypeFile *file) { | |
277 return file->glyf != NULL; | |
278 } | |
279 | |
280 bool ots_glyf_serialise(OTSStream *out, OpenTypeFile *file) { | |
281 const OpenTypeGLYF *glyf = file->glyf; | |
282 | |
283 for (unsigned i = 0; i < glyf->iov.size(); ++i) { | |
284 if (!out->Write(glyf->iov[i].first, glyf->iov[i].second)) { | |
285 return OTS_FAILURE_MSG("Falied to write glyph %d", i); | |
286 } | |
287 } | |
288 | |
289 return true; | |
290 } | |
291 | |
292 void ots_glyf_free(OpenTypeFile *file) { | |
293 delete file->glyf; | |
294 } | |
295 | |
296 } // namespace ots | |
297 | |
298 #undef TABLE_NAME | |
OLD | NEW |