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

Side by Side Diff: third_party/ots/src/name.cc

Issue 775893002: Updating OTS repo from https://github.com/khaledhosny/ots.git (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Updating with 4800 warning fix Created 6 years 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 unified diff | Download patch
« no previous file with comments | « third_party/ots/src/name.h ('k') | third_party/ots/src/os2.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "name.h"
6
7 #include <algorithm>
8 #include <cstring>
9
10 #include "cff.h"
11
12 // name - Naming Table
13 // http://www.microsoft.com/typography/otspec/name.htm
14
15 #define TABLE_NAME "name"
16
17 namespace {
18
19 bool ValidInPsName(char c) {
20 return (c > 0x20 && c < 0x7f && !std::strchr("[](){}<>/%", c));
21 }
22
23 bool CheckPsNameAscii(const std::string& name) {
24 for (unsigned i = 0; i < name.size(); ++i) {
25 if (!ValidInPsName(name[i])) {
26 return false;
27 }
28 }
29 return true;
30 }
31
32 bool CheckPsNameUtf16Be(const std::string& name) {
33 if ((name.size() & 1) != 0)
34 return false;
35
36 for (unsigned i = 0; i < name.size(); i += 2) {
37 if (name[i] != 0) {
38 return false;
39 }
40 if (!ValidInPsName(name[i+1])) {
41 return false;
42 }
43 }
44 return true;
45 }
46
47 void AssignToUtf16BeFromAscii(std::string* target,
48 const std::string& source) {
49 target->resize(source.size() * 2);
50 for (unsigned i = 0, j = 0; i < source.size(); i++) {
51 (*target)[j++] = '\0';
52 (*target)[j++] = source[i];
53 }
54 }
55
56 } // namespace
57
58
59 namespace ots {
60
61 bool ots_name_parse(OpenTypeFile* file, const uint8_t* data, size_t length) {
62 Buffer table(data, length);
63
64 OpenTypeNAME* name = new OpenTypeNAME;
65 file->name = name;
66
67 uint16_t format = 0;
68 if (!table.ReadU16(&format) || format > 1) {
69 return OTS_FAILURE_MSG("Failed to read name table format or bad format %d", format);
70 }
71
72 uint16_t count = 0;
73 if (!table.ReadU16(&count)) {
74 return OTS_FAILURE_MSG("Failed to read name count");
75 }
76
77 uint16_t string_offset = 0;
78 if (!table.ReadU16(&string_offset) || string_offset > length) {
79 return OTS_FAILURE_MSG("Failed to read strings offset");
80 }
81 const char* string_base = reinterpret_cast<const char*>(data) +
82 string_offset;
83
84 NameRecord prev_record;
85 bool sort_required = false;
86
87 // Read all the names, discarding any with invalid IDs,
88 // and any where the offset/length would be outside the table.
89 // A stricter alternative would be to reject the font if there
90 // are invalid name records, but it's not clear that is necessary.
91 for (unsigned i = 0; i < count; ++i) {
92 NameRecord rec;
93 uint16_t name_length, name_offset = 0;
94 if (!table.ReadU16(&rec.platform_id) ||
95 !table.ReadU16(&rec.encoding_id) ||
96 !table.ReadU16(&rec.language_id) ||
97 !table.ReadU16(&rec.name_id) ||
98 !table.ReadU16(&name_length) ||
99 !table.ReadU16(&name_offset)) {
100 return OTS_FAILURE_MSG("Failed to read name entry %d", i);
101 }
102 // check platform & encoding, discard names with unknown values
103 switch (rec.platform_id) {
104 case 0: // Unicode
105 if (rec.encoding_id > 6) {
106 continue;
107 }
108 break;
109 case 1: // Macintosh
110 if (rec.encoding_id > 32) {
111 continue;
112 }
113 break;
114 case 2: // ISO
115 if (rec.encoding_id > 2) {
116 continue;
117 }
118 break;
119 case 3: // Windows: IDs 7 to 9 are "reserved"
120 if (rec.encoding_id > 6 && rec.encoding_id != 10) {
121 continue;
122 }
123 break;
124 case 4: // Custom (OTF Windows NT compatibility)
125 if (rec.encoding_id > 255) {
126 continue;
127 }
128 break;
129 default: // unknown platform
130 continue;
131 }
132
133 const unsigned name_end = static_cast<unsigned>(string_offset) +
134 name_offset + name_length;
135 if (name_end > length) {
136 continue;
137 }
138 rec.text.resize(name_length);
139 rec.text.assign(string_base + name_offset, name_length);
140
141 if (rec.name_id == 6) {
142 // PostScript name: check that it is valid, if not then discard it
143 if (rec.platform_id == 1) {
144 if (file->cff && !file->cff->name.empty()) {
145 rec.text = file->cff->name;
146 } else if (!CheckPsNameAscii(rec.text)) {
147 continue;
148 }
149 } else if (rec.platform_id == 0 || rec.platform_id == 3) {
150 if (file->cff && !file->cff->name.empty()) {
151 AssignToUtf16BeFromAscii(&rec.text, file->cff->name);
152 } else if (!CheckPsNameUtf16Be(rec.text)) {
153 continue;
154 }
155 }
156 }
157
158 if ((i > 0) && !(prev_record < rec)) {
159 OTS_WARNING("name records are not sorted.");
160 sort_required = true;
161 }
162
163 name->names.push_back(rec);
164 prev_record = rec;
165 }
166
167 if (format == 1) {
168 // extended name table format with language tags
169 uint16_t lang_tag_count;
170 if (!table.ReadU16(&lang_tag_count)) {
171 return OTS_FAILURE_MSG("Failed to read language tag count");
172 }
173 for (unsigned i = 0; i < lang_tag_count; ++i) {
174 uint16_t tag_length = 0;
175 uint16_t tag_offset = 0;
176 if (!table.ReadU16(&tag_length) || !table.ReadU16(&tag_offset)) {
177 return OTS_FAILURE_MSG("Faile to read tag length or offset");
178 }
179 const unsigned tag_end = static_cast<unsigned>(string_offset) +
180 tag_offset + tag_length;
181 if (tag_end > length) {
182 return OTS_FAILURE_MSG("bad end of tag %d > %ld for name entry %d", tag_ end, length, i);
183 }
184 std::string tag(string_base + tag_offset, tag_length);
185 name->lang_tags.push_back(tag);
186 }
187 }
188
189 if (table.offset() > string_offset) {
190 // the string storage apparently overlapped the name/tag records;
191 // consider this font to be badly broken
192 return OTS_FAILURE_MSG("Bad table offset %ld > %d", table.offset(), string_o ffset);
193 }
194
195 // check existence of required name strings (synthesize if necessary)
196 // [0 - copyright - skip]
197 // 1 - family
198 // 2 - subfamily
199 // [3 - unique ID - skip]
200 // 4 - full name
201 // 5 - version
202 // 6 - postscript name
203 static const uint16_t kStdNameCount = 7;
204 static const char* kStdNames[kStdNameCount] = {
205 NULL,
206 "OTS derived font",
207 "Unspecified",
208 NULL,
209 "OTS derived font",
210 "1.000",
211 "OTS-derived-font"
212 };
213 // The spec says that "In CFF OpenType fonts, these two name strings, when
214 // translated to ASCII, must also be identical to the font name as stored in
215 // the CFF's Name INDEX." And actually, Mac OS X's font parser requires that.
216 if (file->cff && !file->cff->name.empty()) {
217 kStdNames[6] = file->cff->name.c_str();
218 }
219
220 // scan the names to check whether the required "standard" ones are present;
221 // if not, we'll add our fixed versions here
222 bool mac_name[kStdNameCount] = { 0 };
223 bool win_name[kStdNameCount] = { 0 };
224 for (std::vector<NameRecord>::iterator name_iter = name->names.begin();
225 name_iter != name->names.end(); name_iter++) {
226 const uint16_t id = name_iter->name_id;
227 if (id >= kStdNameCount || kStdNames[id] == NULL) {
228 continue;
229 }
230 if (name_iter->platform_id == 1) {
231 mac_name[id] = true;
232 continue;
233 }
234 if (name_iter->platform_id == 3) {
235 win_name[id] = true;
236 continue;
237 }
238 }
239
240 for (uint16_t i = 0; i < kStdNameCount; ++i) {
241 if (kStdNames[i] == NULL) {
242 continue;
243 }
244 if (!mac_name[i]) {
245 NameRecord rec(1 /* platform_id */, 0 /* encoding_id */,
246 0 /* language_id */ , i /* name_id */);
247 rec.text.assign(kStdNames[i]);
248 name->names.push_back(rec);
249 sort_required = true;
250 }
251 if (!win_name[i]) {
252 NameRecord rec(3 /* platform_id */, 1 /* encoding_id */,
253 1033 /* language_id */ , i /* name_id */);
254 AssignToUtf16BeFromAscii(&rec.text, std::string(kStdNames[i]));
255 name->names.push_back(rec);
256 sort_required = true;
257 }
258 }
259
260 if (sort_required) {
261 std::sort(name->names.begin(), name->names.end());
262 }
263
264 return true;
265 }
266
267 bool ots_name_should_serialise(OpenTypeFile* file) {
268 return file->name != NULL;
269 }
270
271 bool ots_name_serialise(OTSStream* out, OpenTypeFile* file) {
272 const OpenTypeNAME* name = file->name;
273
274 uint16_t name_count = static_cast<uint16_t>(name->names.size());
275 uint16_t lang_tag_count = static_cast<uint16_t>(name->lang_tags.size());
276 uint16_t format = 0;
277 size_t string_offset = 6 + name_count * 12;
278
279 if (name->lang_tags.size() > 0) {
280 // lang tags require a format-1 name table
281 format = 1;
282 string_offset += 2 + lang_tag_count * 4;
283 }
284 if (string_offset > 0xffff) {
285 return OTS_FAILURE_MSG("Bad string offset %ld", string_offset);
286 }
287 if (!out->WriteU16(format) ||
288 !out->WriteU16(name_count) ||
289 !out->WriteU16(static_cast<uint16_t>(string_offset))) {
290 return OTS_FAILURE_MSG("Failed to write name header");
291 }
292
293 std::string string_data;
294 for (std::vector<NameRecord>::const_iterator name_iter = name->names.begin();
295 name_iter != name->names.end(); name_iter++) {
296 const NameRecord& rec = *name_iter;
297 if (string_data.size() + rec.text.size() >
298 std::numeric_limits<uint16_t>::max() ||
299 !out->WriteU16(rec.platform_id) ||
300 !out->WriteU16(rec.encoding_id) ||
301 !out->WriteU16(rec.language_id) ||
302 !out->WriteU16(rec.name_id) ||
303 !out->WriteU16(static_cast<uint16_t>(rec.text.size())) ||
304 !out->WriteU16(static_cast<uint16_t>(string_data.size())) ) {
305 return OTS_FAILURE_MSG("Faile to write name entry");
306 }
307 string_data.append(rec.text);
308 }
309
310 if (format == 1) {
311 if (!out->WriteU16(lang_tag_count)) {
312 return OTS_FAILURE_MSG("Faile to write language tag count");
313 }
314 for (std::vector<std::string>::const_iterator tag_iter =
315 name->lang_tags.begin();
316 tag_iter != name->lang_tags.end(); tag_iter++) {
317 if (string_data.size() + tag_iter->size() >
318 std::numeric_limits<uint16_t>::max() ||
319 !out->WriteU16(static_cast<uint16_t>(tag_iter->size())) ||
320 !out->WriteU16(static_cast<uint16_t>(string_data.size()))) {
321 return OTS_FAILURE_MSG("Failed to write string");
322 }
323 string_data.append(*tag_iter);
324 }
325 }
326
327 if (!out->Write(string_data.data(), string_data.size())) {
328 return OTS_FAILURE_MSG("Faile to write string data");
329 }
330
331 return true;
332 }
333
334 void ots_name_free(OpenTypeFile* file) {
335 delete file->name;
336 }
337
338 } // namespace
339
340 #undef TABLE_NAME
OLDNEW
« no previous file with comments | « third_party/ots/src/name.h ('k') | third_party/ots/src/os2.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698