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 "vdmx.h" | |
6 | |
7 // VDMX - Vertical Device Metrics | |
8 // http://www.microsoft.com/typography/otspec/vdmx.htm | |
9 | |
10 #define TABLE_NAME "VDMX" | |
11 | |
12 #define DROP_THIS_TABLE(...) \ | |
13 do { \ | |
14 OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \ | |
15 OTS_FAILURE_MSG("Table discarded"); \ | |
16 delete file->vdmx; \ | |
17 file->vdmx = 0; \ | |
18 } while (0) | |
19 | |
20 namespace ots { | |
21 | |
22 bool ots_vdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { | |
23 Buffer table(data, length); | |
24 file->vdmx = new OpenTypeVDMX; | |
25 OpenTypeVDMX * const vdmx = file->vdmx; | |
26 | |
27 if (!table.ReadU16(&vdmx->version) || | |
28 !table.ReadU16(&vdmx->num_recs) || | |
29 !table.ReadU16(&vdmx->num_ratios)) { | |
30 return OTS_FAILURE_MSG("Failed to read table header"); | |
31 } | |
32 | |
33 if (vdmx->version > 1) { | |
34 DROP_THIS_TABLE("bad version: %u", vdmx->version); | |
35 return true; // continue transcoding | |
36 } | |
37 | |
38 vdmx->rat_ranges.reserve(vdmx->num_ratios); | |
39 for (unsigned i = 0; i < vdmx->num_ratios; ++i) { | |
40 OpenTypeVDMXRatioRecord rec; | |
41 | |
42 if (!table.ReadU8(&rec.charset) || | |
43 !table.ReadU8(&rec.x_ratio) || | |
44 !table.ReadU8(&rec.y_start_ratio) || | |
45 !table.ReadU8(&rec.y_end_ratio)) { | |
46 return OTS_FAILURE_MSG("Failed to read ratio header %d", i); | |
47 } | |
48 | |
49 if (rec.charset > 1) { | |
50 DROP_THIS_TABLE("bad charset: %u", rec.charset); | |
51 return true; | |
52 } | |
53 | |
54 if (rec.y_start_ratio > rec.y_end_ratio) { | |
55 DROP_THIS_TABLE("bad y ratio"); | |
56 return true; | |
57 } | |
58 | |
59 // All values set to zero signal the default grouping to use; | |
60 // if present, this must be the last Ratio group in the table. | |
61 if ((i < vdmx->num_ratios - 1u) && | |
62 (rec.x_ratio == 0) && | |
63 (rec.y_start_ratio == 0) && | |
64 (rec.y_end_ratio == 0)) { | |
65 // workaround for fonts which have 2 or more {0, 0, 0} terminators. | |
66 DROP_THIS_TABLE("superfluous terminator found"); | |
67 return true; | |
68 } | |
69 | |
70 vdmx->rat_ranges.push_back(rec); | |
71 } | |
72 | |
73 vdmx->offsets.reserve(vdmx->num_ratios); | |
74 const size_t current_offset = table.offset(); | |
75 // current_offset is less than (2 bytes * 3) + (4 bytes * USHRT_MAX) = 256k. | |
76 for (unsigned i = 0; i < vdmx->num_ratios; ++i) { | |
77 uint16_t offset; | |
78 if (!table.ReadU16(&offset)) { | |
79 return OTS_FAILURE_MSG("Failed to read ratio offset %d", i); | |
80 } | |
81 if (current_offset + offset >= length) { // thus doesn't overflow. | |
82 return OTS_FAILURE_MSG("Bad ratio offset %d for ration %d", offset, i); | |
83 } | |
84 | |
85 vdmx->offsets.push_back(offset); | |
86 } | |
87 | |
88 vdmx->groups.reserve(vdmx->num_recs); | |
89 for (unsigned i = 0; i < vdmx->num_recs; ++i) { | |
90 OpenTypeVDMXGroup group; | |
91 if (!table.ReadU16(&group.recs) || | |
92 !table.ReadU8(&group.startsz) || | |
93 !table.ReadU8(&group.endsz)) { | |
94 return OTS_FAILURE_MSG("Failed to read record header %d", i); | |
95 } | |
96 group.entries.reserve(group.recs); | |
97 for (unsigned j = 0; j < group.recs; ++j) { | |
98 OpenTypeVDMXVTable vt; | |
99 if (!table.ReadU16(&vt.y_pel_height) || | |
100 !table.ReadS16(&vt.y_max) || | |
101 !table.ReadS16(&vt.y_min)) { | |
102 return OTS_FAILURE_MSG("Failed to read reacord %d group %d", i, j); | |
103 } | |
104 if (vt.y_max < vt.y_min) { | |
105 DROP_THIS_TABLE("bad y min/max"); | |
106 return true; | |
107 } | |
108 | |
109 // This table must appear in sorted order (sorted by yPelHeight), | |
110 // but need not be continuous. | |
111 if ((j != 0) && (group.entries[j - 1].y_pel_height >= vt.y_pel_height)) { | |
112 DROP_THIS_TABLE("the table is not sorted"); | |
113 return true; | |
114 } | |
115 | |
116 group.entries.push_back(vt); | |
117 } | |
118 vdmx->groups.push_back(group); | |
119 } | |
120 | |
121 return true; | |
122 } | |
123 | |
124 bool ots_vdmx_should_serialise(OpenTypeFile *file) { | |
125 if (!file->glyf) return false; // this table is not for CFF fonts. | |
126 return file->vdmx != NULL; | |
127 } | |
128 | |
129 bool ots_vdmx_serialise(OTSStream *out, OpenTypeFile *file) { | |
130 OpenTypeVDMX * const vdmx = file->vdmx; | |
131 | |
132 if (!out->WriteU16(vdmx->version) || | |
133 !out->WriteU16(vdmx->num_recs) || | |
134 !out->WriteU16(vdmx->num_ratios)) { | |
135 return OTS_FAILURE_MSG("Failed to write table header"); | |
136 } | |
137 | |
138 for (unsigned i = 0; i < vdmx->rat_ranges.size(); ++i) { | |
139 const OpenTypeVDMXRatioRecord& rec = vdmx->rat_ranges[i]; | |
140 if (!out->Write(&rec.charset, 1) || | |
141 !out->Write(&rec.x_ratio, 1) || | |
142 !out->Write(&rec.y_start_ratio, 1) || | |
143 !out->Write(&rec.y_end_ratio, 1)) { | |
144 return OTS_FAILURE_MSG("Failed to write ratio %d", i); | |
145 } | |
146 } | |
147 | |
148 for (unsigned i = 0; i < vdmx->offsets.size(); ++i) { | |
149 if (!out->WriteU16(vdmx->offsets[i])) { | |
150 return OTS_FAILURE_MSG("Failed to write ratio offset %d", i); | |
151 } | |
152 } | |
153 | |
154 for (unsigned i = 0; i < vdmx->groups.size(); ++i) { | |
155 const OpenTypeVDMXGroup& group = vdmx->groups[i]; | |
156 if (!out->WriteU16(group.recs) || | |
157 !out->Write(&group.startsz, 1) || | |
158 !out->Write(&group.endsz, 1)) { | |
159 return OTS_FAILURE_MSG("Failed to write group %d", i); | |
160 } | |
161 for (unsigned j = 0; j < group.entries.size(); ++j) { | |
162 const OpenTypeVDMXVTable& vt = group.entries[j]; | |
163 if (!out->WriteU16(vt.y_pel_height) || | |
164 !out->WriteS16(vt.y_max) || | |
165 !out->WriteS16(vt.y_min)) { | |
166 return OTS_FAILURE_MSG("Failed to write group %d entry %d", i, j); | |
167 } | |
168 } | |
169 } | |
170 | |
171 return true; | |
172 } | |
173 | |
174 void ots_vdmx_free(OpenTypeFile *file) { | |
175 delete file->vdmx; | |
176 } | |
177 | |
178 } // namespace ots | |
179 | |
180 #undef TABLE_NAME | |
181 #undef DROP_THIS_TABLE | |
OLD | NEW |