tor-browser

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

hdmx.cc (3740B)


      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 "hdmx.h"
      6 #include "head.h"
      7 #include "maxp.h"
      8 
      9 // hdmx - Horizontal Device Metrics
     10 // http://www.microsoft.com/typography/otspec/hdmx.htm
     11 
     12 namespace ots {
     13 
     14 bool OpenTypeHDMX::Parse(const uint8_t *data, size_t length) {
     15  Buffer table(data, length);
     16 
     17  OpenTypeMAXP *maxp = static_cast<OpenTypeMAXP*>(
     18      GetFont()->GetTypedTable(OTS_TAG_MAXP));
     19  OpenTypeHEAD *head = static_cast<OpenTypeHEAD*>(
     20      GetFont()->GetTypedTable(OTS_TAG_HEAD));
     21  if (!head || !maxp) {
     22    return Error("Missing maxp or head tables in font, needed by hdmx");
     23  }
     24 
     25  if ((head->flags & 0x14) == 0) {
     26    // http://www.microsoft.com/typography/otspec/recom.htm#hdmx
     27    return Drop("the table should not be present when bit 2 and 4 of the "
     28                "head->flags are not set");
     29  }
     30 
     31  int16_t num_recs;
     32  if (!table.ReadU16(&this->version) ||
     33      !table.ReadS16(&num_recs) ||
     34      !table.ReadS32(&this->size_device_record)) {
     35    return Error("Failed to read table header");
     36  }
     37  if (this->version != 0) {
     38    return Drop("Unsupported version: %u", this->version);
     39  }
     40  if (num_recs <= 0) {
     41    return Drop("Bad numRecords: %d", num_recs);
     42  }
     43  const int32_t actual_size_device_record = maxp->num_glyphs + 2;
     44  if (this->size_device_record < actual_size_device_record) {
     45    return Drop("Bad sizeDeviceRecord: %d", this->size_device_record);
     46  }
     47 
     48  this->pad_len = this->size_device_record - actual_size_device_record;
     49  if (this->pad_len > 3) {
     50    return Error("Bad DeviceRecord padding %d", this->pad_len);
     51  }
     52 
     53  uint8_t last_pixel_size = 0;
     54  this->records.reserve(num_recs);
     55  for (int i = 0; i < num_recs; ++i) {
     56    OpenTypeHDMXDeviceRecord rec;
     57 
     58    if (!table.ReadU8(&rec.pixel_size) ||
     59        !table.ReadU8(&rec.max_width)) {
     60      return Error("Failed to read DeviceRecord %d", i);
     61    }
     62    if ((i != 0) &&
     63        (rec.pixel_size <= last_pixel_size)) {
     64      return Drop("DeviceRecord's are not sorted");
     65    }
     66    last_pixel_size = rec.pixel_size;
     67 
     68    rec.widths.reserve(maxp->num_glyphs);
     69    for (unsigned j = 0; j < maxp->num_glyphs; ++j) {
     70      uint8_t width;
     71      if (!table.ReadU8(&width)) {
     72        return Error("Failed to read glyph width %d in DeviceRecord %d", j, i);
     73      }
     74      rec.widths.push_back(width);
     75    }
     76 
     77    if ((this->pad_len > 0) &&
     78        !table.Skip(this->pad_len)) {
     79      return Error("DeviceRecord %d should be padded by %d", i, this->pad_len);
     80    }
     81 
     82    this->records.push_back(rec);
     83  }
     84 
     85  return true;
     86 }
     87 
     88 bool OpenTypeHDMX::ShouldSerialize() {
     89  return Table::ShouldSerialize() &&
     90         // this table is not for CFF fonts.
     91         GetFont()->GetTable(OTS_TAG_GLYF) != NULL;
     92 }
     93 
     94 bool OpenTypeHDMX::Serialize(OTSStream *out) {
     95  const int16_t num_recs = static_cast<int16_t>(this->records.size());
     96  if (this->records.size() >
     97          static_cast<size_t>(std::numeric_limits<int16_t>::max()) ||
     98      !out->WriteU16(this->version) ||
     99      !out->WriteS16(num_recs) ||
    100      !out->WriteS32(this->size_device_record)) {
    101    return Error("Failed to write table header");
    102  }
    103 
    104  for (int16_t i = 0; i < num_recs; ++i) {
    105    const OpenTypeHDMXDeviceRecord& rec = this->records[i];
    106    if (!out->Write(&rec.pixel_size, 1) ||
    107        !out->Write(&rec.max_width, 1) ||
    108        !out->Write(&rec.widths[0], rec.widths.size())) {
    109      return Error("Failed to write DeviceRecord %d", i);
    110    }
    111    if ((this->pad_len > 0) &&
    112        !out->Write((const uint8_t *)"\x00\x00\x00", this->pad_len)) {
    113      return Error("Failed to write padding of length %d", this->pad_len);
    114    }
    115  }
    116 
    117  return true;
    118 }
    119 
    120 }  // namespace ots