Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / ots / src / vdmx.cc
blobcd80946aee50b1965a4d9e1882a23a9159383712
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.
5 #include "vdmx.h"
7 // VDMX - Vertical Device Metrics
8 // http://www.microsoft.com/typography/otspec/vdmx.htm
10 #define TABLE_NAME "VDMX"
12 #define DROP_THIS_TABLE(...) \
13 do { \
14 OTS_FAILURE_MSG_(font->file, TABLE_NAME ": " __VA_ARGS__); \
15 OTS_FAILURE_MSG("Table discarded"); \
16 delete font->vdmx; \
17 font->vdmx = 0; \
18 } while (0)
20 namespace ots {
22 bool ots_vdmx_parse(Font *font, const uint8_t *data, size_t length) {
23 Buffer table(data, length);
24 font->vdmx = new OpenTypeVDMX;
25 OpenTypeVDMX * const vdmx = font->vdmx;
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");
33 if (vdmx->version > 1) {
34 DROP_THIS_TABLE("bad version: %u", vdmx->version);
35 return true; // continue transcoding
38 vdmx->rat_ranges.reserve(vdmx->num_ratios);
39 for (unsigned i = 0; i < vdmx->num_ratios; ++i) {
40 OpenTypeVDMXRatioRecord rec;
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);
49 if (rec.charset > 1) {
50 DROP_THIS_TABLE("bad charset: %u", rec.charset);
51 return true;
54 if (rec.y_start_ratio > rec.y_end_ratio) {
55 DROP_THIS_TABLE("bad y ratio");
56 return true;
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;
70 vdmx->rat_ranges.push_back(rec);
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);
81 if (current_offset + offset >= length) { // thus doesn't overflow.
82 return OTS_FAILURE_MSG("Bad ratio offset %d for ration %d", offset, i);
85 vdmx->offsets.push_back(offset);
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);
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);
104 if (vt.y_max < vt.y_min) {
105 DROP_THIS_TABLE("bad y min/max");
106 return true;
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;
116 group.entries.push_back(vt);
118 vdmx->groups.push_back(group);
121 return true;
124 bool ots_vdmx_should_serialise(Font *font) {
125 if (!font->glyf) return false; // this table is not for CFF fonts.
126 return font->vdmx != NULL;
129 bool ots_vdmx_serialise(OTSStream *out, Font *font) {
130 OpenTypeVDMX * const vdmx = font->vdmx;
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");
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);
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);
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);
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);
171 return true;
174 void ots_vdmx_reuse(Font *font, Font *other) {
175 font->vdmx = other->vdmx;
176 font->vdmx_reused = true;
179 void ots_vdmx_free(Font *font) {
180 delete font->vdmx;
183 } // namespace ots
185 #undef TABLE_NAME
186 #undef DROP_THIS_TABLE