Update V8 to version 4.7.52.
[chromium-blink-merge.git] / third_party / ots / src / name.cc
bloba0dd1eaf5d510e8753394d1b279f210e19a7c02c
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
3 // found in the LICENSE file.
5 #include "name.h"
7 #include <algorithm>
8 #include <cstring>
10 // name - Naming Table
11 // http://www.microsoft.com/typography/otspec/name.htm
13 #define TABLE_NAME "name"
15 namespace {
17 bool ValidInPsName(char c) {
18 return (c > 0x20 && c < 0x7f && !std::strchr("[](){}<>/%", c));
21 bool CheckPsNameAscii(const std::string& name) {
22 for (unsigned i = 0; i < name.size(); ++i) {
23 if (!ValidInPsName(name[i])) {
24 return false;
27 return true;
30 bool CheckPsNameUtf16Be(const std::string& name) {
31 if ((name.size() & 1) != 0)
32 return false;
34 for (unsigned i = 0; i < name.size(); i += 2) {
35 if (name[i] != 0) {
36 return false;
38 if (!ValidInPsName(name[i+1])) {
39 return false;
42 return true;
45 void AssignToUtf16BeFromAscii(std::string* target,
46 const std::string& source) {
47 target->resize(source.size() * 2);
48 for (unsigned i = 0, j = 0; i < source.size(); i++) {
49 (*target)[j++] = '\0';
50 (*target)[j++] = source[i];
54 } // namespace
57 namespace ots {
59 bool ots_name_parse(Font *font, const uint8_t* data, size_t length) {
60 Buffer table(data, length);
62 OpenTypeNAME* name = new OpenTypeNAME;
63 font->name = name;
65 uint16_t format = 0;
66 if (!table.ReadU16(&format) || format > 1) {
67 return OTS_FAILURE_MSG("Failed to read name table format or bad format %d", format);
70 uint16_t count = 0;
71 if (!table.ReadU16(&count)) {
72 return OTS_FAILURE_MSG("Failed to read name count");
75 uint16_t string_offset = 0;
76 if (!table.ReadU16(&string_offset) || string_offset > length) {
77 return OTS_FAILURE_MSG("Failed to read strings offset");
79 const char* string_base = reinterpret_cast<const char*>(data) +
80 string_offset;
82 NameRecord prev_record;
83 bool sort_required = false;
85 // Read all the names, discarding any with invalid IDs,
86 // and any where the offset/length would be outside the table.
87 // A stricter alternative would be to reject the font if there
88 // are invalid name records, but it's not clear that is necessary.
89 for (unsigned i = 0; i < count; ++i) {
90 NameRecord rec;
91 uint16_t name_length, name_offset = 0;
92 if (!table.ReadU16(&rec.platform_id) ||
93 !table.ReadU16(&rec.encoding_id) ||
94 !table.ReadU16(&rec.language_id) ||
95 !table.ReadU16(&rec.name_id) ||
96 !table.ReadU16(&name_length) ||
97 !table.ReadU16(&name_offset)) {
98 return OTS_FAILURE_MSG("Failed to read name entry %d", i);
100 // check platform & encoding, discard names with unknown values
101 switch (rec.platform_id) {
102 case 0: // Unicode
103 if (rec.encoding_id > 6) {
104 continue;
106 break;
107 case 1: // Macintosh
108 if (rec.encoding_id > 32) {
109 continue;
111 break;
112 case 2: // ISO
113 if (rec.encoding_id > 2) {
114 continue;
116 break;
117 case 3: // Windows: IDs 7 to 9 are "reserved"
118 if (rec.encoding_id > 6 && rec.encoding_id != 10) {
119 continue;
121 break;
122 case 4: // Custom (OTF Windows NT compatibility)
123 if (rec.encoding_id > 255) {
124 continue;
126 break;
127 default: // unknown platform
128 continue;
131 const unsigned name_end = static_cast<unsigned>(string_offset) +
132 name_offset + name_length;
133 if (name_end > length) {
134 continue;
136 rec.text.resize(name_length);
137 rec.text.assign(string_base + name_offset, name_length);
139 if (rec.name_id == 6) {
140 // PostScript name: check that it is valid, if not then discard it
141 if (rec.platform_id == 1) {
142 if (!CheckPsNameAscii(rec.text)) {
143 continue;
145 } else if (rec.platform_id == 0 || rec.platform_id == 3) {
146 if (!CheckPsNameUtf16Be(rec.text)) {
147 continue;
152 if ((i > 0) && !(prev_record < rec)) {
153 OTS_WARNING("name records are not sorted.");
154 sort_required = true;
157 name->names.push_back(rec);
158 prev_record = rec;
161 if (format == 1) {
162 // extended name table format with language tags
163 uint16_t lang_tag_count;
164 if (!table.ReadU16(&lang_tag_count)) {
165 return OTS_FAILURE_MSG("Failed to read language tag count");
167 for (unsigned i = 0; i < lang_tag_count; ++i) {
168 uint16_t tag_length = 0;
169 uint16_t tag_offset = 0;
170 if (!table.ReadU16(&tag_length) || !table.ReadU16(&tag_offset)) {
171 return OTS_FAILURE_MSG("Faile to read tag length or offset");
173 const unsigned tag_end = static_cast<unsigned>(string_offset) +
174 tag_offset + tag_length;
175 if (tag_end > length) {
176 return OTS_FAILURE_MSG("bad end of tag %d > %ld for name entry %d", tag_end, length, i);
178 std::string tag(string_base + tag_offset, tag_length);
179 name->lang_tags.push_back(tag);
183 if (table.offset() > string_offset) {
184 // the string storage apparently overlapped the name/tag records;
185 // consider this font to be badly broken
186 return OTS_FAILURE_MSG("Bad table offset %ld > %d", table.offset(), string_offset);
189 // check existence of required name strings (synthesize if necessary)
190 // [0 - copyright - skip]
191 // 1 - family
192 // 2 - subfamily
193 // [3 - unique ID - skip]
194 // 4 - full name
195 // 5 - version
196 // 6 - postscript name
197 static const uint16_t kStdNameCount = 7;
198 static const char* kStdNames[kStdNameCount] = {
199 NULL,
200 "OTS derived font",
201 "Unspecified",
202 NULL,
203 "OTS derived font",
204 "1.000",
205 "OTS-derived-font"
208 // scan the names to check whether the required "standard" ones are present;
209 // if not, we'll add our fixed versions here
210 bool mac_name[kStdNameCount] = { 0 };
211 bool win_name[kStdNameCount] = { 0 };
212 for (std::vector<NameRecord>::iterator name_iter = name->names.begin();
213 name_iter != name->names.end(); name_iter++) {
214 const uint16_t id = name_iter->name_id;
215 if (id >= kStdNameCount || kStdNames[id] == NULL) {
216 continue;
218 if (name_iter->platform_id == 1) {
219 mac_name[id] = true;
220 continue;
222 if (name_iter->platform_id == 3) {
223 win_name[id] = true;
224 continue;
228 for (uint16_t i = 0; i < kStdNameCount; ++i) {
229 if (kStdNames[i] == NULL) {
230 continue;
232 if (!mac_name[i] && !win_name[i]) {
233 NameRecord mac_rec(1 /* platform_id */, 0 /* encoding_id */,
234 0 /* language_id */ , i /* name_id */);
235 mac_rec.text.assign(kStdNames[i]);
237 NameRecord win_rec(3 /* platform_id */, 1 /* encoding_id */,
238 1033 /* language_id */ , i /* name_id */);
239 AssignToUtf16BeFromAscii(&win_rec.text, std::string(kStdNames[i]));
241 name->names.push_back(mac_rec);
242 name->names.push_back(win_rec);
243 sort_required = true;
247 if (sort_required) {
248 std::sort(name->names.begin(), name->names.end());
251 return true;
254 bool ots_name_should_serialise(Font *font) {
255 return font->name != NULL;
258 bool ots_name_serialise(OTSStream* out, Font *font) {
259 const OpenTypeNAME* name = font->name;
261 uint16_t name_count = static_cast<uint16_t>(name->names.size());
262 uint16_t lang_tag_count = static_cast<uint16_t>(name->lang_tags.size());
263 uint16_t format = 0;
264 size_t string_offset = 6 + name_count * 12;
266 if (name->lang_tags.size() > 0) {
267 // lang tags require a format-1 name table
268 format = 1;
269 string_offset += 2 + lang_tag_count * 4;
271 if (string_offset > 0xffff) {
272 return OTS_FAILURE_MSG("Bad string offset %ld", string_offset);
274 if (!out->WriteU16(format) ||
275 !out->WriteU16(name_count) ||
276 !out->WriteU16(static_cast<uint16_t>(string_offset))) {
277 return OTS_FAILURE_MSG("Failed to write name header");
280 std::string string_data;
281 for (std::vector<NameRecord>::const_iterator name_iter = name->names.begin();
282 name_iter != name->names.end(); name_iter++) {
283 const NameRecord& rec = *name_iter;
284 if (string_data.size() + rec.text.size() >
285 std::numeric_limits<uint16_t>::max() ||
286 !out->WriteU16(rec.platform_id) ||
287 !out->WriteU16(rec.encoding_id) ||
288 !out->WriteU16(rec.language_id) ||
289 !out->WriteU16(rec.name_id) ||
290 !out->WriteU16(static_cast<uint16_t>(rec.text.size())) ||
291 !out->WriteU16(static_cast<uint16_t>(string_data.size())) ) {
292 return OTS_FAILURE_MSG("Faile to write name entry");
294 string_data.append(rec.text);
297 if (format == 1) {
298 if (!out->WriteU16(lang_tag_count)) {
299 return OTS_FAILURE_MSG("Faile to write language tag count");
301 for (std::vector<std::string>::const_iterator tag_iter =
302 name->lang_tags.begin();
303 tag_iter != name->lang_tags.end(); tag_iter++) {
304 if (string_data.size() + tag_iter->size() >
305 std::numeric_limits<uint16_t>::max() ||
306 !out->WriteU16(static_cast<uint16_t>(tag_iter->size())) ||
307 !out->WriteU16(static_cast<uint16_t>(string_data.size()))) {
308 return OTS_FAILURE_MSG("Failed to write string");
310 string_data.append(*tag_iter);
314 if (!out->Write(string_data.data(), string_data.size())) {
315 return OTS_FAILURE_MSG("Faile to write string data");
318 return true;
321 void ots_name_reuse(Font *font, Font *other) {
322 font->name = other->name;
323 font->name_reused = true;
326 void ots_name_free(Font *font) {
327 delete font->name;
330 } // namespace
332 #undef TABLE_NAME