font.cc (12150B)
1 /* Copyright 2013 Google Inc. All Rights Reserved. 2 3 Distributed under MIT license. 4 See file LICENSE for detail or copy at https://opensource.org/licenses/MIT 5 */ 6 7 /* Font management utilities */ 8 9 #include "./font.h" 10 11 #include <algorithm> 12 13 #include "./buffer.h" 14 #include "./port.h" 15 #include "./store_bytes.h" 16 #include "./table_tags.h" 17 #include "./woff2_common.h" 18 19 namespace woff2 { 20 21 Font::Table* Font::FindTable(uint32_t tag) { 22 std::map<uint32_t, Font::Table>::iterator it = tables.find(tag); 23 return it == tables.end() ? 0 : &it->second; 24 } 25 26 const Font::Table* Font::FindTable(uint32_t tag) const { 27 std::map<uint32_t, Font::Table>::const_iterator it = tables.find(tag); 28 return it == tables.end() ? 0 : &it->second; 29 } 30 31 std::vector<uint32_t> Font::OutputOrderedTags() const { 32 std::vector<uint32_t> output_order; 33 34 for (const auto& i : tables) { 35 const Font::Table& table = i.second; 36 // This is a transformed table, we will write it together with the 37 // original version. 38 if (table.tag & 0x80808080) { 39 continue; 40 } 41 output_order.push_back(table.tag); 42 } 43 44 // Alphabetize then put loca immediately after glyf 45 auto glyf_loc = std::find(output_order.begin(), output_order.end(), 46 kGlyfTableTag); 47 auto loca_loc = std::find(output_order.begin(), output_order.end(), 48 kLocaTableTag); 49 if (glyf_loc != output_order.end() && loca_loc != output_order.end()) { 50 output_order.erase(loca_loc); 51 output_order.insert(std::find(output_order.begin(), output_order.end(), 52 kGlyfTableTag) + 1, kLocaTableTag); 53 } 54 55 return output_order; 56 } 57 58 bool ReadTrueTypeFont(Buffer* file, const uint8_t* data, size_t len, 59 Font* font) { 60 // We don't care about the search_range, entry_selector and range_shift 61 // fields, they will always be computed upon writing the font. 62 if (!file->ReadU16(&font->num_tables) || 63 !file->Skip(6)) { 64 return FONT_COMPRESSION_FAILURE(); 65 } 66 67 std::map<uint32_t, uint32_t> intervals; 68 for (uint16_t i = 0; i < font->num_tables; ++i) { 69 Font::Table table; 70 table.flag_byte = 0; 71 table.reuse_of = NULL; 72 if (!file->ReadU32(&table.tag) || 73 !file->ReadU32(&table.checksum) || 74 !file->ReadU32(&table.offset) || 75 !file->ReadU32(&table.length)) { 76 return FONT_COMPRESSION_FAILURE(); 77 } 78 if ((table.offset & 3) != 0 || 79 table.length > len || 80 len - table.length < table.offset) { 81 return FONT_COMPRESSION_FAILURE(); 82 } 83 intervals[table.offset] = table.length; 84 table.data = data + table.offset; 85 if (font->tables.find(table.tag) != font->tables.end()) { 86 return FONT_COMPRESSION_FAILURE(); 87 } 88 font->tables[table.tag] = table; 89 } 90 91 // Check that tables are non-overlapping. 92 uint32_t last_offset = 12UL + 16UL * font->num_tables; 93 for (const auto& i : intervals) { 94 if (i.first < last_offset || i.first + i.second < i.first) { 95 return FONT_COMPRESSION_FAILURE(); 96 } 97 last_offset = i.first + i.second; 98 } 99 100 // Sanity check key tables 101 const Font::Table* head_table = font->FindTable(kHeadTableTag); 102 if (head_table != NULL && head_table->length < 52) { 103 return FONT_COMPRESSION_FAILURE(); 104 } 105 106 return true; 107 } 108 109 bool ReadCollectionFont(Buffer* file, const uint8_t* data, size_t len, 110 Font* font, 111 std::map<uint32_t, Font::Table*>* all_tables) { 112 if (!file->ReadU32(&font->flavor)) { 113 return FONT_COMPRESSION_FAILURE(); 114 } 115 if (!ReadTrueTypeFont(file, data, len, font)) { 116 return FONT_COMPRESSION_FAILURE(); 117 } 118 119 for (auto& entry : font->tables) { 120 Font::Table& table = entry.second; 121 122 if (all_tables->find(table.offset) == all_tables->end()) { 123 (*all_tables)[table.offset] = font->FindTable(table.tag); 124 } else { 125 table.reuse_of = (*all_tables)[table.offset]; 126 if (table.tag != table.reuse_of->tag) { 127 return FONT_COMPRESSION_FAILURE(); 128 } 129 } 130 131 } 132 return true; 133 } 134 135 bool ReadTrueTypeCollection(Buffer* file, const uint8_t* data, size_t len, 136 FontCollection* font_collection) { 137 uint32_t num_fonts; 138 139 if (!file->ReadU32(&font_collection->header_version) || 140 !file->ReadU32(&num_fonts)) { 141 return FONT_COMPRESSION_FAILURE(); 142 } 143 144 std::vector<uint32_t> offsets; 145 for (size_t i = 0; i < num_fonts; i++) { 146 uint32_t offset; 147 if (!file->ReadU32(&offset)) { 148 return FONT_COMPRESSION_FAILURE(); 149 } 150 offsets.push_back(offset); 151 } 152 153 font_collection->fonts.resize(offsets.size()); 154 std::vector<Font>::iterator font_it = font_collection->fonts.begin(); 155 156 std::map<uint32_t, Font::Table*> all_tables; 157 for (const auto offset : offsets) { 158 file->set_offset(offset); 159 Font& font = *font_it++; 160 if (!ReadCollectionFont(file, data, len, &font, &all_tables)) { 161 return FONT_COMPRESSION_FAILURE(); 162 } 163 } 164 165 return true; 166 } 167 168 bool ReadFont(const uint8_t* data, size_t len, Font* font) { 169 Buffer file(data, len); 170 171 if (!file.ReadU32(&font->flavor)) { 172 return FONT_COMPRESSION_FAILURE(); 173 } 174 175 if (font->flavor == kTtcFontFlavor) { 176 return FONT_COMPRESSION_FAILURE(); 177 } 178 return ReadTrueTypeFont(&file, data, len, font); 179 } 180 181 bool ReadFontCollection(const uint8_t* data, size_t len, 182 FontCollection* font_collection) { 183 Buffer file(data, len); 184 185 if (!file.ReadU32(&font_collection->flavor)) { 186 return FONT_COMPRESSION_FAILURE(); 187 } 188 189 if (font_collection->flavor != kTtcFontFlavor) { 190 font_collection->fonts.resize(1); 191 Font& font = font_collection->fonts[0]; 192 font.flavor = font_collection->flavor; 193 return ReadTrueTypeFont(&file, data, len, &font); 194 } 195 return ReadTrueTypeCollection(&file, data, len, font_collection); 196 } 197 198 size_t FontFileSize(const Font& font) { 199 size_t max_offset = 12ULL + 16ULL * font.num_tables; 200 for (const auto& i : font.tables) { 201 const Font::Table& table = i.second; 202 size_t padding_size = (4 - (table.length & 3)) & 3; 203 size_t end_offset = (padding_size + table.offset) + table.length; 204 max_offset = std::max(max_offset, end_offset); 205 } 206 return max_offset; 207 } 208 209 size_t FontCollectionFileSize(const FontCollection& font_collection) { 210 size_t max_offset = 0; 211 for (auto& font : font_collection.fonts) { 212 // font file size actually just finds max offset 213 max_offset = std::max(max_offset, FontFileSize(font)); 214 } 215 return max_offset; 216 } 217 218 bool WriteFont(const Font& font, uint8_t* dst, size_t dst_size) { 219 size_t offset = 0; 220 return WriteFont(font, &offset, dst, dst_size); 221 } 222 223 bool WriteTableRecord(const Font::Table* table, size_t* offset, uint8_t* dst, 224 size_t dst_size) { 225 if (dst_size < *offset + kSfntEntrySize) { 226 return FONT_COMPRESSION_FAILURE(); 227 } 228 if (table->IsReused()) { 229 table = table->reuse_of; 230 } 231 StoreU32(table->tag, offset, dst); 232 StoreU32(table->checksum, offset, dst); 233 StoreU32(table->offset, offset, dst); 234 StoreU32(table->length, offset, dst); 235 return true; 236 } 237 238 bool WriteTable(const Font::Table& table, size_t* offset, uint8_t* dst, 239 size_t dst_size) { 240 if (!WriteTableRecord(&table, offset, dst, dst_size)) { 241 return false; 242 } 243 244 // Write the actual table data if it's the first time we've seen it 245 if (!table.IsReused()) { 246 if (table.offset + table.length < table.offset || 247 dst_size < table.offset + table.length) { 248 return FONT_COMPRESSION_FAILURE(); 249 } 250 memcpy(dst + table.offset, table.data, table.length); 251 size_t padding_size = (4 - (table.length & 3)) & 3; 252 if (table.offset + table.length + padding_size < padding_size || 253 dst_size < table.offset + table.length + padding_size) { 254 return FONT_COMPRESSION_FAILURE(); 255 } 256 memset(dst + table.offset + table.length, 0, padding_size); 257 } 258 return true; 259 } 260 261 bool WriteFont(const Font& font, size_t* offset, uint8_t* dst, 262 size_t dst_size) { 263 if (dst_size < 12ULL + 16ULL * font.num_tables) { 264 return FONT_COMPRESSION_FAILURE(); 265 } 266 StoreU32(font.flavor, offset, dst); 267 Store16(font.num_tables, offset, dst); 268 uint16_t max_pow2 = font.num_tables ? Log2Floor(font.num_tables) : 0; 269 uint16_t search_range = max_pow2 ? 1 << (max_pow2 + 4) : 0; 270 uint16_t range_shift = (font.num_tables << 4) - search_range; 271 Store16(search_range, offset, dst); 272 Store16(max_pow2, offset, dst); 273 Store16(range_shift, offset, dst); 274 275 for (const auto& i : font.tables) { 276 if (!WriteTable(i.second, offset, dst, dst_size)) { 277 return false; 278 } 279 } 280 281 return true; 282 } 283 284 bool WriteFontCollection(const FontCollection& font_collection, uint8_t* dst, 285 size_t dst_size) { 286 size_t offset = 0; 287 288 // It's simpler if this just a simple sfnt 289 if (font_collection.flavor != kTtcFontFlavor) { 290 return WriteFont(font_collection.fonts[0], &offset, dst, dst_size); 291 } 292 293 // Write TTC header 294 StoreU32(kTtcFontFlavor, &offset, dst); 295 StoreU32(font_collection.header_version, &offset, dst); 296 StoreU32(font_collection.fonts.size(), &offset, dst); 297 298 // Offset Table, zeroed for now 299 size_t offset_table = offset; // where to write offsets later 300 for (size_t i = 0; i < font_collection.fonts.size(); i++) { 301 StoreU32(0, &offset, dst); 302 } 303 304 if (font_collection.header_version == 0x00020000) { 305 StoreU32(0, &offset, dst); // ulDsigTag 306 StoreU32(0, &offset, dst); // ulDsigLength 307 StoreU32(0, &offset, dst); // ulDsigOffset 308 } 309 310 // Write fonts and their offsets. 311 for (size_t i = 0; i < font_collection.fonts.size(); i++) { 312 const auto& font = font_collection.fonts[i]; 313 StoreU32(offset, &offset_table, dst); 314 if (!WriteFont(font, &offset, dst, dst_size)) { 315 return false; 316 } 317 } 318 319 return true; 320 } 321 322 int NumGlyphs(const Font& font) { 323 const Font::Table* head_table = font.FindTable(kHeadTableTag); 324 const Font::Table* loca_table = font.FindTable(kLocaTableTag); 325 if (head_table == NULL || loca_table == NULL || head_table->length < 52) { 326 return 0; 327 } 328 int index_fmt = IndexFormat(font); 329 int loca_record_size = (index_fmt == 0 ? 2 : 4); 330 if (loca_table->length < loca_record_size) { 331 return 0; 332 } 333 return (loca_table->length / loca_record_size) - 1; 334 } 335 336 int IndexFormat(const Font& font) { 337 const Font::Table* head_table = font.FindTable(kHeadTableTag); 338 if (head_table == NULL) { 339 return 0; 340 } 341 return head_table->data[51]; 342 } 343 344 bool Font::Table::IsReused() const { 345 return this->reuse_of != NULL; 346 } 347 348 bool GetGlyphData(const Font& font, int glyph_index, 349 const uint8_t** glyph_data, size_t* glyph_size) { 350 if (glyph_index < 0) { 351 return FONT_COMPRESSION_FAILURE(); 352 } 353 const Font::Table* head_table = font.FindTable(kHeadTableTag); 354 const Font::Table* loca_table = font.FindTable(kLocaTableTag); 355 const Font::Table* glyf_table = font.FindTable(kGlyfTableTag); 356 if (head_table == NULL || loca_table == NULL || glyf_table == NULL || 357 head_table->length < 52) { 358 return FONT_COMPRESSION_FAILURE(); 359 } 360 361 int index_fmt = IndexFormat(font); 362 363 Buffer loca_buf(loca_table->data, loca_table->length); 364 if (index_fmt == 0) { 365 uint16_t offset1, offset2; 366 if (!loca_buf.Skip(2 * glyph_index) || 367 !loca_buf.ReadU16(&offset1) || 368 !loca_buf.ReadU16(&offset2) || 369 offset2 < offset1 || 370 2 * offset2 > glyf_table->length) { 371 return FONT_COMPRESSION_FAILURE(); 372 } 373 *glyph_data = glyf_table->data + 2 * offset1; 374 *glyph_size = 2 * (offset2 - offset1); 375 } else { 376 uint32_t offset1, offset2; 377 if (!loca_buf.Skip(4 * glyph_index) || 378 !loca_buf.ReadU32(&offset1) || 379 !loca_buf.ReadU32(&offset2) || 380 offset2 < offset1 || 381 offset2 > glyf_table->length) { 382 return FONT_COMPRESSION_FAILURE(); 383 } 384 *glyph_data = glyf_table->data + offset1; 385 *glyph_size = offset2 - offset1; 386 } 387 return true; 388 } 389 390 bool RemoveDigitalSignature(Font* font) { 391 std::map<uint32_t, Font::Table>::iterator it = 392 font->tables.find(kDsigTableTag); 393 if (it != font->tables.end()) { 394 font->tables.erase(it); 395 font->num_tables = font->tables.size(); 396 } 397 return true; 398 } 399 400 } // namespace woff2