avar.cc (5054B)
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 "avar.h" 6 7 #include "fvar.h" 8 9 #include "variations.h" 10 11 namespace ots { 12 13 // ----------------------------------------------------------------------------- 14 // OpenTypeAVAR 15 // ----------------------------------------------------------------------------- 16 17 bool OpenTypeAVAR::Parse(const uint8_t* data, size_t length) { 18 Buffer table(data, length); 19 if (!table.ReadU16(&this->majorVersion) || 20 !table.ReadU16(&this->minorVersion) || 21 !table.ReadU16(&this->reserved) || 22 !table.ReadU16(&this->axisCount)) { 23 return Drop("Failed to read table header"); 24 } 25 if (this->majorVersion > 2) { 26 return Drop("Unknown table version"); 27 } 28 if (this->majorVersion == 1) { 29 // We can fix table 30 if (this->minorVersion > 0) { 31 // we only know how to serialize version 1.0 32 Warning("Downgrading minor version to 0"); 33 this->minorVersion = 0; 34 } 35 if (this->reserved != 0) { 36 Warning("Expected reserved=0"); 37 this->reserved = 0; 38 } 39 } else { 40 // We serialize data unchanged, so drop even for minor errors 41 if (this->minorVersion > 0) { 42 return Drop("Unknown minor table version"); 43 } 44 if (this->reserved != 0) { 45 return Drop("Expected reserved=0"); 46 } 47 } 48 49 OpenTypeFVAR* fvar = static_cast<OpenTypeFVAR*>( 50 GetFont()->GetTypedTable(OTS_TAG_FVAR)); 51 if (!fvar) { 52 return DropVariations("Required fvar table is missing"); 53 } 54 if (axisCount != fvar->AxisCount()) { 55 return Drop("Axis count mismatch"); 56 } 57 58 for (size_t i = 0; i < this->axisCount; i++) { 59 this->axisSegmentMaps.emplace_back(); 60 uint16_t positionMapCount; 61 if (!table.ReadU16(&positionMapCount)) { 62 return Drop("Failed to read position map count"); 63 } 64 int foundRequiredMappings = 0; 65 for (size_t j = 0; j < positionMapCount; j++) { 66 AxisValueMap map; 67 if (!table.ReadS16(&map.fromCoordinate) || 68 !table.ReadS16(&map.toCoordinate)) { 69 return Drop("Failed to read axis value map"); 70 } 71 if (map.fromCoordinate < -0x4000 || 72 map.fromCoordinate > 0x4000 || 73 map.toCoordinate < -0x4000 || 74 map.toCoordinate > 0x4000) { 75 return Drop("Axis value map coordinate out of range"); 76 } 77 if (j > 0) { 78 if (map.fromCoordinate <= this->axisSegmentMaps[i].back().fromCoordinate || 79 map.toCoordinate < this->axisSegmentMaps[i].back().toCoordinate) { 80 return Drop("Axis value map out of order"); 81 } 82 } 83 if ((map.fromCoordinate == -0x4000 && map.toCoordinate == -0x4000) || 84 (map.fromCoordinate == 0 && map.toCoordinate == 0) || 85 (map.fromCoordinate == 0x4000 && map.toCoordinate == 0x4000)) { 86 ++foundRequiredMappings; 87 } 88 this->axisSegmentMaps[i].push_back(map); 89 } 90 if (positionMapCount > 0 && foundRequiredMappings != 3) { 91 return Drop("A required mapping (for -1, 0 or 1) is missing"); 92 } 93 } 94 95 if (this->majorVersion < 2) 96 return true; 97 98 uint32_t axisIndexMapOffset; 99 uint32_t varStoreOffset; 100 101 if (!table.ReadU32(&axisIndexMapOffset) || 102 !table.ReadU32(&varStoreOffset)) { 103 return Drop("Failed to read version 2 offsets"); 104 } 105 106 Font *font = GetFont(); 107 uint32_t headerSize = table.offset(); 108 109 if (axisIndexMapOffset) { 110 if (axisIndexMapOffset < headerSize || axisIndexMapOffset >= length) { 111 return Drop("Bad delta set index offset in table header"); 112 } 113 if (!ParseDeltaSetIndexMap(font, data + axisIndexMapOffset, length - axisIndexMapOffset)) { 114 return Drop("Failed to parse delta set index map"); 115 } 116 } 117 118 if (varStoreOffset) { 119 if (varStoreOffset < headerSize || varStoreOffset >= length) { 120 return Drop("Bad item variation store offset in table header"); 121 } 122 if (!ParseItemVariationStore(font, data + varStoreOffset, length - varStoreOffset)) { 123 return Drop("Failed to parse item variation store"); 124 } 125 } 126 127 this->m_data = data; 128 this->m_length = length; 129 130 return true; 131 } 132 133 bool OpenTypeAVAR::Serialize(OTSStream* out) { 134 if (this->majorVersion >= 2) { 135 if (!out->Write(this->m_data, this->m_length)) { 136 return Error("Failed to write table"); 137 } 138 return true; 139 } 140 141 if (!out->WriteU16(this->majorVersion) || 142 !out->WriteU16(this->minorVersion) || 143 !out->WriteU16(this->reserved) || 144 !out->WriteU16(this->axisCount)) { 145 return Error("Failed to write table"); 146 } 147 148 for (size_t i = 0; i < this->axisCount; i++) { 149 const auto& axisValueMap = this->axisSegmentMaps[i]; 150 if (!out->WriteU16(axisValueMap.size())) { 151 return Error("Failed to write table"); 152 } 153 for (size_t j = 0; j < axisValueMap.size(); j++) { 154 if (!out->WriteS16(axisValueMap[j].fromCoordinate) || 155 !out->WriteS16(axisValueMap[j].toCoordinate)) { 156 return Error("Failed to write table"); 157 } 158 } 159 } 160 161 return true; 162 } 163 164 } // namespace ots