OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "layout.h" | 5 #include "layout.h" |
6 | 6 |
7 #include <vector> | |
8 | |
9 #include "gdef.h" | |
10 | |
7 // OpenType Layout Common Table Formats | 11 // OpenType Layout Common Table Formats |
8 // http://www.microsoft.com/typography/otspec/chapter2.htm | 12 // http://www.microsoft.com/typography/otspec/chapter2.htm |
9 | 13 |
10 namespace { | 14 namespace { |
11 | 15 |
16 // The 'DFLT' tag of script table. | |
17 const uint32_t kScriptTableTagDflt = 0x44464c54; | |
18 // The value which represents there is no required feature index. | |
19 const uint16_t kNoRequiredFeatureIndexDefined = 0xFFFF; | |
20 // The lookup flag bit which indicates existence of MarkFilteringSet. | |
21 const uint16_t kUseMarkFilteringSetBit = 0x0010; | |
22 // The mask for MarkAttachmentType. | |
23 const uint16_t kMarkAttachmentTypeMask = 0xFF00; | |
24 // The maximum type number of format for device tables. | |
25 const uint16_t kMaxDeltaFormatType = 3; | |
26 | |
27 struct ScriptRecord { | |
28 uint32_t tag; | |
29 uint16_t offset; | |
30 }; | |
31 | |
32 struct LangSysRecord { | |
33 uint32_t tag; | |
34 uint16_t offset; | |
35 }; | |
36 | |
37 struct FeatureRecord { | |
38 uint32_t tag; | |
39 uint16_t offset; | |
40 }; | |
41 | |
42 bool ParseLangSysTable(ots::Buffer *subtable, const uint32_t tag, | |
43 const uint16_t num_features) { | |
44 uint16_t offset_lookup_order = 0; | |
45 uint16_t req_feature_index = 0; | |
46 uint16_t feature_count = 0; | |
47 if (!subtable->ReadU16(&offset_lookup_order) || | |
48 !subtable->ReadU16(&req_feature_index) || | |
49 !subtable->ReadU16(&feature_count)) { | |
50 return OTS_FAILURE(); | |
51 } | |
52 // |offset_lookup_order| is reserved and should be NULL. | |
53 if (offset_lookup_order != 0) { | |
54 OTS_FAILURE(); | |
Yusuke Sato
2011/02/04 06:12:52
return is missing.
bashi
2011/02/07 01:17:07
Done.
| |
55 } | |
56 if (req_feature_index != kNoRequiredFeatureIndexDefined && | |
57 req_feature_index >= num_features) { | |
58 return OTS_FAILURE(); | |
59 } | |
60 if (feature_count > num_features) { | |
61 return OTS_FAILURE(); | |
62 } | |
63 | |
64 for (unsigned i = 0; i < feature_count; ++i) { | |
65 uint16_t feature_index = 0; | |
66 if (!subtable->ReadU16(&feature_index)) { | |
67 return OTS_FAILURE(); | |
68 } | |
69 if (feature_index >= num_features) { | |
70 return OTS_FAILURE(); | |
71 } | |
72 } | |
73 return true; | |
74 } | |
75 | |
76 bool ParseScriptTable(const uint8_t *data, const size_t length, | |
77 const uint32_t tag, const uint16_t num_features) { | |
78 ots::Buffer subtable(data, length); | |
79 | |
80 uint16_t offset_default_lang_sys = 0; | |
81 uint16_t lang_sys_count = 0; | |
82 if (!subtable.ReadU16(&offset_default_lang_sys) || | |
83 !subtable.ReadU16(&lang_sys_count)) { | |
84 return OTS_FAILURE(); | |
85 } | |
86 | |
87 // The spec requires a script table for 'DFLT' tag must contain non-NULL | |
88 // |offset_default_lang_sys| and |lang_sys_count| == 0 | |
89 if (tag == kScriptTableTagDflt && | |
90 (offset_default_lang_sys == 0 || lang_sys_count != 0)) { | |
91 OTS_WARNING("DFLT table doesn't satisfy the spec."); | |
92 OTS_FAILURE(); | |
Yusuke Sato
2011/02/04 06:12:52
ditto. please grep your change again.
bashi
2011/02/07 01:17:07
Done.
| |
93 } | |
94 | |
95 const unsigned lang_sys_record_end = static_cast<unsigned>(4) + | |
96 lang_sys_count * 6; | |
97 std::vector<LangSysRecord> lang_sys_records; | |
98 lang_sys_records.resize(lang_sys_count); | |
99 uint32_t last_tag = 0; | |
100 for (unsigned i = 0; i < lang_sys_count; ++i) { | |
101 if (!subtable.ReadU32(&lang_sys_records[i].tag) || | |
102 !subtable.ReadU16(&lang_sys_records[i].offset)) { | |
103 return OTS_FAILURE(); | |
104 } | |
105 // The record array must store the records alphabetically by tag | |
106 if (last_tag != 0 && last_tag > lang_sys_records[i].tag) { | |
107 return OTS_FAILURE(); | |
108 } | |
109 if (lang_sys_records[i].offset < lang_sys_record_end || | |
110 lang_sys_records[i].offset >= length) { | |
111 return OTS_FAILURE(); | |
112 } | |
113 last_tag = lang_sys_records[i].tag; | |
114 } | |
115 | |
116 // Check lang sys tables | |
117 for (unsigned i = 0; i < lang_sys_count; ++i) { | |
118 subtable.set_offset(lang_sys_records[i].offset); | |
119 if (!ParseLangSysTable(&subtable, lang_sys_records[i].tag, num_features)) { | |
120 return OTS_FAILURE(); | |
121 } | |
122 } | |
123 | |
124 return true; | |
125 } | |
126 | |
127 bool ParseFeatureTable(const uint8_t *data, const size_t length, | |
128 const uint16_t num_lookups) { | |
129 ots::Buffer subtable(data, length); | |
130 | |
131 uint16_t offset_feature_params = 0; | |
132 uint16_t lookup_count = 0; | |
133 if (!subtable.ReadU16(&offset_feature_params) || | |
134 !subtable.ReadU16(&lookup_count)) { | |
135 return OTS_FAILURE(); | |
136 } | |
137 | |
138 const unsigned feature_table_end = static_cast<unsigned>(4) + | |
139 num_lookups * 2; | |
140 // |offset_feature_params| is generally set to NULL. | |
141 if (offset_feature_params != 0 && | |
142 (offset_feature_params < feature_table_end || | |
143 offset_feature_params >= length)) { | |
144 return OTS_FAILURE(); | |
145 } | |
146 | |
147 for (unsigned i = 0; i < lookup_count; ++i) { | |
148 uint16_t lookup_index = 0; | |
149 if (!subtable.ReadU16(&lookup_index)) { | |
150 return OTS_FAILURE(); | |
151 } | |
152 // lookup index starts with 0. | |
153 if (lookup_index >= num_lookups) { | |
154 return OTS_FAILURE(); | |
155 } | |
156 } | |
157 return true; | |
158 } | |
159 | |
160 bool LookupTypeParserLess(const ots::LookupTypeParser& parser, | |
161 const uint16_t type) { | |
162 return parser.type < type; | |
163 } | |
164 | |
165 bool ParseLookupTable(ots::OpenTypeFile *file, const uint8_t *data, | |
166 const size_t length, const size_t num_types, | |
167 const ots::LookupTypeParser* parsers) { | |
168 ots::Buffer subtable(data, length); | |
169 | |
170 uint16_t lookup_type = 0; | |
171 uint16_t lookup_flag = 0; | |
172 uint16_t subtable_count = 0; | |
173 if (!subtable.ReadU16(&lookup_type) || | |
174 !subtable.ReadU16(&lookup_flag) || | |
175 !subtable.ReadU16(&subtable_count)) { | |
176 return OTS_FAILURE(); | |
177 } | |
178 | |
179 if (lookup_type == 0 || lookup_type > num_types) { | |
180 return OTS_FAILURE(); | |
181 } | |
182 | |
183 // Check lookup flags. | |
184 if (lookup_flag & kMarkAttachmentTypeMask && | |
Yusuke Sato
2011/02/04 06:12:52
I slightly prefer:
if ((lookup_flag & kMarkAttach
bashi
2011/02/07 01:17:07
Done.
| |
185 (!file->gdef || !file->gdef->has_mark_attachment_class_def)) { | |
186 return OTS_FAILURE(); | |
187 } | |
188 bool use_mark_filtering_set = false; | |
189 if (lookup_flag & kUseMarkFilteringSetBit) { | |
190 if (!file->gdef || !file->gdef->has_mark_glyph_sets_def) { | |
191 return OTS_FAILURE(); | |
192 } | |
193 use_mark_filtering_set = true; | |
194 } | |
195 | |
196 std::vector<uint16_t> subtables; | |
197 subtables.reserve(subtable_count); | |
198 // If the |kUseMarkFilteringSetBit| of |lookup_flag| is set, | |
199 // extra 2 bytes will follow after subtable offset array. | |
200 const unsigned lookup_table_end = | |
201 static_cast<unsigned>(use_mark_filtering_set ? 8 : 6) + | |
202 subtable_count * 2; | |
203 for (unsigned i = 0; i < subtable_count; ++i) { | |
204 if (!subtable.ReadU16(&subtables[i])) { | |
205 return OTS_FAILURE(); | |
206 } | |
207 if (subtables[i] < lookup_table_end || subtables[i] >= length) { | |
208 return OTS_FAILURE(); | |
209 } | |
210 } | |
211 | |
212 if (use_mark_filtering_set) { | |
213 uint16_t mark_filtering_set = 0; | |
214 if (!subtable.ReadU16(&mark_filtering_set)) { | |
215 return OTS_FAILURE(); | |
216 } | |
217 if (file->gdef->num_mark_glyph_sets == 0 || | |
218 mark_filtering_set >= file->gdef->num_mark_glyph_sets) { | |
219 return OTS_FAILURE(); | |
220 } | |
221 } | |
222 | |
223 // Parse lookup subtables for this lookup type. | |
224 for (unsigned i = 0; i < subtable_count; ++i) { | |
225 const ots::LookupTypeParser *parser = | |
226 std::lower_bound(parsers, parsers + num_types, lookup_type, | |
227 LookupTypeParserLess); | |
228 if (parser == parsers + num_types || parser->type != lookup_type || | |
229 !parser->parse) { | |
230 return OTS_FAILURE(); | |
231 } | |
232 if (!parser->parse(file, data + subtables[i], length - subtables[i])) { | |
233 return OTS_FAILURE(); | |
234 } | |
235 } | |
236 return true; | |
237 } | |
238 | |
12 bool ParseClassDefFormat1(const uint8_t *data, size_t length, | 239 bool ParseClassDefFormat1(const uint8_t *data, size_t length, |
13 const uint16_t num_glyphs, | 240 const uint16_t num_glyphs, |
14 const uint16_t num_classes) { | 241 const uint16_t num_classes) { |
15 ots::Buffer subtable(data, length); | 242 ots::Buffer subtable(data, length); |
16 | 243 |
17 // Skip format field. | 244 // Skip format field. |
18 if (!subtable.Skip(2)) { | 245 if (!subtable.Skip(2)) { |
19 return OTS_FAILURE(); | 246 return OTS_FAILURE(); |
20 } | 247 } |
21 | 248 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
80 return OTS_FAILURE(); | 307 return OTS_FAILURE(); |
81 } | 308 } |
82 if (start > end || (last_end && start <= last_end)) { | 309 if (start > end || (last_end && start <= last_end)) { |
83 OTS_WARNING("glyph range is overlapping."); | 310 OTS_WARNING("glyph range is overlapping."); |
84 return OTS_FAILURE(); | 311 return OTS_FAILURE(); |
85 } | 312 } |
86 if (class_value == 0 || class_value > num_classes) { | 313 if (class_value == 0 || class_value > num_classes) { |
87 OTS_WARNING("bad class value: %u", class_value); | 314 OTS_WARNING("bad class value: %u", class_value); |
88 return OTS_FAILURE(); | 315 return OTS_FAILURE(); |
89 } | 316 } |
317 last_end = end; | |
90 } | 318 } |
91 | 319 |
92 return true; | 320 return true; |
93 } | 321 } |
94 | 322 |
95 bool ParseCoverageFormat1(const uint8_t *data, size_t length, | 323 bool ParseCoverageFormat1(const uint8_t *data, size_t length, |
96 const uint16_t num_glyphs) { | 324 const uint16_t num_glyphs) { |
97 ots::Buffer subtable(data, length); | 325 ots::Buffer subtable(data, length); |
98 | 326 |
99 // Skip format field. | 327 // Skip format field. |
(...skipping 29 matching lines...) Expand all Loading... | |
129 | 357 |
130 // Skip format field. | 358 // Skip format field. |
131 if (!subtable.Skip(2)) { | 359 if (!subtable.Skip(2)) { |
132 return OTS_FAILURE(); | 360 return OTS_FAILURE(); |
133 } | 361 } |
134 | 362 |
135 uint16_t range_count = 0; | 363 uint16_t range_count = 0; |
136 if (!subtable.ReadU16(&range_count)) { | 364 if (!subtable.ReadU16(&range_count)) { |
137 return OTS_FAILURE(); | 365 return OTS_FAILURE(); |
138 } | 366 } |
139 if (range_count >= num_glyphs) { | 367 if (range_count > num_glyphs) { |
140 OTS_WARNING("bad range count: %u", range_count); | 368 OTS_WARNING("bad range count: %u", range_count); |
141 return OTS_FAILURE(); | 369 return OTS_FAILURE(); |
142 } | 370 } |
143 uint16_t last_end = 0; | 371 uint16_t last_end = 0; |
372 uint16_t last_start_coverage_index = 0; | |
144 for (unsigned i = 0; i < range_count; ++i) { | 373 for (unsigned i = 0; i < range_count; ++i) { |
145 uint16_t start = 0; | 374 uint16_t start = 0; |
146 uint16_t end = 0; | 375 uint16_t end = 0; |
147 uint16_t start_coverage_index = 0; | 376 uint16_t start_coverage_index = 0; |
148 if (!subtable.ReadU16(&start) || | 377 if (!subtable.ReadU16(&start) || |
149 !subtable.ReadU16(&end) || | 378 !subtable.ReadU16(&end) || |
150 !subtable.ReadU16(&start_coverage_index)) { | 379 !subtable.ReadU16(&start_coverage_index)) { |
151 return OTS_FAILURE(); | 380 return OTS_FAILURE(); |
152 } | 381 } |
153 if (start > end || (last_end && start <= last_end)) { | 382 if (start > end || (last_end && start <= last_end)) { |
154 OTS_WARNING("glyph range is overlapping."); | 383 OTS_WARNING("glyph range is overlapping."); |
155 return OTS_FAILURE(); | 384 return OTS_FAILURE(); |
156 } | 385 } |
386 if (start_coverage_index != last_start_coverage_index) { | |
387 OTS_WARNING("bad start coverage index."); | |
388 return OTS_FAILURE(); | |
389 } | |
390 last_end = end; | |
391 last_start_coverage_index += end - start + 1; | |
157 } | 392 } |
158 | 393 |
159 return true; | 394 return true; |
160 } | 395 } |
161 | 396 |
162 } // namespace | 397 } // namespace |
163 | 398 |
164 namespace ots { | 399 namespace ots { |
165 | 400 |
401 // Parsing ScriptListTable requires number of features so we need to | |
402 // parse FeatureListTable before calling this function. | |
403 bool ParseScriptListTable(const uint8_t *data, const size_t length, | |
404 const uint16_t num_features) { | |
405 Buffer subtable(data, length); | |
406 | |
407 uint16_t script_count = 0; | |
408 if (!subtable.ReadU16(&script_count)) { | |
409 return OTS_FAILURE(); | |
410 } | |
411 | |
412 const unsigned script_record_end = static_cast<unsigned>(2) + | |
413 script_count * 6; | |
414 std::vector<ScriptRecord> script_list; | |
415 script_list.reserve(script_count); | |
416 uint32_t last_tag = 0; | |
417 for (unsigned i = 0; i < script_count; ++i) { | |
418 if (!subtable.ReadU32(&script_list[i].tag) || | |
419 !subtable.ReadU16(&script_list[i].offset)) { | |
420 return OTS_FAILURE(); | |
421 } | |
422 // Script tags should be arranged alphabetically by tag | |
423 if (last_tag != 0 && last_tag > script_list[i].tag) { | |
424 return OTS_FAILURE(); | |
425 } | |
426 last_tag = script_list[i].tag; | |
427 if (script_list[i].offset < script_record_end || | |
428 script_list[i].offset >= length) { | |
429 return OTS_FAILURE(); | |
430 } | |
431 } | |
432 | |
433 // Check script records. | |
434 for (unsigned i = 0; i < script_count; ++i) { | |
435 if (!ParseScriptTable(data + script_list[i].offset, | |
436 length - script_list[i].offset, | |
437 script_list[i].tag, num_features)) { | |
438 return OTS_FAILURE(); | |
439 } | |
440 } | |
441 | |
442 return true; | |
443 } | |
444 | |
445 // Parsing FeatureListTable requires number of lookups so we need to parse | |
446 // LookupListTable before calling this function. | |
447 bool ParseFeatureListTable(const uint8_t *data, const size_t length, | |
448 const uint16_t num_lookups, | |
449 uint16_t* num_features) { | |
450 Buffer subtable(data, length); | |
451 | |
452 uint16_t feature_count = 0; | |
453 if (!subtable.ReadU16(&feature_count)) { | |
454 return OTS_FAILURE(); | |
455 } | |
456 | |
457 std::vector<FeatureRecord> feature_records; | |
458 feature_records.resize(feature_count); | |
459 const unsigned feature_record_end = static_cast<unsigned>(2) + | |
460 feature_count * 6; | |
461 uint32_t last_tag = 0; | |
462 for (unsigned i = 0; i < feature_count; ++i) { | |
463 if (!subtable.ReadU32(&feature_records[i].tag) || | |
464 !subtable.ReadU16(&feature_records[i].offset)) { | |
465 return OTS_FAILURE(); | |
466 } | |
467 // Feature record array should be arranged alphabetically by tag | |
468 if (last_tag != 0 && last_tag > feature_records[i].tag) { | |
469 return OTS_FAILURE(); | |
470 } | |
471 last_tag = feature_records[i].tag; | |
472 if (feature_records[i].offset < feature_record_end || | |
473 feature_records[i].offset >= length) { | |
474 return OTS_FAILURE(); | |
475 } | |
476 } | |
477 | |
478 for (unsigned i = 0; i < feature_count; ++i) { | |
479 if (!ParseFeatureTable(data + feature_records[i].offset, | |
480 length - feature_records[i].offset, num_lookups)) { | |
481 return OTS_FAILURE(); | |
482 } | |
483 } | |
484 *num_features = feature_count; | |
485 return true; | |
486 } | |
487 | |
488 // For parsing GPOS/GSUB tables, this function should be called at first to | |
489 // obtain the number of lookups because parsing FeatureTableList requires | |
490 // the number. | |
491 bool ParseLookupListTable(OpenTypeFile *file, const uint8_t *data, | |
492 const size_t length, const size_t num_types, | |
493 const LookupTypeParser* parsers, | |
494 uint16_t *num_lookups) { | |
495 Buffer subtable(data, length); | |
496 | |
497 if (!subtable.ReadU16(num_lookups)) { | |
498 return OTS_FAILURE(); | |
499 } | |
500 | |
501 std::vector<uint16_t> lookups; | |
502 lookups.reserve(*num_lookups); | |
503 const unsigned lookup_end = static_cast<unsigned>(2) + | |
504 (*num_lookups) * 2; | |
505 for (unsigned i = 0; i < *num_lookups; ++i) { | |
506 if (!subtable.ReadU16(&lookups[i])) { | |
507 return OTS_FAILURE(); | |
508 } | |
509 if (lookups[i] < lookup_end || lookups[i] >= length) { | |
510 return OTS_FAILURE(); | |
511 } | |
512 } | |
513 | |
514 for (unsigned i = 0; i < *num_lookups; ++i) { | |
515 if (!ParseLookupTable(file, data + lookups[i], length - lookups[i], | |
516 num_types, parsers)) { | |
517 return OTS_FAILURE(); | |
518 } | |
519 } | |
520 | |
521 return true; | |
522 } | |
523 | |
166 bool ParseClassDefTable(const uint8_t *data, size_t length, | 524 bool ParseClassDefTable(const uint8_t *data, size_t length, |
167 const uint16_t num_glyphs, | 525 const uint16_t num_glyphs, |
168 const uint16_t num_classes) { | 526 const uint16_t num_classes) { |
169 Buffer subtable(data, length); | 527 Buffer subtable(data, length); |
170 | 528 |
171 uint16_t format = 0; | 529 uint16_t format = 0; |
172 if (!subtable.ReadU16(&format)) { | 530 if (!subtable.ReadU16(&format)) { |
173 return OTS_FAILURE(); | 531 return OTS_FAILURE(); |
174 } | 532 } |
175 if (format == 1) { | 533 if (format == 1) { |
(...skipping 15 matching lines...) Expand all Loading... | |
191 } | 549 } |
192 if (format == 1) { | 550 if (format == 1) { |
193 return ParseCoverageFormat1(data, length, num_glyphs); | 551 return ParseCoverageFormat1(data, length, num_glyphs); |
194 } else if (format == 2) { | 552 } else if (format == 2) { |
195 return ParseCoverageFormat2(data, length, num_glyphs); | 553 return ParseCoverageFormat2(data, length, num_glyphs); |
196 } | 554 } |
197 | 555 |
198 return OTS_FAILURE(); | 556 return OTS_FAILURE(); |
199 } | 557 } |
200 | 558 |
559 bool ParseDeviceTable(const uint8_t *data, size_t length) { | |
560 Buffer subtable(data, length); | |
561 | |
562 uint16_t start_size = 0; | |
563 uint16_t end_size = 0; | |
564 uint16_t delta_format = 0; | |
565 if (!subtable.ReadU16(&start_size) || | |
566 !subtable.ReadU16(&end_size) || | |
567 !subtable.ReadU16(&delta_format)) { | |
568 return OTS_FAILURE(); | |
569 } | |
570 if (start_size > end_size) { | |
571 OTS_WARNING("bad size range: %u > %u", start_size, end_size); | |
572 return OTS_FAILURE(); | |
573 } | |
574 if (delta_format == 0 || delta_format > kMaxDeltaFormatType) { | |
575 OTS_WARNING("bad delta format: %u", delta_format); | |
576 return OTS_FAILURE(); | |
577 } | |
578 // The number of delta values per uint16. The device table should contain | |
579 // at least |num_units| * 2 bytes compressed data. | |
580 const unsigned num_units = (end_size - start_size) / | |
581 (1 << (4 - delta_format)) + 1; | |
582 // Just skip |num_units| * 2 bytes since the compressed data could take | |
583 // arbitrary values. | |
584 if (!subtable.Skip(num_units * 2)) { | |
585 return OTS_FAILURE(); | |
586 } | |
587 return true; | |
588 } | |
589 | |
201 } // namespace ots | 590 } // namespace ots |
202 | 591 |
OLD | NEW |