metrics.cc (5342B)
1 // Copyright (c) 2011-2017 The OTS 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 "metrics.h" 6 7 #include "head.h" 8 #include "maxp.h" 9 10 // OpenType horizontal and vertical common header format 11 // http://www.microsoft.com/typography/otspec/hhea.htm 12 // http://www.microsoft.com/typography/otspec/vhea.htm 13 14 namespace ots { 15 16 bool OpenTypeMetricsHeader::Parse(const uint8_t *data, size_t length) { 17 Buffer table(data, length); 18 19 // Skip already read version. 20 if (!table.Skip(4)) { 21 return false; 22 } 23 24 if (!table.ReadS16(&this->ascent) || 25 !table.ReadS16(&this->descent) || 26 !table.ReadS16(&this->linegap) || 27 !table.ReadU16(&this->adv_width_max) || 28 !table.ReadS16(&this->min_sb1) || 29 !table.ReadS16(&this->min_sb2) || 30 !table.ReadS16(&this->max_extent) || 31 !table.ReadS16(&this->caret_slope_rise) || 32 !table.ReadS16(&this->caret_slope_run) || 33 !table.ReadS16(&this->caret_offset)) { 34 return Error("Failed to read table"); 35 } 36 37 if (this->ascent < 0) { 38 Warning("Negative ascent, setting to 0: %d", this->ascent); 39 this->ascent = 0; 40 } 41 if (this->linegap < 0) { 42 Warning("Negative linegap, setting to: %d", this->linegap); 43 this->linegap = 0; 44 } 45 46 OpenTypeHEAD *head = static_cast<OpenTypeHEAD*>( 47 GetFont()->GetTypedTable(OTS_TAG_HEAD)); 48 if (!head) { 49 return Error("Missing head font table"); 50 } 51 52 // if the font is non-slanted, caret_offset should be zero. 53 if (!(head->mac_style & 2) && 54 (this->caret_offset != 0)) { 55 Warning("Non-zero caretOffset but head.macStyle italic bit is not set, setting to caretOffset to 0: %d", this->caret_offset); 56 this->caret_offset = 0; 57 } 58 59 // skip the reserved bytes 60 if (!table.Skip(8)) { 61 return Error("Failed to read reserved bytes"); 62 } 63 64 int16_t data_format; 65 if (!table.ReadS16(&data_format)) { 66 return Error("Failed to read metricDataFormat"); 67 } 68 if (data_format) { 69 return Error("Unsupported metricDataFormat: %d", data_format); 70 } 71 72 if (!table.ReadU16(&this->num_metrics)) { 73 return Error("Failed to read number of metrics"); 74 } 75 76 OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>( 77 GetFont()->GetTypedTable(OTS_TAG_MAXP)); 78 if (!maxp) { 79 return Error("Missing maxp font table"); 80 } 81 82 if (this->num_metrics > maxp->num_glyphs) { 83 return Error("Bad number of metrics %d", this->num_metrics); 84 } 85 86 return true; 87 } 88 89 bool OpenTypeMetricsHeader::Serialize(OTSStream *out) { 90 if (!out->WriteU32(this->version) || 91 !out->WriteS16(this->ascent) || 92 !out->WriteS16(this->descent) || 93 !out->WriteS16(this->linegap) || 94 !out->WriteU16(this->adv_width_max) || 95 !out->WriteS16(this->min_sb1) || 96 !out->WriteS16(this->min_sb2) || 97 !out->WriteS16(this->max_extent) || 98 !out->WriteS16(this->caret_slope_rise) || 99 !out->WriteS16(this->caret_slope_run) || 100 !out->WriteS16(this->caret_offset) || 101 !out->WriteR64(0) || // reserved 102 !out->WriteS16(0) || // metric data format 103 !out->WriteU16(this->num_metrics)) { 104 return Error("Failed to write metrics"); 105 } 106 107 return true; 108 } 109 110 bool OpenTypeMetricsTable::Parse(const uint8_t *data, size_t length) { 111 Buffer table(data, length); 112 113 // OpenTypeMetricsHeader is a superclass of both 'hhea' and 'vhea', 114 // so the cast here is OK, whichever m_header_tag we have. 115 OpenTypeMetricsHeader *header = static_cast<OpenTypeMetricsHeader*>( 116 GetFont()->GetTypedTable(m_header_tag)); 117 if (!header) { 118 return Error("Required %c%c%c%c table missing", OTS_UNTAG(m_header_tag)); 119 } 120 // |num_metrics| is a uint16_t, so it's bounded < 65536. This limits that 121 // amount of memory that we'll allocate for this to a sane amount. 122 const unsigned num_metrics = header->num_metrics; 123 124 OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>( 125 GetFont()->GetTypedTable(OTS_TAG_MAXP)); 126 if (!maxp) { 127 return Error("Required maxp table missing"); 128 } 129 if (num_metrics > maxp->num_glyphs) { 130 return Error("Bad number of metrics %d", num_metrics); 131 } 132 if (!num_metrics) { 133 return Error("No metrics!"); 134 } 135 const unsigned num_sbs = maxp->num_glyphs - num_metrics; 136 137 this->entries.reserve(num_metrics); 138 for (unsigned i = 0; i < num_metrics; ++i) { 139 uint16_t adv = 0; 140 int16_t sb = 0; 141 if (!table.ReadU16(&adv) || !table.ReadS16(&sb)) { 142 return Error("Failed to read metric %d", i); 143 } 144 this->entries.push_back(std::make_pair(adv, sb)); 145 } 146 147 this->sbs.reserve(num_sbs); 148 for (unsigned i = 0; i < num_sbs; ++i) { 149 int16_t sb; 150 if (!table.ReadS16(&sb)) { 151 // Some Japanese fonts (e.g., mona.ttf) fail this test. 152 return Error("Failed to read side bearing %d", i + num_metrics); 153 } 154 this->sbs.push_back(sb); 155 } 156 157 return true; 158 } 159 160 bool OpenTypeMetricsTable::Serialize(OTSStream *out) { 161 for (unsigned i = 0; i < this->entries.size(); ++i) { 162 if (!out->WriteU16(this->entries[i].first) || 163 !out->WriteS16(this->entries[i].second)) { 164 return Error("Failed to write metric %d", i); 165 } 166 } 167 168 for (unsigned i = 0; i < this->sbs.size(); ++i) { 169 if (!out->WriteS16(this->sbs[i])) { 170 return Error("Failed to write side bearing %ld", i + this->entries.size()); 171 } 172 } 173 174 return true; 175 } 176 177 } // namespace ots