OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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 "gsub.h" | |
6 | |
7 #include <limits> | |
8 #include <vector> | |
9 | |
10 #include "layout.h" | |
11 #include "maxp.h" | |
12 | |
13 // GSUB - The Glyph Substitution Table | |
14 // http://www.microsoft.com/typography/otspec/gsub.htm | |
15 | |
16 #define TABLE_NAME "GSUB" | |
17 | |
18 namespace { | |
19 | |
20 // The GSUB header size | |
21 const size_t kGsubHeaderSize = 4 + 3 * 2; | |
22 | |
23 enum GSUB_TYPE { | |
24 GSUB_TYPE_SINGLE = 1, | |
25 GSUB_TYPE_MULTIPLE = 2, | |
26 GSUB_TYPE_ALTERNATE = 3, | |
27 GSUB_TYPE_LIGATURE = 4, | |
28 GSUB_TYPE_CONTEXT = 5, | |
29 GSUB_TYPE_CHANGING_CONTEXT = 6, | |
30 GSUB_TYPE_EXTENSION_SUBSTITUTION = 7, | |
31 GSUB_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE = 8, | |
32 GSUB_TYPE_RESERVED = 9 | |
33 }; | |
34 | |
35 // Lookup type parsers. | |
36 bool ParseSingleSubstitution(const ots::OpenTypeFile *file, | |
37 const uint8_t *data, const size_t length); | |
38 bool ParseMutipleSubstitution(const ots::OpenTypeFile *file, | |
39 const uint8_t *data, const size_t length); | |
40 bool ParseAlternateSubstitution(const ots::OpenTypeFile *file, | |
41 const uint8_t *data, const size_t length); | |
42 bool ParseLigatureSubstitution(const ots::OpenTypeFile *file, | |
43 const uint8_t *data, const size_t length); | |
44 bool ParseContextSubstitution(const ots::OpenTypeFile *file, | |
45 const uint8_t *data, const size_t length); | |
46 bool ParseChainingContextSubstitution(const ots::OpenTypeFile *file, | |
47 const uint8_t *data, | |
48 const size_t length); | |
49 bool ParseExtensionSubstitution(const ots::OpenTypeFile *file, | |
50 const uint8_t *data, const size_t length); | |
51 bool ParseReverseChainingContextSingleSubstitution( | |
52 const ots::OpenTypeFile *file, const uint8_t *data, const size_t length); | |
53 | |
54 const ots::LookupSubtableParser::TypeParser kGsubTypeParsers[] = { | |
55 {GSUB_TYPE_SINGLE, ParseSingleSubstitution}, | |
56 {GSUB_TYPE_MULTIPLE, ParseMutipleSubstitution}, | |
57 {GSUB_TYPE_ALTERNATE, ParseAlternateSubstitution}, | |
58 {GSUB_TYPE_LIGATURE, ParseLigatureSubstitution}, | |
59 {GSUB_TYPE_CONTEXT, ParseContextSubstitution}, | |
60 {GSUB_TYPE_CHANGING_CONTEXT, ParseChainingContextSubstitution}, | |
61 {GSUB_TYPE_EXTENSION_SUBSTITUTION, ParseExtensionSubstitution}, | |
62 {GSUB_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE, | |
63 ParseReverseChainingContextSingleSubstitution} | |
64 }; | |
65 | |
66 const ots::LookupSubtableParser kGsubLookupSubtableParser = { | |
67 arraysize(kGsubTypeParsers), | |
68 GSUB_TYPE_EXTENSION_SUBSTITUTION, kGsubTypeParsers | |
69 }; | |
70 | |
71 // Lookup Type 1: | |
72 // Single Substitution Subtable | |
73 bool ParseSingleSubstitution(const ots::OpenTypeFile *file, | |
74 const uint8_t *data, const size_t length) { | |
75 ots::Buffer subtable(data, length); | |
76 | |
77 uint16_t format = 0; | |
78 uint16_t offset_coverage = 0; | |
79 | |
80 if (!subtable.ReadU16(&format) || | |
81 !subtable.ReadU16(&offset_coverage)) { | |
82 return OTS_FAILURE_MSG("Failed to read single subst table header"); | |
83 } | |
84 | |
85 const uint16_t num_glyphs = file->maxp->num_glyphs; | |
86 if (format == 1) { | |
87 // Parse SingleSubstFormat1 | |
88 int16_t delta_glyph_id = 0; | |
89 if (!subtable.ReadS16(&delta_glyph_id)) { | |
90 return OTS_FAILURE_MSG("Failed to read glyph shift from format 1 single su
bst table"); | |
91 } | |
92 if (std::abs(delta_glyph_id) >= num_glyphs) { | |
93 return OTS_FAILURE_MSG("bad glyph shift of %d in format 1 single subst tab
le", delta_glyph_id); | |
94 } | |
95 } else if (format == 2) { | |
96 // Parse SingleSubstFormat2 | |
97 uint16_t glyph_count = 0; | |
98 if (!subtable.ReadU16(&glyph_count)) { | |
99 return OTS_FAILURE_MSG("Failed to read glyph cound in format 2 single subs
t table"); | |
100 } | |
101 if (glyph_count > num_glyphs) { | |
102 return OTS_FAILURE_MSG("Bad glyph count %d > %d in format 2 single subst t
able", glyph_count, num_glyphs); | |
103 } | |
104 for (unsigned i = 0; i < glyph_count; ++i) { | |
105 uint16_t substitute = 0; | |
106 if (!subtable.ReadU16(&substitute)) { | |
107 return OTS_FAILURE_MSG("Failed to read substitution %d in format 2 singl
e subst table", i); | |
108 } | |
109 if (substitute >= num_glyphs) { | |
110 return OTS_FAILURE_MSG("too large substitute: %u", substitute); | |
111 } | |
112 } | |
113 } else { | |
114 return OTS_FAILURE_MSG("Bad single subst table format %d", format); | |
115 } | |
116 | |
117 if (offset_coverage < subtable.offset() || offset_coverage >= length) { | |
118 return OTS_FAILURE_MSG("Bad coverage offset %x", offset_coverage); | |
119 } | |
120 if (!ots::ParseCoverageTable(file, data + offset_coverage, | |
121 length - offset_coverage, num_glyphs)) { | |
122 return OTS_FAILURE_MSG("Failed to parse coverage table"); | |
123 } | |
124 | |
125 return true; | |
126 } | |
127 | |
128 bool ParseSequenceTable(const ots::OpenTypeFile *file, | |
129 const uint8_t *data, const size_t length, | |
130 const uint16_t num_glyphs) { | |
131 ots::Buffer subtable(data, length); | |
132 | |
133 uint16_t glyph_count = 0; | |
134 if (!subtable.ReadU16(&glyph_count)) { | |
135 return OTS_FAILURE_MSG("Failed to read glyph count in sequence table"); | |
136 } | |
137 if (glyph_count > num_glyphs) { | |
138 return OTS_FAILURE_MSG("bad glyph count %d > %d", glyph_count, num_glyphs); | |
139 } | |
140 for (unsigned i = 0; i < glyph_count; ++i) { | |
141 uint16_t substitute = 0; | |
142 if (!subtable.ReadU16(&substitute)) { | |
143 return OTS_FAILURE_MSG("Failedt o read substitution %d in sequence table",
i); | |
144 } | |
145 if (substitute >= num_glyphs) { | |
146 return OTS_FAILURE_MSG("Bad subsitution (%d) %d > %d", i, substitute, num_
glyphs); | |
147 } | |
148 } | |
149 | |
150 return true; | |
151 } | |
152 | |
153 // Lookup Type 2: | |
154 // Multiple Substitution Subtable | |
155 bool ParseMutipleSubstitution(const ots::OpenTypeFile *file, | |
156 const uint8_t *data, const size_t length) { | |
157 ots::Buffer subtable(data, length); | |
158 | |
159 uint16_t format = 0; | |
160 uint16_t offset_coverage = 0; | |
161 uint16_t sequence_count = 0; | |
162 | |
163 if (!subtable.ReadU16(&format) || | |
164 !subtable.ReadU16(&offset_coverage) || | |
165 !subtable.ReadU16(&sequence_count)) { | |
166 return OTS_FAILURE_MSG("Can't read header of multiple subst table"); | |
167 } | |
168 | |
169 if (format != 1) { | |
170 return OTS_FAILURE_MSG("Bad multiple subst table format %d", format); | |
171 } | |
172 | |
173 const uint16_t num_glyphs = file->maxp->num_glyphs; | |
174 const unsigned sequence_end = static_cast<unsigned>(6) + | |
175 sequence_count * 2; | |
176 if (sequence_end > std::numeric_limits<uint16_t>::max()) { | |
177 return OTS_FAILURE_MSG("Bad segence end %d, in multiple subst", sequence_end
); | |
178 } | |
179 for (unsigned i = 0; i < sequence_count; ++i) { | |
180 uint16_t offset_sequence = 0; | |
181 if (!subtable.ReadU16(&offset_sequence)) { | |
182 return OTS_FAILURE_MSG("Failed to read sequence offset for sequence %d", i
); | |
183 } | |
184 if (offset_sequence < sequence_end || offset_sequence >= length) { | |
185 return OTS_FAILURE_MSG("Bad sequence offset %d for sequence %d", offset_se
quence, i); | |
186 } | |
187 if (!ParseSequenceTable(file, data + offset_sequence, length - offset_sequen
ce, | |
188 num_glyphs)) { | |
189 return OTS_FAILURE_MSG("Failed to parse sequence table %d", i); | |
190 } | |
191 } | |
192 | |
193 if (offset_coverage < sequence_end || offset_coverage >= length) { | |
194 return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage); | |
195 } | |
196 if (!ots::ParseCoverageTable(file, data + offset_coverage, | |
197 length - offset_coverage, num_glyphs)) { | |
198 return OTS_FAILURE_MSG("Failed to parse coverage table"); | |
199 } | |
200 | |
201 return true; | |
202 } | |
203 | |
204 bool ParseAlternateSetTable(const ots::OpenTypeFile *file, | |
205 const uint8_t *data, const size_t length, | |
206 const uint16_t num_glyphs) { | |
207 ots::Buffer subtable(data, length); | |
208 | |
209 uint16_t glyph_count = 0; | |
210 if (!subtable.ReadU16(&glyph_count)) { | |
211 return OTS_FAILURE_MSG("Failed to read alternate set header"); | |
212 } | |
213 if (glyph_count > num_glyphs) { | |
214 return OTS_FAILURE_MSG("Bad glyph count %d > %d in alternate set table", gly
ph_count, num_glyphs); | |
215 } | |
216 for (unsigned i = 0; i < glyph_count; ++i) { | |
217 uint16_t alternate = 0; | |
218 if (!subtable.ReadU16(&alternate)) { | |
219 return OTS_FAILURE_MSG("Can't read alternate %d", i); | |
220 } | |
221 if (alternate >= num_glyphs) { | |
222 return OTS_FAILURE_MSG("Too large alternate: %u", alternate); | |
223 } | |
224 } | |
225 return true; | |
226 } | |
227 | |
228 // Lookup Type 3: | |
229 // Alternate Substitution Subtable | |
230 bool ParseAlternateSubstitution(const ots::OpenTypeFile *file, | |
231 const uint8_t *data, const size_t length) { | |
232 ots::Buffer subtable(data, length); | |
233 | |
234 uint16_t format = 0; | |
235 uint16_t offset_coverage = 0; | |
236 uint16_t alternate_set_count = 0; | |
237 | |
238 if (!subtable.ReadU16(&format) || | |
239 !subtable.ReadU16(&offset_coverage) || | |
240 !subtable.ReadU16(&alternate_set_count)) { | |
241 return OTS_FAILURE_MSG("Can't read alternate subst header"); | |
242 } | |
243 | |
244 if (format != 1) { | |
245 return OTS_FAILURE_MSG("Bad alternate subst table format %d", format); | |
246 } | |
247 | |
248 const uint16_t num_glyphs = file->maxp->num_glyphs; | |
249 const unsigned alternate_set_end = static_cast<unsigned>(6) + | |
250 alternate_set_count * 2; | |
251 if (alternate_set_end > std::numeric_limits<uint16_t>::max()) { | |
252 return OTS_FAILURE_MSG("Bad end of alternate set %d", alternate_set_end); | |
253 } | |
254 for (unsigned i = 0; i < alternate_set_count; ++i) { | |
255 uint16_t offset_alternate_set = 0; | |
256 if (!subtable.ReadU16(&offset_alternate_set)) { | |
257 return OTS_FAILURE_MSG("Can't read alternate set offset for set %d", i); | |
258 } | |
259 if (offset_alternate_set < alternate_set_end || | |
260 offset_alternate_set >= length) { | |
261 return OTS_FAILURE_MSG("Bad alternate set offset %d for set %d", offset_al
ternate_set, i); | |
262 } | |
263 if (!ParseAlternateSetTable(file, data + offset_alternate_set, | |
264 length - offset_alternate_set, | |
265 num_glyphs)) { | |
266 return OTS_FAILURE_MSG("Failed to parse alternate set"); | |
267 } | |
268 } | |
269 | |
270 if (offset_coverage < alternate_set_end || offset_coverage >= length) { | |
271 return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage); | |
272 } | |
273 if (!ots::ParseCoverageTable(file, data + offset_coverage, | |
274 length - offset_coverage, num_glyphs)) { | |
275 return OTS_FAILURE_MSG("Failed to parse coverage table"); | |
276 } | |
277 | |
278 return true; | |
279 } | |
280 | |
281 bool ParseLigatureTable(const ots::OpenTypeFile *file, | |
282 const uint8_t *data, const size_t length, | |
283 const uint16_t num_glyphs) { | |
284 ots::Buffer subtable(data, length); | |
285 | |
286 uint16_t lig_glyph = 0; | |
287 uint16_t comp_count = 0; | |
288 | |
289 if (!subtable.ReadU16(&lig_glyph) || | |
290 !subtable.ReadU16(&comp_count)) { | |
291 return OTS_FAILURE_MSG("Failed to read ligatuer table header"); | |
292 } | |
293 | |
294 if (lig_glyph >= num_glyphs) { | |
295 return OTS_FAILURE_MSG("too large lig_glyph: %u", lig_glyph); | |
296 } | |
297 if (comp_count == 0 || comp_count > num_glyphs) { | |
298 return OTS_FAILURE_MSG("Bad component count of %d", comp_count); | |
299 } | |
300 for (unsigned i = 0; i < comp_count - static_cast<unsigned>(1); ++i) { | |
301 uint16_t component = 0; | |
302 if (!subtable.ReadU16(&component)) { | |
303 return OTS_FAILURE_MSG("Can't read ligature component %d", i); | |
304 } | |
305 if (component >= num_glyphs) { | |
306 return OTS_FAILURE_MSG("Bad ligature component %d of %d", i, component); | |
307 } | |
308 } | |
309 | |
310 return true; | |
311 } | |
312 | |
313 bool ParseLigatureSetTable(const ots::OpenTypeFile *file, | |
314 const uint8_t *data, const size_t length, | |
315 const uint16_t num_glyphs) { | |
316 ots::Buffer subtable(data, length); | |
317 | |
318 uint16_t ligature_count = 0; | |
319 | |
320 if (!subtable.ReadU16(&ligature_count)) { | |
321 return OTS_FAILURE_MSG("Can't read ligature count in ligature set"); | |
322 } | |
323 | |
324 const unsigned ligature_end = static_cast<unsigned>(2) + ligature_count * 2; | |
325 if (ligature_end > std::numeric_limits<uint16_t>::max()) { | |
326 return OTS_FAILURE_MSG("Bad end of ligature %d in ligature set", ligature_en
d); | |
327 } | |
328 for (unsigned i = 0; i < ligature_count; ++i) { | |
329 uint16_t offset_ligature = 0; | |
330 if (!subtable.ReadU16(&offset_ligature)) { | |
331 return OTS_FAILURE_MSG("Failed to read ligature offset %d", i); | |
332 } | |
333 if (offset_ligature < ligature_end || offset_ligature >= length) { | |
334 return OTS_FAILURE_MSG("Bad ligature offset %d for ligature %d", offset_li
gature, i); | |
335 } | |
336 if (!ParseLigatureTable(file, data + offset_ligature, length - offset_ligatu
re, | |
337 num_glyphs)) { | |
338 return OTS_FAILURE_MSG("Failed to parse ligature %d", i); | |
339 } | |
340 } | |
341 | |
342 return true; | |
343 } | |
344 | |
345 // Lookup Type 4: | |
346 // Ligature Substitution Subtable | |
347 bool ParseLigatureSubstitution(const ots::OpenTypeFile *file, | |
348 const uint8_t *data, const size_t length) { | |
349 ots::Buffer subtable(data, length); | |
350 | |
351 uint16_t format = 0; | |
352 uint16_t offset_coverage = 0; | |
353 uint16_t lig_set_count = 0; | |
354 | |
355 if (!subtable.ReadU16(&format) || | |
356 !subtable.ReadU16(&offset_coverage) || | |
357 !subtable.ReadU16(&lig_set_count)) { | |
358 return OTS_FAILURE_MSG("Failed to read ligature substitution header"); | |
359 } | |
360 | |
361 if (format != 1) { | |
362 return OTS_FAILURE_MSG("Bad ligature substitution table format %d", format); | |
363 } | |
364 | |
365 const uint16_t num_glyphs = file->maxp->num_glyphs; | |
366 const unsigned ligature_set_end = static_cast<unsigned>(6) + | |
367 lig_set_count * 2; | |
368 if (ligature_set_end > std::numeric_limits<uint16_t>::max()) { | |
369 return OTS_FAILURE_MSG("Bad end of ligature set %d in ligature substitution
table", ligature_set_end); | |
370 } | |
371 for (unsigned i = 0; i < lig_set_count; ++i) { | |
372 uint16_t offset_ligature_set = 0; | |
373 if (!subtable.ReadU16(&offset_ligature_set)) { | |
374 return OTS_FAILURE_MSG("Can't read ligature set offset %d", i); | |
375 } | |
376 if (offset_ligature_set < ligature_set_end || | |
377 offset_ligature_set >= length) { | |
378 return OTS_FAILURE_MSG("Bad ligature set offset %d for set %d", offset_lig
ature_set, i); | |
379 } | |
380 if (!ParseLigatureSetTable(file, data + offset_ligature_set, | |
381 length - offset_ligature_set, num_glyphs)) { | |
382 return OTS_FAILURE_MSG("Failed to parse ligature set %d", i); | |
383 } | |
384 } | |
385 | |
386 if (offset_coverage < ligature_set_end || offset_coverage >= length) { | |
387 return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage); | |
388 } | |
389 if (!ots::ParseCoverageTable(file, data + offset_coverage, | |
390 length - offset_coverage, num_glyphs)) { | |
391 return OTS_FAILURE_MSG("Failed to parse coverage table"); | |
392 } | |
393 | |
394 return true; | |
395 } | |
396 | |
397 // Lookup Type 5: | |
398 // Contextual Substitution Subtable | |
399 bool ParseContextSubstitution(const ots::OpenTypeFile *file, | |
400 const uint8_t *data, const size_t length) { | |
401 return ots::ParseContextSubtable(file, data, length, file->maxp->num_glyphs, | |
402 file->gsub->num_lookups); | |
403 } | |
404 | |
405 // Lookup Type 6: | |
406 // Chaining Contextual Substitution Subtable | |
407 bool ParseChainingContextSubstitution(const ots::OpenTypeFile *file, | |
408 const uint8_t *data, | |
409 const size_t length) { | |
410 return ots::ParseChainingContextSubtable(file, data, length, | |
411 file->maxp->num_glyphs, | |
412 file->gsub->num_lookups); | |
413 } | |
414 | |
415 // Lookup Type 7: | |
416 // Extension Substition | |
417 bool ParseExtensionSubstitution(const ots::OpenTypeFile *file, | |
418 const uint8_t *data, const size_t length) { | |
419 return ots::ParseExtensionSubtable(file, data, length, | |
420 &kGsubLookupSubtableParser); | |
421 } | |
422 | |
423 // Lookup Type 8: | |
424 // Reverse Chaining Contexual Single Substitution Subtable | |
425 bool ParseReverseChainingContextSingleSubstitution( | |
426 const ots::OpenTypeFile *file, const uint8_t *data, const size_t length) { | |
427 ots::Buffer subtable(data, length); | |
428 | |
429 uint16_t format = 0; | |
430 uint16_t offset_coverage = 0; | |
431 | |
432 if (!subtable.ReadU16(&format) || | |
433 !subtable.ReadU16(&offset_coverage)) { | |
434 return OTS_FAILURE_MSG("Failed to read reverse chaining header"); | |
435 } | |
436 | |
437 const uint16_t num_glyphs = file->maxp->num_glyphs; | |
438 | |
439 uint16_t backtrack_glyph_count = 0; | |
440 if (!subtable.ReadU16(&backtrack_glyph_count)) { | |
441 return OTS_FAILURE_MSG("Failed to read backtrack glyph count in reverse chai
ning table"); | |
442 } | |
443 if (backtrack_glyph_count > num_glyphs) { | |
444 return OTS_FAILURE_MSG("Bad backtrack glyph count of %d", backtrack_glyph_co
unt); | |
445 } | |
446 std::vector<uint16_t> offsets_backtrack; | |
447 offsets_backtrack.reserve(backtrack_glyph_count); | |
448 for (unsigned i = 0; i < backtrack_glyph_count; ++i) { | |
449 uint16_t offset = 0; | |
450 if (!subtable.ReadU16(&offset)) { | |
451 return OTS_FAILURE_MSG("Failed to read backtrack offset %d", i); | |
452 } | |
453 offsets_backtrack.push_back(offset); | |
454 } | |
455 | |
456 uint16_t lookahead_glyph_count = 0; | |
457 if (!subtable.ReadU16(&lookahead_glyph_count)) { | |
458 return OTS_FAILURE_MSG("Failed to read look ahead glyph count"); | |
459 } | |
460 if (lookahead_glyph_count > num_glyphs) { | |
461 return OTS_FAILURE_MSG("Bad look ahead glyph count %d", lookahead_glyph_coun
t); | |
462 } | |
463 std::vector<uint16_t> offsets_lookahead; | |
464 offsets_lookahead.reserve(lookahead_glyph_count); | |
465 for (unsigned i = 0; i < lookahead_glyph_count; ++i) { | |
466 uint16_t offset = 0; | |
467 if (!subtable.ReadU16(&offset)) { | |
468 return OTS_FAILURE_MSG("Can't read look ahead offset %d", i); | |
469 } | |
470 offsets_lookahead.push_back(offset); | |
471 } | |
472 | |
473 uint16_t glyph_count = 0; | |
474 if (!subtable.ReadU16(&glyph_count)) { | |
475 return OTS_FAILURE_MSG("Can't read glyph count in reverse chaining table"); | |
476 } | |
477 if (glyph_count > num_glyphs) { | |
478 return OTS_FAILURE_MSG("Bad glyph count of %d", glyph_count); | |
479 } | |
480 for (unsigned i = 0; i < glyph_count; ++i) { | |
481 uint16_t substitute = 0; | |
482 if (!subtable.ReadU16(&substitute)) { | |
483 return OTS_FAILURE_MSG("Failed to read substitution %d reverse chaining ta
ble", i); | |
484 } | |
485 if (substitute >= num_glyphs) { | |
486 return OTS_FAILURE_MSG("Bad substitute glyph %d in reverse chaining table
substitution %d", substitute, i); | |
487 } | |
488 } | |
489 | |
490 const unsigned substitute_end = static_cast<unsigned>(10) + | |
491 (backtrack_glyph_count + lookahead_glyph_count + glyph_count) * 2; | |
492 if (substitute_end > std::numeric_limits<uint16_t>::max()) { | |
493 return OTS_FAILURE_MSG("Bad substitute end offset in reverse chaining table"
); | |
494 } | |
495 | |
496 if (offset_coverage < substitute_end || offset_coverage >= length) { | |
497 return OTS_FAILURE_MSG("Bad coverage offset %d in reverse chaining table", o
ffset_coverage); | |
498 } | |
499 if (!ots::ParseCoverageTable(file, data + offset_coverage, | |
500 length - offset_coverage, num_glyphs)) { | |
501 return OTS_FAILURE_MSG("Failed to parse coverage table in reverse chaining t
able"); | |
502 } | |
503 | |
504 for (unsigned i = 0; i < backtrack_glyph_count; ++i) { | |
505 if (offsets_backtrack[i] < substitute_end || | |
506 offsets_backtrack[i] >= length) { | |
507 return OTS_FAILURE_MSG("Bad backtrack offset %d for backtrack %d in revers
e chaining table", offsets_backtrack[i], i); | |
508 } | |
509 if (!ots::ParseCoverageTable(file, data + offsets_backtrack[i], | |
510 length - offsets_backtrack[i], num_glyphs)) { | |
511 return OTS_FAILURE_MSG("Failed to parse coverage table for backtrack %d in
reverse chaining table", i); | |
512 } | |
513 } | |
514 | |
515 for (unsigned i = 0; i < lookahead_glyph_count; ++i) { | |
516 if (offsets_lookahead[i] < substitute_end || | |
517 offsets_lookahead[i] >= length) { | |
518 return OTS_FAILURE_MSG("Bad lookahead offset %d for lookahead %d in revers
e chaining table", offsets_lookahead[i], i); | |
519 } | |
520 if (!ots::ParseCoverageTable(file, data + offsets_lookahead[i], | |
521 length - offsets_lookahead[i], num_glyphs)) { | |
522 return OTS_FAILURE_MSG("Failed to parse lookahead coverage table %d in rev
erse chaining table", i); | |
523 } | |
524 } | |
525 | |
526 return true; | |
527 } | |
528 | |
529 } // namespace | |
530 | |
531 #define DROP_THIS_TABLE(msg_) \ | |
532 do { \ | |
533 OTS_FAILURE_MSG(msg_ ", table discarded"); \ | |
534 file->gsub->data = 0; \ | |
535 file->gsub->length = 0; \ | |
536 } while (0) | |
537 | |
538 namespace ots { | |
539 | |
540 // As far as I checked, following fonts contain invalid values in GSUB table. | |
541 // OTS will drop their GSUB table. | |
542 // | |
543 // # too large substitute (value is 0xFFFF) | |
544 // kaiu.ttf | |
545 // mingliub2.ttf | |
546 // mingliub1.ttf | |
547 // mingliub0.ttf | |
548 // GraublauWeb.otf | |
549 // GraublauWebBold.otf | |
550 // | |
551 // # too large alternate (value is 0xFFFF) | |
552 // ManchuFont.ttf | |
553 // | |
554 // # bad offset to lang sys table (NULL offset) | |
555 // DejaVuMonoSansBold.ttf | |
556 // DejaVuMonoSansBoldOblique.ttf | |
557 // DejaVuMonoSansOblique.ttf | |
558 // DejaVuSansMono-BoldOblique.ttf | |
559 // DejaVuSansMono-Oblique.ttf | |
560 // DejaVuSansMono-Bold.ttf | |
561 // | |
562 // # bad start coverage index | |
563 // GenBasBI.ttf | |
564 // GenBasI.ttf | |
565 // AndBasR.ttf | |
566 // GenBkBasI.ttf | |
567 // CharisSILR.ttf | |
568 // CharisSILBI.ttf | |
569 // CharisSILI.ttf | |
570 // CharisSILB.ttf | |
571 // DoulosSILR.ttf | |
572 // CharisSILBI.ttf | |
573 // GenBkBasB.ttf | |
574 // GenBkBasR.ttf | |
575 // GenBkBasBI.ttf | |
576 // GenBasB.ttf | |
577 // GenBasR.ttf | |
578 // | |
579 // # glyph range is overlapping | |
580 // KacstTitleL.ttf | |
581 // KacstDecorative.ttf | |
582 // KacstTitle.ttf | |
583 // KacstArt.ttf | |
584 // KacstPoster.ttf | |
585 // KacstQurn.ttf | |
586 // KacstDigital.ttf | |
587 // KacstBook.ttf | |
588 // KacstFarsi.ttf | |
589 | |
590 bool ots_gsub_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { | |
591 // Parsing gsub table requires |file->maxp->num_glyphs| | |
592 if (!file->maxp) { | |
593 return OTS_FAILURE_MSG("Missing maxp table in font, needed by GSUB"); | |
594 } | |
595 | |
596 Buffer table(data, length); | |
597 | |
598 OpenTypeGSUB *gsub = new OpenTypeGSUB; | |
599 file->gsub = gsub; | |
600 | |
601 uint32_t version = 0; | |
602 uint16_t offset_script_list = 0; | |
603 uint16_t offset_feature_list = 0; | |
604 uint16_t offset_lookup_list = 0; | |
605 if (!table.ReadU32(&version) || | |
606 !table.ReadU16(&offset_script_list) || | |
607 !table.ReadU16(&offset_feature_list) || | |
608 !table.ReadU16(&offset_lookup_list)) { | |
609 DROP_THIS_TABLE("Incomplete table"); | |
610 return true; | |
611 } | |
612 | |
613 if (version != 0x00010000) { | |
614 DROP_THIS_TABLE("Bad version"); | |
615 return true; | |
616 } | |
617 | |
618 if (offset_lookup_list) { | |
619 if (offset_lookup_list < kGsubHeaderSize || offset_lookup_list >= length) { | |
620 DROP_THIS_TABLE("Bad lookup list offset in table header"); | |
621 return true; | |
622 } | |
623 | |
624 if (!ParseLookupListTable(file, data + offset_lookup_list, | |
625 length - offset_lookup_list, | |
626 &kGsubLookupSubtableParser, | |
627 &gsub->num_lookups)) { | |
628 DROP_THIS_TABLE("Failed to parse lookup list table"); | |
629 return true; | |
630 } | |
631 } | |
632 | |
633 uint16_t num_features = 0; | |
634 if (offset_feature_list) { | |
635 if (offset_feature_list < kGsubHeaderSize || offset_feature_list >= length)
{ | |
636 DROP_THIS_TABLE("Bad feature list offset in table header"); | |
637 return true; | |
638 } | |
639 | |
640 if (!ParseFeatureListTable(file, data + offset_feature_list, | |
641 length - offset_feature_list, gsub->num_lookups, | |
642 &num_features)) { | |
643 DROP_THIS_TABLE("Failed to parse feature list table"); | |
644 return true; | |
645 } | |
646 } | |
647 | |
648 if (offset_script_list) { | |
649 if (offset_script_list < kGsubHeaderSize || offset_script_list >= length) { | |
650 DROP_THIS_TABLE("Bad script list offset in table header"); | |
651 return true; | |
652 } | |
653 | |
654 if (!ParseScriptListTable(file, data + offset_script_list, | |
655 length - offset_script_list, num_features)) { | |
656 DROP_THIS_TABLE("Failed to parse script list table"); | |
657 return true; | |
658 } | |
659 } | |
660 | |
661 gsub->data = data; | |
662 gsub->length = length; | |
663 return true; | |
664 } | |
665 | |
666 bool ots_gsub_should_serialise(OpenTypeFile *file) { | |
667 return file->gsub != NULL && file->gsub->data != NULL; | |
668 } | |
669 | |
670 bool ots_gsub_serialise(OTSStream *out, OpenTypeFile *file) { | |
671 if (!out->Write(file->gsub->data, file->gsub->length)) { | |
672 return OTS_FAILURE_MSG("Failed to write GSUB table"); | |
673 } | |
674 | |
675 return true; | |
676 } | |
677 | |
678 void ots_gsub_free(OpenTypeFile *file) { | |
679 delete file->gsub; | |
680 } | |
681 | |
682 } // namespace ots | |
683 | |
684 #undef TABLE_NAME | |
685 #undef DROP_THIS_TABLE | |
OLD | NEW |