1 // Copyright (c) 2011-2017 The OTS 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.
14 // OpenType Layout Common Table Formats
15 // http://www.microsoft.com/typography/otspec/chapter2.htm
17 #define TABLE_NAME "Layout" // XXX: use individual table names
21 // The 'DFLT' tag of script table.
22 const uint32_t kScriptTableTagDflt
= 0x44464c54;
23 // The value which represents there is no required feature index.
24 const uint16_t kNoRequiredFeatureIndexDefined
= 0xFFFF;
25 // The lookup flag bit which indicates existence of MarkFilteringSet.
26 const uint16_t kUseMarkFilteringSetBit
= 0x0010;
27 // The maximum type number of format for device tables.
28 const uint16_t kMaxDeltaFormatType
= 3;
29 // In variation fonts, Device Tables are replaced by VariationIndex tables,
30 // indicated by this flag in the deltaFormat field.
31 const uint16_t kVariationIndex
= 0x8000;
38 struct LangSysRecord
{
43 struct FeatureRecord
{
48 bool ParseLangSysTable(const ots::Font
*font
,
49 ots::Buffer
*subtable
, const uint32_t tag
,
50 const uint16_t num_features
) {
51 uint16_t offset_lookup_order
= 0;
52 uint16_t req_feature_index
= 0;
53 uint16_t feature_count
= 0;
54 if (!subtable
->ReadU16(&offset_lookup_order
) ||
55 !subtable
->ReadU16(&req_feature_index
) ||
56 !subtable
->ReadU16(&feature_count
)) {
57 return OTS_FAILURE_MSG("Failed to read langsys header for tag %c%c%c%c", OTS_UNTAG(tag
));
59 // |offset_lookup_order| is reserved and should be NULL.
60 if (offset_lookup_order
!= 0) {
61 return OTS_FAILURE_MSG("Bad lookup offset order %d for langsys tag %c%c%c%c", offset_lookup_order
, OTS_UNTAG(tag
));
63 if (req_feature_index
!= kNoRequiredFeatureIndexDefined
&&
64 req_feature_index
>= num_features
) {
65 return OTS_FAILURE_MSG("Bad required features index %d for langsys tag %c%c%c%c", req_feature_index
, OTS_UNTAG(tag
));
67 if (feature_count
> num_features
) {
68 return OTS_FAILURE_MSG("Bad feature count %d for langsys tag %c%c%c%c", feature_count
, OTS_UNTAG(tag
));
71 for (unsigned i
= 0; i
< feature_count
; ++i
) {
72 uint16_t feature_index
= 0;
73 if (!subtable
->ReadU16(&feature_index
)) {
74 return OTS_FAILURE_MSG("Failed to read feature index %d for langsys tag %c%c%c%c", i
, OTS_UNTAG(tag
));
76 if (feature_index
>= num_features
) {
77 return OTS_FAILURE_MSG("Bad feature index %d for feature %d for langsys tag %c%c%c%c", feature_index
, i
, OTS_UNTAG(tag
));
83 bool ParseScriptTable(const ots::Font
*font
,
84 const uint8_t *data
, const size_t length
,
85 const uint32_t tag
, const uint16_t num_features
) {
86 ots::Buffer
subtable(data
, length
);
88 uint16_t offset_default_lang_sys
= 0;
89 uint16_t lang_sys_count
= 0;
90 if (!subtable
.ReadU16(&offset_default_lang_sys
) ||
91 !subtable
.ReadU16(&lang_sys_count
)) {
92 return OTS_FAILURE_MSG("Failed to read script header for script tag %c%c%c%c", OTS_UNTAG(tag
));
95 // The spec requires a script table for 'DFLT' tag must contain non-NULL
96 // |offset_default_lang_sys|.
97 // https://www.microsoft.com/typography/otspec/chapter2.htm
98 if (tag
== kScriptTableTagDflt
) {
99 if (offset_default_lang_sys
== 0) {
100 return OTS_FAILURE_MSG("DFLT script doesn't satisfy the spec. DefaultLangSys is NULL");
104 const unsigned lang_sys_record_end
=
105 6 * static_cast<unsigned>(lang_sys_count
) + 4;
106 if (lang_sys_record_end
> std::numeric_limits
<uint16_t>::max()) {
107 return OTS_FAILURE_MSG("Bad end of langsys record %d for script tag %c%c%c%c", lang_sys_record_end
, OTS_UNTAG(tag
));
110 std::vector
<LangSysRecord
> lang_sys_records
;
111 lang_sys_records
.resize(lang_sys_count
);
112 uint32_t last_tag
= 0;
113 for (unsigned i
= 0; i
< lang_sys_count
; ++i
) {
114 if (!subtable
.ReadU32(&lang_sys_records
[i
].tag
) ||
115 !subtable
.ReadU16(&lang_sys_records
[i
].offset
)) {
116 return OTS_FAILURE_MSG("Failed to read langsys record header %d for script tag %c%c%c%c", i
, OTS_UNTAG(tag
));
118 // The record array must store the records alphabetically by tag
119 if (last_tag
!= 0 && last_tag
> lang_sys_records
[i
].tag
) {
120 return OTS_FAILURE_MSG("Bad last tag %d for langsys record %d for script tag %c%c%c%c", last_tag
, i
, OTS_UNTAG(tag
));
122 if (lang_sys_records
[i
].offset
< lang_sys_record_end
||
123 lang_sys_records
[i
].offset
>= length
) {
124 return OTS_FAILURE_MSG("bad offset to lang sys table: %x",
125 lang_sys_records
[i
].offset
);
127 last_tag
= lang_sys_records
[i
].tag
;
130 // Check lang sys tables
131 for (unsigned i
= 0; i
< lang_sys_count
; ++i
) {
132 subtable
.set_offset(lang_sys_records
[i
].offset
);
133 if (!ParseLangSysTable(font
, &subtable
, lang_sys_records
[i
].tag
, num_features
)) {
134 return OTS_FAILURE_MSG("Failed to parse langsys table %d (%c%c%c%c) for script tag %c%c%c%c", i
, OTS_UNTAG(lang_sys_records
[i
].tag
), OTS_UNTAG(tag
));
141 bool ParseFeatureTable(const ots::Font
*font
,
142 const uint8_t *data
, const size_t length
,
143 const uint16_t num_lookups
) {
144 ots::Buffer
subtable(data
, length
);
146 uint16_t offset_feature_params
= 0;
147 uint16_t lookup_count
= 0;
148 if (!subtable
.ReadU16(&offset_feature_params
) ||
149 !subtable
.ReadU16(&lookup_count
)) {
150 return OTS_FAILURE_MSG("Failed to read feature table header");
153 const unsigned feature_table_end
=
154 2 * static_cast<unsigned>(lookup_count
) + 4;
155 if (feature_table_end
> std::numeric_limits
<uint16_t>::max()) {
156 return OTS_FAILURE_MSG("Bad end of feature table %d", feature_table_end
);
158 // |offset_feature_params| is generally set to NULL.
159 if (offset_feature_params
!= 0 &&
160 (offset_feature_params
< feature_table_end
||
161 offset_feature_params
>= length
)) {
162 return OTS_FAILURE_MSG("Bad feature params offset %d", offset_feature_params
);
165 for (unsigned i
= 0; i
< lookup_count
; ++i
) {
166 uint16_t lookup_index
= 0;
167 if (!subtable
.ReadU16(&lookup_index
)) {
168 return OTS_FAILURE_MSG("Failed to read lookup index for lookup %d", i
);
170 // lookup index starts with 0.
171 if (lookup_index
>= num_lookups
) {
172 return OTS_FAILURE_MSG("Bad lookup index %d for lookup %d", lookup_index
, i
);
178 bool ParseClassDefFormat1(const ots::Font
*font
,
179 const uint8_t *data
, size_t length
,
180 const uint16_t num_glyphs
,
181 const uint16_t num_classes
) {
182 ots::Buffer
subtable(data
, length
);
184 // Skip format field.
185 if (!subtable
.Skip(2)) {
186 return OTS_FAILURE_MSG("Failed to skip class definition header");
189 uint16_t start_glyph
= 0;
190 if (!subtable
.ReadU16(&start_glyph
)) {
191 return OTS_FAILURE_MSG("Failed to read starting glyph of class definition");
193 if (start_glyph
> num_glyphs
) {
194 return OTS_FAILURE_MSG("Bad starting glyph %d in class definition", start_glyph
);
197 uint16_t glyph_count
= 0;
198 if (!subtable
.ReadU16(&glyph_count
)) {
199 return OTS_FAILURE_MSG("Failed to read glyph count in class definition");
201 if (glyph_count
> num_glyphs
) {
202 return OTS_FAILURE_MSG("bad glyph count: %u", glyph_count
);
204 for (unsigned i
= 0; i
< glyph_count
; ++i
) {
205 uint16_t class_value
= 0;
206 if (!subtable
.ReadU16(&class_value
)) {
207 return OTS_FAILURE_MSG("Failed to read class value for glyph %d in class definition", i
);
209 if (class_value
> num_classes
) {
210 return OTS_FAILURE_MSG("Bad class value %d for glyph %d in class definition", class_value
, i
);
217 bool ParseClassDefFormat2(const ots::Font
*font
,
218 const uint8_t *data
, size_t length
,
219 const uint16_t num_glyphs
,
220 const uint16_t num_classes
) {
221 ots::Buffer
subtable(data
, length
);
223 // Skip format field.
224 if (!subtable
.Skip(2)) {
225 return OTS_FAILURE_MSG("Failed to read class definition format");
228 uint16_t range_count
= 0;
229 if (!subtable
.ReadU16(&range_count
)) {
230 return OTS_FAILURE_MSG("Failed to read classRangeCount");
232 if (range_count
> num_glyphs
) {
233 return OTS_FAILURE_MSG("classRangeCount > glyph count: %u > %u", range_count
, num_glyphs
);
236 uint16_t last_end
= 0;
237 for (unsigned i
= 0; i
< range_count
; ++i
) {
240 uint16_t class_value
= 0;
241 if (!subtable
.ReadU16(&start
) ||
242 !subtable
.ReadU16(&end
) ||
243 !subtable
.ReadU16(&class_value
)) {
244 return OTS_FAILURE_MSG("Failed to read ClassRangeRecord %d", i
);
247 return OTS_FAILURE_MSG("ClassRangeRecord %d, start > end: %u > %u", i
, start
, end
);
249 if (last_end
&& start
<= last_end
) {
250 return OTS_FAILURE_MSG("ClassRangeRecord %d start overlaps with end of the previous one: %u <= %u", i
, start
, last_end
);
252 if (class_value
> num_classes
) {
253 return OTS_FAILURE_MSG("ClassRangeRecord %d class > number of classes: %u > %u", i
, class_value
, num_classes
);
261 bool ParseCoverageFormat1(const ots::Font
*font
,
262 const uint8_t *data
, size_t length
,
263 const uint16_t num_glyphs
,
264 const uint16_t expected_num_glyphs
) {
265 ots::Buffer
subtable(data
, length
);
267 // Skip format field.
268 if (!subtable
.Skip(2)) {
269 return OTS_FAILURE_MSG("Failed to skip coverage format");
272 uint16_t glyph_count
= 0;
273 if (!subtable
.ReadU16(&glyph_count
)) {
274 return OTS_FAILURE_MSG("Failed to read glyph count in coverage");
276 if (glyph_count
> num_glyphs
) {
277 return OTS_FAILURE_MSG("bad glyph count: %u", glyph_count
);
279 for (unsigned i
= 0; i
< glyph_count
; ++i
) {
281 if (!subtable
.ReadU16(&glyph
)) {
282 return OTS_FAILURE_MSG("Failed to read glyph %d in coverage", i
);
284 if (glyph
> num_glyphs
) {
285 return OTS_FAILURE_MSG("bad glyph ID: %u", glyph
);
289 if (expected_num_glyphs
&& expected_num_glyphs
!= glyph_count
) {
290 return OTS_FAILURE_MSG("unexpected number of glyphs: %u", glyph_count
);
296 bool ParseCoverageFormat2(const ots::Font
*font
,
297 const uint8_t *data
, size_t length
,
298 const uint16_t num_glyphs
,
299 const uint16_t expected_num_glyphs
) {
300 ots::Buffer
subtable(data
, length
);
302 // Skip format field.
303 if (!subtable
.Skip(2)) {
304 return OTS_FAILURE_MSG("Failed to skip format of coverage type 2");
307 uint16_t range_count
= 0;
308 if (!subtable
.ReadU16(&range_count
)) {
309 return OTS_FAILURE_MSG("Failed to read range count in coverage");
311 if (range_count
> num_glyphs
) {
312 return OTS_FAILURE_MSG("bad range count: %u", range_count
);
314 uint16_t last_end
= 0;
315 uint16_t last_start_coverage_index
= 0;
316 for (unsigned i
= 0; i
< range_count
; ++i
) {
319 uint16_t start_coverage_index
= 0;
320 if (!subtable
.ReadU16(&start
) ||
321 !subtable
.ReadU16(&end
) ||
322 !subtable
.ReadU16(&start_coverage_index
)) {
323 return OTS_FAILURE_MSG("Failed to read range %d in coverage", i
);
326 // Some of the Adobe Pro fonts have ranges that overlap by one element: the
327 // start of one range is equal to the end of the previous range. Therefore
328 // the < in the following condition should be <= were it not for this.
329 // See crbug.com/134135.
330 if (start
> end
|| (last_end
&& start
< last_end
)) {
331 return OTS_FAILURE_MSG("glyph range is overlapping.");
333 if (start_coverage_index
!= last_start_coverage_index
) {
334 return OTS_FAILURE_MSG("bad start coverage index.");
337 last_start_coverage_index
+= end
- start
+ 1;
340 if (expected_num_glyphs
&&
341 expected_num_glyphs
!= last_start_coverage_index
) {
342 return OTS_FAILURE_MSG("unexpected number of glyphs: %u", last_start_coverage_index
);
348 // Parsers for Contextual subtables in GSUB/GPOS tables.
350 bool ParseLookupRecord(const ots::Font
*font
,
351 ots::Buffer
*subtable
, const uint16_t num_glyphs
,
352 const uint16_t num_lookups
) {
353 uint16_t sequence_index
= 0;
354 uint16_t lookup_list_index
= 0;
355 if (!subtable
->ReadU16(&sequence_index
) ||
356 !subtable
->ReadU16(&lookup_list_index
)) {
357 return OTS_FAILURE_MSG("Failed to read header for lookup record");
359 if (sequence_index
>= num_glyphs
) {
360 return OTS_FAILURE_MSG("Bad sequence index %d in lookup record", sequence_index
);
362 if (lookup_list_index
>= num_lookups
) {
363 return OTS_FAILURE_MSG("Bad lookup list index %d in lookup record", lookup_list_index
);
368 bool ParseRuleSubtable(const ots::Font
*font
,
369 const uint8_t *data
, const size_t length
,
370 const uint16_t num_glyphs
,
371 const uint16_t num_lookups
) {
372 ots::Buffer
subtable(data
, length
);
374 uint16_t glyph_count
= 0;
375 uint16_t lookup_count
= 0;
376 if (!subtable
.ReadU16(&glyph_count
) ||
377 !subtable
.ReadU16(&lookup_count
)) {
378 return OTS_FAILURE_MSG("Failed to read rule subtable header");
381 if (glyph_count
== 0) {
382 return OTS_FAILURE_MSG("Bad glyph count %d in rule subtable", glyph_count
);
384 for (unsigned i
= 0; i
< glyph_count
- static_cast<unsigned>(1); ++i
) {
385 uint16_t glyph_id
= 0;
386 if (!subtable
.ReadU16(&glyph_id
)) {
387 return OTS_FAILURE_MSG("Failed to read glyph %d", i
);
389 if (glyph_id
> num_glyphs
) {
390 return OTS_FAILURE_MSG("Bad glyph %d for entry %d", glyph_id
, i
);
394 for (unsigned i
= 0; i
< lookup_count
; ++i
) {
395 if (!ParseLookupRecord(font
, &subtable
, num_glyphs
, num_lookups
)) {
396 return OTS_FAILURE_MSG("Failed to parse lookup record %d", i
);
402 bool ParseRuleSetTable(const ots::Font
*font
,
403 const uint8_t *data
, const size_t length
,
404 const uint16_t num_glyphs
,
405 const uint16_t num_lookups
) {
406 ots::Buffer
subtable(data
, length
);
408 uint16_t rule_count
= 0;
409 if (!subtable
.ReadU16(&rule_count
)) {
410 return OTS_FAILURE_MSG("Failed to read rule count in rule set");
412 const unsigned rule_end
= 2 * static_cast<unsigned>(rule_count
) + 2;
413 if (rule_end
> std::numeric_limits
<uint16_t>::max()) {
414 return OTS_FAILURE_MSG("Bad end of rule %d in rule set", rule_end
);
417 for (unsigned i
= 0; i
< rule_count
; ++i
) {
418 uint16_t offset_rule
= 0;
419 if (!subtable
.ReadU16(&offset_rule
)) {
420 return OTS_FAILURE_MSG("Failed to read rule offset for rule set %d", i
);
422 if (offset_rule
< rule_end
|| offset_rule
>= length
) {
423 return OTS_FAILURE_MSG("Bad rule offset %d in set %d", offset_rule
, i
);
425 if (!ParseRuleSubtable(font
, data
+ offset_rule
, length
- offset_rule
,
426 num_glyphs
, num_lookups
)) {
427 return OTS_FAILURE_MSG("Failed to parse rule set %d", i
);
434 bool ParseContextFormat1(const ots::Font
*font
,
435 const uint8_t *data
, const size_t length
,
436 const uint16_t num_glyphs
,
437 const uint16_t num_lookups
) {
438 ots::Buffer
subtable(data
, length
);
440 uint16_t offset_coverage
= 0;
441 uint16_t rule_set_count
= 0;
442 // Skip format field.
443 if (!subtable
.Skip(2) ||
444 !subtable
.ReadU16(&offset_coverage
) ||
445 !subtable
.ReadU16(&rule_set_count
)) {
446 return OTS_FAILURE_MSG("Failed to read header of context format 1");
449 const unsigned rule_set_end
= static_cast<unsigned>(6) +
451 if (rule_set_end
> std::numeric_limits
<uint16_t>::max()) {
452 return OTS_FAILURE_MSG("Bad end of rule set %d of context format 1", rule_set_end
);
454 if (offset_coverage
< rule_set_end
|| offset_coverage
>= length
) {
455 return OTS_FAILURE_MSG("Bad coverage offset %d in context format 1", offset_coverage
);
457 if (!ots::ParseCoverageTable(font
, data
+ offset_coverage
,
458 length
- offset_coverage
, num_glyphs
)) {
459 return OTS_FAILURE_MSG("Failed to parse coverage table in context format 1");
462 for (unsigned i
= 0; i
< rule_set_count
; ++i
) {
463 uint16_t offset_rule
= 0;
464 if (!subtable
.ReadU16(&offset_rule
)) {
465 return OTS_FAILURE_MSG("Failed to read rule offset %d in context format 1", i
);
467 if (offset_rule
< rule_set_end
|| offset_rule
>= length
) {
468 return OTS_FAILURE_MSG("Bad rule offset %d in rule %d in context format 1", offset_rule
, i
);
470 if (!ParseRuleSetTable(font
, data
+ offset_rule
, length
- offset_rule
,
471 num_glyphs
, num_lookups
)) {
472 return OTS_FAILURE_MSG("Failed to parse rule set %d in context format 1", i
);
479 bool ParseClassRuleTable(const ots::Font
*font
,
480 const uint8_t *data
, const size_t length
,
481 const uint16_t num_glyphs
,
482 const uint16_t num_lookups
) {
483 ots::Buffer
subtable(data
, length
);
485 uint16_t glyph_count
= 0;
486 uint16_t lookup_count
= 0;
487 if (!subtable
.ReadU16(&glyph_count
) ||
488 !subtable
.ReadU16(&lookup_count
)) {
489 return OTS_FAILURE_MSG("Failed to read header of class rule table");
492 if (glyph_count
== 0 || glyph_count
>= num_glyphs
) {
493 return OTS_FAILURE_MSG("Bad glyph count %d in class rule table", glyph_count
);
496 // ClassRule table contains an array of classes. Each value of classes
497 // could take arbitrary values including zero so we don't check these value.
498 const unsigned num_classes
= glyph_count
- static_cast<unsigned>(1);
499 if (!subtable
.Skip(2 * num_classes
)) {
500 return OTS_FAILURE_MSG("Failed to skip classes in class rule table");
503 for (unsigned i
= 0; i
< lookup_count
; ++i
) {
504 if (!ParseLookupRecord(font
, &subtable
, num_glyphs
, num_lookups
)) {
505 return OTS_FAILURE_MSG("Failed to parse lookup record %d in class rule table", i
);
511 bool ParseClassSetTable(const ots::Font
*font
,
512 const uint8_t *data
, const size_t length
,
513 const uint16_t num_glyphs
,
514 const uint16_t num_lookups
) {
515 ots::Buffer
subtable(data
, length
);
517 uint16_t class_rule_count
= 0;
518 if (!subtable
.ReadU16(&class_rule_count
)) {
519 return OTS_FAILURE_MSG("Failed to read class rule count in class set table");
521 const unsigned class_rule_end
=
522 2 * static_cast<unsigned>(class_rule_count
) + 2;
523 if (class_rule_end
> std::numeric_limits
<uint16_t>::max()) {
524 return OTS_FAILURE_MSG("bad class rule end %d in class set table", class_rule_end
);
526 for (unsigned i
= 0; i
< class_rule_count
; ++i
) {
527 uint16_t offset_class_rule
= 0;
528 if (!subtable
.ReadU16(&offset_class_rule
)) {
529 return OTS_FAILURE_MSG("Failed to read class rule offset %d in class set table", i
);
531 if (offset_class_rule
< class_rule_end
|| offset_class_rule
>= length
) {
532 return OTS_FAILURE_MSG("Bad class rule offset %d in class %d", offset_class_rule
, i
);
534 if (!ParseClassRuleTable(font
, data
+ offset_class_rule
,
535 length
- offset_class_rule
, num_glyphs
,
537 return OTS_FAILURE_MSG("Failed to parse class rule table %d", i
);
544 bool ParseContextFormat2(const ots::Font
*font
,
545 const uint8_t *data
, const size_t length
,
546 const uint16_t num_glyphs
,
547 const uint16_t num_lookups
) {
548 ots::Buffer
subtable(data
, length
);
550 uint16_t offset_coverage
= 0;
551 uint16_t offset_class_def
= 0;
552 uint16_t class_set_cnt
= 0;
553 // Skip format field.
554 if (!subtable
.Skip(2) ||
555 !subtable
.ReadU16(&offset_coverage
) ||
556 !subtable
.ReadU16(&offset_class_def
) ||
557 !subtable
.ReadU16(&class_set_cnt
)) {
558 return OTS_FAILURE_MSG("Failed to read header for context format 2");
561 const unsigned class_set_end
= 2 * static_cast<unsigned>(class_set_cnt
) + 8;
562 if (class_set_end
> std::numeric_limits
<uint16_t>::max()) {
563 return OTS_FAILURE_MSG("Bad end of class set %d for context format 2", class_set_end
);
565 if (offset_coverage
< class_set_end
|| offset_coverage
>= length
) {
566 return OTS_FAILURE_MSG("Bad coverage offset %d in context format 2", offset_coverage
);
568 if (!ots::ParseCoverageTable(font
, data
+ offset_coverage
,
569 length
- offset_coverage
, num_glyphs
)) {
570 return OTS_FAILURE_MSG("Failed to parse coverage table in context format 2");
573 if (offset_class_def
< class_set_end
|| offset_class_def
>= length
) {
574 return OTS_FAILURE_MSG("bad class definition offset %d in context format 2", offset_class_def
);
576 if (!ots::ParseClassDefTable(font
, data
+ offset_class_def
,
577 length
- offset_class_def
,
578 num_glyphs
, ots::kMaxClassDefValue
)) {
579 return OTS_FAILURE_MSG("Failed to parse class definition table in context format 2");
582 for (unsigned i
= 0; i
< class_set_cnt
; ++i
) {
583 uint16_t offset_class_rule
= 0;
584 if (!subtable
.ReadU16(&offset_class_rule
)) {
585 return OTS_FAILURE_MSG("Failed to read class rule offset %d in context format 2", i
);
587 if (offset_class_rule
) {
588 if (offset_class_rule
< class_set_end
|| offset_class_rule
>= length
) {
589 return OTS_FAILURE_MSG("Bad class rule offset %d for rule %d in context format 2", offset_class_rule
, i
);
591 if (!ParseClassSetTable(font
, data
+ offset_class_rule
,
592 length
- offset_class_rule
, num_glyphs
,
594 return OTS_FAILURE_MSG("Failed to parse class set %d in context format 2", i
);
602 bool ParseContextFormat3(const ots::Font
*font
,
603 const uint8_t *data
, const size_t length
,
604 const uint16_t num_glyphs
,
605 const uint16_t num_lookups
) {
606 ots::Buffer
subtable(data
, length
);
608 uint16_t glyph_count
= 0;
609 uint16_t lookup_count
= 0;
610 // Skip format field.
611 if (!subtable
.Skip(2) ||
612 !subtable
.ReadU16(&glyph_count
) ||
613 !subtable
.ReadU16(&lookup_count
)) {
614 return OTS_FAILURE_MSG("Failed to read header in context format 3");
617 if (glyph_count
>= num_glyphs
) {
618 return OTS_FAILURE_MSG("Bad glyph count %d in context format 3", glyph_count
);
620 const unsigned lookup_record_end
= 2 * static_cast<unsigned>(glyph_count
) +
621 4 * static_cast<unsigned>(lookup_count
) + 6;
622 if (lookup_record_end
> std::numeric_limits
<uint16_t>::max()) {
623 return OTS_FAILURE_MSG("Bad end of lookup %d in context format 3", lookup_record_end
);
625 for (unsigned i
= 0; i
< glyph_count
; ++i
) {
626 uint16_t offset_coverage
= 0;
627 if (!subtable
.ReadU16(&offset_coverage
)) {
628 return OTS_FAILURE_MSG("Failed to read coverage offset %d in conxtext format 3", i
);
630 if (offset_coverage
< lookup_record_end
|| offset_coverage
>= length
) {
631 return OTS_FAILURE_MSG("Bad coverage offset %d for glyph %d in context format 3", offset_coverage
, i
);
633 if (!ots::ParseCoverageTable(font
, data
+ offset_coverage
,
634 length
- offset_coverage
, num_glyphs
)) {
635 return OTS_FAILURE_MSG("Failed to parse coverage table for glyph %d in context format 3", i
);
639 for (unsigned i
= 0; i
< lookup_count
; ++i
) {
640 if (!ParseLookupRecord(font
, &subtable
, num_glyphs
, num_lookups
)) {
641 return OTS_FAILURE_MSG("Failed to parse lookup record %d in context format 3", i
);
648 // Parsers for Chaning Contextual subtables in GSUB/GPOS tables.
650 bool ParseChainRuleSubtable(const ots::Font
*font
,
651 const uint8_t *data
, const size_t length
,
652 const uint16_t num_glyphs
,
653 const uint16_t num_lookups
) {
654 ots::Buffer
subtable(data
, length
);
656 uint16_t backtrack_count
= 0;
657 if (!subtable
.ReadU16(&backtrack_count
)) {
658 return OTS_FAILURE_MSG("Failed to read backtrack count in chain rule subtable");
660 for (unsigned i
= 0; i
< backtrack_count
; ++i
) {
661 uint16_t glyph_id
= 0;
662 if (!subtable
.ReadU16(&glyph_id
)) {
663 return OTS_FAILURE_MSG("Failed to read backtrack glyph %d in chain rule subtable", i
);
665 if (glyph_id
> num_glyphs
) {
666 return OTS_FAILURE_MSG("Bad glyph id %d for bactrack glyph %d in chain rule subtable", glyph_id
, i
);
670 uint16_t input_count
= 0;
671 if (!subtable
.ReadU16(&input_count
)) {
672 return OTS_FAILURE_MSG("Failed to read input count in chain rule subtable");
674 if (input_count
== 0) {
675 return OTS_FAILURE_MSG("Bad input count %d in chain rule subtable", input_count
);
677 for (unsigned i
= 0; i
< input_count
- static_cast<unsigned>(1); ++i
) {
678 uint16_t glyph_id
= 0;
679 if (!subtable
.ReadU16(&glyph_id
)) {
680 return OTS_FAILURE_MSG("Failed to read input glyph %d in chain rule subtable", i
);
682 if (glyph_id
> num_glyphs
) {
683 return OTS_FAILURE_MSG("Bad glyph id %d for input glyph %d in chain rule subtable", glyph_id
, i
);
687 uint16_t lookahead_count
= 0;
688 if (!subtable
.ReadU16(&lookahead_count
)) {
689 return OTS_FAILURE_MSG("Failed to read lookahead count in chain rule subtable");
691 for (unsigned i
= 0; i
< lookahead_count
; ++i
) {
692 uint16_t glyph_id
= 0;
693 if (!subtable
.ReadU16(&glyph_id
)) {
694 return OTS_FAILURE_MSG("Failed to read lookahead glyph %d in chain rule subtable", i
);
696 if (glyph_id
> num_glyphs
) {
697 return OTS_FAILURE_MSG("Bad glyph id %d for lookadhead glyph %d in chain rule subtable", glyph_id
, i
);
701 uint16_t lookup_count
= 0;
702 if (!subtable
.ReadU16(&lookup_count
)) {
703 return OTS_FAILURE_MSG("Failed to read lookup count in chain rule subtable");
705 for (unsigned i
= 0; i
< lookup_count
; ++i
) {
706 if (!ParseLookupRecord(font
, &subtable
, num_glyphs
, num_lookups
)) {
707 return OTS_FAILURE_MSG("Failed to parse lookup record %d in chain rule subtable", i
);
714 bool ParseChainRuleSetTable(const ots::Font
*font
,
715 const uint8_t *data
, const size_t length
,
716 const uint16_t num_glyphs
,
717 const uint16_t num_lookups
) {
718 ots::Buffer
subtable(data
, length
);
720 uint16_t chain_rule_count
= 0;
721 if (!subtable
.ReadU16(&chain_rule_count
)) {
722 return OTS_FAILURE_MSG("Failed to read rule count in chain rule set");
724 const unsigned chain_rule_end
=
725 2 * static_cast<unsigned>(chain_rule_count
) + 2;
726 if (chain_rule_end
> std::numeric_limits
<uint16_t>::max()) {
727 return OTS_FAILURE_MSG("Bad end of chain rule %d in chain rule set", chain_rule_end
);
729 for (unsigned i
= 0; i
< chain_rule_count
; ++i
) {
730 uint16_t offset_chain_rule
= 0;
731 if (!subtable
.ReadU16(&offset_chain_rule
)) {
732 return OTS_FAILURE_MSG("Failed to read chain rule offset %d in chain rule set", i
);
734 if (offset_chain_rule
< chain_rule_end
|| offset_chain_rule
>= length
) {
735 return OTS_FAILURE_MSG("Bad chain rule offset %d for chain rule %d in chain rule set", offset_chain_rule
, i
);
737 if (!ParseChainRuleSubtable(font
, data
+ offset_chain_rule
,
738 length
- offset_chain_rule
,
739 num_glyphs
, num_lookups
)) {
740 return OTS_FAILURE_MSG("Failed to parse chain rule %d in chain rule set", i
);
747 bool ParseChainContextFormat1(const ots::Font
*font
,
748 const uint8_t *data
, const size_t length
,
749 const uint16_t num_glyphs
,
750 const uint16_t num_lookups
) {
751 ots::Buffer
subtable(data
, length
);
753 uint16_t offset_coverage
= 0;
754 uint16_t chain_rule_set_count
= 0;
755 // Skip format field.
756 if (!subtable
.Skip(2) ||
757 !subtable
.ReadU16(&offset_coverage
) ||
758 !subtable
.ReadU16(&chain_rule_set_count
)) {
759 return OTS_FAILURE_MSG("Failed to read header of chain context format 1");
762 const unsigned chain_rule_set_end
=
763 2 * static_cast<unsigned>(chain_rule_set_count
) + 6;
764 if (chain_rule_set_end
> std::numeric_limits
<uint16_t>::max()) {
765 return OTS_FAILURE_MSG("Bad chain rule end %d in chain context format 1", chain_rule_set_end
);
767 if (offset_coverage
< chain_rule_set_end
|| offset_coverage
>= length
) {
768 return OTS_FAILURE_MSG("Bad coverage offset %d in chain context format 1", chain_rule_set_end
);
770 if (!ots::ParseCoverageTable(font
, data
+ offset_coverage
,
771 length
- offset_coverage
, num_glyphs
)) {
772 return OTS_FAILURE_MSG("Failed to parse coverage table for chain context format 1");
775 for (unsigned i
= 0; i
< chain_rule_set_count
; ++i
) {
776 uint16_t offset_chain_rule_set
= 0;
777 if (!subtable
.ReadU16(&offset_chain_rule_set
)) {
778 return OTS_FAILURE_MSG("Failed to read chain rule offset %d in chain context format 1", i
);
780 if (offset_chain_rule_set
< chain_rule_set_end
||
781 offset_chain_rule_set
>= length
) {
782 return OTS_FAILURE_MSG("Bad chain rule set offset %d for chain rule set %d in chain context format 1", offset_chain_rule_set
, i
);
784 if (!ParseChainRuleSetTable(font
, data
+ offset_chain_rule_set
,
785 length
- offset_chain_rule_set
,
786 num_glyphs
, num_lookups
)) {
787 return OTS_FAILURE_MSG("Failed to parse chain rule set %d in chain context format 1", i
);
794 bool ParseChainClassRuleSubtable(const ots::Font
*font
,
795 const uint8_t *data
, const size_t length
,
796 const uint16_t num_glyphs
,
797 const uint16_t num_lookups
) {
798 ots::Buffer
subtable(data
, length
);
800 // In this subtable, we don't check the value of classes for now since
801 // these could take arbitrary values.
803 uint16_t backtrack_count
= 0;
804 if (!subtable
.ReadU16(&backtrack_count
)) {
805 return OTS_FAILURE_MSG("Failed to read backtrack count in chain class rule subtable");
807 if (!subtable
.Skip(2 * backtrack_count
)) {
808 return OTS_FAILURE_MSG("Failed to skip backtrack offsets in chain class rule subtable");
811 uint16_t input_count
= 0;
812 if (!subtable
.ReadU16(&input_count
)) {
813 return OTS_FAILURE_MSG("Failed to read input count in chain class rule subtable");
815 if (input_count
== 0) {
816 return OTS_FAILURE_MSG("Bad input count %d in chain class rule subtable", input_count
);
818 if (!subtable
.Skip(2 * (input_count
- 1))) {
819 return OTS_FAILURE_MSG("Failed to skip input offsets in chain class rule subtable");
822 uint16_t lookahead_count
= 0;
823 if (!subtable
.ReadU16(&lookahead_count
)) {
824 return OTS_FAILURE_MSG("Failed to read lookahead count in chain class rule subtable");
826 if (!subtable
.Skip(2 * lookahead_count
)) {
827 return OTS_FAILURE_MSG("Failed to skip lookahead offsets in chain class rule subtable");
830 uint16_t lookup_count
= 0;
831 if (!subtable
.ReadU16(&lookup_count
)) {
832 return OTS_FAILURE_MSG("Failed to read lookup count in chain class rule subtable");
834 for (unsigned i
= 0; i
< lookup_count
; ++i
) {
835 if (!ParseLookupRecord(font
, &subtable
, num_glyphs
, num_lookups
)) {
836 return OTS_FAILURE_MSG("Failed to parse lookup record %d in chain class rule subtable", i
);
843 bool ParseChainClassSetTable(const ots::Font
*font
,
844 const uint8_t *data
, const size_t length
,
845 const uint16_t num_glyphs
,
846 const uint16_t num_lookups
) {
847 ots::Buffer
subtable(data
, length
);
849 uint16_t chain_class_rule_count
= 0;
850 if (!subtable
.ReadU16(&chain_class_rule_count
)) {
851 return OTS_FAILURE_MSG("Failed to read rule count in chain class set");
853 const unsigned chain_class_rule_end
=
854 2 * static_cast<unsigned>(chain_class_rule_count
) + 2;
855 if (chain_class_rule_end
> std::numeric_limits
<uint16_t>::max()) {
856 return OTS_FAILURE_MSG("Bad end of chain class set %d in chain class set", chain_class_rule_end
);
858 for (unsigned i
= 0; i
< chain_class_rule_count
; ++i
) {
859 uint16_t offset_chain_class_rule
= 0;
860 if (!subtable
.ReadU16(&offset_chain_class_rule
)) {
861 return OTS_FAILURE_MSG("Failed to read chain class rule offset %d in chain class set", i
);
863 if (offset_chain_class_rule
< chain_class_rule_end
||
864 offset_chain_class_rule
>= length
) {
865 return OTS_FAILURE_MSG("Bad chain class rule offset %d for chain class %d in chain class set", offset_chain_class_rule
, i
);
867 if (!ParseChainClassRuleSubtable(font
, data
+ offset_chain_class_rule
,
868 length
- offset_chain_class_rule
,
869 num_glyphs
, num_lookups
)) {
870 return OTS_FAILURE_MSG("Failed to parse chain class rule %d in chain class set", i
);
877 bool ParseChainContextFormat2(const ots::Font
*font
,
878 const uint8_t *data
, const size_t length
,
879 const uint16_t num_glyphs
,
880 const uint16_t num_lookups
) {
881 ots::Buffer
subtable(data
, length
);
883 uint16_t offset_coverage
= 0;
884 uint16_t offset_backtrack_class_def
= 0;
885 uint16_t offset_input_class_def
= 0;
886 uint16_t offset_lookahead_class_def
= 0;
887 uint16_t chain_class_set_count
= 0;
888 // Skip format field.
889 if (!subtable
.Skip(2) ||
890 !subtable
.ReadU16(&offset_coverage
) ||
891 !subtable
.ReadU16(&offset_backtrack_class_def
) ||
892 !subtable
.ReadU16(&offset_input_class_def
) ||
893 !subtable
.ReadU16(&offset_lookahead_class_def
) ||
894 !subtable
.ReadU16(&chain_class_set_count
)) {
895 return OTS_FAILURE_MSG("Failed to read header of chain context format 2");
898 const unsigned chain_class_set_end
=
899 2 * static_cast<unsigned>(chain_class_set_count
) + 12;
900 if (chain_class_set_end
> std::numeric_limits
<uint16_t>::max()) {
901 return OTS_FAILURE_MSG("Bad chain class set end %d in chain context format 2", chain_class_set_end
);
903 if (offset_coverage
< chain_class_set_end
|| offset_coverage
>= length
) {
904 return OTS_FAILURE_MSG("Bad coverage offset %d in chain context format 2", offset_coverage
);
906 if (!ots::ParseCoverageTable(font
, data
+ offset_coverage
,
907 length
- offset_coverage
, num_glyphs
)) {
908 return OTS_FAILURE_MSG("Failed to parse coverage table in chain context format 2");
911 // Classes for backtrack/lookahead sequences might not be defined.
912 if (offset_backtrack_class_def
) {
913 if (offset_backtrack_class_def
< chain_class_set_end
||
914 offset_backtrack_class_def
>= length
) {
915 return OTS_FAILURE_MSG("Bad backtrack class offset %d in chain context format 2", offset_backtrack_class_def
);
917 if (!ots::ParseClassDefTable(font
, data
+ offset_backtrack_class_def
,
918 length
- offset_backtrack_class_def
,
919 num_glyphs
, ots::kMaxClassDefValue
)) {
920 return OTS_FAILURE_MSG("Failed to parse backtrack class defn table in chain context format 2");
924 if (offset_input_class_def
< chain_class_set_end
||
925 offset_input_class_def
>= length
) {
926 return OTS_FAILURE_MSG("Bad input class defn offset %d in chain context format 2", offset_input_class_def
);
928 if (!ots::ParseClassDefTable(font
, data
+ offset_input_class_def
,
929 length
- offset_input_class_def
,
930 num_glyphs
, ots::kMaxClassDefValue
)) {
931 return OTS_FAILURE_MSG("Failed to parse input class defn in chain context format 2");
934 if (offset_lookahead_class_def
) {
935 if (offset_lookahead_class_def
< chain_class_set_end
||
936 offset_lookahead_class_def
>= length
) {
937 return OTS_FAILURE_MSG("Bad lookahead class defn offset %d in chain context format 2", offset_lookahead_class_def
);
939 if (!ots::ParseClassDefTable(font
, data
+ offset_lookahead_class_def
,
940 length
- offset_lookahead_class_def
,
941 num_glyphs
, ots::kMaxClassDefValue
)) {
942 return OTS_FAILURE_MSG("Failed to parse lookahead class defn in chain context format 2");
946 for (unsigned i
= 0; i
< chain_class_set_count
; ++i
) {
947 uint16_t offset_chain_class_set
= 0;
948 if (!subtable
.ReadU16(&offset_chain_class_set
)) {
949 return OTS_FAILURE_MSG("Failed to read chain class set offset %d", i
);
951 // |offset_chain_class_set| could be NULL.
952 if (offset_chain_class_set
) {
953 if (offset_chain_class_set
< chain_class_set_end
||
954 offset_chain_class_set
>= length
) {
955 return OTS_FAILURE_MSG("Bad chain set class offset %d for chain set %d in chain context format 2", offset_chain_class_set
, i
);
957 if (!ParseChainClassSetTable(font
, data
+ offset_chain_class_set
,
958 length
- offset_chain_class_set
,
959 num_glyphs
, num_lookups
)) {
960 return OTS_FAILURE_MSG("Failed to parse chain class set table %d in chain context format 2", i
);
968 bool ParseChainContextFormat3(const ots::Font
*font
,
969 const uint8_t *data
, const size_t length
,
970 const uint16_t num_glyphs
,
971 const uint16_t num_lookups
) {
972 ots::Buffer
subtable(data
, length
);
974 uint16_t backtrack_count
= 0;
975 // Skip format field.
976 if (!subtable
.Skip(2) ||
977 !subtable
.ReadU16(&backtrack_count
)) {
978 return OTS_FAILURE_MSG("Failed to read backtrack count in chain context format 3");
981 std::vector
<uint16_t> offsets_backtrack
;
982 offsets_backtrack
.reserve(backtrack_count
);
983 for (unsigned i
= 0; i
< backtrack_count
; ++i
) {
985 if (!subtable
.ReadU16(&offset
)) {
986 return OTS_FAILURE_MSG("Failed to read backtrack offset %d in chain context format 3", i
);
988 offsets_backtrack
.push_back(offset
);
990 if (offsets_backtrack
.size() != backtrack_count
) {
991 return OTS_FAILURE_MSG("Bad backtrack offsets size %ld in chain context format 3", offsets_backtrack
.size());
994 uint16_t input_count
= 0;
995 if (!subtable
.ReadU16(&input_count
)) {
996 return OTS_FAILURE_MSG("Failed to read input count in chain context format 3");
998 std::vector
<uint16_t> offsets_input
;
999 offsets_input
.reserve(input_count
);
1000 for (unsigned i
= 0; i
< input_count
; ++i
) {
1001 uint16_t offset
= 0;
1002 if (!subtable
.ReadU16(&offset
)) {
1003 return OTS_FAILURE_MSG("Failed to read input offset %d in chain context format 3", i
);
1005 offsets_input
.push_back(offset
);
1007 if (offsets_input
.size() != input_count
) {
1008 return OTS_FAILURE_MSG("Bad input offsets size %ld in chain context format 3", offsets_input
.size());
1011 uint16_t lookahead_count
= 0;
1012 if (!subtable
.ReadU16(&lookahead_count
)) {
1013 return OTS_FAILURE_MSG("Failed ot read lookahead count in chain context format 3");
1015 std::vector
<uint16_t> offsets_lookahead
;
1016 offsets_lookahead
.reserve(lookahead_count
);
1017 for (unsigned i
= 0; i
< lookahead_count
; ++i
) {
1018 uint16_t offset
= 0;
1019 if (!subtable
.ReadU16(&offset
)) {
1020 return OTS_FAILURE_MSG("Failed to read lookahead offset %d in chain context format 3", i
);
1022 offsets_lookahead
.push_back(offset
);
1024 if (offsets_lookahead
.size() != lookahead_count
) {
1025 return OTS_FAILURE_MSG("Bad lookahead offsets size %ld in chain context format 3", offsets_lookahead
.size());
1028 uint16_t lookup_count
= 0;
1029 if (!subtable
.ReadU16(&lookup_count
)) {
1030 return OTS_FAILURE_MSG("Failed to read lookup count in chain context format 3");
1032 for (unsigned i
= 0; i
< lookup_count
; ++i
) {
1033 if (!ParseLookupRecord(font
, &subtable
, num_glyphs
, num_lookups
)) {
1034 return OTS_FAILURE_MSG("Failed to parse lookup %d in chain context format 3", i
);
1038 const unsigned lookup_record_end
=
1039 2 * (static_cast<unsigned>(backtrack_count
) +
1040 static_cast<unsigned>(input_count
) +
1041 static_cast<unsigned>(lookahead_count
)) +
1042 4 * static_cast<unsigned>(lookup_count
) + 10;
1043 if (lookup_record_end
> std::numeric_limits
<uint16_t>::max()) {
1044 return OTS_FAILURE_MSG("Bad end of lookup record %d in chain context format 3", lookup_record_end
);
1046 for (unsigned i
= 0; i
< backtrack_count
; ++i
) {
1047 if (offsets_backtrack
[i
] < lookup_record_end
||
1048 offsets_backtrack
[i
] >= length
) {
1049 return OTS_FAILURE_MSG("Bad backtrack offset of %d for backtrack %d in chain context format 3", offsets_backtrack
[i
], i
);
1051 if (!ots::ParseCoverageTable(font
, data
+ offsets_backtrack
[i
],
1052 length
- offsets_backtrack
[i
], num_glyphs
)) {
1053 return OTS_FAILURE_MSG("Failed to parse backtrack coverage %d in chain context format 3", i
);
1056 for (unsigned i
= 0; i
< input_count
; ++i
) {
1057 if (offsets_input
[i
] < lookup_record_end
|| offsets_input
[i
] >= length
) {
1058 return OTS_FAILURE_MSG("Bad input offset %d for input %d in chain context format 3", offsets_input
[i
], i
);
1060 if (!ots::ParseCoverageTable(font
, data
+ offsets_input
[i
],
1061 length
- offsets_input
[i
], num_glyphs
)) {
1062 return OTS_FAILURE_MSG("Failed to parse input coverage table %d in chain context format 3", i
);
1065 for (unsigned i
= 0; i
< lookahead_count
; ++i
) {
1066 if (offsets_lookahead
[i
] < lookup_record_end
||
1067 offsets_lookahead
[i
] >= length
) {
1068 return OTS_FAILURE_MSG("Bad lookadhead offset %d for lookahead %d in chain context format 3", offsets_lookahead
[i
], i
);
1070 if (!ots::ParseCoverageTable(font
, data
+ offsets_lookahead
[i
],
1071 length
- offsets_lookahead
[i
], num_glyphs
)) {
1072 return OTS_FAILURE_MSG("Failed to parse lookahead coverage table %d in chain context format 3", i
);
1079 bool ParseFeatureTableSubstitutionTable(const ots::Font
*font
,
1080 const uint8_t *data
, const size_t length
,
1081 const uint16_t num_lookups
) {
1082 ots::Buffer
subtable(data
, length
);
1084 uint16_t version_major
= 0;
1085 uint16_t version_minor
= 0;
1086 uint16_t substitution_count
= 0;
1087 const size_t kFeatureTableSubstitutionHeaderSize
= 3 * sizeof(uint16_t);
1089 if (!subtable
.ReadU16(&version_major
) ||
1090 !subtable
.ReadU16(&version_minor
) ||
1091 !subtable
.ReadU16(&substitution_count
)) {
1092 return OTS_FAILURE_MSG("Failed to read feature table substitution table header");
1095 for (uint16_t i
= 0; i
< substitution_count
; i
++) {
1096 uint16_t feature_index
= 0;
1097 uint32_t alternate_feature_table_offset
= 0;
1098 const size_t kFeatureTableSubstitutionRecordSize
= sizeof(uint16_t) + sizeof(uint32_t);
1100 if (!subtable
.ReadU16(&feature_index
) ||
1101 !subtable
.ReadU32(&alternate_feature_table_offset
)) {
1102 return OTS_FAILURE_MSG("Failed to read feature table substitution record");
1105 if (alternate_feature_table_offset
< kFeatureTableSubstitutionHeaderSize
+
1106 kFeatureTableSubstitutionRecordSize
* substitution_count
||
1107 alternate_feature_table_offset
>= length
) {
1108 return OTS_FAILURE_MSG("Invalid alternate feature table offset");
1111 if (!ParseFeatureTable(font
, data
+ alternate_feature_table_offset
,
1112 length
- alternate_feature_table_offset
, num_lookups
)) {
1113 return OTS_FAILURE_MSG("Failed to parse alternate feature table");
1120 bool ParseConditionTable(const ots::Font
*font
,
1121 const uint8_t *data
, const size_t length
,
1122 const uint16_t axis_count
) {
1123 ots::Buffer
subtable(data
, length
);
1125 uint16_t format
= 0;
1126 if (!subtable
.ReadU16(&format
)) {
1127 return OTS_FAILURE_MSG("Failed to read condition table format");
1131 // An unknown format is not an error, but should be ignored per spec.
1135 uint16_t axis_index
= 0;
1136 int16_t filter_range_min_value
= 0;
1137 int16_t filter_range_max_value
= 0;
1138 if (!subtable
.ReadU16(&axis_index
) ||
1139 !subtable
.ReadS16(&filter_range_min_value
) ||
1140 !subtable
.ReadS16(&filter_range_max_value
)) {
1141 return OTS_FAILURE_MSG("Failed to read condition table (format 1)");
1144 if (axis_index
>= axis_count
) {
1145 return OTS_FAILURE_MSG("Axis index out of range in condition");
1148 // Check min/max values are within range -1.0 .. 1.0 and properly ordered
1149 if (filter_range_min_value
< -0x4000 || // -1.0 in F2DOT14 format
1150 filter_range_max_value
> 0x4000 || // +1.0 in F2DOT14 format
1151 filter_range_min_value
> filter_range_max_value
) {
1152 return OTS_FAILURE_MSG("Invalid filter range in condition");
1158 bool ParseConditionSetTable(const ots::Font
*font
,
1159 const uint8_t *data
, const size_t length
,
1160 const uint16_t axis_count
) {
1161 ots::Buffer
subtable(data
, length
);
1163 uint16_t condition_count
= 0;
1164 if (!subtable
.ReadU16(&condition_count
)) {
1165 return OTS_FAILURE_MSG("Failed to read condition count");
1168 for (uint16_t i
= 0; i
< condition_count
; i
++) {
1169 uint32_t condition_offset
= 0;
1170 if (!subtable
.ReadU32(&condition_offset
)) {
1171 return OTS_FAILURE_MSG("Failed to read condition offset");
1173 if (condition_offset
< subtable
.offset() || condition_offset
>= length
) {
1174 return OTS_FAILURE_MSG("Offset out of range");
1176 if (!ParseConditionTable(font
, data
+ condition_offset
, length
- condition_offset
,
1178 return OTS_FAILURE_MSG("Failed to parse condition table");
1189 // Parsing ScriptListTable requires number of features so we need to
1190 // parse FeatureListTable before calling this function.
1191 bool OpenTypeLayoutTable::ParseScriptListTable(const uint8_t *data
, const size_t length
) {
1192 Font
* font
= GetFont();
1193 Buffer
subtable(data
, length
);
1195 uint16_t script_count
= 0;
1196 if (!subtable
.ReadU16(&script_count
)) {
1197 return Error("Failed to read script count in script list table");
1200 const unsigned script_record_end
=
1201 6 * static_cast<unsigned>(script_count
) + 2;
1202 if (script_record_end
> std::numeric_limits
<uint16_t>::max()) {
1203 return Error("Bad end of script record %d in script list table", script_record_end
);
1205 std::vector
<ScriptRecord
> script_list
;
1206 script_list
.reserve(script_count
);
1207 uint32_t last_tag
= 0;
1208 for (unsigned i
= 0; i
< script_count
; ++i
) {
1209 ScriptRecord record
;
1210 if (!subtable
.ReadU32(&record
.tag
) ||
1211 !subtable
.ReadU16(&record
.offset
)) {
1212 return Error("Failed to read script record %d in script list table", i
);
1214 // Script tags should be arranged alphabetically by tag
1215 if (last_tag
!= 0 && last_tag
> record
.tag
) {
1216 // Several fonts don't arrange tags alphabetically.
1217 // It seems that the order of tags might not be a security issue
1218 // so we just warn it.
1219 OTS_WARNING("tags aren't arranged alphabetically.");
1221 last_tag
= record
.tag
;
1222 if (record
.offset
< script_record_end
|| record
.offset
>= length
) {
1223 return Error("Bad record offset %d for script %c%c%c%c entry %d in script list table", record
.offset
, OTS_UNTAG(record
.tag
), i
);
1225 script_list
.push_back(record
);
1227 if (script_list
.size() != script_count
) {
1228 return Error("Bad script list size %ld in script list table", script_list
.size());
1231 // Check script records.
1232 for (unsigned i
= 0; i
< script_count
; ++i
) {
1233 if (!ParseScriptTable(font
, data
+ script_list
[i
].offset
,
1234 length
- script_list
[i
].offset
,
1235 script_list
[i
].tag
, m_num_features
)) {
1236 return Error("Failed to parse script table %d", i
);
1243 // Parsing FeatureListTable requires number of lookups so we need to parse
1244 // LookupListTable before calling this function.
1245 bool OpenTypeLayoutTable::ParseFeatureListTable(const uint8_t *data
, const size_t length
) {
1246 Font
*font
= GetFont();
1247 Buffer
subtable(data
, length
);
1249 uint16_t feature_count
= 0;
1250 if (!subtable
.ReadU16(&feature_count
)) {
1251 return Error("Failed to read feature count");
1254 std::vector
<FeatureRecord
> feature_records
;
1255 feature_records
.resize(feature_count
);
1256 const unsigned feature_record_end
=
1257 6 * static_cast<unsigned>(feature_count
) + 2;
1258 if (feature_record_end
> std::numeric_limits
<uint16_t>::max()) {
1259 return Error("Bad end of feature record %d", feature_record_end
);
1261 uint32_t last_tag
= 0;
1262 for (unsigned i
= 0; i
< feature_count
; ++i
) {
1263 if (!subtable
.ReadU32(&feature_records
[i
].tag
) ||
1264 !subtable
.ReadU16(&feature_records
[i
].offset
)) {
1265 return Error("Failed to read feature header %d", i
);
1267 // Feature record array should be arranged alphabetically by tag
1268 if (last_tag
!= 0 && last_tag
> feature_records
[i
].tag
) {
1269 // Several fonts don't arrange tags alphabetically.
1270 // It seems that the order of tags might not be a security issue
1271 // so we just warn it.
1272 OTS_WARNING("tags aren't arranged alphabetically.");
1274 last_tag
= feature_records
[i
].tag
;
1275 if (feature_records
[i
].offset
< feature_record_end
||
1276 feature_records
[i
].offset
>= length
) {
1277 return Error("Bad feature offset %d for feature %d %c%c%c%c", feature_records
[i
].offset
, i
, OTS_UNTAG(feature_records
[i
].tag
));
1281 for (unsigned i
= 0; i
< feature_count
; ++i
) {
1282 if (!ParseFeatureTable(font
, data
+ feature_records
[i
].offset
,
1283 length
- feature_records
[i
].offset
, m_num_lookups
)) {
1284 return Error("Failed to parse feature table %d", i
);
1287 m_num_features
= feature_count
;
1291 bool OpenTypeLayoutTable::ParseLookupTable(const uint8_t *data
,
1292 const size_t length
) {
1293 Font
* font
= GetFont();
1294 Buffer
subtable(data
, length
);
1296 uint16_t lookup_type
= 0;
1297 uint16_t lookup_flag
= 0;
1298 uint16_t subtable_count
= 0;
1299 if (!subtable
.ReadU16(&lookup_type
) ||
1300 !subtable
.ReadU16(&lookup_flag
) ||
1301 !subtable
.ReadU16(&subtable_count
)) {
1302 return Error("Failed to read lookup table header");
1305 if (!ValidLookupSubtableType(lookup_type
)) {
1306 return Error("Bad lookup type %d", lookup_type
);
1309 bool use_mark_filtering_set
= lookup_flag
& kUseMarkFilteringSetBit
;
1311 std::vector
<uint16_t> subtables
;
1312 subtables
.reserve(subtable_count
);
1313 // If the |kUseMarkFilteringSetBit| of |lookup_flag| is set,
1314 // extra 2 bytes will follow after subtable offset array.
1315 const unsigned lookup_table_end
= 2 * static_cast<unsigned>(subtable_count
) +
1316 (use_mark_filtering_set
? 8 : 6);
1317 if (lookup_table_end
> std::numeric_limits
<uint16_t>::max()) {
1318 return Error("Bad end of lookup %d", lookup_table_end
);
1320 for (unsigned i
= 0; i
< subtable_count
; ++i
) {
1321 uint16_t offset_subtable
= 0;
1322 if (!subtable
.ReadU16(&offset_subtable
)) {
1323 return Error("Failed to read subtable offset %d", i
);
1325 if (offset_subtable
< lookup_table_end
||
1326 offset_subtable
>= length
) {
1327 return Error("Bad subtable offset %d for subtable %d", offset_subtable
, i
);
1329 subtables
.push_back(offset_subtable
);
1331 if (subtables
.size() != subtable_count
) {
1332 return Error("Bad subtable size %ld", subtables
.size());
1335 if (use_mark_filtering_set
) {
1336 uint16_t mark_filtering_set
= 0;
1337 if (!subtable
.ReadU16(&mark_filtering_set
)) {
1338 return Error("Failed to read mark filtering set");
1341 OpenTypeGDEF
*gdef
= static_cast<OpenTypeGDEF
*>(
1342 font
->GetTypedTable(OTS_TAG_GDEF
));
1344 if (gdef
&& (gdef
->num_mark_glyph_sets
== 0 ||
1345 mark_filtering_set
>= gdef
->num_mark_glyph_sets
)) {
1346 return Error("Bad mark filtering set %d", mark_filtering_set
);
1350 // Parse lookup subtables for this lookup type.
1351 for (unsigned i
= 0; i
< subtable_count
; ++i
) {
1352 if (!ParseLookupSubtable(data
+ subtables
[i
], length
- subtables
[i
],
1354 return Error("Failed to parse subtable %d", i
);
1360 // For parsing GPOS/GSUB tables, this function should be called at first to
1361 // obtain the number of lookups because parsing FeatureTableList requires
1363 bool OpenTypeLayoutTable::ParseLookupListTable(const uint8_t *data
,
1364 const size_t length
) {
1365 Buffer
subtable(data
, length
);
1367 if (!subtable
.ReadU16(&m_num_lookups
)) {
1368 return Error("Failed to read number of lookups");
1371 std::vector
<uint16_t> lookups
;
1372 lookups
.reserve(m_num_lookups
);
1373 const unsigned lookup_end
=
1374 2 * static_cast<unsigned>(m_num_lookups
) + 2;
1375 if (lookup_end
> std::numeric_limits
<uint16_t>::max()) {
1376 return Error("Bad end of lookups %d", lookup_end
);
1378 for (unsigned i
= 0; i
< m_num_lookups
; ++i
) {
1379 uint16_t offset
= 0;
1380 if (!subtable
.ReadU16(&offset
)) {
1381 return Error("Failed to read lookup offset %d", i
);
1383 if (offset
< lookup_end
|| offset
>= length
) {
1384 return Error("Bad lookup offset %d for lookup %d", offset
, i
);
1386 lookups
.push_back(offset
);
1388 if (lookups
.size() != m_num_lookups
) {
1389 return Error("Bad lookup offsets list size %ld", lookups
.size());
1392 for (unsigned i
= 0; i
< m_num_lookups
; ++i
) {
1393 if (!ParseLookupTable(data
+ lookups
[i
], length
- lookups
[i
])) {
1394 return Error("Failed to parse lookup %d", i
);
1401 bool ParseClassDefTable(const ots::Font
*font
,
1402 const uint8_t *data
, size_t length
,
1403 const uint16_t num_glyphs
,
1404 const uint16_t num_classes
) {
1405 Buffer
subtable(data
, length
);
1407 uint16_t format
= 0;
1408 if (!subtable
.ReadU16(&format
)) {
1409 return OTS_FAILURE_MSG("Failed to read class defn format");
1412 return ParseClassDefFormat1(font
, data
, length
, num_glyphs
, num_classes
);
1413 } else if (format
== 2) {
1414 return ParseClassDefFormat2(font
, data
, length
, num_glyphs
, num_classes
);
1417 return OTS_FAILURE_MSG("Bad class defn format %d", format
);
1420 bool ParseCoverageTable(const ots::Font
*font
,
1421 const uint8_t *data
, size_t length
,
1422 const uint16_t num_glyphs
,
1423 const uint16_t expected_num_glyphs
) {
1424 Buffer
subtable(data
, length
);
1426 uint16_t format
= 0;
1427 if (!subtable
.ReadU16(&format
)) {
1428 return OTS_FAILURE_MSG("Failed to read coverage table format");
1431 return ParseCoverageFormat1(font
, data
, length
, num_glyphs
, expected_num_glyphs
);
1432 } else if (format
== 2) {
1433 return ParseCoverageFormat2(font
, data
, length
, num_glyphs
, expected_num_glyphs
);
1436 return OTS_FAILURE_MSG("Bad coverage table format %d", format
);
1439 bool ParseDeviceTable(const ots::Font
*font
,
1440 const uint8_t *data
, size_t length
) {
1441 Buffer
subtable(data
, length
);
1443 uint16_t start_size
= 0;
1444 uint16_t end_size
= 0;
1445 uint16_t delta_format
= 0;
1446 if (!subtable
.ReadU16(&start_size
) ||
1447 !subtable
.ReadU16(&end_size
) ||
1448 !subtable
.ReadU16(&delta_format
)) {
1449 return OTS_FAILURE_MSG("Failed to read device table header");
1451 if (delta_format
== kVariationIndex
) {
1452 // start_size and end_size are replaced by deltaSetOuterIndex
1453 // and deltaSetInnerIndex respectively, but we don't attempt to
1454 // check them here, so nothing more to do.
1457 if (start_size
> end_size
) {
1458 return OTS_FAILURE_MSG("Bad device table size range: %u > %u", start_size
, end_size
);
1460 if (delta_format
== 0 || delta_format
> kMaxDeltaFormatType
) {
1461 return OTS_FAILURE_MSG("Bad device table delta format: 0x%x", delta_format
);
1463 // The number of delta values per uint16. The device table should contain
1464 // at least |num_units| * 2 bytes compressed data.
1465 const unsigned num_units
= (end_size
- start_size
) /
1466 (1 << (4 - delta_format
)) + 1;
1467 // Just skip |num_units| * 2 bytes since the compressed data could take
1468 // arbitrary values.
1469 if (!subtable
.Skip(num_units
* 2)) {
1470 return OTS_FAILURE_MSG("Failed to skip data in device table");
1475 bool OpenTypeLayoutTable::ParseContextSubtable(const uint8_t *data
,
1476 const size_t length
) {
1477 Font
*font
= GetFont();
1478 Buffer
subtable(data
, length
);
1480 uint16_t format
= 0;
1481 if (!subtable
.ReadU16(&format
)) {
1482 return Error("Failed to read context subtable format");
1485 OpenTypeMAXP
*maxp
= static_cast<OpenTypeMAXP
*>(
1486 font
->GetTypedTable(OTS_TAG_MAXP
));
1488 return Error("Required maxp table missing");
1492 if (!ParseContextFormat1(font
, data
, length
, maxp
->num_glyphs
, m_num_lookups
)) {
1493 return Error("Failed to parse context format 1 subtable");
1495 } else if (format
== 2) {
1496 if (!ParseContextFormat2(font
, data
, length
, maxp
->num_glyphs
, m_num_lookups
)) {
1497 return Error("Failed to parse context format 2 subtable");
1499 } else if (format
== 3) {
1500 if (!ParseContextFormat3(font
, data
, length
, maxp
->num_glyphs
, m_num_lookups
)) {
1501 return Error("Failed to parse context format 3 subtable");
1504 return Error("Bad context subtable format %d", format
);
1510 bool OpenTypeLayoutTable::ParseChainingContextSubtable(const uint8_t *data
,
1511 const size_t length
) {
1512 Font
*font
= GetFont();
1513 Buffer
subtable(data
, length
);
1515 uint16_t format
= 0;
1516 if (!subtable
.ReadU16(&format
)) {
1517 return Error("Failed to read chaining context subtable format");
1520 OpenTypeMAXP
*maxp
= static_cast<OpenTypeMAXP
*>(
1521 font
->GetTypedTable(OTS_TAG_MAXP
));
1523 return Error("Required maxp table missing");
1527 if (!ParseChainContextFormat1(font
, data
, length
, maxp
->num_glyphs
, m_num_lookups
)) {
1528 return Error("Failed to parse chaining context format 1 subtable");
1530 } else if (format
== 2) {
1531 if (!ParseChainContextFormat2(font
, data
, length
, maxp
->num_glyphs
, m_num_lookups
)) {
1532 return Error("Failed to parse chaining context format 2 subtable");
1534 } else if (format
== 3) {
1535 if (!ParseChainContextFormat3(font
, data
, length
, maxp
->num_glyphs
, m_num_lookups
)) {
1536 return Error("Failed to parse chaining context format 3 subtable");
1539 return Error("Bad chaining context subtable format %d", format
);
1545 bool OpenTypeLayoutTable::ParseExtensionSubtable(const uint8_t *data
,
1546 const size_t length
) {
1547 Buffer
subtable(data
, length
);
1549 uint16_t format
= 0;
1550 uint16_t lookup_type
= 0;
1551 uint32_t offset_extension
= 0;
1552 if (!subtable
.ReadU16(&format
) ||
1553 !subtable
.ReadU16(&lookup_type
) ||
1554 !subtable
.ReadU32(&offset_extension
)) {
1555 return Error("Failed to read extension table header");
1559 return Error("Bad extension table format %d", format
);
1561 // |lookup_type| should be other than |parser->extension_type|.
1562 if (!ValidLookupSubtableType(lookup_type
, true)) {
1563 return Error("Bad lookup type %d in extension table", lookup_type
);
1566 const unsigned format_end
= static_cast<unsigned>(8);
1567 if (offset_extension
< format_end
||
1568 offset_extension
>= length
) {
1569 return Error("Bad extension offset %d", offset_extension
);
1572 // Parse the extension subtable of |lookup_type|.
1573 if (!ParseLookupSubtable(data
+ offset_extension
, length
- offset_extension
,
1575 return Error("Failed to parse lookup from extension lookup");
1581 // Parsing feature variations table (in GSUB/GPOS v1.1)
1582 bool OpenTypeLayoutTable::ParseFeatureVariationsTable(const uint8_t *data
, const size_t length
) {
1583 Font
*font
= GetFont();
1584 Buffer
subtable(data
, length
);
1586 uint16_t version_major
= 0;
1587 uint16_t version_minor
= 0;
1588 uint32_t feature_variation_record_count
= 0;
1590 if (!subtable
.ReadU16(&version_major
) ||
1591 !subtable
.ReadU16(&version_minor
) ||
1592 !subtable
.ReadU32(&feature_variation_record_count
)) {
1593 return Error("Failed to read feature variations table header");
1596 OpenTypeFVAR
* fvar
= static_cast<OpenTypeFVAR
*>(font
->GetTypedTable(OTS_TAG_FVAR
));
1598 return Error("Not a variation font");
1600 const uint16_t axis_count
= fvar
->AxisCount();
1602 const size_t kEndOfFeatureVariationRecords
=
1603 2 * sizeof(uint16_t) + sizeof(uint32_t) +
1604 feature_variation_record_count
* 2 * sizeof(uint32_t);
1606 for (uint32_t i
= 0; i
< feature_variation_record_count
; i
++) {
1607 uint32_t condition_set_offset
= 0;
1608 uint32_t feature_table_substitution_offset
= 0;
1609 if (!subtable
.ReadU32(&condition_set_offset
) ||
1610 !subtable
.ReadU32(&feature_table_substitution_offset
)) {
1611 return Error("Failed to read feature variation record");
1614 if (condition_set_offset
) {
1615 if (condition_set_offset
< kEndOfFeatureVariationRecords
||
1616 condition_set_offset
>= length
) {
1617 return Error("Condition set offset out of range");
1619 if (!ParseConditionSetTable(font
, data
+ condition_set_offset
,
1620 length
- condition_set_offset
,
1622 return Error("Failed to parse condition set table");
1626 if (feature_table_substitution_offset
) {
1627 if (feature_table_substitution_offset
< kEndOfFeatureVariationRecords
||
1628 feature_table_substitution_offset
>= length
) {
1629 return Error("Feature table substitution offset out of range");
1631 if (!ParseFeatureTableSubstitutionTable(font
, data
+ feature_table_substitution_offset
,
1632 length
- feature_table_substitution_offset
,
1634 return Error("Failed to parse feature table substitution table");
1642 // GSUB/GPOS header size for table version 1.0
1643 const size_t kHeaderSize_1_0
= 4 + 3 * 2;
1644 // GSUB/GPOS header size for table versio 1.1
1645 const size_t kHeaderSize_1_1
= 4 + 3 * 2 + 4;
1647 bool OpenTypeLayoutTable::Parse(const uint8_t *data
, size_t length
) {
1648 Buffer
table(data
, length
);
1650 uint16_t version_major
= 0, version_minor
= 0;
1651 uint16_t offset_script_list
= 0;
1652 uint16_t offset_feature_list
= 0;
1653 uint16_t offset_lookup_list
= 0;
1654 uint32_t offset_feature_variations
= 0;
1655 if (!table
.ReadU16(&version_major
) ||
1656 !table
.ReadU16(&version_minor
) ||
1657 !table
.ReadU16(&offset_script_list
) ||
1658 !table
.ReadU16(&offset_feature_list
) ||
1659 !table
.ReadU16(&offset_lookup_list
)) {
1660 return Error("Incomplete table");
1663 if (version_major
!= 1 || version_minor
> 1) {
1664 return Error("Bad version");
1667 if (version_minor
> 0) {
1668 if (!table
.ReadU32(&offset_feature_variations
)) {
1669 return Error("Incomplete table");
1673 const size_t header_size
=
1674 (version_minor
== 0) ? kHeaderSize_1_0
: kHeaderSize_1_1
;
1676 if (offset_lookup_list
) {
1677 if (offset_lookup_list
< header_size
|| offset_lookup_list
>= length
) {
1678 return Error("Bad lookup list offset in table header");
1681 if (!ParseLookupListTable(data
+ offset_lookup_list
,
1682 length
- offset_lookup_list
)) {
1683 return Error("Failed to parse lookup list table");
1687 if (offset_feature_list
) {
1688 if (offset_feature_list
< header_size
|| offset_feature_list
>= length
) {
1689 return Error("Bad feature list offset in table header");
1692 if (!ParseFeatureListTable(data
+ offset_feature_list
,
1693 length
- offset_feature_list
)) {
1694 return Error("Failed to parse feature list table");
1698 if (offset_script_list
) {
1699 if (offset_script_list
< header_size
|| offset_script_list
>= length
) {
1700 return Error("Bad script list offset in table header");
1703 if (!ParseScriptListTable(data
+ offset_script_list
,
1704 length
- offset_script_list
)) {
1705 return Error("Failed to parse script list table");
1709 if (offset_feature_variations
) {
1710 if (offset_feature_variations
< header_size
|| offset_feature_variations
>= length
) {
1711 return Error("Bad feature variations offset in table header");
1714 if (!ParseFeatureVariationsTable(data
+ offset_feature_variations
,
1715 length
- offset_feature_variations
)) {
1716 return Error("Failed to parse feature variations table");
1720 this->m_data
= data
;
1721 this->m_length
= length
;
1725 bool OpenTypeLayoutTable::Serialize(OTSStream
*out
) {
1726 if (!out
->Write(this->m_data
, this->m_length
)) {
1727 return Error("Failed to write table");