tor-browser

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

gvar.cc (6796B)


      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 "gvar.h"
      6 
      7 #include "fvar.h"
      8 #include "maxp.h"
      9 #include "variations.h"
     10 #include "ots-memory-stream.h"
     11 
     12 #define TABLE_NAME "gvar"
     13 
     14 namespace ots {
     15 
     16 // -----------------------------------------------------------------------------
     17 // OpenTypeGVAR
     18 // -----------------------------------------------------------------------------
     19 
     20 static bool ParseSharedTuples(const Font* font, const uint8_t* data, size_t length,
     21                              size_t sharedTupleCount, size_t axisCount) {
     22  Buffer subtable(data, length);
     23  for (unsigned i = 0; i < sharedTupleCount; i++) {
     24    for (unsigned j = 0; j < axisCount; j++) {
     25      int16_t coordinate;
     26      if (!subtable.ReadS16(&coordinate)) {
     27        return OTS_FAILURE_MSG("Failed to read shared tuple coordinate");
     28      }
     29    }
     30  }
     31  return true;
     32 }
     33 
     34 static bool ParseGlyphVariationDataArray(const Font* font, const uint8_t* data, size_t length,
     35                                         uint16_t flags, size_t glyphCount, size_t axisCount,
     36                                         size_t sharedTupleCount,
     37                                         const uint8_t* glyphVariationData,
     38                                         size_t glyphVariationDataLength) {
     39  Buffer subtable(data, length);
     40 
     41  bool glyphVariationDataOffsetsAreLong = (flags & 0x0001u);
     42  uint32_t prevOffset = 0;
     43  for (size_t i = 0; i < glyphCount + 1; i++) {
     44    uint32_t offset;
     45    if (glyphVariationDataOffsetsAreLong) {
     46      if (!subtable.ReadU32(&offset)) {
     47        return OTS_FAILURE_MSG("Failed to read GlyphVariationData offset");
     48      }
     49    } else {
     50      uint16_t halfOffset;
     51      if (!subtable.ReadU16(&halfOffset)) {
     52        return OTS_FAILURE_MSG("Failed to read GlyphVariationData offset");
     53      }
     54      offset = halfOffset * 2;
     55    }
     56 
     57    if (i > 0 && offset > prevOffset) {
     58      if (prevOffset > glyphVariationDataLength) {
     59        return OTS_FAILURE_MSG("Invalid GlyphVariationData offset");
     60      }
     61      if (!ParseVariationData(font, glyphVariationData + prevOffset,
     62                              glyphVariationDataLength - prevOffset,
     63                              axisCount, sharedTupleCount)) {
     64        return OTS_FAILURE_MSG("Failed to parse GlyphVariationData");
     65      }
     66    }
     67    prevOffset = offset;
     68  }
     69 
     70  return true;
     71 }
     72 
     73 bool OpenTypeGVAR::Parse(const uint8_t* data, size_t length) {
     74  Buffer table(data, length);
     75 
     76  uint16_t majorVersion;
     77  uint16_t minorVersion;
     78  uint16_t axisCount;
     79  uint16_t sharedTupleCount;
     80  uint32_t sharedTuplesOffset;
     81  uint16_t glyphCount;
     82  uint16_t flags;
     83  uint32_t glyphVariationDataArrayOffset;
     84 
     85  if (!table.ReadU16(&majorVersion) ||
     86      !table.ReadU16(&minorVersion) ||
     87      !table.ReadU16(&axisCount) ||
     88      !table.ReadU16(&sharedTupleCount) ||
     89      !table.ReadU32(&sharedTuplesOffset) ||
     90      !table.ReadU16(&glyphCount) ||
     91      !table.ReadU16(&flags) ||
     92      !table.ReadU32(&glyphVariationDataArrayOffset)) {
     93    return DropVariations("Failed to read table header");
     94  }
     95  if (majorVersion != 1) {
     96    return DropVariations("Unknown table version");
     97  }
     98 
     99  // check axisCount == fvar->axisCount
    100  OpenTypeFVAR* fvar = static_cast<OpenTypeFVAR*>(
    101      GetFont()->GetTypedTable(OTS_TAG_FVAR));
    102  if (!fvar) {
    103    return DropVariations("Required fvar table is missing");
    104  }
    105  if (axisCount != fvar->AxisCount()) {
    106    return DropVariations("Axis count mismatch");
    107  }
    108 
    109  // check glyphCount == maxp->num_glyphs
    110  OpenTypeMAXP* maxp = static_cast<OpenTypeMAXP*>(
    111      GetFont()->GetTypedTable(OTS_TAG_MAXP));
    112  if (!maxp) {
    113    return DropVariations("Required maxp table is missing");
    114  }
    115  if (glyphCount != maxp->num_glyphs) {
    116    return DropVariations("Glyph count mismatch");
    117  }
    118 
    119  if (sharedTupleCount > 0) {
    120    if (sharedTuplesOffset < table.offset() || sharedTuplesOffset > length) {
    121      return DropVariations("Invalid sharedTuplesOffset");
    122    }
    123    if (!ParseSharedTuples(GetFont(),
    124                           data + sharedTuplesOffset, length - sharedTuplesOffset,
    125                           sharedTupleCount, axisCount)) {
    126      return DropVariations("Failed to parse shared tuples");
    127    }
    128  }
    129 
    130  if (glyphVariationDataArrayOffset) {
    131    if (glyphVariationDataArrayOffset > length) {
    132      return DropVariations("Invalid glyphVariationDataArrayOffset");
    133    }
    134    if (!ParseGlyphVariationDataArray(GetFont(),
    135                                      data + table.offset(), length - table.offset(),
    136                                      flags, glyphCount, axisCount, sharedTupleCount,
    137                                      data + glyphVariationDataArrayOffset,
    138                                      length - glyphVariationDataArrayOffset)) {
    139      return DropVariations("Failed to read glyph variation data array");
    140    }
    141  }
    142 
    143  this->m_data = data;
    144  this->m_length = length;
    145 
    146  return true;
    147 }
    148 
    149 #ifdef OTS_SYNTHESIZE_MISSING_GVAR
    150 bool OpenTypeGVAR::InitEmpty() {
    151  // Generate an empty but well-formed 'gvar' table for the font.
    152  const ots::Font* font = GetFont();
    153 
    154  OpenTypeFVAR* fvar = static_cast<OpenTypeFVAR*>(font->GetTypedTable(OTS_TAG_FVAR));
    155  if (!fvar) {
    156    return DropVariations("Required fvar table missing");
    157  }
    158 
    159  OpenTypeMAXP* maxp = static_cast<OpenTypeMAXP*>(font->GetTypedTable(OTS_TAG_MAXP));
    160  if (!maxp) {
    161    return DropVariations("Required maxp table missing");
    162  }
    163 
    164  uint16_t majorVersion = 1;
    165  uint16_t minorVersion = 0;
    166  uint16_t axisCount = fvar->AxisCount();
    167  uint16_t sharedTupleCount = 0;
    168  uint32_t sharedTuplesOffset = 0;
    169  uint16_t glyphCount = maxp->num_glyphs;
    170  uint16_t flags = 0;
    171  uint32_t glyphVariationDataArrayOffset = 0;
    172 
    173  size_t length = 6 * sizeof(uint16_t) + 2 * sizeof(uint32_t)  // basic header fields
    174      + (glyphCount + 1) * sizeof(uint16_t);  // glyphVariationDataOffsets[] array
    175 
    176  uint8_t* data = new uint8_t[length];
    177  MemoryStream stream(data, length);
    178  if (!stream.WriteU16(majorVersion) ||
    179      !stream.WriteU16(minorVersion) ||
    180      !stream.WriteU16(axisCount) ||
    181      !stream.WriteU16(sharedTupleCount) ||
    182      !stream.WriteU32(sharedTuplesOffset) ||
    183      !stream.WriteU16(glyphCount) ||
    184      !stream.WriteU16(flags) ||
    185      !stream.WriteU32(glyphVariationDataArrayOffset) ||
    186      !stream.Pad((glyphCount + 1) * sizeof(uint16_t))) {
    187    delete[] data;
    188    return DropVariations("Failed to generate dummy gvar table");
    189  }
    190 
    191  this->m_data = data;
    192  this->m_length = length;
    193  this->m_ownsData = true;
    194 
    195  return true;
    196 }
    197 #endif
    198 
    199 bool OpenTypeGVAR::Serialize(OTSStream* out) {
    200  if (!out->Write(this->m_data, this->m_length)) {
    201    return Error("Failed to write gvar table");
    202  }
    203 
    204  return true;
    205 }
    206 
    207 }  // namespace ots
    208 
    209 #undef TABLE_NAME