1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/ots/src/name.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,334 @@ 1.4 +// Copyright (c) 2011 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "name.h" 1.9 + 1.10 +#include <algorithm> 1.11 +#include <cstring> 1.12 + 1.13 +#include "cff.h" 1.14 + 1.15 +// name - Naming Table 1.16 +// http://www.microsoft.com/typography/otspec/name.htm 1.17 + 1.18 +#define TABLE_NAME "name" 1.19 + 1.20 +namespace { 1.21 + 1.22 +bool ValidInPsName(char c) { 1.23 + return (c > 0x20 && c < 0x7f && !std::strchr("[](){}<>/%", c)); 1.24 +} 1.25 + 1.26 +bool CheckPsNameAscii(const std::string& name) { 1.27 + for (unsigned i = 0; i < name.size(); ++i) { 1.28 + if (!ValidInPsName(name[i])) { 1.29 + return false; 1.30 + } 1.31 + } 1.32 + return true; 1.33 +} 1.34 + 1.35 +bool CheckPsNameUtf16Be(const std::string& name) { 1.36 + if ((name.size() & 1) != 0) 1.37 + return false; 1.38 + 1.39 + for (unsigned i = 0; i < name.size(); i += 2) { 1.40 + if (name[i] != 0) { 1.41 + return false; 1.42 + } 1.43 + if (!ValidInPsName(name[i+1])) { 1.44 + return false; 1.45 + } 1.46 + } 1.47 + return true; 1.48 +} 1.49 + 1.50 +void AssignToUtf16BeFromAscii(std::string* target, 1.51 + const std::string& source) { 1.52 + target->resize(source.size() * 2); 1.53 + for (unsigned i = 0, j = 0; i < source.size(); i++) { 1.54 + (*target)[j++] = '\0'; 1.55 + (*target)[j++] = source[i]; 1.56 + } 1.57 +} 1.58 + 1.59 +} // namespace 1.60 + 1.61 + 1.62 +namespace ots { 1.63 + 1.64 +bool ots_name_parse(OpenTypeFile* file, const uint8_t* data, size_t length) { 1.65 + Buffer table(data, length); 1.66 + 1.67 + OpenTypeNAME* name = new OpenTypeNAME; 1.68 + file->name = name; 1.69 + 1.70 + uint16_t format = 0; 1.71 + if (!table.ReadU16(&format) || format > 1) { 1.72 + return OTS_FAILURE_MSG("Failed to read name table format or bad format %d", format); 1.73 + } 1.74 + 1.75 + uint16_t count = 0; 1.76 + if (!table.ReadU16(&count)) { 1.77 + return OTS_FAILURE_MSG("Failed to read name count"); 1.78 + } 1.79 + 1.80 + uint16_t string_offset = 0; 1.81 + if (!table.ReadU16(&string_offset) || string_offset > length) { 1.82 + return OTS_FAILURE_MSG("Failed to read strings offset"); 1.83 + } 1.84 + const char* string_base = reinterpret_cast<const char*>(data) + 1.85 + string_offset; 1.86 + 1.87 + NameRecord prev_record; 1.88 + bool sort_required = false; 1.89 + 1.90 + // Read all the names, discarding any with invalid IDs, 1.91 + // and any where the offset/length would be outside the table. 1.92 + // A stricter alternative would be to reject the font if there 1.93 + // are invalid name records, but it's not clear that is necessary. 1.94 + for (unsigned i = 0; i < count; ++i) { 1.95 + NameRecord rec; 1.96 + uint16_t name_length, name_offset; 1.97 + if (!table.ReadU16(&rec.platform_id) || 1.98 + !table.ReadU16(&rec.encoding_id) || 1.99 + !table.ReadU16(&rec.language_id) || 1.100 + !table.ReadU16(&rec.name_id) || 1.101 + !table.ReadU16(&name_length) || 1.102 + !table.ReadU16(&name_offset)) { 1.103 + return OTS_FAILURE_MSG("Failed to read name entry %d", i); 1.104 + } 1.105 + // check platform & encoding, discard names with unknown values 1.106 + switch (rec.platform_id) { 1.107 + case 0: // Unicode 1.108 + if (rec.encoding_id > 6) { 1.109 + continue; 1.110 + } 1.111 + break; 1.112 + case 1: // Macintosh 1.113 + if (rec.encoding_id > 32) { 1.114 + continue; 1.115 + } 1.116 + break; 1.117 + case 2: // ISO 1.118 + if (rec.encoding_id > 2) { 1.119 + continue; 1.120 + } 1.121 + break; 1.122 + case 3: // Windows: IDs 7 to 9 are "reserved" 1.123 + if (rec.encoding_id > 6 && rec.encoding_id != 10) { 1.124 + continue; 1.125 + } 1.126 + break; 1.127 + case 4: // Custom (OTF Windows NT compatibility) 1.128 + if (rec.encoding_id > 255) { 1.129 + continue; 1.130 + } 1.131 + break; 1.132 + default: // unknown platform 1.133 + continue; 1.134 + } 1.135 + 1.136 + const unsigned name_end = static_cast<unsigned>(string_offset) + 1.137 + name_offset + name_length; 1.138 + if (name_end > length) { 1.139 + continue; 1.140 + } 1.141 + rec.text.resize(name_length); 1.142 + rec.text.assign(string_base + name_offset, name_length); 1.143 + 1.144 + if (rec.name_id == 6) { 1.145 + // PostScript name: check that it is valid, if not then discard it 1.146 + if (rec.platform_id == 1) { 1.147 + if (file->cff && !file->cff->name.empty()) { 1.148 + rec.text = file->cff->name; 1.149 + } else if (!CheckPsNameAscii(rec.text)) { 1.150 + continue; 1.151 + } 1.152 + } else if (rec.platform_id == 0 || rec.platform_id == 3) { 1.153 + if (file->cff && !file->cff->name.empty()) { 1.154 + AssignToUtf16BeFromAscii(&rec.text, file->cff->name); 1.155 + } else if (!CheckPsNameUtf16Be(rec.text)) { 1.156 + continue; 1.157 + } 1.158 + } 1.159 + } 1.160 + 1.161 + if ((i > 0) && !(prev_record < rec)) { 1.162 + OTS_WARNING("name records are not sorted."); 1.163 + sort_required = true; 1.164 + } 1.165 + 1.166 + name->names.push_back(rec); 1.167 + prev_record = rec; 1.168 + } 1.169 + 1.170 + if (format == 1) { 1.171 + // extended name table format with language tags 1.172 + uint16_t lang_tag_count; 1.173 + if (!table.ReadU16(&lang_tag_count)) { 1.174 + return OTS_FAILURE_MSG("Failed to read language tag count"); 1.175 + } 1.176 + for (unsigned i = 0; i < lang_tag_count; ++i) { 1.177 + uint16_t tag_length = 0; 1.178 + uint16_t tag_offset = 0; 1.179 + if (!table.ReadU16(&tag_length) || !table.ReadU16(&tag_offset)) { 1.180 + return OTS_FAILURE_MSG("Faile to read tag length or offset"); 1.181 + } 1.182 + const unsigned tag_end = static_cast<unsigned>(string_offset) + 1.183 + tag_offset + tag_length; 1.184 + if (tag_end > length) { 1.185 + return OTS_FAILURE_MSG("bad end of tag %d > %ld for name entry %d", tag_end, length, i); 1.186 + } 1.187 + std::string tag(string_base + tag_offset, tag_length); 1.188 + name->lang_tags.push_back(tag); 1.189 + } 1.190 + } 1.191 + 1.192 + if (table.offset() > string_offset) { 1.193 + // the string storage apparently overlapped the name/tag records; 1.194 + // consider this font to be badly broken 1.195 + return OTS_FAILURE_MSG("Bad table offset %ld > %d", table.offset(), string_offset); 1.196 + } 1.197 + 1.198 + // check existence of required name strings (synthesize if necessary) 1.199 + // [0 - copyright - skip] 1.200 + // 1 - family 1.201 + // 2 - subfamily 1.202 + // [3 - unique ID - skip] 1.203 + // 4 - full name 1.204 + // 5 - version 1.205 + // 6 - postscript name 1.206 + static const unsigned kStdNameCount = 7; 1.207 + static const char* kStdNames[kStdNameCount] = { 1.208 + NULL, 1.209 + "OTS derived font", 1.210 + "Unspecified", 1.211 + NULL, 1.212 + "OTS derived font", 1.213 + "1.000", 1.214 + "OTS-derived-font" 1.215 + }; 1.216 + // The spec says that "In CFF OpenType fonts, these two name strings, when 1.217 + // translated to ASCII, must also be identical to the font name as stored in 1.218 + // the CFF's Name INDEX." And actually, Mac OS X's font parser requires that. 1.219 + if (file->cff && !file->cff->name.empty()) { 1.220 + kStdNames[6] = file->cff->name.c_str(); 1.221 + } 1.222 + 1.223 + // scan the names to check whether the required "standard" ones are present; 1.224 + // if not, we'll add our fixed versions here 1.225 + bool mac_name[kStdNameCount] = { 0 }; 1.226 + bool win_name[kStdNameCount] = { 0 }; 1.227 + for (std::vector<NameRecord>::iterator name_iter = name->names.begin(); 1.228 + name_iter != name->names.end(); name_iter++) { 1.229 + const uint16_t id = name_iter->name_id; 1.230 + if (id >= kStdNameCount || kStdNames[id] == NULL) { 1.231 + continue; 1.232 + } 1.233 + if (name_iter->platform_id == 1) { 1.234 + mac_name[id] = true; 1.235 + continue; 1.236 + } 1.237 + if (name_iter->platform_id == 3) { 1.238 + win_name[id] = true; 1.239 + continue; 1.240 + } 1.241 + } 1.242 + 1.243 + for (unsigned i = 0; i < kStdNameCount; ++i) { 1.244 + if (kStdNames[i] == NULL) { 1.245 + continue; 1.246 + } 1.247 + if (!mac_name[i]) { 1.248 + NameRecord rec(1 /* platform_id */, 0 /* encoding_id */, 1.249 + 0 /* language_id */ , i /* name_id */); 1.250 + rec.text.assign(kStdNames[i]); 1.251 + name->names.push_back(rec); 1.252 + sort_required = true; 1.253 + } 1.254 + if (!win_name[i]) { 1.255 + NameRecord rec(3 /* platform_id */, 1 /* encoding_id */, 1.256 + 1033 /* language_id */ , i /* name_id */); 1.257 + AssignToUtf16BeFromAscii(&rec.text, std::string(kStdNames[i])); 1.258 + name->names.push_back(rec); 1.259 + sort_required = true; 1.260 + } 1.261 + } 1.262 + 1.263 + if (sort_required) { 1.264 + std::sort(name->names.begin(), name->names.end()); 1.265 + } 1.266 + 1.267 + return true; 1.268 +} 1.269 + 1.270 +bool ots_name_should_serialise(OpenTypeFile* file) { 1.271 + return file->name != NULL; 1.272 +} 1.273 + 1.274 +bool ots_name_serialise(OTSStream* out, OpenTypeFile* file) { 1.275 + const OpenTypeNAME* name = file->name; 1.276 + 1.277 + uint16_t name_count = name->names.size(); 1.278 + uint16_t lang_tag_count = name->lang_tags.size(); 1.279 + uint16_t format = 0; 1.280 + size_t string_offset = 6 + name_count * 12; 1.281 + 1.282 + if (name->lang_tags.size() > 0) { 1.283 + // lang tags require a format-1 name table 1.284 + format = 1; 1.285 + string_offset += 2 + lang_tag_count * 4; 1.286 + } 1.287 + if (string_offset > 0xffff) { 1.288 + return OTS_FAILURE_MSG("Bad string offset %ld", string_offset); 1.289 + } 1.290 + if (!out->WriteU16(format) || 1.291 + !out->WriteU16(name_count) || 1.292 + !out->WriteU16(string_offset)) { 1.293 + return OTS_FAILURE_MSG("Failed to write name header"); 1.294 + } 1.295 + 1.296 + std::string string_data; 1.297 + for (std::vector<NameRecord>::const_iterator name_iter = name->names.begin(); 1.298 + name_iter != name->names.end(); name_iter++) { 1.299 + const NameRecord& rec = *name_iter; 1.300 + if (!out->WriteU16(rec.platform_id) || 1.301 + !out->WriteU16(rec.encoding_id) || 1.302 + !out->WriteU16(rec.language_id) || 1.303 + !out->WriteU16(rec.name_id) || 1.304 + !out->WriteU16(rec.text.size()) || 1.305 + !out->WriteU16(string_data.size()) ) { 1.306 + return OTS_FAILURE_MSG("Faile to write name entry"); 1.307 + } 1.308 + string_data.append(rec.text); 1.309 + } 1.310 + 1.311 + if (format == 1) { 1.312 + if (!out->WriteU16(lang_tag_count)) { 1.313 + return OTS_FAILURE_MSG("Faile to write language tag count"); 1.314 + } 1.315 + for (std::vector<std::string>::const_iterator tag_iter = 1.316 + name->lang_tags.begin(); 1.317 + tag_iter != name->lang_tags.end(); tag_iter++) { 1.318 + if (!out->WriteU16(tag_iter->size()) || 1.319 + !out->WriteU16(string_data.size())) { 1.320 + return OTS_FAILURE_MSG("Failed to write string"); 1.321 + } 1.322 + string_data.append(*tag_iter); 1.323 + } 1.324 + } 1.325 + 1.326 + if (!out->Write(string_data.data(), string_data.size())) { 1.327 + return OTS_FAILURE_MSG("Faile to write string data"); 1.328 + } 1.329 + 1.330 + return true; 1.331 +} 1.332 + 1.333 +void ots_name_free(OpenTypeFile* file) { 1.334 + delete file->name; 1.335 +} 1.336 + 1.337 +} // namespace