tor-browser

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

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