1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/ots/src/metrics.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,186 @@ 1.4 +// Copyright (c) 2011 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 "metrics.h" 1.9 + 1.10 +#include "head.h" 1.11 +#include "maxp.h" 1.12 + 1.13 +// OpenType horizontal and vertical common header format 1.14 +// http://www.microsoft.com/typography/otspec/hhea.htm 1.15 +// http://www.microsoft.com/typography/otspec/vhea.htm 1.16 + 1.17 +#define TABLE_NAME "metrics" // XXX: use individual table names 1.18 + 1.19 +namespace ots { 1.20 + 1.21 +bool ParseMetricsHeader(OpenTypeFile *file, Buffer *table, 1.22 + OpenTypeMetricsHeader *header) { 1.23 + if (!table->ReadS16(&header->ascent) || 1.24 + !table->ReadS16(&header->descent) || 1.25 + !table->ReadS16(&header->linegap) || 1.26 + !table->ReadU16(&header->adv_width_max) || 1.27 + !table->ReadS16(&header->min_sb1) || 1.28 + !table->ReadS16(&header->min_sb2) || 1.29 + !table->ReadS16(&header->max_extent) || 1.30 + !table->ReadS16(&header->caret_slope_rise) || 1.31 + !table->ReadS16(&header->caret_slope_run) || 1.32 + !table->ReadS16(&header->caret_offset)) { 1.33 + return OTS_FAILURE_MSG("Failed to read metrics header"); 1.34 + } 1.35 + 1.36 + if (header->ascent < 0) { 1.37 + OTS_WARNING("bad ascent: %d", header->ascent); 1.38 + header->ascent = 0; 1.39 + } 1.40 + if (header->linegap < 0) { 1.41 + OTS_WARNING("bad linegap: %d", header->linegap); 1.42 + header->linegap = 0; 1.43 + } 1.44 + 1.45 + if (!file->head) { 1.46 + return OTS_FAILURE_MSG("Missing head font table"); 1.47 + } 1.48 + 1.49 + // if the font is non-slanted, caret_offset should be zero. 1.50 + if (!(file->head->mac_style & 2) && 1.51 + (header->caret_offset != 0)) { 1.52 + OTS_WARNING("bad caret offset: %d", header->caret_offset); 1.53 + header->caret_offset = 0; 1.54 + } 1.55 + 1.56 + // skip the reserved bytes 1.57 + if (!table->Skip(8)) { 1.58 + return OTS_FAILURE_MSG("Failed to skip reserverd bytes"); 1.59 + } 1.60 + 1.61 + int16_t data_format; 1.62 + if (!table->ReadS16(&data_format)) { 1.63 + return OTS_FAILURE_MSG("Failed to read data format"); 1.64 + } 1.65 + if (data_format) { 1.66 + return OTS_FAILURE_MSG("Bad data format %d", data_format); 1.67 + } 1.68 + 1.69 + if (!table->ReadU16(&header->num_metrics)) { 1.70 + return OTS_FAILURE_MSG("Failed to read number of metrics"); 1.71 + } 1.72 + 1.73 + if (!file->maxp) { 1.74 + return OTS_FAILURE_MSG("Missing maxp font table"); 1.75 + } 1.76 + 1.77 + if (header->num_metrics > file->maxp->num_glyphs) { 1.78 + return OTS_FAILURE_MSG("Bad number of metrics %d", header->num_metrics); 1.79 + } 1.80 + 1.81 + return true; 1.82 +} 1.83 + 1.84 +bool SerialiseMetricsHeader(const ots::OpenTypeFile *file, 1.85 + OTSStream *out, 1.86 + const OpenTypeMetricsHeader *header) { 1.87 + if (!out->WriteU32(header->version) || 1.88 + !out->WriteS16(header->ascent) || 1.89 + !out->WriteS16(header->descent) || 1.90 + !out->WriteS16(header->linegap) || 1.91 + !out->WriteU16(header->adv_width_max) || 1.92 + !out->WriteS16(header->min_sb1) || 1.93 + !out->WriteS16(header->min_sb2) || 1.94 + !out->WriteS16(header->max_extent) || 1.95 + !out->WriteS16(header->caret_slope_rise) || 1.96 + !out->WriteS16(header->caret_slope_run) || 1.97 + !out->WriteS16(header->caret_offset) || 1.98 + !out->WriteR64(0) || // reserved 1.99 + !out->WriteS16(0) || // metric data format 1.100 + !out->WriteU16(header->num_metrics)) { 1.101 + return OTS_FAILURE_MSG("Failed to write metrics"); 1.102 + } 1.103 + 1.104 + return true; 1.105 +} 1.106 + 1.107 +bool ParseMetricsTable(const ots::OpenTypeFile *file, 1.108 + Buffer *table, 1.109 + const uint16_t num_glyphs, 1.110 + const OpenTypeMetricsHeader *header, 1.111 + OpenTypeMetricsTable *metrics) { 1.112 + // |num_metrics| is a uint16_t, so it's bounded < 65536. This limits that 1.113 + // amount of memory that we'll allocate for this to a sane amount. 1.114 + const unsigned num_metrics = header->num_metrics; 1.115 + 1.116 + if (num_metrics > num_glyphs) { 1.117 + return OTS_FAILURE_MSG("Bad number of metrics %d", num_metrics); 1.118 + } 1.119 + if (!num_metrics) { 1.120 + return OTS_FAILURE_MSG("No metrics!"); 1.121 + } 1.122 + const unsigned num_sbs = num_glyphs - num_metrics; 1.123 + 1.124 + metrics->entries.reserve(num_metrics); 1.125 + for (unsigned i = 0; i < num_metrics; ++i) { 1.126 + uint16_t adv = 0; 1.127 + int16_t sb = 0; 1.128 + if (!table->ReadU16(&adv) || !table->ReadS16(&sb)) { 1.129 + return OTS_FAILURE_MSG("Failed to read metric %d", i); 1.130 + } 1.131 + 1.132 + // Since so many fonts don't have proper value on |adv| and |sb|, 1.133 + // we should not call ots_failure() here. For example, about 20% of fonts 1.134 + // in http://www.princexml.com/fonts/ (200+ fonts) fails these tests. 1.135 + if (adv > header->adv_width_max) { 1.136 + OTS_WARNING("bad adv: %u > %u", adv, header->adv_width_max); 1.137 + adv = header->adv_width_max; 1.138 + } 1.139 + 1.140 + if (sb < header->min_sb1) { 1.141 + OTS_WARNING("bad sb: %d < %d", sb, header->min_sb1); 1.142 + sb = header->min_sb1; 1.143 + } 1.144 + 1.145 + metrics->entries.push_back(std::make_pair(adv, sb)); 1.146 + } 1.147 + 1.148 + metrics->sbs.reserve(num_sbs); 1.149 + for (unsigned i = 0; i < num_sbs; ++i) { 1.150 + int16_t sb; 1.151 + if (!table->ReadS16(&sb)) { 1.152 + // Some Japanese fonts (e.g., mona.ttf) fail this test. 1.153 + return OTS_FAILURE_MSG("Failed to read side bearing %d", i + num_metrics); 1.154 + } 1.155 + 1.156 + if (sb < header->min_sb1) { 1.157 + // The same as above. Three fonts in http://www.fontsquirrel.com/fontface 1.158 + // (e.g., Notice2Std.otf) have weird lsb values. 1.159 + OTS_WARNING("bad lsb: %d < %d", sb, header->min_sb1); 1.160 + sb = header->min_sb1; 1.161 + } 1.162 + 1.163 + metrics->sbs.push_back(sb); 1.164 + } 1.165 + 1.166 + return true; 1.167 +} 1.168 + 1.169 +bool SerialiseMetricsTable(const ots::OpenTypeFile *file, 1.170 + OTSStream *out, 1.171 + const OpenTypeMetricsTable *metrics) { 1.172 + for (unsigned i = 0; i < metrics->entries.size(); ++i) { 1.173 + if (!out->WriteU16(metrics->entries[i].first) || 1.174 + !out->WriteS16(metrics->entries[i].second)) { 1.175 + return OTS_FAILURE_MSG("Failed to write metric %d", i); 1.176 + } 1.177 + } 1.178 + 1.179 + for (unsigned i = 0; i < metrics->sbs.size(); ++i) { 1.180 + if (!out->WriteS16(metrics->sbs[i])) { 1.181 + return OTS_FAILURE_MSG("Failed to write side bearing %ld", i + metrics->entries.size()); 1.182 + } 1.183 + } 1.184 + 1.185 + return true; 1.186 +} 1.187 + 1.188 +} // namespace ots 1.189 +