tor-browser

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

variations.cc (8508B)


      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 "layout.h"
      6 
      7 #include "fvar.h"
      8 
      9 // OpenType Variations Common Table Formats
     10 
     11 #define TABLE_NAME "Variations" // XXX: use individual table names
     12 
     13 namespace {
     14 
     15 bool ParseVariationRegionList(const ots::Font* font, const uint8_t* data, const size_t length,
     16                              uint16_t* regionCount) {
     17  ots::Buffer subtable(data, length);
     18 
     19  uint16_t axisCount;
     20 
     21  if (!subtable.ReadU16(&axisCount) ||
     22      !subtable.ReadU16(regionCount)) {
     23    return OTS_FAILURE_MSG("Failed to read variation region list header");
     24  }
     25 
     26  if (*regionCount == 0) {
     27    return true;
     28  }
     29 
     30  const ots::OpenTypeFVAR* fvar =
     31    static_cast<ots::OpenTypeFVAR*>(font->GetTypedTable(OTS_TAG_FVAR));
     32  if (!fvar) {
     33    return OTS_FAILURE_MSG("Required fvar table is missing");
     34  }
     35  if (axisCount != fvar->AxisCount()) {
     36    return OTS_FAILURE_MSG("Axis count mismatch");
     37  }
     38 
     39  for (unsigned i = 0; i < *regionCount; i++) {
     40    for (unsigned j = 0; j < axisCount; j++) {
     41      int16_t startCoord, peakCoord, endCoord;
     42      if (!subtable.ReadS16(&startCoord) ||
     43          !subtable.ReadS16(&peakCoord) ||
     44          !subtable.ReadS16(&endCoord)) {
     45        return OTS_FAILURE_MSG("Failed to read region axis coordinates");
     46      }
     47      if (startCoord > peakCoord || peakCoord > endCoord) {
     48        return OTS_FAILURE_MSG("Region axis coordinates out of order");
     49      }
     50      if (startCoord < -0x4000 || endCoord > 0x4000) {
     51        return OTS_FAILURE_MSG("Region axis coordinate out of range");
     52      }
     53      if ((peakCoord < 0 && endCoord > 0) ||
     54          (peakCoord > 0 && startCoord < 0)) {
     55        return OTS_FAILURE_MSG("Invalid region axis coordinates");
     56      }
     57    }
     58  }
     59 
     60  return true;
     61 }
     62 
     63 bool
     64 ParseVariationDataSubtable(const ots::Font* font, const uint8_t* data, const size_t length,
     65                           const uint16_t regionCount,
     66                           uint16_t* regionIndexCount) {
     67  ots::Buffer subtable(data, length);
     68 
     69  uint16_t itemCount;
     70  uint16_t wordDeltaCount;
     71 
     72  const uint16_t LONG_WORDS	= 0x8000u;
     73  const uint16_t WORD_DELTA_COUNT_MASK = 0x7FFF;
     74 
     75  if (!subtable.ReadU16(&itemCount) ||
     76      !subtable.ReadU16(&wordDeltaCount) ||
     77      !subtable.ReadU16(regionIndexCount)) {
     78    return OTS_FAILURE_MSG("Failed to read variation data subtable header");
     79  }
     80 
     81  size_t valueSize = (wordDeltaCount & LONG_WORDS) ? 2 : 1;
     82  wordDeltaCount &= WORD_DELTA_COUNT_MASK;
     83 
     84  if (wordDeltaCount > *regionIndexCount) {
     85    return OTS_FAILURE_MSG("Bad word delta count");
     86  }
     87 
     88  for (unsigned i = 0; i < *regionIndexCount; i++) {
     89    uint16_t regionIndex;
     90    if (!subtable.ReadU16(&regionIndex) || regionIndex >= regionCount) {
     91      return OTS_FAILURE_MSG("Bad region index");
     92    }
     93  }
     94 
     95  if (!subtable.Skip(valueSize * size_t(itemCount) * (size_t(wordDeltaCount) + size_t(*regionIndexCount)))) {
     96    return OTS_FAILURE_MSG("Failed to read delta data");
     97  }
     98 
     99  return true;
    100 }
    101 
    102 } // namespace
    103 
    104 namespace ots {
    105 
    106 bool
    107 ParseItemVariationStore(const Font* font,
    108                        const uint8_t* data, const size_t length,
    109                        std::vector<uint16_t>* regionIndexCounts) {
    110  Buffer subtable(data, length);
    111 
    112  uint16_t format;
    113  uint32_t variationRegionListOffset;
    114  uint16_t itemVariationDataCount;
    115 
    116  if (!subtable.ReadU16(&format) ||
    117      !subtable.ReadU32(&variationRegionListOffset) ||
    118      !subtable.ReadU16(&itemVariationDataCount)) {
    119    return OTS_FAILURE_MSG("Failed to read item variation store header");
    120  }
    121 
    122  if (format != 1) {
    123    return OTS_FAILURE_MSG("Unknown item variation store format");
    124  }
    125 
    126  if (variationRegionListOffset < subtable.offset() + 4 * itemVariationDataCount ||
    127      variationRegionListOffset > length) {
    128    return OTS_FAILURE_MSG("Invalid variation region list offset");
    129  }
    130 
    131  uint16_t regionCount;
    132  if (!ParseVariationRegionList(font,
    133                                data + variationRegionListOffset,
    134                                length - variationRegionListOffset,
    135                                &regionCount)) {
    136    return OTS_FAILURE_MSG("Failed to parse variation region list");
    137  }
    138 
    139  for (unsigned i = 0; i < itemVariationDataCount; i++) {
    140    uint32_t offset;
    141    if (!subtable.ReadU32(&offset)) {
    142      return OTS_FAILURE_MSG("Failed to read variation data subtable offset");
    143    }
    144    if (offset >= length) {
    145      return OTS_FAILURE_MSG("Bad offset to variation data subtable");
    146    }
    147    uint16_t regionIndexCount = 0;
    148    if (!ParseVariationDataSubtable(font, data + offset, length - offset,
    149                                    regionCount,
    150                                    &regionIndexCount)) {
    151      return OTS_FAILURE_MSG("Failed to parse variation data subtable");
    152    }
    153    if (regionIndexCounts) {
    154      regionIndexCounts->push_back(regionIndexCount);
    155    }
    156  }
    157 
    158  return true;
    159 }
    160 
    161 bool ParseDeltaSetIndexMap(const Font* font, const uint8_t* data, const size_t length) {
    162  Buffer subtable(data, length);
    163 
    164  uint16_t entryFormat;
    165  uint16_t mapCount;
    166 
    167  if (!subtable.ReadU16(&entryFormat) ||
    168      !subtable.ReadU16(&mapCount)) {
    169    return OTS_FAILURE_MSG("Failed to read delta set index map header");
    170  }
    171 
    172  const uint16_t MAP_ENTRY_SIZE_MASK = 0x0030;
    173 
    174  const uint16_t entrySize = (((entryFormat & MAP_ENTRY_SIZE_MASK) >> 4) + 1);
    175  if (!subtable.Skip(entrySize * mapCount)) {
    176    return OTS_FAILURE_MSG("Failed to read delta set index map data");
    177  }
    178 
    179  return true;
    180 }
    181 
    182 bool ParseVariationData(const Font* font, const uint8_t* data, size_t length,
    183                        size_t axisCount, size_t sharedTupleCount) {
    184  Buffer subtable(data, length);
    185 
    186  uint16_t tupleVariationCount;
    187  uint16_t dataOffset;
    188  if (!subtable.ReadU16(&tupleVariationCount) ||
    189      !subtable.ReadU16(&dataOffset)) {
    190    return OTS_FAILURE_MSG("Failed to read variation data header");
    191  }
    192 
    193  if (dataOffset > length) {
    194    return OTS_FAILURE_MSG("Invalid serialized data offset");
    195  }
    196 
    197  tupleVariationCount &= 0x0FFF; // mask off flags
    198 
    199  const uint16_t EMBEDDED_PEAK_TUPLE = 0x8000;
    200  const uint16_t INTERMEDIATE_REGION = 0x4000;
    201  const uint16_t TUPLE_INDEX_MASK    = 0x0FFF;
    202 
    203  for (unsigned i = 0; i < tupleVariationCount; i++) {
    204    uint16_t variationDataSize;
    205    uint16_t tupleIndex;
    206 
    207    if (!subtable.ReadU16(&variationDataSize) ||
    208        !subtable.ReadU16(&tupleIndex)) {
    209      return OTS_FAILURE_MSG("Failed to read tuple variation header");
    210    }
    211 
    212    if (tupleIndex & EMBEDDED_PEAK_TUPLE) {
    213      for (unsigned axis = 0; axis < axisCount; axis++) {
    214        int16_t coordinate;
    215        if (!subtable.ReadS16(&coordinate)) {
    216          return OTS_FAILURE_MSG("Failed to read tuple coordinate");
    217        }
    218        if (coordinate < -0x4000 || coordinate > 0x4000) {
    219          return OTS_FAILURE_MSG("Tuple coordinate not in the range [-1.0, 1.0]: %g", coordinate / 16384.);
    220        }
    221      }
    222    }
    223 
    224    if (tupleIndex & INTERMEDIATE_REGION) {
    225      std::vector<int16_t> startTuple(axisCount);
    226      for (unsigned axis = 0; axis < axisCount; axis++) {
    227        int16_t coordinate;
    228        if (!subtable.ReadS16(&coordinate)) {
    229          return OTS_FAILURE_MSG("Failed to read tuple coordinate");
    230        }
    231        if (coordinate < -0x4000 || coordinate > 0x4000) {
    232          return OTS_FAILURE_MSG("Tuple coordinate not in the range [-1.0, 1.0]: %g", coordinate / 16384.);
    233        }
    234        startTuple.push_back(coordinate);
    235      }
    236 
    237      std::vector<int16_t> endTuple(axisCount);
    238      for (unsigned axis = 0; axis < axisCount; axis++) {
    239        int16_t coordinate;
    240        if (!subtable.ReadS16(&coordinate)) {
    241          return OTS_FAILURE_MSG("Failed to read tuple coordinate");
    242        }
    243        if (coordinate < -0x4000 || coordinate > 0x4000) {
    244          return OTS_FAILURE_MSG("Tuple coordinate not in the range [-1.0, 1.0]: %g", coordinate / 16384.);
    245        }
    246        endTuple.push_back(coordinate);
    247      }
    248 
    249      for (unsigned axis = 0; axis < axisCount; axis++) {
    250        if (startTuple[axis] > endTuple[axis]) {
    251          return OTS_FAILURE_MSG("Invalid intermediate range");
    252        }
    253      }
    254    }
    255 
    256    if (!(tupleIndex & EMBEDDED_PEAK_TUPLE)) {
    257      tupleIndex &= TUPLE_INDEX_MASK;
    258      if (tupleIndex >= sharedTupleCount) {
    259        return OTS_FAILURE_MSG("Tuple index out of range");
    260      }
    261    }
    262  }
    263 
    264  // TODO: we don't attempt to interpret the serialized data block
    265 
    266  return true;
    267 }
    268 
    269 } // namespace ots
    270 
    271 #undef TABLE_NAME