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