Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(85)

Side by Side Diff: third_party/ots/src/gsub.cc

Issue 775893002: Updating OTS repo from https://github.com/khaledhosny/ots.git (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Updating with 4800 warning fix Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/ots/src/gsub.h ('k') | third_party/ots/src/hdmx.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « third_party/ots/src/gsub.h ('k') | third_party/ots/src/hdmx.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698