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

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
« src/gdef.cc ('K') | « 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 <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
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
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
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
OLDNEW
« src/gdef.cc ('K') | « src/layout.h ('k') | test/SConstruct » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698