gfx/ots/src/vdmx.cc

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

mercurial