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(®ionIndex) || 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 ®ionCount)) { 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 ®ionIndexCount)) { 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