1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/ots/src/vdmx.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,183 @@ 1.4 +// Copyright (c) 2009 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include "vdmx.h" 1.9 + 1.10 +// VDMX - Vertical Device Metrics 1.11 +// http://www.microsoft.com/typography/otspec/vdmx.htm 1.12 + 1.13 +#define TABLE_NAME "VDMX" 1.14 + 1.15 +#define DROP_THIS_TABLE \ 1.16 + do { \ 1.17 + delete file->vdmx; \ 1.18 + file->vdmx = 0; \ 1.19 + OTS_FAILURE_MSG("Table discarded"); \ 1.20 + } while (0) 1.21 + 1.22 +namespace ots { 1.23 + 1.24 +bool ots_vdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) { 1.25 + Buffer table(data, length); 1.26 + file->vdmx = new OpenTypeVDMX; 1.27 + OpenTypeVDMX * const vdmx = file->vdmx; 1.28 + 1.29 + if (!table.ReadU16(&vdmx->version) || 1.30 + !table.ReadU16(&vdmx->num_recs) || 1.31 + !table.ReadU16(&vdmx->num_ratios)) { 1.32 + return OTS_FAILURE_MSG("Failed to read table header"); 1.33 + } 1.34 + 1.35 + if (vdmx->version > 1) { 1.36 + OTS_WARNING("bad version: %u", vdmx->version); 1.37 + DROP_THIS_TABLE; 1.38 + return true; // continue transcoding 1.39 + } 1.40 + 1.41 + vdmx->rat_ranges.reserve(vdmx->num_ratios); 1.42 + for (unsigned i = 0; i < vdmx->num_ratios; ++i) { 1.43 + OpenTypeVDMXRatioRecord rec; 1.44 + 1.45 + if (!table.ReadU8(&rec.charset) || 1.46 + !table.ReadU8(&rec.x_ratio) || 1.47 + !table.ReadU8(&rec.y_start_ratio) || 1.48 + !table.ReadU8(&rec.y_end_ratio)) { 1.49 + return OTS_FAILURE_MSG("Failed to read ratio header %d", i); 1.50 + } 1.51 + 1.52 + if (rec.charset > 1) { 1.53 + OTS_WARNING("bad charset: %u", rec.charset); 1.54 + DROP_THIS_TABLE; 1.55 + return true; 1.56 + } 1.57 + 1.58 + if (rec.y_start_ratio > rec.y_end_ratio) { 1.59 + OTS_WARNING("bad y ratio"); 1.60 + DROP_THIS_TABLE; 1.61 + return true; 1.62 + } 1.63 + 1.64 + // All values set to zero signal the default grouping to use; 1.65 + // if present, this must be the last Ratio group in the table. 1.66 + if ((i < vdmx->num_ratios - 1u) && 1.67 + (rec.x_ratio == 0) && 1.68 + (rec.y_start_ratio == 0) && 1.69 + (rec.y_end_ratio == 0)) { 1.70 + // workaround for fonts which have 2 or more {0, 0, 0} terminators. 1.71 + OTS_WARNING("superfluous terminator found"); 1.72 + DROP_THIS_TABLE; 1.73 + return true; 1.74 + } 1.75 + 1.76 + vdmx->rat_ranges.push_back(rec); 1.77 + } 1.78 + 1.79 + vdmx->offsets.reserve(vdmx->num_ratios); 1.80 + const size_t current_offset = table.offset(); 1.81 + // current_offset is less than (2 bytes * 3) + (4 bytes * USHRT_MAX) = 256k. 1.82 + for (unsigned i = 0; i < vdmx->num_ratios; ++i) { 1.83 + uint16_t offset; 1.84 + if (!table.ReadU16(&offset)) { 1.85 + return OTS_FAILURE_MSG("Failed to read ratio offset %d", i); 1.86 + } 1.87 + if (current_offset + offset >= length) { // thus doesn't overflow. 1.88 + return OTS_FAILURE_MSG("Bad ratio offset %d for ration %d", offset, i); 1.89 + } 1.90 + 1.91 + vdmx->offsets.push_back(offset); 1.92 + } 1.93 + 1.94 + vdmx->groups.reserve(vdmx->num_recs); 1.95 + for (unsigned i = 0; i < vdmx->num_recs; ++i) { 1.96 + OpenTypeVDMXGroup group; 1.97 + if (!table.ReadU16(&group.recs) || 1.98 + !table.ReadU8(&group.startsz) || 1.99 + !table.ReadU8(&group.endsz)) { 1.100 + return OTS_FAILURE_MSG("Failed to read record header %d", i); 1.101 + } 1.102 + group.entries.reserve(group.recs); 1.103 + for (unsigned j = 0; j < group.recs; ++j) { 1.104 + OpenTypeVDMXVTable vt; 1.105 + if (!table.ReadU16(&vt.y_pel_height) || 1.106 + !table.ReadS16(&vt.y_max) || 1.107 + !table.ReadS16(&vt.y_min)) { 1.108 + return OTS_FAILURE_MSG("Failed to read reacord %d group %d", i, j); 1.109 + } 1.110 + if (vt.y_max < vt.y_min) { 1.111 + OTS_WARNING("bad y min/max"); 1.112 + DROP_THIS_TABLE; 1.113 + return true; 1.114 + } 1.115 + 1.116 + // This table must appear in sorted order (sorted by yPelHeight), 1.117 + // but need not be continuous. 1.118 + if ((j != 0) && (group.entries[j - 1].y_pel_height >= vt.y_pel_height)) { 1.119 + OTS_WARNING("the table is not sorted"); 1.120 + DROP_THIS_TABLE; 1.121 + return true; 1.122 + } 1.123 + 1.124 + group.entries.push_back(vt); 1.125 + } 1.126 + vdmx->groups.push_back(group); 1.127 + } 1.128 + 1.129 + return true; 1.130 +} 1.131 + 1.132 +bool ots_vdmx_should_serialise(OpenTypeFile *file) { 1.133 + if (!file->glyf) return false; // this table is not for CFF fonts. 1.134 + return file->vdmx != NULL; 1.135 +} 1.136 + 1.137 +bool ots_vdmx_serialise(OTSStream *out, OpenTypeFile *file) { 1.138 + OpenTypeVDMX * const vdmx = file->vdmx; 1.139 + 1.140 + if (!out->WriteU16(vdmx->version) || 1.141 + !out->WriteU16(vdmx->num_recs) || 1.142 + !out->WriteU16(vdmx->num_ratios)) { 1.143 + return OTS_FAILURE_MSG("Failed to write table header"); 1.144 + } 1.145 + 1.146 + for (unsigned i = 0; i < vdmx->rat_ranges.size(); ++i) { 1.147 + const OpenTypeVDMXRatioRecord& rec = vdmx->rat_ranges[i]; 1.148 + if (!out->Write(&rec.charset, 1) || 1.149 + !out->Write(&rec.x_ratio, 1) || 1.150 + !out->Write(&rec.y_start_ratio, 1) || 1.151 + !out->Write(&rec.y_end_ratio, 1)) { 1.152 + return OTS_FAILURE_MSG("Failed to write ratio %d", i); 1.153 + } 1.154 + } 1.155 + 1.156 + for (unsigned i = 0; i < vdmx->offsets.size(); ++i) { 1.157 + if (!out->WriteU16(vdmx->offsets[i])) { 1.158 + return OTS_FAILURE_MSG("Failed to write ratio offset %d", i); 1.159 + } 1.160 + } 1.161 + 1.162 + for (unsigned i = 0; i < vdmx->groups.size(); ++i) { 1.163 + const OpenTypeVDMXGroup& group = vdmx->groups[i]; 1.164 + if (!out->WriteU16(group.recs) || 1.165 + !out->Write(&group.startsz, 1) || 1.166 + !out->Write(&group.endsz, 1)) { 1.167 + return OTS_FAILURE_MSG("Failed to write group %d", i); 1.168 + } 1.169 + for (unsigned j = 0; j < group.entries.size(); ++j) { 1.170 + const OpenTypeVDMXVTable& vt = group.entries[j]; 1.171 + if (!out->WriteU16(vt.y_pel_height) || 1.172 + !out->WriteS16(vt.y_max) || 1.173 + !out->WriteS16(vt.y_min)) { 1.174 + return OTS_FAILURE_MSG("Failed to write group %d entry %d", i, j); 1.175 + } 1.176 + } 1.177 + } 1.178 + 1.179 + return true; 1.180 +} 1.181 + 1.182 +void ots_vdmx_free(OpenTypeFile *file) { 1.183 + delete file->vdmx; 1.184 +} 1.185 + 1.186 +} // namespace ots