gfx/ots/src/kern.cc

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

mercurial