1 // Copyright (c) 2011 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 "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/opentype/otspec/hhea.htm 12 // http://www.microsoft.com/opentype/otspec/vhea.htm 13 14 namespace ots { 15 16 bool ParseMetricsHeader(OpenTypeFile *file, Buffer *table, 17 OpenTypeMetricsHeader *header) { 18 if (!table->ReadS16(&header->ascent) || 19 !table->ReadS16(&header->descent) || 20 !table->ReadS16(&header->linegap) || 21 !table->ReadU16(&header->adv_width_max) || 22 !table->ReadS16(&header->min_sb1) || 23 !table->ReadS16(&header->min_sb2) || 24 !table->ReadS16(&header->max_extent) || 25 !table->ReadS16(&header->caret_slope_rise) || 26 !table->ReadS16(&header->caret_slope_run) || 27 !table->ReadS16(&header->caret_offset)) { 28 return OTS_FAILURE(); 29 } 30 31 if (header->ascent < 0) { 32 OTS_WARNING("bad ascent: %d", header->ascent); 33 header->ascent = 0; 34 } 35 if (header->linegap < 0) { 36 OTS_WARNING("bad linegap: %d", header->linegap); 37 header->linegap = 0; 38 } 39 40 if (!file->head) { 41 return OTS_FAILURE(); 42 } 43 44 // if the font is non-slanted, caret_offset should be zero. 45 if (!(file->head->mac_style & 2) && 46 (header->caret_offset != 0)) { 47 OTS_WARNING("bad caret offset: %d", header->caret_offset); 48 header->caret_offset = 0; 49 } 50 51 // skip the reserved bytes 52 if (!table->Skip(8)) { 53 return OTS_FAILURE(); 54 } 55 56 int16_t data_format; 57 if (!table->ReadS16(&data_format)) { 58 return OTS_FAILURE(); 59 } 60 if (data_format) { 61 return OTS_FAILURE(); 62 } 63 64 if (!table->ReadU16(&header->num_metrics)) { 65 return OTS_FAILURE(); 66 } 67 68 if (!file->maxp) { 69 return OTS_FAILURE(); 70 } 71 72 if (header->num_metrics > file->maxp->num_glyphs) { 73 return OTS_FAILURE(); 74 } 75 76 return true; 77 } 78 79 bool SerialiseMetricsHeader(OTSStream *out, 80 const OpenTypeMetricsHeader *header) { 81 if (!out->WriteU32(header->version) || 82 !out->WriteS16(header->ascent) || 83 !out->WriteS16(header->descent) || 84 !out->WriteS16(header->linegap) || 85 !out->WriteU16(header->adv_width_max) || 86 !out->WriteS16(header->min_sb1) || 87 !out->WriteS16(header->min_sb2) || 88 !out->WriteS16(header->max_extent) || 89 !out->WriteS16(header->caret_slope_rise) || 90 !out->WriteS16(header->caret_slope_run) || 91 !out->WriteS16(header->caret_offset) || 92 !out->WriteR64(0) || // reserved 93 !out->WriteS16(0) || // metric data format 94 !out->WriteU16(header->num_metrics)) { 95 return OTS_FAILURE(); 96 } 97 98 return true; 99 } 100 101 bool ParseMetricsTable(Buffer *table, 102 const uint16_t num_glyphs, 103 const OpenTypeMetricsHeader *header, 104 OpenTypeMetricsTable *metrics) { 105 // |num_metrics| is a uint16_t, so it's bounded < 65536. This limits that 106 // amount of memory that we'll allocate for this to a sane amount. 107 const unsigned num_metrics = header->num_metrics; 108 109 if (num_metrics > num_glyphs) { 110 return OTS_FAILURE(); 111 } 112 if (!num_metrics) { 113 return OTS_FAILURE(); 114 } 115 const unsigned num_sbs = num_glyphs - num_metrics; 116 117 metrics->entries.reserve(num_metrics); 118 for (unsigned i = 0; i < num_metrics; ++i) { 119 uint16_t adv = 0; 120 int16_t sb = 0; 121 if (!table->ReadU16(&adv) || !table->ReadS16(&sb)) { 122 return OTS_FAILURE(); 123 } 124 125 // Since so many fonts don't have proper value on |adv| and |sb|, 126 // we should not call ots_failure() here. For example, about 20% of fonts 127 // in http://www.princexml.com/fonts/ (200+ fonts) fails these tests. 128 if (adv > header->adv_width_max) { 129 OTS_WARNING("bad adv: %u > %u", adv, header->adv_width_max); 130 adv = header->adv_width_max; 131 } 132 133 if (sb < header->min_sb1) { 134 OTS_WARNING("bad sb: %d < %d", sb, header->min_sb1); 135 sb = header->min_sb1; 136 } 137 138 metrics->entries.push_back(std::make_pair(adv, sb)); 139 } 140 141 metrics->sbs.reserve(num_sbs); 142 for (unsigned i = 0; i < num_sbs; ++i) { 143 int16_t sb; 144 if (!table->ReadS16(&sb)) { 145 // Some Japanese fonts (e.g., mona.ttf) fail this test. 146 return OTS_FAILURE(); 147 } 148 149 if (sb < header->min_sb1) { 150 // The same as above. Three fonts in http://www.fontsquirrel.com/fontface 151 // (e.g., Notice2Std.otf) have weird lsb values. 152 OTS_WARNING("bad lsb: %d < %d", sb, header->min_sb1); 153 sb = header->min_sb1; 154 } 155 156 metrics->sbs.push_back(sb); 157 } 158 159 return true; 160 } 161 162 bool SerialiseMetricsTable(OTSStream *out, 163 const OpenTypeMetricsTable *metrics) { 164 for (unsigned i = 0; i < metrics->entries.size(); ++i) { 165 if (!out->WriteU16(metrics->entries[i].first) || 166 !out->WriteS16(metrics->entries[i].second)) { 167 return OTS_FAILURE(); 168 } 169 } 170 171 for (unsigned i = 0; i < metrics->sbs.size(); ++i) { 172 if (!out->WriteS16(metrics->sbs[i])) { 173 return OTS_FAILURE(); 174 } 175 } 176 177 return true; 178 } 179 180 } // namespace ots 181 182