tor-browser

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

fvar.cc (5523B)


      1 // Copyright (c) 2018 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 "fvar.h"
      6 
      7 namespace ots {
      8 
      9 // -----------------------------------------------------------------------------
     10 // OpenTypeFVAR
     11 // -----------------------------------------------------------------------------
     12 
     13 bool OpenTypeFVAR::Parse(const uint8_t* data, size_t length) {
     14  Buffer table(data, length);
     15  if (!table.ReadU16(&this->majorVersion) ||
     16      !table.ReadU16(&this->minorVersion) ||
     17      !table.ReadU16(&this->axesArrayOffset) ||
     18      !table.ReadU16(&this->reserved) ||
     19      !table.ReadU16(&this->axisCount) ||
     20      !table.ReadU16(&this->axisSize) ||
     21      !table.ReadU16(&this->instanceCount) ||
     22      !table.ReadU16(&this->instanceSize)) {
     23    return DropVariations("Failed to read table header");
     24  }
     25  if (this->majorVersion != 1) {
     26    return DropVariations("Unknown table version");
     27  }
     28  if (this->minorVersion > 0) {
     29    Warning("Downgrading minor version to 0");
     30    this->minorVersion = 0;
     31  }
     32  if (this->axesArrayOffset > length || this->axesArrayOffset < table.offset()) {
     33    return DropVariations("Bad axesArrayOffset");
     34  }
     35  if (this->reserved != 2) {
     36    Warning("Expected reserved=2");
     37    this->reserved = 2;
     38  }
     39  if (this->axisCount == 0) {
     40    return DropVariations("No variation axes");
     41  }
     42  if (this->axisSize != 20) {
     43    return DropVariations("Invalid axisSize");
     44  }
     45  // instanceCount is not validated
     46  if (this->instanceSize == this->axisCount * sizeof(Fixed) + 6) {
     47    this->instancesHavePostScriptNameID = true;
     48  } else if (this->instanceSize == this->axisCount * sizeof(Fixed) + 4) {
     49    this->instancesHavePostScriptNameID = false;
     50  } else {
     51    return DropVariations("Invalid instanceSize");
     52  }
     53 
     54  // When we serialize, the axes array will go here, even if it was
     55  // originally at a different offset. So we update the axesArrayOffset
     56  // field for the header.
     57  uint32_t origAxesArrayOffset = this->axesArrayOffset;
     58  this->axesArrayOffset = table.offset();
     59 
     60  table.set_offset(origAxesArrayOffset);
     61  for (unsigned i = 0; i < this->axisCount; i++) {
     62    this->axes.emplace_back();
     63    auto& axis = this->axes[i];
     64    if (!table.ReadU32(&axis.axisTag) ||
     65        !table.ReadS32(&axis.minValue) ||
     66        !table.ReadS32(&axis.defaultValue) ||
     67        !table.ReadS32(&axis.maxValue) ||
     68        !table.ReadU16(&axis.flags) ||
     69        !table.ReadU16(&axis.axisNameID)) {
     70      return DropVariations("Failed to read axis record");
     71    }
     72    if (!CheckTag(axis.axisTag)) {
     73      return DropVariations("Bad axis tag");
     74    }
     75    if (!(axis.minValue <= axis.defaultValue && axis.defaultValue <= axis.maxValue)) {
     76      return DropVariations("Bad axis value range");
     77    }
     78    if ((axis.flags & 0xFFFEu) != 0) {
     79      Warning("Discarding unknown axis flags");
     80      axis.flags &= ~0xFFFEu;
     81    }
     82    if (axis.axisNameID <= 255 || axis.axisNameID >= 32768) {
     83      Warning("Axis nameID out of range");
     84      // We don't check that the name actually exists -- assume the client can handle
     85      // a missing name when it tries to read the table.
     86    }
     87  }
     88 
     89  for (unsigned i = 0; i < this->instanceCount; i++) {
     90    this->instances.emplace_back();
     91    auto& inst = this->instances[i];
     92    if (!table.ReadU16(&inst.subfamilyNameID) ||
     93        !table.ReadU16(&inst.flags)) {
     94      return DropVariations("Failed to read instance record");
     95    }
     96    inst.coordinates.reserve(this->axisCount);
     97    for (unsigned j = 0; j < this->axisCount; j++) {
     98      inst.coordinates.emplace_back();
     99      auto& coord = inst.coordinates[j];
    100      if (!table.ReadS32(&coord)) {
    101        return DropVariations("Failed to read instance coordinates");
    102      }
    103    }
    104    if (this->instancesHavePostScriptNameID) {
    105      if (!table.ReadU16(&inst.postScriptNameID)) {
    106        return DropVariations("Failed to read instance psname ID");
    107      }
    108    }
    109  }
    110 
    111  if (table.remaining()) {
    112    return Warning("%zu bytes unparsed", table.remaining());
    113  }
    114 
    115  return true;
    116 }
    117 
    118 bool OpenTypeFVAR::Serialize(OTSStream* out) {
    119  if (!out->WriteU16(this->majorVersion) ||
    120      !out->WriteU16(this->minorVersion) ||
    121      !out->WriteU16(this->axesArrayOffset) ||
    122      !out->WriteU16(this->reserved) ||
    123      !out->WriteU16(this->axisCount) ||
    124      !out->WriteU16(this->axisSize) ||
    125      !out->WriteU16(this->instanceCount) ||
    126      !out->WriteU16(this->instanceSize)) {
    127    return Error("Failed to write table");
    128  }
    129 
    130  for (unsigned i = 0; i < this->axisCount; i++) {
    131    const auto& axis = this->axes[i];
    132    if (!out->WriteU32(axis.axisTag) ||
    133        !out->WriteS32(axis.minValue) ||
    134        !out->WriteS32(axis.defaultValue) ||
    135        !out->WriteS32(axis.maxValue) ||
    136        !out->WriteU16(axis.flags) ||
    137        !out->WriteU16(axis.axisNameID)) {
    138      return Error("Failed to write table");
    139    }
    140  }
    141 
    142  for (unsigned i = 0; i < this->instanceCount; i++) {
    143    const auto& inst = this->instances[i];
    144    if (!out->WriteU16(inst.subfamilyNameID) ||
    145        !out->WriteU16(inst.flags)) {
    146      return Error("Failed to write table");
    147    }
    148    for (unsigned j = 0; j < this->axisCount; j++) {
    149      const auto& coord = inst.coordinates[j];
    150      if (!out->WriteS32(coord)) {
    151        return Error("Failed to write table");
    152      }
    153    }
    154    if (this->instancesHavePostScriptNameID) {
    155      if (!out->WriteU16(inst.postScriptNameID)) {
    156        return Error("Failed to write table");
    157      }
    158    }
    159  }
    160 
    161  return true;
    162 }
    163 
    164 }  // namespace ots