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