Line data Source code
1 : // Copyright (c) 2009 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 "cmap.h"
6 :
7 : #include <algorithm>
8 : #include <set>
9 : #include <utility>
10 : #include <vector>
11 :
12 : #include "maxp.h"
13 : #include "os2.h"
14 :
15 : // cmap - Character To Glyph Index Mapping Table
16 : // http://www.microsoft.com/typography/otspec/cmap.htm
17 :
18 : #define TABLE_NAME "cmap"
19 :
20 : namespace {
21 :
22 : struct CMAPSubtableHeader {
23 : uint16_t platform;
24 : uint16_t encoding;
25 : uint32_t offset;
26 : uint16_t format;
27 : uint32_t length;
28 : uint32_t language;
29 : };
30 :
31 : struct Subtable314Range {
32 : uint16_t start_range;
33 : uint16_t end_range;
34 : int16_t id_delta;
35 : uint16_t id_range_offset;
36 : uint32_t id_range_offset_offset;
37 : };
38 :
39 : // Glyph array size for the Mac Roman (format 0) table.
40 : const size_t kFormat0ArraySize = 256;
41 :
42 : // The upper limit of the Unicode code point.
43 : const uint32_t kUnicodeUpperLimit = 0x10FFFF;
44 :
45 : // The maximum number of UVS records (See below).
46 : const uint32_t kMaxCMAPSelectorRecords = 259;
47 : // The range of UVSes are:
48 : // 0x180B-0x180D (3 code points)
49 : // 0xFE00-0xFE0F (16 code points)
50 : // 0xE0100-0xE01EF (240 code points)
51 : const uint32_t kMongolianVSStart = 0x180B;
52 : const uint32_t kMongolianVSEnd = 0x180D;
53 : const uint32_t kVSStart = 0xFE00;
54 : const uint32_t kVSEnd = 0xFE0F;
55 : const uint32_t kIVSStart = 0xE0100;
56 : const uint32_t kIVSEnd = 0xE01EF;
57 : const uint32_t kUVSUpperLimit = 0xFFFFFF;
58 :
59 : // Parses Format 4 tables
60 0 : bool ParseFormat4(ots::Font *font, int platform, int encoding,
61 : const uint8_t *data, size_t length, uint16_t num_glyphs) {
62 0 : ots::Buffer subtable(data, length);
63 :
64 : // 0.3.4, 3.0.4 or 3.1.4 subtables are complex and, rather than expanding the
65 : // whole thing and recompacting it, we validate it and include it verbatim
66 : // in the output.
67 :
68 0 : if (!font->os2) {
69 0 : return OTS_FAILURE_MSG("Required OS/2 table missing");
70 : }
71 :
72 0 : if (!subtable.Skip(4)) {
73 0 : return OTS_FAILURE_MSG("Can't read 4 bytes at start of cmap format 4 subtable");
74 : }
75 0 : uint16_t language = 0;
76 0 : if (!subtable.ReadU16(&language)) {
77 0 : return OTS_FAILURE_MSG("Can't read language");
78 : }
79 0 : if (language) {
80 : // Platform ID 3 (windows) subtables should have language '0'.
81 0 : return OTS_FAILURE_MSG("Languages should be 0 (%d)", language);
82 : }
83 :
84 : uint16_t segcountx2, search_range, entry_selector, range_shift;
85 0 : segcountx2 = search_range = entry_selector = range_shift = 0;
86 0 : if (!subtable.ReadU16(&segcountx2) ||
87 0 : !subtable.ReadU16(&search_range) ||
88 0 : !subtable.ReadU16(&entry_selector) ||
89 0 : !subtable.ReadU16(&range_shift)) {
90 0 : return OTS_FAILURE_MSG("Failed to read subcmap structure");
91 : }
92 :
93 0 : if (segcountx2 & 1 || search_range & 1) {
94 0 : return OTS_FAILURE_MSG("Bad subcmap structure");
95 : }
96 0 : const uint16_t segcount = segcountx2 >> 1;
97 : // There must be at least one segment according the spec.
98 0 : if (segcount < 1) {
99 0 : return OTS_FAILURE_MSG("Segcount < 1 (%d)", segcount);
100 : }
101 :
102 : // log2segcount is the maximal x s.t. 2^x < segcount
103 0 : unsigned log2segcount = 0;
104 0 : while (1u << (log2segcount + 1) <= segcount) {
105 0 : log2segcount++;
106 : }
107 :
108 0 : const uint16_t expected_search_range = 2 * 1u << log2segcount;
109 0 : if (expected_search_range != search_range) {
110 0 : return OTS_FAILURE_MSG("expected search range != search range (%d != %d)", expected_search_range, search_range);
111 : }
112 :
113 0 : if (entry_selector != log2segcount) {
114 0 : return OTS_FAILURE_MSG("entry selector != log2(segement count) (%d != %d)", entry_selector, log2segcount);
115 : }
116 :
117 0 : const uint16_t expected_range_shift = segcountx2 - search_range;
118 0 : if (range_shift != expected_range_shift) {
119 0 : return OTS_FAILURE_MSG("unexpected range shift (%d != %d)", range_shift, expected_range_shift);
120 : }
121 :
122 0 : std::vector<Subtable314Range> ranges(segcount);
123 :
124 0 : for (unsigned i = 0; i < segcount; ++i) {
125 0 : if (!subtable.ReadU16(&ranges[i].end_range)) {
126 0 : return OTS_FAILURE_MSG("Failed to read segment %d", i);
127 : }
128 : }
129 :
130 : uint16_t padding;
131 0 : if (!subtable.ReadU16(&padding)) {
132 0 : return OTS_FAILURE_MSG("Failed to read cmap subtable segment padding");
133 : }
134 0 : if (padding) {
135 0 : return OTS_FAILURE_MSG("Non zero cmap subtable segment padding (%d)", padding);
136 : }
137 :
138 0 : for (unsigned i = 0; i < segcount; ++i) {
139 0 : if (!subtable.ReadU16(&ranges[i].start_range)) {
140 0 : return OTS_FAILURE_MSG("Failed to read segment start range %d", i);
141 : }
142 : }
143 0 : for (unsigned i = 0; i < segcount; ++i) {
144 0 : if (!subtable.ReadS16(&ranges[i].id_delta)) {
145 0 : return OTS_FAILURE_MSG("Failed to read segment delta %d", i);
146 : }
147 : }
148 0 : for (unsigned i = 0; i < segcount; ++i) {
149 0 : ranges[i].id_range_offset_offset = subtable.offset();
150 0 : if (!subtable.ReadU16(&ranges[i].id_range_offset)) {
151 0 : return OTS_FAILURE_MSG("Failed to read segment range offset %d", i);
152 : }
153 :
154 0 : if (ranges[i].id_range_offset & 1) {
155 : // Some font generators seem to put 65535 on id_range_offset
156 : // for 0xFFFF-0xFFFF range.
157 : // (e.g., many fonts in http://www.princexml.com/fonts/)
158 0 : if (i == segcount - 1u) {
159 0 : OTS_WARNING("bad id_range_offset");
160 0 : ranges[i].id_range_offset = 0;
161 : // The id_range_offset value in the transcoded font will not change
162 : // since this table is not actually "transcoded" yet.
163 : } else {
164 0 : return OTS_FAILURE_MSG("Bad segment offset (%d)", ranges[i].id_range_offset);
165 : }
166 : }
167 : }
168 :
169 : // ranges must be ascending order, based on the end_code. Ranges may not
170 : // overlap.
171 0 : for (unsigned i = 1; i < segcount; ++i) {
172 0 : if ((i == segcount - 1u) &&
173 0 : (ranges[i - 1].start_range == 0xffff) &&
174 0 : (ranges[i - 1].end_range == 0xffff) &&
175 0 : (ranges[i].start_range == 0xffff) &&
176 0 : (ranges[i].end_range == 0xffff)) {
177 : // Some fonts (e.g., Germania.ttf) have multiple 0xffff terminators.
178 : // We'll accept them as an exception.
179 0 : OTS_WARNING("multiple 0xffff terminators found");
180 0 : continue;
181 : }
182 :
183 : // Note: some Linux fonts (e.g., LucidaSansOblique.ttf, bsmi00lp.ttf) have
184 : // unsorted table...
185 0 : if (ranges[i].end_range <= ranges[i - 1].end_range) {
186 0 : return OTS_FAILURE_MSG("Out of order end range (%d <= %d)", ranges[i].end_range, ranges[i-1].end_range);
187 : }
188 0 : if (ranges[i].start_range <= ranges[i - 1].end_range) {
189 0 : return OTS_FAILURE_MSG("out of order start range (%d <= %d)", ranges[i].start_range, ranges[i-1].end_range);
190 : }
191 :
192 : // On many fonts, the value of {first, last}_char_index are incorrect.
193 : // Fix them.
194 0 : if (font->os2->first_char_index != 0xFFFF &&
195 0 : ranges[i].start_range != 0xFFFF &&
196 0 : font->os2->first_char_index > ranges[i].start_range) {
197 0 : font->os2->first_char_index = ranges[i].start_range;
198 : }
199 0 : if (font->os2->last_char_index != 0xFFFF &&
200 0 : ranges[i].end_range != 0xFFFF &&
201 0 : font->os2->last_char_index < ranges[i].end_range) {
202 0 : font->os2->last_char_index = ranges[i].end_range;
203 : }
204 : }
205 :
206 : // The last range must end at 0xffff
207 0 : if (ranges[segcount - 1].start_range != 0xffff || ranges[segcount - 1].end_range != 0xffff) {
208 0 : return OTS_FAILURE_MSG("Final segment start and end must be 0xFFFF (0x%04X-0x%04X)",
209 : ranges[segcount - 1].start_range, ranges[segcount - 1].end_range);
210 : }
211 :
212 : // A format 4 CMAP subtable is complex. To be safe we simulate a lookup of
213 : // each code-point defined in the table and make sure that they are all valid
214 : // glyphs and that we don't access anything out-of-bounds.
215 0 : for (unsigned i = 0; i < segcount; ++i) {
216 0 : for (unsigned cp = ranges[i].start_range; cp <= ranges[i].end_range; ++cp) {
217 0 : const uint16_t code_point = static_cast<uint16_t>(cp);
218 0 : if (ranges[i].id_range_offset == 0) {
219 : // this is explictly allowed to overflow in the spec
220 0 : const uint16_t glyph = code_point + ranges[i].id_delta;
221 0 : if (glyph >= num_glyphs) {
222 0 : return OTS_FAILURE_MSG("Range glyph reference too high (%d > %d)", glyph, num_glyphs - 1);
223 : }
224 : } else {
225 0 : const uint16_t range_delta = code_point - ranges[i].start_range;
226 : // this might seem odd, but it's true. The offset is relative to the
227 : // location of the offset value itself.
228 0 : const uint32_t glyph_id_offset = ranges[i].id_range_offset_offset +
229 0 : ranges[i].id_range_offset +
230 0 : range_delta * 2;
231 : // We need to be able to access a 16-bit value from this offset
232 0 : if (glyph_id_offset + 1 >= length) {
233 0 : return OTS_FAILURE_MSG("bad glyph id offset (%d > %ld)", glyph_id_offset, length);
234 : }
235 : uint16_t glyph;
236 0 : std::memcpy(&glyph, data + glyph_id_offset, 2);
237 0 : glyph = ntohs(glyph);
238 0 : if (glyph >= num_glyphs) {
239 0 : return OTS_FAILURE_MSG("Range glyph reference too high (%d > %d)", glyph, num_glyphs - 1);
240 : }
241 : }
242 : }
243 : }
244 :
245 : // We accept the table.
246 : // TODO(yusukes): transcode the subtable.
247 0 : if (platform == 3 && encoding == 0) {
248 0 : font->cmap->subtable_3_0_4_data = data;
249 0 : font->cmap->subtable_3_0_4_length = length;
250 0 : } else if (platform == 3 && encoding == 1) {
251 0 : font->cmap->subtable_3_1_4_data = data;
252 0 : font->cmap->subtable_3_1_4_length = length;
253 0 : } else if (platform == 0 && encoding == 3) {
254 0 : font->cmap->subtable_0_3_4_data = data;
255 0 : font->cmap->subtable_0_3_4_length = length;
256 : } else {
257 0 : return OTS_FAILURE_MSG("Unknown cmap subtable type (platform=%d, encoding=%d)", platform, encoding);
258 : }
259 :
260 0 : return true;
261 : }
262 :
263 0 : bool Parse31012(ots::Font *font,
264 : const uint8_t *data, size_t length, uint16_t num_glyphs) {
265 0 : ots::Buffer subtable(data, length);
266 :
267 : // Format 12 tables are simple. We parse these and fully serialise them
268 : // later.
269 :
270 0 : if (!subtable.Skip(8)) {
271 0 : return OTS_FAILURE_MSG("failed to skip the first 8 bytes of format 12 subtable");
272 : }
273 0 : uint32_t language = 0;
274 0 : if (!subtable.ReadU32(&language)) {
275 0 : return OTS_FAILURE_MSG("can't read format 12 subtable language");
276 : }
277 0 : if (language) {
278 0 : return OTS_FAILURE_MSG("format 12 subtable language should be zero (%d)", language);
279 : }
280 :
281 0 : uint32_t num_groups = 0;
282 0 : if (!subtable.ReadU32(&num_groups)) {
283 0 : return OTS_FAILURE_MSG("can't read number of format 12 subtable groups");
284 : }
285 0 : if (num_groups == 0 || subtable.remaining() / 12 < num_groups) {
286 0 : return OTS_FAILURE_MSG("Bad format 12 subtable group count %d", num_groups);
287 : }
288 :
289 : std::vector<ots::OpenTypeCMAPSubtableRange> &groups
290 0 : = font->cmap->subtable_3_10_12;
291 0 : groups.resize(num_groups);
292 :
293 0 : for (unsigned i = 0; i < num_groups; ++i) {
294 0 : if (!subtable.ReadU32(&groups[i].start_range) ||
295 0 : !subtable.ReadU32(&groups[i].end_range) ||
296 0 : !subtable.ReadU32(&groups[i].start_glyph_id)) {
297 0 : return OTS_FAILURE_MSG("can't read format 12 subtable group");
298 : }
299 :
300 0 : if (groups[i].start_range > kUnicodeUpperLimit ||
301 0 : groups[i].end_range > kUnicodeUpperLimit ||
302 0 : groups[i].start_glyph_id > 0xFFFF) {
303 0 : return OTS_FAILURE_MSG("bad format 12 subtable group (startCharCode=0x%4X, endCharCode=0x%4X, startGlyphID=%d)",
304 : groups[i].start_range, groups[i].end_range, groups[i].start_glyph_id);
305 : }
306 :
307 : // We assert that the glyph value is within range. Because of the range
308 : // limits, above, we don't need to worry about overflow.
309 0 : if (groups[i].end_range < groups[i].start_range) {
310 0 : return OTS_FAILURE_MSG("format 12 subtable group endCharCode before startCharCode (0x%4X < 0x%4X)",
311 : groups[i].end_range, groups[i].start_range);
312 : }
313 0 : if ((groups[i].end_range - groups[i].start_range) +
314 0 : groups[i].start_glyph_id > num_glyphs) {
315 0 : return OTS_FAILURE_MSG("bad format 12 subtable group startGlyphID (%d)", groups[i].start_glyph_id);
316 : }
317 : }
318 :
319 : // the groups must be sorted by start code and may not overlap
320 0 : for (unsigned i = 1; i < num_groups; ++i) {
321 0 : if (groups[i].start_range <= groups[i - 1].start_range) {
322 0 : return OTS_FAILURE_MSG("out of order format 12 subtable group (startCharCode=0x%4X <= startCharCode=0x%4X of previous group)",
323 : groups[i].start_range, groups[i-1].start_range);
324 : }
325 0 : if (groups[i].start_range <= groups[i - 1].end_range) {
326 0 : return OTS_FAILURE_MSG("overlapping format 12 subtable groups (startCharCode=0x%4X <= endCharCode=0x%4X of previous group)",
327 : groups[i].start_range, groups[i-1].end_range);
328 : }
329 : }
330 :
331 0 : return true;
332 : }
333 :
334 0 : bool Parse31013(ots::Font *font,
335 : const uint8_t *data, size_t length, uint16_t num_glyphs) {
336 0 : ots::Buffer subtable(data, length);
337 :
338 : // Format 13 tables are simple. We parse these and fully serialise them
339 : // later.
340 :
341 0 : if (!subtable.Skip(8)) {
342 0 : return OTS_FAILURE_MSG("Bad cmap subtable length");
343 : }
344 0 : uint32_t language = 0;
345 0 : if (!subtable.ReadU32(&language)) {
346 0 : return OTS_FAILURE_MSG("Can't read cmap subtable language");
347 : }
348 0 : if (language) {
349 0 : return OTS_FAILURE_MSG("Cmap subtable language should be zero but is %d", language);
350 : }
351 :
352 0 : uint32_t num_groups = 0;
353 0 : if (!subtable.ReadU32(&num_groups)) {
354 0 : return OTS_FAILURE_MSG("Can't read number of groups in a cmap subtable");
355 : }
356 :
357 : // We limit the number of groups in the same way as in 3.10.12 tables. See
358 : // the comment there in
359 0 : if (num_groups == 0 || subtable.remaining() / 12 < num_groups) {
360 0 : return OTS_FAILURE_MSG("Bad format 13 subtable group count %d", num_groups);
361 : }
362 :
363 : std::vector<ots::OpenTypeCMAPSubtableRange> &groups
364 0 : = font->cmap->subtable_3_10_13;
365 0 : groups.resize(num_groups);
366 :
367 0 : for (unsigned i = 0; i < num_groups; ++i) {
368 0 : if (!subtable.ReadU32(&groups[i].start_range) ||
369 0 : !subtable.ReadU32(&groups[i].end_range) ||
370 0 : !subtable.ReadU32(&groups[i].start_glyph_id)) {
371 0 : return OTS_FAILURE_MSG("Can't read subrange structure in a cmap subtable");
372 : }
373 :
374 : // We conservatively limit all of the values to protect some parsers from
375 : // overflows
376 0 : if (groups[i].start_range > kUnicodeUpperLimit ||
377 0 : groups[i].end_range > kUnicodeUpperLimit ||
378 0 : groups[i].start_glyph_id > 0xFFFF) {
379 0 : return OTS_FAILURE_MSG("Bad subrange with start_range=%d, end_range=%d, start_glyph_id=%d", groups[i].start_range, groups[i].end_range, groups[i].start_glyph_id);
380 : }
381 :
382 0 : if (groups[i].start_glyph_id >= num_glyphs) {
383 0 : return OTS_FAILURE_MSG("Subrange starting glyph id too high (%d > %d)", groups[i].start_glyph_id, num_glyphs);
384 : }
385 : }
386 :
387 : // the groups must be sorted by start code and may not overlap
388 0 : for (unsigned i = 1; i < num_groups; ++i) {
389 0 : if (groups[i].start_range <= groups[i - 1].start_range) {
390 0 : return OTS_FAILURE_MSG("Overlapping subrange starts (%d >= %d)", groups[i]. start_range, groups[i-1].start_range);
391 : }
392 0 : if (groups[i].start_range <= groups[i - 1].end_range) {
393 0 : return OTS_FAILURE_MSG("Overlapping subranges (%d <= %d)", groups[i].start_range, groups[i-1].end_range);
394 : }
395 : }
396 :
397 0 : return true;
398 : }
399 :
400 0 : bool Parse0514(ots::Font *font,
401 : const uint8_t *data, size_t length, uint16_t num_glyphs) {
402 : // Unicode Variation Selector table
403 0 : ots::Buffer subtable(data, length);
404 :
405 : // Format 14 tables are simple. We parse these and fully serialise them
406 : // later.
407 :
408 : // Skip format (USHORT) and length (ULONG)
409 0 : if (!subtable.Skip(6)) {
410 0 : return OTS_FAILURE_MSG("Can't read start of cmap subtable");
411 : }
412 :
413 0 : uint32_t num_records = 0;
414 0 : if (!subtable.ReadU32(&num_records)) {
415 0 : return OTS_FAILURE_MSG("Can't read number of records in cmap subtable");
416 : }
417 0 : if (num_records == 0 || num_records > kMaxCMAPSelectorRecords) {
418 0 : return OTS_FAILURE_MSG("Bad format 14 subtable records count %d", num_records);
419 : }
420 :
421 : std::vector<ots::OpenTypeCMAPSubtableVSRecord>& records
422 0 : = font->cmap->subtable_0_5_14;
423 0 : records.resize(num_records);
424 :
425 0 : for (unsigned i = 0; i < num_records; ++i) {
426 0 : if (!subtable.ReadU24(&records[i].var_selector) ||
427 0 : !subtable.ReadU32(&records[i].default_offset) ||
428 0 : !subtable.ReadU32(&records[i].non_default_offset)) {
429 0 : return OTS_FAILURE_MSG("Can't read record structure of record %d in cmap subtale", i);
430 : }
431 : // Checks the value of variation selector
432 0 : if (!((records[i].var_selector >= kMongolianVSStart &&
433 0 : records[i].var_selector <= kMongolianVSEnd) ||
434 0 : (records[i].var_selector >= kVSStart &&
435 0 : records[i].var_selector <= kVSEnd) ||
436 0 : (records[i].var_selector >= kIVSStart &&
437 0 : records[i].var_selector <= kIVSEnd))) {
438 0 : return OTS_FAILURE_MSG("Bad record variation selector (%04X) in record %i", records[i].var_selector, i);
439 : }
440 0 : if (i > 0 &&
441 0 : records[i-1].var_selector >= records[i].var_selector) {
442 0 : return OTS_FAILURE_MSG("Out of order variation selector (%04X >= %04X) in record %d", records[i-1].var_selector, records[i].var_selector, i);
443 : }
444 :
445 : // Checks offsets
446 0 : if (!records[i].default_offset && !records[i].non_default_offset) {
447 0 : return OTS_FAILURE_MSG("No default aoffset in variation selector record %d", i);
448 : }
449 0 : if (records[i].default_offset &&
450 0 : records[i].default_offset >= length) {
451 0 : return OTS_FAILURE_MSG("Default offset too high (%d >= %ld) in record %d", records[i].default_offset, length, i);
452 : }
453 0 : if (records[i].non_default_offset &&
454 0 : records[i].non_default_offset >= length) {
455 0 : return OTS_FAILURE_MSG("Non default offset too high (%d >= %ld) in record %d", records[i].non_default_offset, length, i);
456 : }
457 : }
458 :
459 0 : for (unsigned i = 0; i < num_records; ++i) {
460 : // Checks default UVS table
461 0 : if (records[i].default_offset) {
462 0 : subtable.set_offset(records[i].default_offset);
463 0 : uint32_t num_ranges = 0;
464 0 : if (!subtable.ReadU32(&num_ranges)) {
465 0 : return OTS_FAILURE_MSG("Can't read number of ranges in record %d", i);
466 : }
467 0 : if (num_ranges == 0 || subtable.remaining() / 4 < num_ranges) {
468 0 : return OTS_FAILURE_MSG("Bad number of ranges (%d) in record %d", num_ranges, i);
469 : }
470 :
471 0 : uint32_t last_unicode_value = 0;
472 : std::vector<ots::OpenTypeCMAPSubtableVSRange>& ranges
473 0 : = records[i].ranges;
474 0 : ranges.resize(num_ranges);
475 :
476 0 : for (unsigned j = 0; j < num_ranges; ++j) {
477 0 : if (!subtable.ReadU24(&ranges[j].unicode_value) ||
478 0 : !subtable.ReadU8(&ranges[j].additional_count)) {
479 0 : return OTS_FAILURE_MSG("Can't read range info in variation selector record %d", i);
480 : }
481 : const uint32_t check_value =
482 0 : ranges[j].unicode_value + ranges[j].additional_count;
483 0 : if (ranges[j].unicode_value == 0 ||
484 0 : ranges[j].unicode_value > kUnicodeUpperLimit ||
485 0 : check_value > kUVSUpperLimit ||
486 0 : (last_unicode_value &&
487 0 : ranges[j].unicode_value <= last_unicode_value)) {
488 0 : return OTS_FAILURE_MSG("Bad Unicode value *%04X) in variation selector range %d record %d", ranges[j].unicode_value, j, i);
489 : }
490 0 : last_unicode_value = check_value;
491 : }
492 : }
493 :
494 : // Checks non default UVS table
495 0 : if (records[i].non_default_offset) {
496 0 : subtable.set_offset(records[i].non_default_offset);
497 0 : uint32_t num_mappings = 0;
498 0 : if (!subtable.ReadU32(&num_mappings)) {
499 0 : return OTS_FAILURE_MSG("Can't read number of mappings in variation selector record %d", i);
500 : }
501 0 : if (num_mappings == 0 || subtable.remaining() / 5 < num_mappings) {
502 0 : return OTS_FAILURE_MSG("Bad number of mappings (%d) in variation selector record %d", num_mappings, i);
503 : }
504 :
505 0 : uint32_t last_unicode_value = 0;
506 : std::vector<ots::OpenTypeCMAPSubtableVSMapping>& mappings
507 0 : = records[i].mappings;
508 0 : mappings.resize(num_mappings);
509 :
510 0 : for (unsigned j = 0; j < num_mappings; ++j) {
511 0 : if (!subtable.ReadU24(&mappings[j].unicode_value) ||
512 0 : !subtable.ReadU16(&mappings[j].glyph_id)) {
513 0 : return OTS_FAILURE_MSG("Can't read mapping %d in variation selector record %d", j, i);
514 : }
515 0 : if (mappings[j].glyph_id == 0 ||
516 0 : mappings[j].unicode_value == 0 ||
517 0 : mappings[j].unicode_value > kUnicodeUpperLimit ||
518 0 : (last_unicode_value &&
519 0 : mappings[j].unicode_value <= last_unicode_value)) {
520 0 : return OTS_FAILURE_MSG("Bad mapping (%04X -> %d) in mapping %d of variation selector %d", mappings[j].unicode_value, mappings[j].glyph_id, j, i);
521 : }
522 0 : last_unicode_value = mappings[j].unicode_value;
523 : }
524 : }
525 : }
526 :
527 0 : if (subtable.offset() != length) {
528 0 : return OTS_FAILURE_MSG("Bad subtable offset (%ld != %ld)", subtable.offset(), length);
529 : }
530 0 : font->cmap->subtable_0_5_14_length = subtable.offset();
531 0 : return true;
532 : }
533 :
534 0 : bool Parse100(ots::Font *font, const uint8_t *data, size_t length) {
535 : // Mac Roman table
536 0 : ots::Buffer subtable(data, length);
537 :
538 0 : if (!subtable.Skip(4)) {
539 0 : return OTS_FAILURE_MSG("Bad cmap subtable");
540 : }
541 0 : uint16_t language = 0;
542 0 : if (!subtable.ReadU16(&language)) {
543 0 : return OTS_FAILURE_MSG("Can't read language in cmap subtable");
544 : }
545 0 : if (language) {
546 : // simsun.ttf has non-zero language id.
547 0 : OTS_WARNING("language id should be zero: %u", language);
548 : }
549 :
550 0 : font->cmap->subtable_1_0_0.reserve(kFormat0ArraySize);
551 0 : for (size_t i = 0; i < kFormat0ArraySize; ++i) {
552 0 : uint8_t glyph_id = 0;
553 0 : if (!subtable.ReadU8(&glyph_id)) {
554 0 : return OTS_FAILURE_MSG("Can't read glyph id at array[%ld] in cmap subtable", i);
555 : }
556 0 : font->cmap->subtable_1_0_0.push_back(glyph_id);
557 : }
558 :
559 0 : return true;
560 : }
561 :
562 : } // namespace
563 :
564 : namespace ots {
565 :
566 0 : bool ots_cmap_parse(Font *font, const uint8_t *data, size_t length) {
567 0 : Buffer table(data, length);
568 0 : font->cmap = new OpenTypeCMAP;
569 :
570 0 : uint16_t version = 0;
571 0 : uint16_t num_tables = 0;
572 0 : if (!table.ReadU16(&version) ||
573 0 : !table.ReadU16(&num_tables)) {
574 0 : return OTS_FAILURE_MSG("Can't read structure of cmap");
575 : }
576 :
577 0 : if (version != 0) {
578 0 : return OTS_FAILURE_MSG("Non zero cmap version (%d)", version);
579 : }
580 0 : if (!num_tables) {
581 0 : return OTS_FAILURE_MSG("No subtables in cmap!");
582 : }
583 :
584 0 : std::vector<CMAPSubtableHeader> subtable_headers;
585 :
586 : // read the subtable headers
587 0 : subtable_headers.reserve(num_tables);
588 0 : for (unsigned i = 0; i < num_tables; ++i) {
589 : CMAPSubtableHeader subt;
590 :
591 0 : if (!table.ReadU16(&subt.platform) ||
592 0 : !table.ReadU16(&subt.encoding) ||
593 0 : !table.ReadU32(&subt.offset)) {
594 0 : return OTS_FAILURE_MSG("Can't read subtable information cmap subtable %d", i);
595 : }
596 :
597 0 : subtable_headers.push_back(subt);
598 : }
599 :
600 0 : const size_t data_offset = table.offset();
601 :
602 : // make sure that all the offsets are valid.
603 0 : for (unsigned i = 0; i < num_tables; ++i) {
604 0 : if (subtable_headers[i].offset > 1024 * 1024 * 1024) {
605 0 : return OTS_FAILURE_MSG("Bad subtable offset in cmap subtable %d", i);
606 : }
607 0 : if (subtable_headers[i].offset < data_offset ||
608 0 : subtable_headers[i].offset >= length) {
609 0 : return OTS_FAILURE_MSG("Bad subtable offset (%d) in cmap subtable %d", subtable_headers[i].offset, i);
610 : }
611 : }
612 :
613 : // the format of the table is the first couple of bytes in the table. The
614 : // length of the table is stored in a format-specific way.
615 0 : for (unsigned i = 0; i < num_tables; ++i) {
616 0 : table.set_offset(subtable_headers[i].offset);
617 0 : if (!table.ReadU16(&subtable_headers[i].format)) {
618 0 : return OTS_FAILURE_MSG("Can't read cmap subtable header format %d", i);
619 : }
620 :
621 0 : uint16_t len = 0;
622 0 : uint16_t lang = 0;
623 0 : switch (subtable_headers[i].format) {
624 : case 0:
625 : case 4:
626 0 : if (!table.ReadU16(&len)) {
627 0 : return OTS_FAILURE_MSG("Can't read cmap subtable %d length", i);
628 : }
629 0 : if (!table.ReadU16(&lang)) {
630 0 : return OTS_FAILURE_MSG("Can't read cmap subtable %d language", i);
631 : }
632 0 : subtable_headers[i].length = len;
633 0 : subtable_headers[i].language = lang;
634 0 : break;
635 : case 12:
636 : case 13:
637 0 : if (!table.Skip(2)) {
638 0 : return OTS_FAILURE_MSG("Bad cmap subtable %d structure", i);
639 : }
640 0 : if (!table.ReadU32(&subtable_headers[i].length)) {
641 0 : return OTS_FAILURE_MSG("Can read cmap subtable %d length", i);
642 : }
643 0 : if (!table.ReadU32(&subtable_headers[i].language)) {
644 0 : return OTS_FAILURE_MSG("Can't read cmap subtable %d language", i);
645 : }
646 0 : break;
647 : case 14:
648 0 : if (!table.ReadU32(&subtable_headers[i].length)) {
649 0 : return OTS_FAILURE_MSG("Can't read cmap subtable %d length", i);
650 : }
651 0 : subtable_headers[i].language = 0;
652 0 : break;
653 : default:
654 0 : subtable_headers[i].length = 0;
655 0 : subtable_headers[i].language = 0;
656 0 : break;
657 : }
658 : }
659 :
660 : // check if the table is sorted first by platform ID, then by encoding ID.
661 0 : for (unsigned i = 1; i < num_tables; ++i) {
662 0 : if (subtable_headers[i - 1].platform > subtable_headers[i].platform ||
663 0 : (subtable_headers[i - 1].platform == subtable_headers[i].platform &&
664 0 : (subtable_headers[i - 1].encoding > subtable_headers[i].encoding ||
665 0 : (subtable_headers[i - 1].encoding == subtable_headers[i].encoding &&
666 0 : subtable_headers[i - 1].language > subtable_headers[i].language))))
667 0 : OTS_WARNING("subtable %d with platform ID %d, encoding ID %d, language ID %d "
668 : "following subtable with platform ID %d, encoding ID %d, language ID %d",
669 : i,
670 : subtable_headers[i].platform,
671 : subtable_headers[i].encoding,
672 : subtable_headers[i].language,
673 : subtable_headers[i - 1].platform,
674 : subtable_headers[i - 1].encoding,
675 0 : subtable_headers[i - 1].language);
676 : }
677 :
678 : // Now, verify that all the lengths are sane
679 0 : for (unsigned i = 0; i < num_tables; ++i) {
680 0 : if (!subtable_headers[i].length) continue;
681 0 : if (subtable_headers[i].length > 1024 * 1024 * 1024) {
682 0 : return OTS_FAILURE_MSG("Bad cmap subtable %d length", i);
683 : }
684 : // We know that both the offset and length are < 1GB, so the following
685 : // addition doesn't overflow
686 : const uint32_t end_byte
687 0 : = subtable_headers[i].offset + subtable_headers[i].length;
688 0 : if (end_byte > length) {
689 0 : return OTS_FAILURE_MSG("Over long cmap subtable %d @ %d for %d", i, subtable_headers[i].offset, subtable_headers[i].length);
690 : }
691 : }
692 :
693 : // check that the cmap subtables are not overlapping.
694 0 : std::set<std::pair<uint32_t, uint32_t> > uniq_checker;
695 0 : std::vector<std::pair<uint32_t, uint8_t> > overlap_checker;
696 0 : for (unsigned i = 0; i < num_tables; ++i) {
697 : const uint32_t end_byte
698 0 : = subtable_headers[i].offset + subtable_headers[i].length;
699 :
700 0 : if (!uniq_checker.insert(std::make_pair(subtable_headers[i].offset,
701 0 : end_byte)).second) {
702 : // Sometimes Unicode table and MS table share exactly the same data.
703 : // We'll allow this.
704 0 : continue;
705 : }
706 : overlap_checker.push_back(
707 0 : std::make_pair(subtable_headers[i].offset,
708 0 : static_cast<uint8_t>(1) /* start */));
709 : overlap_checker.push_back(
710 0 : std::make_pair(end_byte, static_cast<uint8_t>(0) /* end */));
711 : }
712 0 : std::sort(overlap_checker.begin(), overlap_checker.end());
713 0 : int overlap_count = 0;
714 0 : for (unsigned i = 0; i < overlap_checker.size(); ++i) {
715 0 : overlap_count += (overlap_checker[i].second ? 1 : -1);
716 0 : if (overlap_count > 1) {
717 0 : return OTS_FAILURE_MSG("Excessive overlap count %d", overlap_count);
718 : }
719 : }
720 :
721 : // we grab the number of glyphs in the file from the maxp table to make sure
722 : // that the character map isn't referencing anything beyound this range.
723 0 : if (!font->maxp) {
724 0 : return OTS_FAILURE_MSG("No maxp table in font! Needed by cmap.");
725 : }
726 0 : const uint16_t num_glyphs = font->maxp->num_glyphs;
727 :
728 : // We only support a subset of the possible character map tables. Microsoft
729 : // 'strongly recommends' that everyone supports the Unicode BMP table with
730 : // the UCS-4 table for non-BMP glyphs. We'll pass the following subtables:
731 : // Platform ID Encoding ID Format
732 : // 0 0 4 (Unicode Default)
733 : // 0 1 4 (Unicode 1.1)
734 : // 0 3 4 (Unicode BMP)
735 : // 0 3 12 (Unicode UCS-4)
736 : // 0 5 14 (Unicode Variation Sequences)
737 : // 1 0 0 (Mac Roman)
738 : // 3 0 4 (MS Symbol)
739 : // 3 1 4 (MS Unicode BMP)
740 : // 3 10 12 (MS Unicode UCS-4)
741 : // 3 10 13 (MS UCS-4 Fallback mapping)
742 : //
743 : // Note:
744 : // * 0-0-4 and 0-1-4 tables are (usually) written as a 3-1-4 table. If 3-1-4 table
745 : // also exists, the 0-0-4 or 0-1-4 tables are ignored.
746 : // * Unlike 0-0-4 table, 0-3-4 table is written as a 0-3-4 table.
747 : // Some fonts which include 0-5-14 table seems to be required 0-3-4
748 : // table. The 0-3-4 table will be wriiten even if 3-1-4 table also exists.
749 : // * 0-3-12 table is written as a 3-10-12 table. If 3-10-12 table also
750 : // exists, the 0-3-12 table is ignored.
751 : //
752 :
753 0 : for (unsigned i = 0; i < num_tables; ++i) {
754 0 : if (subtable_headers[i].platform == 0) {
755 : // Unicode platform
756 :
757 0 : if ((subtable_headers[i].encoding == 0 || subtable_headers[i].encoding == 1) &&
758 0 : (subtable_headers[i].format == 4)) {
759 : // parse and output the 0-0-4 and 0-1-4 tables as 3-1-4 table. Sometimes the 0-0-4
760 : // table actually points to MS symbol data and thus should be parsed as
761 : // 3-0-4 table (e.g., marqueem.ttf and quixotic.ttf). This error will be
762 : // recovered in ots_cmap_serialise().
763 0 : if (!ParseFormat4(font, 3, 1, data + subtable_headers[i].offset,
764 0 : subtable_headers[i].length, num_glyphs)) {
765 0 : return OTS_FAILURE_MSG("Failed to parse format 4 cmap subtable %d", i);
766 : }
767 0 : } else if ((subtable_headers[i].encoding == 3) &&
768 0 : (subtable_headers[i].format == 4)) {
769 : // parse and output the 0-3-4 table as 0-3-4 table.
770 0 : if (!ParseFormat4(font, 0, 3, data + subtable_headers[i].offset,
771 0 : subtable_headers[i].length, num_glyphs)) {
772 0 : return OTS_FAILURE_MSG("Failed to parse format 4 cmap subtable %d", i);
773 : }
774 0 : } else if ((subtable_headers[i].encoding == 3) &&
775 0 : (subtable_headers[i].format == 12)) {
776 : // parse and output the 0-3-12 table as 3-10-12 table.
777 0 : if (!Parse31012(font, data + subtable_headers[i].offset,
778 0 : subtable_headers[i].length, num_glyphs)) {
779 0 : return OTS_FAILURE_MSG("Failed to parse format 12 cmap subtable %d", i);
780 : }
781 0 : } else if ((subtable_headers[i].encoding == 5) &&
782 0 : (subtable_headers[i].format == 14)) {
783 0 : if (!Parse0514(font, data + subtable_headers[i].offset,
784 0 : subtable_headers[i].length, num_glyphs)) {
785 0 : return OTS_FAILURE_MSG("Failed to parse format 14 cmap subtable %d", i);
786 : }
787 : }
788 0 : } else if (subtable_headers[i].platform == 1) {
789 : // Mac platform
790 :
791 0 : if ((subtable_headers[i].encoding == 0) &&
792 0 : (subtable_headers[i].format == 0)) {
793 : // parse and output the 1-0-0 table.
794 0 : if (!Parse100(font, data + subtable_headers[i].offset,
795 0 : subtable_headers[i].length)) {
796 0 : return OTS_FAILURE();
797 : }
798 : }
799 0 : } else if (subtable_headers[i].platform == 3) {
800 : // MS platform
801 :
802 0 : switch (subtable_headers[i].encoding) {
803 : case 0:
804 : case 1:
805 0 : if (subtable_headers[i].format == 4) {
806 : // parse 3-0-4 or 3-1-4 table.
807 0 : if (!ParseFormat4(font, subtable_headers[i].platform,
808 0 : subtable_headers[i].encoding,
809 0 : data + subtable_headers[i].offset,
810 0 : subtable_headers[i].length, num_glyphs)) {
811 0 : return OTS_FAILURE();
812 : }
813 : }
814 0 : break;
815 : case 10:
816 0 : if (subtable_headers[i].format == 12) {
817 0 : font->cmap->subtable_3_10_12.clear();
818 0 : if (!Parse31012(font, data + subtable_headers[i].offset,
819 0 : subtable_headers[i].length, num_glyphs)) {
820 0 : return OTS_FAILURE();
821 : }
822 0 : } else if (subtable_headers[i].format == 13) {
823 0 : font->cmap->subtable_3_10_13.clear();
824 0 : if (!Parse31013(font, data + subtable_headers[i].offset,
825 0 : subtable_headers[i].length, num_glyphs)) {
826 0 : return OTS_FAILURE();
827 : }
828 : }
829 0 : break;
830 : }
831 : }
832 : }
833 :
834 0 : return true;
835 : }
836 :
837 0 : bool ots_cmap_should_serialise(Font *font) {
838 0 : return font->cmap != NULL;
839 : }
840 :
841 0 : bool ots_cmap_serialise(OTSStream *out, Font *font) {
842 0 : const bool have_034 = font->cmap->subtable_0_3_4_data != NULL;
843 0 : const bool have_0514 = font->cmap->subtable_0_5_14.size() != 0;
844 0 : const bool have_100 = font->cmap->subtable_1_0_0.size() != 0;
845 0 : const bool have_304 = font->cmap->subtable_3_0_4_data != NULL;
846 : // MS Symbol and MS Unicode tables should not co-exist.
847 : // See the comment above in 0-0-4 parser.
848 0 : const bool have_314 = (!have_304) && font->cmap->subtable_3_1_4_data;
849 0 : const bool have_31012 = font->cmap->subtable_3_10_12.size() != 0;
850 0 : const bool have_31013 = font->cmap->subtable_3_10_13.size() != 0;
851 0 : const uint16_t num_subtables = static_cast<uint16_t>(have_034) +
852 0 : static_cast<uint16_t>(have_0514) +
853 0 : static_cast<uint16_t>(have_100) +
854 0 : static_cast<uint16_t>(have_304) +
855 0 : static_cast<uint16_t>(have_314) +
856 0 : static_cast<uint16_t>(have_31012) +
857 0 : static_cast<uint16_t>(have_31013);
858 0 : const off_t table_start = out->Tell();
859 :
860 : // Some fonts don't have 3-0-4 MS Symbol nor 3-1-4 Unicode BMP tables
861 : // (e.g., old fonts for Mac). We don't support them.
862 0 : if (!have_304 && !have_314 && !have_034 && !have_31012 && !have_31013) {
863 0 : return OTS_FAILURE_MSG("no supported subtables were found");
864 : }
865 :
866 0 : if (!out->WriteU16(0) ||
867 0 : !out->WriteU16(num_subtables)) {
868 0 : return OTS_FAILURE();
869 : }
870 :
871 0 : const off_t record_offset = out->Tell();
872 0 : if (!out->Pad(num_subtables * 8)) {
873 0 : return OTS_FAILURE();
874 : }
875 :
876 0 : const off_t offset_034 = out->Tell();
877 0 : if (have_034) {
878 0 : if (!out->Write(font->cmap->subtable_0_3_4_data,
879 0 : font->cmap->subtable_0_3_4_length)) {
880 0 : return OTS_FAILURE();
881 : }
882 : }
883 :
884 0 : const off_t offset_0514 = out->Tell();
885 0 : if (have_0514) {
886 : const std::vector<ots::OpenTypeCMAPSubtableVSRecord> &records
887 0 : = font->cmap->subtable_0_5_14;
888 0 : const unsigned num_records = records.size();
889 0 : if (!out->WriteU16(14) ||
890 0 : !out->WriteU32(font->cmap->subtable_0_5_14_length) ||
891 0 : !out->WriteU32(num_records)) {
892 0 : return OTS_FAILURE();
893 : }
894 0 : for (unsigned i = 0; i < num_records; ++i) {
895 0 : if (!out->WriteU24(records[i].var_selector) ||
896 0 : !out->WriteU32(records[i].default_offset) ||
897 0 : !out->WriteU32(records[i].non_default_offset)) {
898 0 : return OTS_FAILURE();
899 : }
900 : }
901 0 : for (unsigned i = 0; i < num_records; ++i) {
902 0 : if (records[i].default_offset) {
903 : const std::vector<ots::OpenTypeCMAPSubtableVSRange> &ranges
904 0 : = records[i].ranges;
905 0 : const unsigned num_ranges = ranges.size();
906 0 : if (!out->Seek(records[i].default_offset + offset_0514) ||
907 0 : !out->WriteU32(num_ranges)) {
908 0 : return OTS_FAILURE();
909 : }
910 0 : for (unsigned j = 0; j < num_ranges; ++j) {
911 0 : if (!out->WriteU24(ranges[j].unicode_value) ||
912 0 : !out->WriteU8(ranges[j].additional_count)) {
913 0 : return OTS_FAILURE();
914 : }
915 : }
916 : }
917 0 : if (records[i].non_default_offset) {
918 : const std::vector<ots::OpenTypeCMAPSubtableVSMapping> &mappings
919 0 : = records[i].mappings;
920 0 : const unsigned num_mappings = mappings.size();
921 0 : if (!out->Seek(records[i].non_default_offset + offset_0514) ||
922 0 : !out->WriteU32(num_mappings)) {
923 0 : return OTS_FAILURE();
924 : }
925 0 : for (unsigned j = 0; j < num_mappings; ++j) {
926 0 : if (!out->WriteU24(mappings[j].unicode_value) ||
927 0 : !out->WriteU16(mappings[j].glyph_id)) {
928 0 : return OTS_FAILURE();
929 : }
930 : }
931 : }
932 : }
933 : }
934 :
935 0 : const off_t offset_100 = out->Tell();
936 0 : if (have_100) {
937 0 : if (!out->WriteU16(0) || // format
938 0 : !out->WriteU16(6 + kFormat0ArraySize) || // length
939 0 : !out->WriteU16(0)) { // language
940 0 : return OTS_FAILURE();
941 : }
942 0 : if (!out->Write(&(font->cmap->subtable_1_0_0[0]), kFormat0ArraySize)) {
943 0 : return OTS_FAILURE();
944 : }
945 : }
946 :
947 0 : const off_t offset_304 = out->Tell();
948 0 : if (have_304) {
949 0 : if (!out->Write(font->cmap->subtable_3_0_4_data,
950 0 : font->cmap->subtable_3_0_4_length)) {
951 0 : return OTS_FAILURE();
952 : }
953 : }
954 :
955 0 : const off_t offset_314 = out->Tell();
956 0 : if (have_314) {
957 0 : if (!out->Write(font->cmap->subtable_3_1_4_data,
958 0 : font->cmap->subtable_3_1_4_length)) {
959 0 : return OTS_FAILURE();
960 : }
961 : }
962 :
963 0 : const off_t offset_31012 = out->Tell();
964 0 : if (have_31012) {
965 : std::vector<OpenTypeCMAPSubtableRange> &groups
966 0 : = font->cmap->subtable_3_10_12;
967 0 : const unsigned num_groups = groups.size();
968 0 : if (!out->WriteU16(12) ||
969 0 : !out->WriteU16(0) ||
970 0 : !out->WriteU32(num_groups * 12 + 16) ||
971 0 : !out->WriteU32(0) ||
972 0 : !out->WriteU32(num_groups)) {
973 0 : return OTS_FAILURE();
974 : }
975 :
976 0 : for (unsigned i = 0; i < num_groups; ++i) {
977 0 : if (!out->WriteU32(groups[i].start_range) ||
978 0 : !out->WriteU32(groups[i].end_range) ||
979 0 : !out->WriteU32(groups[i].start_glyph_id)) {
980 0 : return OTS_FAILURE();
981 : }
982 : }
983 : }
984 :
985 0 : const off_t offset_31013 = out->Tell();
986 0 : if (have_31013) {
987 : std::vector<OpenTypeCMAPSubtableRange> &groups
988 0 : = font->cmap->subtable_3_10_13;
989 0 : const unsigned num_groups = groups.size();
990 0 : if (!out->WriteU16(13) ||
991 0 : !out->WriteU16(0) ||
992 0 : !out->WriteU32(num_groups * 12 + 16) ||
993 0 : !out->WriteU32(0) ||
994 0 : !out->WriteU32(num_groups)) {
995 0 : return OTS_FAILURE();
996 : }
997 :
998 0 : for (unsigned i = 0; i < num_groups; ++i) {
999 0 : if (!out->WriteU32(groups[i].start_range) ||
1000 0 : !out->WriteU32(groups[i].end_range) ||
1001 0 : !out->WriteU32(groups[i].start_glyph_id)) {
1002 0 : return OTS_FAILURE();
1003 : }
1004 : }
1005 : }
1006 :
1007 0 : const off_t table_end = out->Tell();
1008 :
1009 : // Now seek back and write the table of offsets
1010 0 : if (!out->Seek(record_offset)) {
1011 0 : return OTS_FAILURE();
1012 : }
1013 :
1014 0 : if (have_034) {
1015 0 : if (!out->WriteU16(0) ||
1016 0 : !out->WriteU16(3) ||
1017 0 : !out->WriteU32(offset_034 - table_start)) {
1018 0 : return OTS_FAILURE();
1019 : }
1020 : }
1021 :
1022 0 : if (have_0514) {
1023 0 : if (!out->WriteU16(0) ||
1024 0 : !out->WriteU16(5) ||
1025 0 : !out->WriteU32(offset_0514 - table_start)) {
1026 0 : return OTS_FAILURE();
1027 : }
1028 : }
1029 :
1030 0 : if (have_100) {
1031 0 : if (!out->WriteU16(1) ||
1032 0 : !out->WriteU16(0) ||
1033 0 : !out->WriteU32(offset_100 - table_start)) {
1034 0 : return OTS_FAILURE();
1035 : }
1036 : }
1037 :
1038 0 : if (have_304) {
1039 0 : if (!out->WriteU16(3) ||
1040 0 : !out->WriteU16(0) ||
1041 0 : !out->WriteU32(offset_304 - table_start)) {
1042 0 : return OTS_FAILURE();
1043 : }
1044 : }
1045 :
1046 0 : if (have_314) {
1047 0 : if (!out->WriteU16(3) ||
1048 0 : !out->WriteU16(1) ||
1049 0 : !out->WriteU32(offset_314 - table_start)) {
1050 0 : return OTS_FAILURE();
1051 : }
1052 : }
1053 :
1054 0 : if (have_31012) {
1055 0 : if (!out->WriteU16(3) ||
1056 0 : !out->WriteU16(10) ||
1057 0 : !out->WriteU32(offset_31012 - table_start)) {
1058 0 : return OTS_FAILURE();
1059 : }
1060 : }
1061 :
1062 0 : if (have_31013) {
1063 0 : if (!out->WriteU16(3) ||
1064 0 : !out->WriteU16(10) ||
1065 0 : !out->WriteU32(offset_31013 - table_start)) {
1066 0 : return OTS_FAILURE();
1067 : }
1068 : }
1069 :
1070 0 : if (!out->Seek(table_end)) {
1071 0 : return OTS_FAILURE();
1072 : }
1073 :
1074 0 : return true;
1075 : }
1076 :
1077 0 : void ots_cmap_reuse(Font *font, Font *other) {
1078 0 : font->cmap = other->cmap;
1079 0 : font->cmap_reused = true;
1080 0 : }
1081 :
1082 0 : void ots_cmap_free(Font *font) {
1083 0 : delete font->cmap;
1084 0 : }
1085 :
1086 : } // namespace ots
1087 :
1088 : #undef TABLE_NAME
|