Line data Source code
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 0 : bool ParseFlagsForSimpleGlyph(ots::Font *font,
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 0 : uint8_t flag = 0;
29 0 : if (!table->ReadU8(&flag)) {
30 0 : return OTS_FAILURE_MSG("Can't read flag");
31 : }
32 :
33 0 : uint32_t delta = 0;
34 0 : if (flag & (1u << 1)) { // x-Short
35 0 : ++delta;
36 0 : } else if (!(flag & (1u << 4))) {
37 0 : delta += 2;
38 : }
39 :
40 0 : if (flag & (1u << 2)) { // y-Short
41 0 : ++delta;
42 0 : } else if (!(flag & (1u << 5))) {
43 0 : delta += 2;
44 : }
45 :
46 0 : if (flag & (1u << 3)) { // repeat
47 0 : if (*flags_count_logical + 1 >= num_flags) {
48 0 : return OTS_FAILURE_MSG("Count too high (%d + 1 >= %d)", *flags_count_logical, num_flags);
49 : }
50 0 : uint8_t repeat = 0;
51 0 : if (!table->ReadU8(&repeat)) {
52 0 : return OTS_FAILURE_MSG("Can't read repeat value");
53 : }
54 0 : if (repeat == 0) {
55 0 : return OTS_FAILURE_MSG("Zero repeat");
56 : }
57 0 : delta += (delta * repeat);
58 :
59 0 : *flags_count_logical += repeat;
60 0 : if (*flags_count_logical >= num_flags) {
61 0 : return OTS_FAILURE_MSG("Count too high (%d >= %d)", *flags_count_logical, num_flags);
62 : }
63 0 : ++(*flags_count_physical);
64 : }
65 :
66 0 : if ((flag & (1u << 6)) || (flag & (1u << 7))) { // reserved flags
67 0 : return OTS_FAILURE_MSG("Bad glyph flag value (%d), reserved flags must be set to zero", flag);
68 : }
69 :
70 0 : *xy_coordinates_length += delta;
71 0 : if (gly_length < *xy_coordinates_length) {
72 0 : return OTS_FAILURE_MSG("Glyph coordinates length too low (%d < %d)", gly_length, *xy_coordinates_length);
73 : }
74 :
75 0 : return true;
76 : }
77 :
78 0 : bool ParseSimpleGlyph(ots::Font *font, 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 0 : ots::OpenTypeGLYF *glyf = font->glyf;
83 :
84 : // read the end-points array
85 0 : uint16_t num_flags = 0;
86 0 : for (int i = 0; i < num_contours; ++i) {
87 0 : uint16_t tmp_index = 0;
88 0 : if (!table->ReadU16(&tmp_index)) {
89 0 : return OTS_FAILURE_MSG("Can't read contour index %d", i);
90 : }
91 0 : if (tmp_index == 0xffffu) {
92 0 : return OTS_FAILURE_MSG("Bad contour index %d", i);
93 : }
94 : // check if the indices are monotonically increasing
95 0 : if (i && (tmp_index + 1 <= num_flags)) {
96 0 : return OTS_FAILURE_MSG("Decreasing contour index %d + 1 <= %d", tmp_index, num_flags);
97 : }
98 0 : num_flags = tmp_index + 1;
99 : }
100 :
101 0 : uint16_t bytecode_length = 0;
102 0 : if (!table->ReadU16(&bytecode_length)) {
103 0 : return OTS_FAILURE_MSG("Can't read bytecode length");
104 : }
105 0 : if ((font->maxp->version_1) &&
106 0 : (font->maxp->max_size_glyf_instructions < bytecode_length)) {
107 0 : return OTS_FAILURE_MSG("Bytecode length too high %d", bytecode_length);
108 : }
109 :
110 0 : const uint32_t gly_header_length = 10 + num_contours * 2 + 2;
111 0 : if (gly_length < (gly_header_length + bytecode_length)) {
112 0 : return OTS_FAILURE_MSG("Glyph header length too high %d", gly_header_length);
113 : }
114 :
115 0 : glyf->iov.push_back(std::make_pair(
116 0 : data + gly_offset,
117 0 : static_cast<size_t>(gly_header_length + bytecode_length)));
118 :
119 0 : if (!table->Skip(bytecode_length)) {
120 0 : return OTS_FAILURE_MSG("Can't skip bytecode of length %d", bytecode_length);
121 : }
122 :
123 0 : uint32_t flags_count_physical = 0; // on memory
124 0 : uint32_t xy_coordinates_length = 0;
125 0 : for (uint32_t flags_count_logical = 0;
126 0 : flags_count_logical < num_flags;
127 : ++flags_count_logical, ++flags_count_physical) {
128 0 : if (!ParseFlagsForSimpleGlyph(font,
129 : table,
130 : gly_length,
131 : num_flags,
132 : &flags_count_logical,
133 : &flags_count_physical,
134 : &xy_coordinates_length)) {
135 0 : return OTS_FAILURE_MSG("Failed to parse glyph flags %d", flags_count_logical);
136 : }
137 : }
138 :
139 0 : if (gly_length < (gly_header_length + bytecode_length +
140 0 : flags_count_physical + xy_coordinates_length)) {
141 0 : return OTS_FAILURE_MSG("Glyph too short %d", gly_length);
142 : }
143 :
144 0 : if (gly_length - (gly_header_length + bytecode_length +
145 0 : 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 0 : return OTS_FAILURE_MSG("Invalid glyph length %d", gly_length);
149 : }
150 :
151 0 : glyf->iov.push_back(std::make_pair(
152 0 : data + gly_offset + gly_header_length + bytecode_length,
153 0 : static_cast<size_t>(flags_count_physical + xy_coordinates_length)));
154 :
155 : *new_size
156 0 : = gly_header_length + flags_count_physical + xy_coordinates_length + bytecode_length;
157 :
158 0 : return true;
159 : }
160 :
161 : } // namespace
162 :
163 : namespace ots {
164 :
165 0 : bool ots_glyf_parse(Font *font, const uint8_t *data, size_t length) {
166 0 : Buffer table(data, length);
167 :
168 0 : if (!font->maxp || !font->loca || !font->head) {
169 0 : return OTS_FAILURE_MSG("Missing maxp or loca or head table needed by glyf table");
170 : }
171 :
172 0 : OpenTypeGLYF *glyf = new OpenTypeGLYF;
173 0 : font->glyf = glyf;
174 :
175 0 : const unsigned num_glyphs = font->maxp->num_glyphs;
176 0 : std::vector<uint32_t> &offsets = font->loca->offsets;
177 :
178 0 : if (offsets.size() != num_glyphs + 1) {
179 0 : return OTS_FAILURE_MSG("Invalide glyph offsets size %ld != %d", offsets.size(), num_glyphs + 1);
180 : }
181 :
182 0 : std::vector<uint32_t> resulting_offsets(num_glyphs + 1);
183 0 : uint32_t current_offset = 0;
184 :
185 0 : for (unsigned i = 0; i < num_glyphs; ++i) {
186 0 : const unsigned gly_offset = offsets[i];
187 : // The LOCA parser checks that these values are monotonic
188 0 : const unsigned gly_length = offsets[i + 1] - offsets[i];
189 0 : if (!gly_length) {
190 : // this glyph has no outline (e.g. the space charactor)
191 0 : resulting_offsets[i] = current_offset;
192 0 : continue;
193 : }
194 :
195 0 : if (gly_offset >= length) {
196 0 : return OTS_FAILURE_MSG("Glyph %d offset %d too high %ld", i, gly_offset, length);
197 : }
198 : // Since these are unsigned types, the compiler is not allowed to assume
199 : // that they never overflow.
200 0 : if (gly_offset + gly_length < gly_offset) {
201 0 : return OTS_FAILURE_MSG("Glyph %d length (%d < 0)!", i, gly_length);
202 : }
203 0 : if (gly_offset + gly_length > length) {
204 0 : return OTS_FAILURE_MSG("Glyph %d length %d too high", i, gly_length);
205 : }
206 :
207 0 : table.set_offset(gly_offset);
208 : int16_t num_contours, xmin, ymin, xmax, ymax;
209 0 : if (!table.ReadS16(&num_contours) ||
210 0 : !table.ReadS16(&xmin) ||
211 0 : !table.ReadS16(&ymin) ||
212 0 : !table.ReadS16(&xmax) ||
213 0 : !table.ReadS16(&ymax)) {
214 0 : return OTS_FAILURE_MSG("Can't read glyph %d header", i);
215 : }
216 :
217 0 : if (num_contours <= -2) {
218 : // -2, -3, -4, ... are reserved for future use.
219 0 : return OTS_FAILURE_MSG("Bad number of contours %d in glyph %d", num_contours, i);
220 : }
221 :
222 : // workaround for fonts in http://www.princexml.com/fonts/
223 0 : if ((xmin == 32767) &&
224 0 : (xmax == -32767) &&
225 0 : (ymin == 32767) &&
226 0 : (ymax == -32767)) {
227 0 : OTS_WARNING("bad xmin/xmax/ymin/ymax values");
228 0 : xmin = xmax = ymin = ymax = 0;
229 : }
230 :
231 0 : if (xmin > xmax || ymin > ymax) {
232 0 : return OTS_FAILURE_MSG("Bad bounding box values bl=(%d, %d), tr=(%d, %d) in glyph %d", xmin, ymin, xmax, ymax, i);
233 : }
234 :
235 0 : unsigned new_size = 0;
236 0 : if (num_contours >= 0) {
237 : // this is a simple glyph and might contain bytecode
238 0 : if (!ParseSimpleGlyph(font, data, &table,
239 : num_contours, gly_offset, gly_length, &new_size)) {
240 0 : 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 0 : glyf->iov.push_back(std::make_pair(data + gly_offset,
245 0 : static_cast<size_t>(gly_length)));
246 0 : new_size = gly_length;
247 : }
248 :
249 0 : 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 0 : const unsigned padding = (4 - (new_size & 3)) % 4;
254 0 : if (padding) {
255 0 : glyf->iov.push_back(std::make_pair(
256 0 : reinterpret_cast<const uint8_t*>("\x00\x00\x00\x00"),
257 0 : static_cast<size_t>(padding)));
258 0 : new_size += padding;
259 : }
260 0 : current_offset += new_size;
261 : }
262 0 : resulting_offsets[num_glyphs] = current_offset;
263 :
264 0 : const uint16_t max16 = std::numeric_limits<uint16_t>::max();
265 0 : if ((*std::max_element(resulting_offsets.begin(),
266 0 : resulting_offsets.end()) >= (max16 * 2u)) &&
267 0 : (font->head->index_to_loc_format != 1)) {
268 0 : OTS_WARNING("2-bytes indexing is not possible (due to the padding above)");
269 0 : font->head->index_to_loc_format = 1;
270 : }
271 :
272 0 : font->loca->offsets = resulting_offsets;
273 0 : return true;
274 : }
275 :
276 0 : bool ots_glyf_should_serialise(Font *font) {
277 0 : return font->glyf != NULL;
278 : }
279 :
280 0 : bool ots_glyf_serialise(OTSStream *out, Font *font) {
281 0 : const OpenTypeGLYF *glyf = font->glyf;
282 :
283 0 : for (unsigned i = 0; i < glyf->iov.size(); ++i) {
284 0 : if (!out->Write(glyf->iov[i].first, glyf->iov[i].second)) {
285 0 : return OTS_FAILURE_MSG("Falied to write glyph %d", i);
286 : }
287 : }
288 :
289 0 : return true;
290 : }
291 :
292 0 : void ots_glyf_reuse(Font *font, Font *other) {
293 0 : font->glyf = other->glyf;
294 0 : font->glyf_reused = true;
295 0 : }
296 :
297 0 : void ots_glyf_free(Font *font) {
298 0 : delete font->glyf;
299 0 : }
300 :
301 : } // namespace ots
302 :
303 : #undef TABLE_NAME
|