// Copyright (c) 2018 The OTS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "avar.h" #include "fvar.h" namespace ots { // ----------------------------------------------------------------------------- // OpenTypeAVAR // ----------------------------------------------------------------------------- bool OpenTypeAVAR::Parse(const uint8_t* data, size_t length) { Buffer table(data, length); if (!table.ReadU16(&this->majorVersion) || !table.ReadU16(&this->minorVersion) || !table.ReadU16(&this->reserved) || !table.ReadU16(&this->axisCount)) { return Drop("Failed to read table header"); } if (this->majorVersion != 1) { return Drop("Unknown table version"); } if (this->minorVersion > 0) { // we only know how to serialize version 1.0 Warning("Downgrading minor version to 0"); this->minorVersion = 0; } if (this->reserved != 0) { Warning("Expected reserved=0"); this->reserved = 0; } OpenTypeFVAR* fvar = static_cast( GetFont()->GetTypedTable(OTS_TAG_FVAR)); if (!fvar) { return DropVariations("Required fvar table is missing"); } if (axisCount != fvar->AxisCount()) { return Drop("Axis count mismatch"); } for (size_t i = 0; i < this->axisCount; i++) { this->axisSegmentMaps.emplace_back(); uint16_t positionMapCount; if (!table.ReadU16(&positionMapCount)) { return Drop("Failed to read position map count"); } int foundRequiredMappings = 0; for (size_t j = 0; j < positionMapCount; j++) { AxisValueMap map; if (!table.ReadS16(&map.fromCoordinate) || !table.ReadS16(&map.toCoordinate)) { return Drop("Failed to read axis value map"); } if (map.fromCoordinate < -0x4000 || map.fromCoordinate > 0x4000 || map.toCoordinate < -0x4000 || map.toCoordinate > 0x4000) { return Drop("Axis value map coordinate out of range"); } if (j > 0) { if (map.fromCoordinate <= this->axisSegmentMaps[i].back().fromCoordinate || map.toCoordinate < this->axisSegmentMaps[i].back().toCoordinate) { return Drop("Axis value map out of order"); } } if ((map.fromCoordinate == -0x4000 && map.toCoordinate == -0x4000) || (map.fromCoordinate == 0 && map.toCoordinate == 0) || (map.fromCoordinate == 0x4000 && map.toCoordinate == 0x4000)) { ++foundRequiredMappings; } this->axisSegmentMaps[i].push_back(map); } if (positionMapCount > 0 && foundRequiredMappings != 3) { return Drop("A required mapping (for -1, 0 or 1) is missing"); } } return true; } bool OpenTypeAVAR::Serialize(OTSStream* out) { if (!out->WriteU16(this->majorVersion) || !out->WriteU16(this->minorVersion) || !out->WriteU16(this->reserved) || !out->WriteU16(this->axisCount)) { return Error("Failed to write table"); } for (size_t i = 0; i < this->axisCount; i++) { const auto& axisValueMap = this->axisSegmentMaps[i]; if (!out->WriteU16(axisValueMap.size())) { return Error("Failed to write table"); } for (size_t j = 0; j < axisValueMap.size(); j++) { if (!out->WriteS16(axisValueMap[j].fromCoordinate) || !out->WriteS16(axisValueMap[j].toCoordinate)) { return Error("Failed to write table"); } } } return true; } } // namespace ots