kern.cc (5924B)
1 // Copyright (c) 2009-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 "kern.h" 6 7 // kern - Kerning 8 // http://www.microsoft.com/typography/otspec/kern.htm 9 10 namespace ots { 11 12 bool OpenTypeKERN::Parse(const uint8_t *data, size_t length) { 13 Buffer table(data, length); 14 15 uint16_t num_tables = 0; 16 if (!table.ReadU16(&this->version) || 17 !table.ReadU16(&num_tables)) { 18 return Error("Failed to read table header"); 19 } 20 21 if (this->version > 0) { 22 return Drop("Unsupported table version: %d", this->version); 23 } 24 25 if (num_tables == 0) { 26 return Drop("nTables is zero"); 27 } 28 29 this->subtables.reserve(num_tables); 30 for (unsigned i = 0; i < num_tables; ++i) { 31 OpenTypeKERNFormat0 subtable; 32 uint16_t sub_length = 0; 33 34 if (!table.ReadU16(&subtable.version) || 35 !table.ReadU16(&sub_length)) { 36 return Error("Failed to read subtable %d header", i); 37 } 38 39 if (subtable.version > 0) { 40 Warning("Ignoring subtable %d with unsupported version: %d", 41 i, subtable.version); 42 continue; 43 } 44 45 const size_t current_offset = table.offset(); 46 if (current_offset - 4 + sub_length > length) { 47 return Error("Bad subtable %d offset %ld", i, current_offset); 48 } 49 50 if (!table.ReadU16(&subtable.coverage)) { 51 return Error("Failed to read subtable %d coverage", i); 52 } 53 54 if (!(subtable.coverage & 0x1)) { 55 Warning( 56 "We don't support vertical data as the renderer doesn't support it."); 57 continue; 58 } 59 if (subtable.coverage & 0xF0) { 60 return Drop("Reserved fields should be zero"); 61 } 62 const uint32_t format = (subtable.coverage & 0xFF00) >> 8; 63 if (format != 0) { 64 Warning("Ignoring subtable %d with unsupported format: %d", i, format); 65 continue; 66 } 67 68 // Parse the format 0 field. 69 uint16_t num_pairs = 0; 70 if (!table.ReadU16(&num_pairs) || 71 !table.ReadU16(&subtable.search_range) || 72 !table.ReadU16(&subtable.entry_selector) || 73 !table.ReadU16(&subtable.range_shift)) { 74 return Error("Failed to read subtable %d format 0 fields", i); 75 } 76 77 if (!num_pairs) { 78 return Drop("Zero length subtable is found"); 79 } 80 81 // Sanity checks for search_range, entry_selector, and range_shift. See the 82 // comment in ots.cc for details. 83 const size_t kFormat0PairSize = 6; // left, right, and value. 2 bytes each. 84 if (num_pairs > (65536 / kFormat0PairSize)) { 85 // Some fonts (e.g. calibri.ttf, pykes_peak_zero.ttf) have pairs >= 10923. 86 return Drop("Too large subtable"); 87 } 88 unsigned max_pow2 = 0; 89 while (1u << (max_pow2 + 1) <= num_pairs) { 90 ++max_pow2; 91 } 92 const uint16_t expected_search_range = (1u << max_pow2) * kFormat0PairSize; 93 if (subtable.search_range != expected_search_range) { 94 Warning("bad search range"); 95 subtable.search_range = expected_search_range; 96 } 97 if (subtable.entry_selector != max_pow2) { 98 return Error("Bad subtable %d entry selector %d", i, subtable.entry_selector); 99 } 100 const uint16_t expected_range_shift = 101 kFormat0PairSize * num_pairs - subtable.search_range; 102 if (subtable.range_shift != expected_range_shift) { 103 Warning("bad range shift"); 104 subtable.range_shift = expected_range_shift; 105 } 106 107 // Read kerning pairs. 108 subtable.pairs.reserve(num_pairs); 109 uint32_t last_pair = 0; 110 for (unsigned j = 0; j < num_pairs; ++j) { 111 OpenTypeKERNFormat0Pair kerning_pair; 112 if (!table.ReadU16(&kerning_pair.left) || 113 !table.ReadU16(&kerning_pair.right) || 114 !table.ReadS16(&kerning_pair.value)) { 115 return Error("Failed to read subtable %d kerning pair %d", i, j); 116 } 117 const uint32_t current_pair 118 = (kerning_pair.left << 16) + kerning_pair.right; 119 if (j != 0 && current_pair <= last_pair) { 120 // Many free fonts don't follow this rule, so we don't call OTS_FAILURE 121 // in order to support these fonts. 122 return Drop("Kerning pairs are not sorted"); 123 } 124 last_pair = current_pair; 125 subtable.pairs.push_back(kerning_pair); 126 } 127 128 this->subtables.push_back(subtable); 129 } 130 131 if (!this->subtables.size()) { 132 return Drop("All subtables were removed"); 133 } 134 135 return true; 136 } 137 138 bool OpenTypeKERN::Serialize(OTSStream *out) { 139 const uint16_t num_subtables = static_cast<uint16_t>(this->subtables.size()); 140 if (num_subtables != this->subtables.size() || 141 !out->WriteU16(this->version) || 142 !out->WriteU16(num_subtables)) { 143 return Error("Failed to write kern table header"); 144 } 145 146 for (uint16_t i = 0; i < num_subtables; ++i) { 147 const size_t length = 14 + (6 * this->subtables[i].pairs.size()); 148 if (length > std::numeric_limits<uint16_t>::max() || 149 !out->WriteU16(this->subtables[i].version) || 150 !out->WriteU16(static_cast<uint16_t>(length)) || 151 !out->WriteU16(this->subtables[i].coverage) || 152 !out->WriteU16( 153 static_cast<uint16_t>(this->subtables[i].pairs.size())) || 154 !out->WriteU16(this->subtables[i].search_range) || 155 !out->WriteU16(this->subtables[i].entry_selector) || 156 !out->WriteU16(this->subtables[i].range_shift)) { 157 return Error("Failed to write kern subtable %d", i); 158 } 159 for (unsigned j = 0; j < this->subtables[i].pairs.size(); ++j) { 160 if (!out->WriteU16(this->subtables[i].pairs[j].left) || 161 !out->WriteU16(this->subtables[i].pairs[j].right) || 162 !out->WriteS16(this->subtables[i].pairs[j].value)) { 163 return Error("Failed to write kern pair %d for subtable %d", j, i); 164 } 165 } 166 } 167 168 return true; 169 } 170 171 bool OpenTypeKERN::ShouldSerialize() { 172 return Table::ShouldSerialize() && 173 // this table is not for CFF fonts. 174 GetFont()->GetTable(OTS_TAG_GLYF) != NULL; 175 } 176 177 } // namespace ots