OLD | NEW |
| (Empty) |
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 "kern.h" | |
6 | |
7 // kern - Kerning | |
8 // http://www.microsoft.com/typography/otspec/kern.htm | |
9 | |
10 #define TABLE_NAME "kern" | |
11 | |
12 #define DROP_THIS_TABLE(msg_) \ | |
13 do { \ | |
14 OTS_FAILURE_MSG(msg_ ", table discarded"); \ | |
15 delete file->kern; \ | |
16 file->kern = 0; \ | |
17 } while (0) | |
18 | |
19 namespace ots { | |
20 | |
21 bool ots_kern_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { | |
22 Buffer table(data, length); | |
23 | |
24 OpenTypeKERN *kern = new OpenTypeKERN; | |
25 file->kern = kern; | |
26 | |
27 uint16_t num_tables = 0; | |
28 if (!table.ReadU16(&kern->version) || | |
29 !table.ReadU16(&num_tables)) { | |
30 return OTS_FAILURE_MSG("Failed to read kern header"); | |
31 } | |
32 | |
33 if (kern->version > 0) { | |
34 DROP_THIS_TABLE("bad table version"); | |
35 return true; | |
36 } | |
37 | |
38 if (num_tables == 0) { | |
39 DROP_THIS_TABLE("num_tables is zero"); | |
40 return true; | |
41 } | |
42 | |
43 kern->subtables.reserve(num_tables); | |
44 for (unsigned i = 0; i < num_tables; ++i) { | |
45 OpenTypeKERNFormat0 subtable; | |
46 uint16_t sub_length = 0; | |
47 | |
48 if (!table.ReadU16(&subtable.version) || | |
49 !table.ReadU16(&sub_length)) { | |
50 return OTS_FAILURE_MSG("Failed to read kern subtable %d header", i); | |
51 } | |
52 | |
53 if (subtable.version > 0) { | |
54 OTS_WARNING("Bad subtable version: %d", subtable.version); | |
55 continue; | |
56 } | |
57 | |
58 const size_t current_offset = table.offset(); | |
59 if (current_offset - 4 + sub_length > length) { | |
60 return OTS_FAILURE_MSG("Bad kern subtable %d offset %ld", i, current_offse
t); | |
61 } | |
62 | |
63 if (!table.ReadU16(&subtable.coverage)) { | |
64 return OTS_FAILURE_MSG("Cailed to read kern subtable %d coverage", i); | |
65 } | |
66 | |
67 if (!(subtable.coverage & 0x1)) { | |
68 OTS_WARNING( | |
69 "We don't support vertical data as the renderer doesn't support it."); | |
70 continue; | |
71 } | |
72 if (subtable.coverage & 0xF0) { | |
73 DROP_THIS_TABLE("Reserved fields should zero-filled."); | |
74 return true; | |
75 } | |
76 const uint32_t format = (subtable.coverage & 0xFF00) >> 8; | |
77 if (format != 0) { | |
78 OTS_WARNING("Format %d is not supported.", format); | |
79 continue; | |
80 } | |
81 | |
82 // Parse the format 0 field. | |
83 uint16_t num_pairs = 0; | |
84 if (!table.ReadU16(&num_pairs) || | |
85 !table.ReadU16(&subtable.search_range) || | |
86 !table.ReadU16(&subtable.entry_selector) || | |
87 !table.ReadU16(&subtable.range_shift)) { | |
88 return OTS_FAILURE_MSG("Failed to read kern subtable %d format 0 fields",
i); | |
89 } | |
90 | |
91 if (!num_pairs) { | |
92 DROP_THIS_TABLE("Zero length subtable is found."); | |
93 return true; | |
94 } | |
95 | |
96 // Sanity checks for search_range, entry_selector, and range_shift. See the | |
97 // comment in ots.cc for details. | |
98 const size_t kFormat0PairSize = 6; // left, right, and value. 2 bytes each. | |
99 if (num_pairs > (65536 / kFormat0PairSize)) { | |
100 // Some fonts (e.g. calibri.ttf, pykes_peak_zero.ttf) have pairs >= 10923. | |
101 DROP_THIS_TABLE("Too large subtable."); | |
102 return true; | |
103 } | |
104 unsigned max_pow2 = 0; | |
105 while (1u << (max_pow2 + 1) <= num_pairs) { | |
106 ++max_pow2; | |
107 } | |
108 const uint16_t expected_search_range = (1u << max_pow2) * kFormat0PairSize; | |
109 if (subtable.search_range != expected_search_range) { | |
110 OTS_WARNING("bad search range"); | |
111 subtable.search_range = expected_search_range; | |
112 } | |
113 if (subtable.entry_selector != max_pow2) { | |
114 return OTS_FAILURE_MSG("Bad subtable %d entry selector %d", i, subtable.en
try_selector); | |
115 } | |
116 const uint16_t expected_range_shift = | |
117 kFormat0PairSize * num_pairs - subtable.search_range; | |
118 if (subtable.range_shift != expected_range_shift) { | |
119 OTS_WARNING("bad range shift"); | |
120 subtable.range_shift = expected_range_shift; | |
121 } | |
122 | |
123 // Read kerning pairs. | |
124 subtable.pairs.reserve(num_pairs); | |
125 uint32_t last_pair = 0; | |
126 for (unsigned j = 0; j < num_pairs; ++j) { | |
127 OpenTypeKERNFormat0Pair kerning_pair; | |
128 if (!table.ReadU16(&kerning_pair.left) || | |
129 !table.ReadU16(&kerning_pair.right) || | |
130 !table.ReadS16(&kerning_pair.value)) { | |
131 return OTS_FAILURE_MSG("Failed to read subtable %d kerning pair %d", i,
j); | |
132 } | |
133 const uint32_t current_pair | |
134 = (kerning_pair.left << 16) + kerning_pair.right; | |
135 if (j != 0 && current_pair <= last_pair) { | |
136 // Many free fonts don't follow this rule, so we don't call OTS_FAILURE | |
137 // in order to support these fonts. | |
138 DROP_THIS_TABLE("Kerning pairs are not sorted."); | |
139 return true; | |
140 } | |
141 last_pair = current_pair; | |
142 subtable.pairs.push_back(kerning_pair); | |
143 } | |
144 | |
145 kern->subtables.push_back(subtable); | |
146 } | |
147 | |
148 if (!kern->subtables.size()) { | |
149 DROP_THIS_TABLE("All subtables are removed."); | |
150 return true; | |
151 } | |
152 | |
153 return true; | |
154 } | |
155 | |
156 bool ots_kern_should_serialise(OpenTypeFile *file) { | |
157 if (!file->glyf) return false; // this table is not for CFF fonts. | |
158 return file->kern != NULL; | |
159 } | |
160 | |
161 bool ots_kern_serialise(OTSStream *out, OpenTypeFile *file) { | |
162 const OpenTypeKERN *kern = file->kern; | |
163 | |
164 const uint16_t num_subtables = static_cast<uint16_t>(kern->subtables.size()); | |
165 if (num_subtables != kern->subtables.size() || | |
166 !out->WriteU16(kern->version) || | |
167 !out->WriteU16(num_subtables)) { | |
168 return OTS_FAILURE_MSG("Can't write kern table header"); | |
169 } | |
170 | |
171 for (uint16_t i = 0; i < num_subtables; ++i) { | |
172 const size_t length = 14 + (6 * kern->subtables[i].pairs.size()); | |
173 if (length > std::numeric_limits<uint16_t>::max() || | |
174 !out->WriteU16(kern->subtables[i].version) || | |
175 !out->WriteU16(static_cast<uint16_t>(length)) || | |
176 !out->WriteU16(kern->subtables[i].coverage) || | |
177 !out->WriteU16( | |
178 static_cast<uint16_t>(kern->subtables[i].pairs.size())) || | |
179 !out->WriteU16(kern->subtables[i].search_range) || | |
180 !out->WriteU16(kern->subtables[i].entry_selector) || | |
181 !out->WriteU16(kern->subtables[i].range_shift)) { | |
182 return OTS_FAILURE_MSG("Failed to write kern subtable %d", i); | |
183 } | |
184 for (unsigned j = 0; j < kern->subtables[i].pairs.size(); ++j) { | |
185 if (!out->WriteU16(kern->subtables[i].pairs[j].left) || | |
186 !out->WriteU16(kern->subtables[i].pairs[j].right) || | |
187 !out->WriteS16(kern->subtables[i].pairs[j].value)) { | |
188 return OTS_FAILURE_MSG("Failed to write kern pair %d for subtable %d", j
, i); | |
189 } | |
190 } | |
191 } | |
192 | |
193 return true; | |
194 } | |
195 | |
196 void ots_kern_free(OpenTypeFile *file) { | |
197 delete file->kern; | |
198 } | |
199 | |
200 } // namespace ots | |
201 | |
202 #undef TABLE_NAME | |
203 #undef DROP_THIS_TABLE | |
OLD | NEW |