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

Side by Side Diff: src/layout.cc

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

Powered by Google App Engine
This is Rietveld 408576698