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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/layout.h ('k') | test/SConstruct » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/layout.cc
===================================================================
--- src/layout.cc (revision 50)
+++ src/layout.cc (working copy)
@@ -4,11 +4,249 @@
#include "layout.h"
+#include <limits>
+#include <vector>
+
+#include "gdef.h"
+
// OpenType Layout Common Table Formats
// http://www.microsoft.com/typography/otspec/chapter2.htm
namespace {
+// The 'DFLT' tag of script table.
+const uint32_t kScriptTableTagDflt = 0x44464c54;
+// The value which represents there is no required feature index.
+const uint16_t kNoRequiredFeatureIndexDefined = 0xFFFF;
+// The lookup flag bit which indicates existence of MarkFilteringSet.
+const uint16_t kUseMarkFilteringSetBit = 0x0010;
+// The mask for MarkAttachmentType.
+const uint16_t kMarkAttachmentTypeMask = 0xFF00;
+// The maximum type number of format for device tables.
+const uint16_t kMaxDeltaFormatType = 3;
+
+struct ScriptRecord {
+ uint32_t tag;
+ uint16_t offset;
+};
+
+struct LangSysRecord {
+ uint32_t tag;
+ uint16_t offset;
+};
+
+struct FeatureRecord {
+ uint32_t tag;
+ uint16_t offset;
+};
+
+bool ParseLangSysTable(ots::Buffer *subtable, const uint32_t tag,
+ const uint16_t num_features) {
+ uint16_t offset_lookup_order = 0;
+ uint16_t req_feature_index = 0;
+ uint16_t feature_count = 0;
+ if (!subtable->ReadU16(&offset_lookup_order) ||
+ !subtable->ReadU16(&req_feature_index) ||
+ !subtable->ReadU16(&feature_count)) {
+ return OTS_FAILURE();
+ }
+ // |offset_lookup_order| is reserved and should be NULL.
+ if (offset_lookup_order != 0) {
+ return OTS_FAILURE();
+ }
+ if (req_feature_index != kNoRequiredFeatureIndexDefined &&
+ req_feature_index >= num_features) {
+ return OTS_FAILURE();
+ }
+ if (feature_count > num_features) {
+ return OTS_FAILURE();
+ }
+
+ for (unsigned i = 0; i < feature_count; ++i) {
+ uint16_t feature_index = 0;
+ if (!subtable->ReadU16(&feature_index)) {
+ return OTS_FAILURE();
+ }
+ if (feature_index >= num_features) {
+ return OTS_FAILURE();
+ }
+ }
+ return true;
+}
+
+bool ParseScriptTable(const uint8_t *data, const size_t length,
+ const uint32_t tag, const uint16_t num_features) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t offset_default_lang_sys = 0;
+ uint16_t lang_sys_count = 0;
+ if (!subtable.ReadU16(&offset_default_lang_sys) ||
+ !subtable.ReadU16(&lang_sys_count)) {
+ return OTS_FAILURE();
+ }
+
+ // The spec requires a script table for 'DFLT' tag must contain non-NULL
+ // |offset_default_lang_sys| and |lang_sys_count| == 0
+ if (tag == kScriptTableTagDflt &&
+ (offset_default_lang_sys == 0 || lang_sys_count != 0)) {
+ OTS_WARNING("DFLT table doesn't satisfy the spec.");
+ return OTS_FAILURE();
+ }
+
+ const unsigned lang_sys_record_end = static_cast<unsigned>(4) +
+ lang_sys_count * 6;
+ if (lang_sys_record_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE();
+ }
+
+ std::vector<LangSysRecord> lang_sys_records;
+ lang_sys_records.resize(lang_sys_count);
+ uint32_t last_tag = 0;
+ for (unsigned i = 0; i < lang_sys_count; ++i) {
+ if (!subtable.ReadU32(&lang_sys_records[i].tag) ||
+ !subtable.ReadU16(&lang_sys_records[i].offset)) {
+ return OTS_FAILURE();
+ }
+ // The record array must store the records alphabetically by tag
+ if (last_tag != 0 && last_tag > lang_sys_records[i].tag) {
+ return OTS_FAILURE();
+ }
+ if (lang_sys_records[i].offset < lang_sys_record_end ||
+ lang_sys_records[i].offset >= length) {
+ return OTS_FAILURE();
+ }
+ last_tag = lang_sys_records[i].tag;
+ }
+
+ // Check lang sys tables
+ for (unsigned i = 0; i < lang_sys_count; ++i) {
+ subtable.set_offset(lang_sys_records[i].offset);
+ if (!ParseLangSysTable(&subtable, lang_sys_records[i].tag, num_features)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ return true;
+}
+
+bool ParseFeatureTable(const uint8_t *data, const size_t length,
+ const uint16_t num_lookups) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t offset_feature_params = 0;
+ uint16_t lookup_count = 0;
+ if (!subtable.ReadU16(&offset_feature_params) ||
+ !subtable.ReadU16(&lookup_count)) {
+ return OTS_FAILURE();
+ }
+
+ const unsigned feature_table_end = static_cast<unsigned>(4) +
+ num_lookups * 2;
+ if (feature_table_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE();
+ }
+ // |offset_feature_params| is generally set to NULL.
+ if (offset_feature_params != 0 &&
+ (offset_feature_params < feature_table_end ||
+ offset_feature_params >= length)) {
+ return OTS_FAILURE();
+ }
+
+ for (unsigned i = 0; i < lookup_count; ++i) {
+ uint16_t lookup_index = 0;
+ if (!subtable.ReadU16(&lookup_index)) {
+ return OTS_FAILURE();
+ }
+ // lookup index starts with 0.
+ if (lookup_index >= num_lookups) {
+ return OTS_FAILURE();
+ }
+ }
+ return true;
+}
+
+bool LookupTypeParserLess(const ots::LookupTypeParser& parser,
+ const uint16_t type) {
+ return parser.type < type;
+}
+
+bool ParseLookupTable(ots::OpenTypeFile *file, const uint8_t *data,
+ const size_t length, const size_t num_types,
+ const ots::LookupTypeParser* parsers) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t lookup_type = 0;
+ uint16_t lookup_flag = 0;
+ uint16_t subtable_count = 0;
+ if (!subtable.ReadU16(&lookup_type) ||
+ !subtable.ReadU16(&lookup_flag) ||
+ !subtable.ReadU16(&subtable_count)) {
+ return OTS_FAILURE();
+ }
+
+ if (lookup_type == 0 || lookup_type > num_types) {
+ return OTS_FAILURE();
+ }
+
+ // Check lookup flags.
+ if ((lookup_flag & kMarkAttachmentTypeMask) &&
+ (!file->gdef || !file->gdef->has_mark_attachment_class_def)) {
+ return OTS_FAILURE();
+ }
+ bool use_mark_filtering_set = false;
+ if (lookup_flag & kUseMarkFilteringSetBit) {
+ if (!file->gdef || !file->gdef->has_mark_glyph_sets_def) {
+ return OTS_FAILURE();
+ }
+ use_mark_filtering_set = true;
+ }
+
+ std::vector<uint16_t> subtables;
+ subtables.reserve(subtable_count);
+ // If the |kUseMarkFilteringSetBit| of |lookup_flag| is set,
+ // extra 2 bytes will follow after subtable offset array.
+ const unsigned lookup_table_end =
+ static_cast<unsigned>(use_mark_filtering_set ? 8 : 6) +
+ subtable_count * 2;
+ if (lookup_table_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE();
+ }
+ for (unsigned i = 0; i < subtable_count; ++i) {
+ if (!subtable.ReadU16(&subtables[i])) {
+ return OTS_FAILURE();
+ }
+ if (subtables[i] < lookup_table_end || subtables[i] >= length) {
+ return OTS_FAILURE();
+ }
+ }
+
+ if (use_mark_filtering_set) {
+ uint16_t mark_filtering_set = 0;
+ if (!subtable.ReadU16(&mark_filtering_set)) {
+ return OTS_FAILURE();
+ }
+ if (file->gdef->num_mark_glyph_sets == 0 ||
+ mark_filtering_set >= file->gdef->num_mark_glyph_sets) {
+ return OTS_FAILURE();
+ }
+ }
+
+ // Parse lookup subtables for this lookup type.
+ for (unsigned i = 0; i < subtable_count; ++i) {
+ const ots::LookupTypeParser *parser =
+ std::lower_bound(parsers, parsers + num_types, lookup_type,
+ LookupTypeParserLess);
+ if (parser == parsers + num_types || parser->type != lookup_type ||
+ !parser->parse) {
+ return OTS_FAILURE();
+ }
+ if (!parser->parse(file, data + subtables[i], length - subtables[i])) {
+ return OTS_FAILURE();
+ }
+ }
+ return true;
+}
+
bool ParseClassDefFormat1(const uint8_t *data, size_t length,
const uint16_t num_glyphs,
const uint16_t num_classes) {
@@ -87,6 +325,7 @@
OTS_WARNING("bad class value: %u", class_value);
return OTS_FAILURE();
}
+ last_end = end;
}
return true;
@@ -136,11 +375,12 @@
if (!subtable.ReadU16(&range_count)) {
return OTS_FAILURE();
}
- if (range_count >= num_glyphs) {
+ if (range_count > num_glyphs) {
OTS_WARNING("bad range count: %u", range_count);
return OTS_FAILURE();
}
uint16_t last_end = 0;
+ uint16_t last_start_coverage_index = 0;
for (unsigned i = 0; i < range_count; ++i) {
uint16_t start = 0;
uint16_t end = 0;
@@ -154,6 +394,12 @@
OTS_WARNING("glyph range is overlapping.");
return OTS_FAILURE();
}
+ if (start_coverage_index != last_start_coverage_index) {
+ OTS_WARNING("bad start coverage index.");
+ return OTS_FAILURE();
+ }
+ last_end = end;
+ last_start_coverage_index += end - start + 1;
}
return true;
@@ -163,6 +409,138 @@
namespace ots {
+// Parsing ScriptListTable requires number of features so we need to
+// parse FeatureListTable before calling this function.
+bool ParseScriptListTable(const uint8_t *data, const size_t length,
+ const uint16_t num_features) {
+ Buffer subtable(data, length);
+
+ uint16_t script_count = 0;
+ if (!subtable.ReadU16(&script_count)) {
+ return OTS_FAILURE();
+ }
+
+ const unsigned script_record_end = static_cast<unsigned>(2) +
+ script_count * 6;
+ if (script_record_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE();
+ }
+ std::vector<ScriptRecord> script_list;
+ script_list.reserve(script_count);
+ uint32_t last_tag = 0;
+ for (unsigned i = 0; i < script_count; ++i) {
+ if (!subtable.ReadU32(&script_list[i].tag) ||
+ !subtable.ReadU16(&script_list[i].offset)) {
+ return OTS_FAILURE();
+ }
+ // Script tags should be arranged alphabetically by tag
+ if (last_tag != 0 && last_tag > script_list[i].tag) {
+ return OTS_FAILURE();
+ }
+ last_tag = script_list[i].tag;
+ if (script_list[i].offset < script_record_end ||
+ script_list[i].offset >= length) {
+ return OTS_FAILURE();
+ }
+ }
+
+ // Check script records.
+ for (unsigned i = 0; i < script_count; ++i) {
+ if (!ParseScriptTable(data + script_list[i].offset,
+ length - script_list[i].offset,
+ script_list[i].tag, num_features)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ return true;
+}
+
+// Parsing FeatureListTable requires number of lookups so we need to parse
+// LookupListTable before calling this function.
+bool ParseFeatureListTable(const uint8_t *data, const size_t length,
+ const uint16_t num_lookups,
+ uint16_t* num_features) {
+ Buffer subtable(data, length);
+
+ uint16_t feature_count = 0;
+ if (!subtable.ReadU16(&feature_count)) {
+ return OTS_FAILURE();
+ }
+
+ std::vector<FeatureRecord> feature_records;
+ feature_records.resize(feature_count);
+ const unsigned feature_record_end = static_cast<unsigned>(2) +
+ feature_count * 6;
+ if (feature_record_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE();
+ }
+ uint32_t last_tag = 0;
+ for (unsigned i = 0; i < feature_count; ++i) {
+ if (!subtable.ReadU32(&feature_records[i].tag) ||
+ !subtable.ReadU16(&feature_records[i].offset)) {
+ return OTS_FAILURE();
+ }
+ // Feature record array should be arranged alphabetically by tag
+ if (last_tag != 0 && last_tag > feature_records[i].tag) {
+ return OTS_FAILURE();
+ }
+ last_tag = feature_records[i].tag;
+ if (feature_records[i].offset < feature_record_end ||
+ feature_records[i].offset >= length) {
+ return OTS_FAILURE();
+ }
+ }
+
+ for (unsigned i = 0; i < feature_count; ++i) {
+ if (!ParseFeatureTable(data + feature_records[i].offset,
+ length - feature_records[i].offset, num_lookups)) {
+ return OTS_FAILURE();
+ }
+ }
+ *num_features = feature_count;
+ return true;
+}
+
+// For parsing GPOS/GSUB tables, this function should be called at first to
+// obtain the number of lookups because parsing FeatureTableList requires
+// the number.
+bool ParseLookupListTable(OpenTypeFile *file, const uint8_t *data,
+ const size_t length, const size_t num_types,
+ const LookupTypeParser* parsers,
+ uint16_t *num_lookups) {
+ Buffer subtable(data, length);
+
+ if (!subtable.ReadU16(num_lookups)) {
+ return OTS_FAILURE();
+ }
+
+ std::vector<uint16_t> lookups;
+ lookups.reserve(*num_lookups);
+ const unsigned lookup_end = static_cast<unsigned>(2) +
+ (*num_lookups) * 2;
+ if (lookup_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE();
+ }
+ for (unsigned i = 0; i < *num_lookups; ++i) {
+ if (!subtable.ReadU16(&lookups[i])) {
+ return OTS_FAILURE();
+ }
+ if (lookups[i] < lookup_end || lookups[i] >= length) {
+ return OTS_FAILURE();
+ }
+ }
+
+ for (unsigned i = 0; i < *num_lookups; ++i) {
+ if (!ParseLookupTable(file, data + lookups[i], length - lookups[i],
+ num_types, parsers)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ return true;
+}
+
bool ParseClassDefTable(const uint8_t *data, size_t length,
const uint16_t num_glyphs,
const uint16_t num_classes) {
@@ -198,5 +576,36 @@
return OTS_FAILURE();
}
+bool ParseDeviceTable(const uint8_t *data, size_t length) {
+ Buffer subtable(data, length);
+
+ uint16_t start_size = 0;
+ uint16_t end_size = 0;
+ uint16_t delta_format = 0;
+ if (!subtable.ReadU16(&start_size) ||
+ !subtable.ReadU16(&end_size) ||
+ !subtable.ReadU16(&delta_format)) {
+ return OTS_FAILURE();
+ }
+ if (start_size > end_size) {
+ OTS_WARNING("bad size range: %u > %u", start_size, end_size);
+ return OTS_FAILURE();
+ }
+ if (delta_format == 0 || delta_format > kMaxDeltaFormatType) {
+ OTS_WARNING("bad delta format: %u", delta_format);
+ return OTS_FAILURE();
+ }
+ // The number of delta values per uint16. The device table should contain
+ // at least |num_units| * 2 bytes compressed data.
+ const unsigned num_units = (end_size - start_size) /
+ (1 << (4 - delta_format)) + 1;
+ // Just skip |num_units| * 2 bytes since the compressed data could take
+ // arbitrary values.
+ if (!subtable.Skip(num_units * 2)) {
+ return OTS_FAILURE();
+ }
+ return true;
+}
+
} // namespace ots
« 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