diff options
Diffstat (limited to 'gfx/ots/src/name.cc')
-rw-r--r-- | gfx/ots/src/name.cc | 150 |
1 files changed, 89 insertions, 61 deletions
diff --git a/gfx/ots/src/name.cc b/gfx/ots/src/name.cc index e55be7537..11deeecaa 100644 --- a/gfx/ots/src/name.cc +++ b/gfx/ots/src/name.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2011-2017 The OTS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,8 +10,6 @@ // name - Naming Table // http://www.microsoft.com/typography/otspec/name.htm -#define TABLE_NAME "name" - namespace { bool ValidInPsName(char c) { @@ -56,25 +54,22 @@ void AssignToUtf16BeFromAscii(std::string* target, namespace ots { -bool ots_name_parse(Font *font, const uint8_t* data, size_t length) { +bool OpenTypeNAME::Parse(const uint8_t* data, size_t length) { Buffer table(data, length); - OpenTypeNAME* name = new OpenTypeNAME; - font->name = name; - uint16_t format = 0; if (!table.ReadU16(&format) || format > 1) { - return OTS_FAILURE_MSG("Failed to read name table format or bad format %d", format); + return Error("Failed to read table format or bad format %d", format); } uint16_t count = 0; if (!table.ReadU16(&count)) { - return OTS_FAILURE_MSG("Failed to read name count"); + return Error("Failed to read name count"); } uint16_t string_offset = 0; if (!table.ReadU16(&string_offset) || string_offset > length) { - return OTS_FAILURE_MSG("Failed to read strings offset"); + return Error("Failed to read or bad stringOffset"); } const char* string_base = reinterpret_cast<const char*>(data) + string_offset; @@ -94,7 +89,7 @@ bool ots_name_parse(Font *font, const uint8_t* data, size_t length) { !table.ReadU16(&rec.name_id) || !table.ReadU16(&name_length) || !table.ReadU16(&name_offset)) { - return OTS_FAILURE_MSG("Failed to read name entry %d", i); + return Error("Failed to read name entry %d", i); } // check platform & encoding, discard names with unknown values switch (rec.platform_id) { @@ -148,40 +143,49 @@ bool ots_name_parse(Font *font, const uint8_t* data, size_t length) { } } - if (!name->names.empty() && !(name->names.back() < rec)) { - OTS_WARNING("name records are not sorted."); + if (!this->names.empty() && !(this->names.back() < rec)) { + Warning("name records are not sorted."); sort_required = true; } - name->names.push_back(rec); + this->names.push_back(rec); + this->name_ids.insert(rec.name_id); } if (format == 1) { // extended name table format with language tags uint16_t lang_tag_count; if (!table.ReadU16(&lang_tag_count)) { - return OTS_FAILURE_MSG("Failed to read language tag count"); + return Error("Failed to read langTagCount"); } for (unsigned i = 0; i < lang_tag_count; ++i) { uint16_t tag_length = 0; uint16_t tag_offset = 0; if (!table.ReadU16(&tag_length) || !table.ReadU16(&tag_offset)) { - return OTS_FAILURE_MSG("Faile to read tag length or offset"); + return Error("Faile to read length or offset for langTagRecord %d", i); } const unsigned tag_end = static_cast<unsigned>(string_offset) + tag_offset + tag_length; if (tag_end > length) { - return OTS_FAILURE_MSG("bad end of tag %d > %ld for name entry %d", tag_end, length, i); + return Error("bad end of tag %d > %ld for langTagRecord %d", tag_end, length, i); + } + // Lang tag is BCP 47 tag per the spec, the recommonded BCP 47 max tag + // length is 35: + // https://tools.ietf.org/html/bcp47#section-4.4.1 + // We are being too generous and allowing for 100 (multiplied by 2 since + // this is UTF-16 string). + if (tag_length > 100 * 2) { + return Error("Too long language tag for LangTagRecord %d: %d", i, tag_length); } std::string tag(string_base + tag_offset, tag_length); - name->lang_tags.push_back(tag); + this->lang_tags.push_back(tag); } } if (table.offset() > string_offset) { // the string storage apparently overlapped the name/tag records; // consider this font to be badly broken - return OTS_FAILURE_MSG("Bad table offset %ld > %d", table.offset(), string_offset); + return Error("Bad table offset %ld > %d", table.offset(), string_offset); } // check existence of required name strings (synthesize if necessary) @@ -207,17 +211,16 @@ bool ots_name_parse(Font *font, const uint8_t* data, size_t length) { // if not, we'll add our fixed versions here bool mac_name[kStdNameCount] = { 0 }; bool win_name[kStdNameCount] = { 0 }; - for (std::vector<NameRecord>::iterator name_iter = name->names.begin(); - name_iter != name->names.end(); ++name_iter) { - const uint16_t id = name_iter->name_id; + for (const auto& name : this->names) { + const uint16_t id = name.name_id; if (id >= kStdNameCount || kStdNames[id] == NULL) { continue; } - if (name_iter->platform_id == 1) { + if (name.platform_id == 1) { mac_name[id] = true; continue; } - if (name_iter->platform_id == 3) { + if (name.platform_id == 3) { win_name[id] = true; continue; } @@ -236,49 +239,41 @@ bool ots_name_parse(Font *font, const uint8_t* data, size_t length) { 1033 /* language_id */ , i /* name_id */); AssignToUtf16BeFromAscii(&win_rec.text, std::string(kStdNames[i])); - name->names.push_back(mac_rec); - name->names.push_back(win_rec); + this->names.push_back(mac_rec); + this->names.push_back(win_rec); sort_required = true; } } if (sort_required) { - std::sort(name->names.begin(), name->names.end()); + std::sort(this->names.begin(), this->names.end()); } return true; } -bool ots_name_should_serialise(Font *font) { - return font->name != NULL; -} - -bool ots_name_serialise(OTSStream* out, Font *font) { - const OpenTypeNAME* name = font->name; - - uint16_t name_count = static_cast<uint16_t>(name->names.size()); - uint16_t lang_tag_count = static_cast<uint16_t>(name->lang_tags.size()); +bool OpenTypeNAME::Serialize(OTSStream* out) { + uint16_t name_count = static_cast<uint16_t>(this->names.size()); + uint16_t lang_tag_count = static_cast<uint16_t>(this->lang_tags.size()); uint16_t format = 0; size_t string_offset = 6 + name_count * 12; - if (name->lang_tags.size() > 0) { + if (this->lang_tags.size() > 0) { // lang tags require a format-1 name table format = 1; string_offset += 2 + lang_tag_count * 4; } if (string_offset > 0xffff) { - return OTS_FAILURE_MSG("Bad string offset %ld", string_offset); + return Error("Bad stringOffset: %ld", string_offset); } if (!out->WriteU16(format) || !out->WriteU16(name_count) || !out->WriteU16(static_cast<uint16_t>(string_offset))) { - return OTS_FAILURE_MSG("Failed to write name header"); + return Error("Failed to write name header"); } std::string string_data; - for (std::vector<NameRecord>::const_iterator name_iter = name->names.begin(); - name_iter != name->names.end(); ++name_iter) { - const NameRecord& rec = *name_iter; + for (const auto& rec : this->names) { if (string_data.size() + rec.text.size() > std::numeric_limits<uint16_t>::max() || !out->WriteU16(rec.platform_id) || @@ -287,44 +282,77 @@ bool ots_name_serialise(OTSStream* out, Font *font) { !out->WriteU16(rec.name_id) || !out->WriteU16(static_cast<uint16_t>(rec.text.size())) || !out->WriteU16(static_cast<uint16_t>(string_data.size())) ) { - return OTS_FAILURE_MSG("Faile to write name entry"); + return Error("Faile to write nameRecord"); } string_data.append(rec.text); } if (format == 1) { if (!out->WriteU16(lang_tag_count)) { - return OTS_FAILURE_MSG("Faile to write language tag count"); + return Error("Faile to write langTagCount"); } - for (std::vector<std::string>::const_iterator tag_iter = - name->lang_tags.begin(); - tag_iter != name->lang_tags.end(); ++tag_iter) { - if (string_data.size() + tag_iter->size() > + for (const auto& tag : this->lang_tags) { + if (string_data.size() + tag.size() > std::numeric_limits<uint16_t>::max() || - !out->WriteU16(static_cast<uint16_t>(tag_iter->size())) || + !out->WriteU16(static_cast<uint16_t>(tag.size())) || !out->WriteU16(static_cast<uint16_t>(string_data.size()))) { - return OTS_FAILURE_MSG("Failed to write string"); + return Error("Failed to write langTagRecord"); } - string_data.append(*tag_iter); + string_data.append(tag); } } if (!out->Write(string_data.data(), string_data.size())) { - return OTS_FAILURE_MSG("Faile to write string data"); + return Error("Faile to write string data"); } return true; } -void ots_name_reuse(Font *font, Font *other) { - font->name = other->name; - font->name_reused = true; -} - -void ots_name_free(Font *font) { - delete font->name; +bool OpenTypeNAME::IsValidNameId(uint16_t nameID, bool addIfMissing) { + if (addIfMissing && !this->name_ids.count(nameID)) { + bool added_unicode = false; + bool added_macintosh = false; + bool added_windows = false; + const size_t names_size = this->names.size(); // original size + for (size_t i = 0; i < names_size; ++i) switch (names[i].platform_id) { + case 0: + if (!added_unicode) { + // If there is an existing NameRecord with platform_id == 0 (Unicode), + // then add a NameRecord for the the specified nameID with arguments + // 0 (Unicode), 0 (v1.0), 0 (unspecified language). + this->names.emplace_back(0, 0, 0, nameID); + this->names.back().text = "NoName"; + added_unicode = true; + } + break; + case 1: + if (!added_macintosh) { + // If there is an existing NameRecord with platform_id == 1 (Macintosh), + // then add a NameRecord for the specified nameID with arguments + // 1 (Macintosh), 0 (Roman), 0 (English). + this->names.emplace_back(1, 0, 0, nameID); + this->names.back().text = "NoName"; + added_macintosh = true; + } + break; + case 3: + if (!added_windows) { + // If there is an existing NameRecord with platform_id == 3 (Windows), + // then add a NameRecord for the specified nameID with arguments + // 3 (Windows), 1 (UCS), 1033 (US English). + this->names.emplace_back(3, 1, 1033, nameID); + this->names.back().text = "NoName"; + added_windows = true; + } + break; + } + if (added_unicode || added_macintosh || added_windows) { + std::sort(this->names.begin(), this->names.end()); + this->name_ids.insert(nameID); + } + } + return this->name_ids.count(nameID); } } // namespace - -#undef TABLE_NAME |