tor-browser

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

vdmx.cc (5403B)


      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 "vdmx.h"
      6 
      7 #include <set>
      8 
      9 // VDMX - Vertical Device Metrics
     10 // http://www.microsoft.com/typography/otspec/vdmx.htm
     11 
     12 namespace ots {
     13 
     14 #define TABLE_NAME "VDMX"
     15 
     16 bool OpenTypeVDMX::Parse(const uint8_t *data, size_t length) {
     17  Buffer table(data, length);
     18  ots::Font* font = this->GetFont();
     19 
     20  if (!table.ReadU16(&this->version) ||
     21      !table.ReadU16(&this->num_recs) ||
     22      !table.ReadU16(&this->num_ratios)) {
     23    return Drop("Failed to read table header");
     24  }
     25 
     26  if (this->version > 1) {
     27    return Drop("Unsupported table version: %u", this->version);
     28  }
     29 
     30  this->rat_ranges.reserve(this->num_ratios);
     31  for (unsigned i = 0; i < this->num_ratios; ++i) {
     32    OpenTypeVDMXRatioRecord rec;
     33 
     34    if (!table.ReadU8(&rec.charset) ||
     35        !table.ReadU8(&rec.x_ratio) ||
     36        !table.ReadU8(&rec.y_start_ratio) ||
     37        !table.ReadU8(&rec.y_end_ratio)) {
     38      return Drop("Failed to read RatioRange record %d", i);
     39    }
     40 
     41    if (rec.charset > 1) {
     42      return Drop("Unsupported character set: %u", rec.charset);
     43    }
     44 
     45    if (rec.y_start_ratio > rec.y_end_ratio) {
     46      return Drop("Bad y ratio");
     47    }
     48 
     49    // All values set to zero signal the default grouping to use;
     50    // if present, this must be the last Ratio group in the table.
     51    if ((i < this->num_ratios - 1u) &&
     52        (rec.x_ratio == 0) &&
     53        (rec.y_start_ratio == 0) &&
     54        (rec.y_end_ratio == 0)) {
     55      // workaround for fonts which have 2 or more {0, 0, 0} terminators.
     56      return Drop("Superfluous terminator found");
     57    }
     58 
     59    this->rat_ranges.push_back(rec);
     60  }
     61 
     62  this->offsets.reserve(this->num_ratios);
     63  const size_t current_offset = table.offset();
     64  std::set<uint16_t> unique_offsets;
     65  // current_offset is less than (2 bytes * 3) + (4 bytes * USHRT_MAX) = 256k.
     66  for (unsigned i = 0; i < this->num_ratios; ++i) {
     67    uint16_t offset;
     68    if (!table.ReadU16(&offset)) {
     69      return Drop("Failed to read ratio offset %d", i);
     70    }
     71    if (current_offset + offset >= length) {  // thus doesn't overflow.
     72      return Drop("Bad ratio offset %d for ration %d", offset, i);
     73    }
     74 
     75    this->offsets.push_back(offset);
     76    unique_offsets.insert(offset);
     77  }
     78 
     79  // Check that num_recs is sufficient to provide as many VDMXGroup records
     80  // as there are unique offsets; if not, update it (we'll return an error
     81  // below if they're not actually present).
     82  if (unique_offsets.size() > this->num_recs) {
     83    OTS_WARNING("increasing num_recs (%u is too small for %u unique offsets)",
     84                this->num_recs, unique_offsets.size());
     85    this->num_recs = unique_offsets.size();
     86  }
     87 
     88  this->groups.reserve(this->num_recs);
     89  for (unsigned i = 0; i < this->num_recs; ++i) {
     90    OpenTypeVDMXGroup group;
     91    if (!table.ReadU16(&group.recs) ||
     92        !table.ReadU8(&group.startsz) ||
     93        !table.ReadU8(&group.endsz)) {
     94      return Drop("Failed to read record header %d", i);
     95    }
     96    group.entries.reserve(group.recs);
     97    for (unsigned j = 0; j < group.recs; ++j) {
     98      OpenTypeVDMXVTable vt;
     99      if (!table.ReadU16(&vt.y_pel_height) ||
    100          !table.ReadS16(&vt.y_max) ||
    101          !table.ReadS16(&vt.y_min)) {
    102        return Drop("Failed to read record %d group %d", i, j);
    103      }
    104      if (vt.y_max < vt.y_min) {
    105        return Drop("bad y min/max");
    106      }
    107 
    108      // This table must appear in sorted order (sorted by yPelHeight),
    109      // but need not be continuous.
    110      if ((j != 0) && (group.entries[j - 1].y_pel_height >= vt.y_pel_height)) {
    111        return Drop("The table is not sorted");
    112      }
    113 
    114      group.entries.push_back(vt);
    115    }
    116    this->groups.push_back(group);
    117  }
    118 
    119  return true;
    120 }
    121 
    122 bool OpenTypeVDMX::ShouldSerialize() {
    123  return Table::ShouldSerialize() &&
    124         // this table is not for CFF fonts.
    125         GetFont()->GetTable(OTS_TAG_GLYF) != NULL;
    126 }
    127 
    128 bool OpenTypeVDMX::Serialize(OTSStream *out) {
    129  if (!out->WriteU16(this->version) ||
    130      !out->WriteU16(this->num_recs) ||
    131      !out->WriteU16(this->num_ratios)) {
    132    return Error("Failed to write table header");
    133  }
    134 
    135  for (unsigned i = 0; i < this->rat_ranges.size(); ++i) {
    136    const OpenTypeVDMXRatioRecord& rec = this->rat_ranges[i];
    137    if (!out->Write(&rec.charset, 1) ||
    138        !out->Write(&rec.x_ratio, 1) ||
    139        !out->Write(&rec.y_start_ratio, 1) ||
    140        !out->Write(&rec.y_end_ratio, 1)) {
    141      return Error("Failed to write RatioRange record %d", i);
    142    }
    143  }
    144 
    145  for (unsigned i = 0; i < this->offsets.size(); ++i) {
    146    if (!out->WriteU16(this->offsets[i])) {
    147      return Error("Failed to write ratio offset %d", i);
    148    }
    149  }
    150 
    151  for (unsigned i = 0; i < this->groups.size(); ++i) {
    152    const OpenTypeVDMXGroup& group = this->groups[i];
    153    if (!out->WriteU16(group.recs) ||
    154        !out->Write(&group.startsz, 1) ||
    155        !out->Write(&group.endsz, 1)) {
    156      return Error("Failed to write group %d", i);
    157    }
    158    for (unsigned j = 0; j < group.entries.size(); ++j) {
    159      const OpenTypeVDMXVTable& vt = group.entries[j];
    160      if (!out->WriteU16(vt.y_pel_height) ||
    161          !out->WriteS16(vt.y_max) ||
    162          !out->WriteS16(vt.y_min)) {
    163        return Error("Failed to write group %d entry %d", i, j);
    164      }
    165    }
    166  }
    167 
    168  return true;
    169 }
    170 
    171 #undef TABLE_NAME
    172 
    173 }  // namespace ots