tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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