blob: 74ca109845bba56677eaa7754ce5259282925c05 [file] [log] [blame]
bashi@google.com00b790a2011-01-27 06:35:42 +00001// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "layout.h"
6
bashi@google.com78a8baa2011-02-07 06:21:25 +00007#include <limits>
8#include <vector>
9
10#include "gdef.h"
11
bashi@google.com00b790a2011-01-27 06:35:42 +000012// OpenType Layout Common Table Formats
13// http://www.microsoft.com/typography/otspec/chapter2.htm
14
15namespace {
16
bashi@google.com78a8baa2011-02-07 06:21:25 +000017// The 'DFLT' tag of script table.
18const uint32_t kScriptTableTagDflt = 0x44464c54;
19// The value which represents there is no required feature index.
20const uint16_t kNoRequiredFeatureIndexDefined = 0xFFFF;
21// The lookup flag bit which indicates existence of MarkFilteringSet.
22const uint16_t kUseMarkFilteringSetBit = 0x0010;
23// The mask for MarkAttachmentType.
24const uint16_t kMarkAttachmentTypeMask = 0xFF00;
25// The maximum type number of format for device tables.
26const uint16_t kMaxDeltaFormatType = 3;
27
28struct ScriptRecord {
29 uint32_t tag;
30 uint16_t offset;
31};
32
33struct LangSysRecord {
34 uint32_t tag;
35 uint16_t offset;
36};
37
38struct FeatureRecord {
39 uint32_t tag;
40 uint16_t offset;
41};
42
43bool 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
77bool 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
132bool 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
168bool LookupTypeParserLess(const ots::LookupTypeParser& parser,
169 const uint16_t type) {
170 return parser.type < type;
171}
172
173bool 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
bashi@google.com00b790a2011-01-27 06:35:42 +0000250bool ParseClassDefFormat1(const uint8_t *data, size_t length,
251 const uint16_t num_glyphs,
252 const uint16_t num_classes) {
253 ots::Buffer subtable(data, length);
254
255 // Skip format field.
256 if (!subtable.Skip(2)) {
257 return OTS_FAILURE();
258 }
259
260 uint16_t start_glyph = 0;
261 if (!subtable.ReadU16(&start_glyph)) {
262 return OTS_FAILURE();
263 }
264 if (start_glyph > num_glyphs) {
265 OTS_WARNING("bad start glyph ID: %u", start_glyph);
266 return OTS_FAILURE();
267 }
268
269 uint16_t glyph_count = 0;
270 if (!subtable.ReadU16(&glyph_count)) {
271 return OTS_FAILURE();
272 }
273 if (glyph_count > num_glyphs) {
274 OTS_WARNING("bad glyph count: %u", glyph_count);
275 return OTS_FAILURE();
276 }
277 for (unsigned i = 0; i < glyph_count; ++i) {
278 uint16_t class_value = 0;
279 if (!subtable.ReadU16(&class_value)) {
280 return OTS_FAILURE();
281 }
282 if (class_value == 0 || class_value > num_classes) {
283 OTS_WARNING("bad class value: %u", class_value);
284 return OTS_FAILURE();
285 }
286 }
287
288 return true;
289}
290
291bool ParseClassDefFormat2(const uint8_t *data, size_t length,
292 const uint16_t num_glyphs,
293 const uint16_t num_classes) {
294 ots::Buffer subtable(data, length);
295
296 // Skip format field.
297 if (!subtable.Skip(2)) {
298 return OTS_FAILURE();
299 }
300
301 uint16_t range_count = 0;
302 if (!subtable.ReadU16(&range_count)) {
303 return OTS_FAILURE();
304 }
305 if (range_count > num_glyphs) {
306 OTS_WARNING("bad range count: %u", range_count);
307 return OTS_FAILURE();
308 }
309
310 uint16_t last_end = 0;
311 for (unsigned i = 0; i < range_count; ++i) {
312 uint16_t start = 0;
313 uint16_t end = 0;
314 uint16_t class_value = 0;
315 if (!subtable.ReadU16(&start) ||
316 !subtable.ReadU16(&end) ||
317 !subtable.ReadU16(&class_value)) {
318 return OTS_FAILURE();
319 }
320 if (start > end || (last_end && start <= last_end)) {
321 OTS_WARNING("glyph range is overlapping.");
322 return OTS_FAILURE();
323 }
324 if (class_value == 0 || class_value > num_classes) {
325 OTS_WARNING("bad class value: %u", class_value);
326 return OTS_FAILURE();
327 }
bashi@google.com78a8baa2011-02-07 06:21:25 +0000328 last_end = end;
bashi@google.com00b790a2011-01-27 06:35:42 +0000329 }
330
331 return true;
332}
333
334bool ParseCoverageFormat1(const uint8_t *data, size_t length,
335 const uint16_t num_glyphs) {
336 ots::Buffer subtable(data, length);
337
338 // Skip format field.
339 if (!subtable.Skip(2)) {
340 return OTS_FAILURE();
341 }
342
343 uint16_t glyph_count = 0;
344 if (!subtable.ReadU16(&glyph_count)) {
345 return OTS_FAILURE();
346 }
347 if (glyph_count > num_glyphs) {
348 OTS_WARNING("bad glyph count: %u", glyph_count);
349 return OTS_FAILURE();
350 }
351 for (unsigned i = 0; i < glyph_count; ++i) {
352 uint16_t glyph = 0;
353 if (!subtable.ReadU16(&glyph)) {
354 return OTS_FAILURE();
355 }
356 if (glyph > num_glyphs) {
357 OTS_WARNING("bad glyph ID: %u", glyph);
358 return OTS_FAILURE();
359 }
360 }
361
362 return true;
363}
364
365bool ParseCoverageFormat2(const uint8_t *data, size_t length,
366 const uint16_t num_glyphs) {
367 ots::Buffer subtable(data, length);
368
369 // Skip format field.
370 if (!subtable.Skip(2)) {
371 return OTS_FAILURE();
372 }
373
374 uint16_t range_count = 0;
375 if (!subtable.ReadU16(&range_count)) {
376 return OTS_FAILURE();
377 }
bashi@google.com78a8baa2011-02-07 06:21:25 +0000378 if (range_count > num_glyphs) {
bashi@google.com00b790a2011-01-27 06:35:42 +0000379 OTS_WARNING("bad range count: %u", range_count);
380 return OTS_FAILURE();
381 }
382 uint16_t last_end = 0;
bashi@google.com78a8baa2011-02-07 06:21:25 +0000383 uint16_t last_start_coverage_index = 0;
bashi@google.com00b790a2011-01-27 06:35:42 +0000384 for (unsigned i = 0; i < range_count; ++i) {
385 uint16_t start = 0;
386 uint16_t end = 0;
387 uint16_t start_coverage_index = 0;
388 if (!subtable.ReadU16(&start) ||
389 !subtable.ReadU16(&end) ||
390 !subtable.ReadU16(&start_coverage_index)) {
391 return OTS_FAILURE();
392 }
393 if (start > end || (last_end && start <= last_end)) {
394 OTS_WARNING("glyph range is overlapping.");
395 return OTS_FAILURE();
396 }
bashi@google.com78a8baa2011-02-07 06:21:25 +0000397 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;
bashi@google.com00b790a2011-01-27 06:35:42 +0000403 }
404
405 return true;
406}
407
408} // namespace
409
410namespace ots {
411
bashi@google.com78a8baa2011-02-07 06:21:25 +0000412// Parsing ScriptListTable requires number of features so we need to
413// parse FeatureListTable before calling this function.
414bool 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.
461bool 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.
508bool 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
bashi@google.com00b790a2011-01-27 06:35:42 +0000544bool ParseClassDefTable(const uint8_t *data, size_t length,
545 const uint16_t num_glyphs,
546 const uint16_t num_classes) {
547 Buffer subtable(data, length);
548
549 uint16_t format = 0;
550 if (!subtable.ReadU16(&format)) {
551 return OTS_FAILURE();
552 }
553 if (format == 1) {
554 return ParseClassDefFormat1(data, length, num_glyphs, num_classes);
555 } else if (format == 2) {
556 return ParseClassDefFormat2(data, length, num_glyphs, num_classes);
557 }
558
559 return OTS_FAILURE();
560}
561
562bool ParseCoverageTable(const uint8_t *data, size_t length,
563 const uint16_t num_glyphs) {
564 Buffer subtable(data, length);
565
566 uint16_t format = 0;
567 if (!subtable.ReadU16(&format)) {
568 return OTS_FAILURE();
569 }
570 if (format == 1) {
571 return ParseCoverageFormat1(data, length, num_glyphs);
572 } else if (format == 2) {
573 return ParseCoverageFormat2(data, length, num_glyphs);
574 }
575
576 return OTS_FAILURE();
577}
578
bashi@google.com78a8baa2011-02-07 06:21:25 +0000579bool 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
bashi@google.com00b790a2011-01-27 06:35:42 +0000610} // namespace ots
611