Backed out 3 changesets (bug 1918178) for causing reftest failures. a=backout
[gecko.git] / gfx / ots / src / variations.cc
blob55afd976cadfdc26898c3675e064baa7a7c2f712
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.
5 #include "layout.h"
7 #include "fvar.h"
9 // OpenType Variations Common Table Formats
11 #define TABLE_NAME "Variations" // XXX: use individual table names
13 namespace {
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);
19 uint16_t axisCount;
21 if (!subtable.ReadU16(&axisCount) ||
22 !subtable.ReadU16(regionCount)) {
23 return OTS_FAILURE_MSG("Failed to read variation region list header");
26 if (*regionCount == 0) {
27 return true;
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");
35 if (axisCount != fvar->AxisCount()) {
36 return OTS_FAILURE_MSG("Axis count mismatch");
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");
47 if (startCoord > peakCoord || peakCoord > endCoord) {
48 return OTS_FAILURE_MSG("Region axis coordinates out of order");
50 if (startCoord < -0x4000 || endCoord > 0x4000) {
51 return OTS_FAILURE_MSG("Region axis coordinate out of range");
53 if ((peakCoord < 0 && endCoord > 0) ||
54 (peakCoord > 0 && startCoord < 0)) {
55 return OTS_FAILURE_MSG("Invalid region axis coordinates");
60 return true;
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);
69 uint16_t itemCount;
70 uint16_t wordDeltaCount;
72 const uint16_t LONG_WORDS = 0x8000u;
73 const uint16_t WORD_DELTA_COUNT_MASK = 0x7FFF;
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");
81 size_t valueSize = (wordDeltaCount & LONG_WORDS) ? 2 : 1;
82 wordDeltaCount &= WORD_DELTA_COUNT_MASK;
84 if (wordDeltaCount > *regionIndexCount) {
85 return OTS_FAILURE_MSG("Bad word delta count");
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");
95 if (!subtable.Skip(valueSize * size_t(itemCount) * (size_t(wordDeltaCount) + size_t(*regionIndexCount)))) {
96 return OTS_FAILURE_MSG("Failed to read delta data");
99 return true;
102 } // namespace
104 namespace ots {
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);
112 uint16_t format;
113 uint32_t variationRegionListOffset;
114 uint16_t itemVariationDataCount;
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");
122 if (format != 1) {
123 return OTS_FAILURE_MSG("Unknown item variation store format");
126 if (variationRegionListOffset < subtable.offset() + 4 * itemVariationDataCount ||
127 variationRegionListOffset > length) {
128 return OTS_FAILURE_MSG("Invalid variation region list offset");
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");
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");
144 if (offset >= length) {
145 return OTS_FAILURE_MSG("Bad offset to variation data subtable");
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");
153 if (regionIndexCounts) {
154 regionIndexCounts->push_back(regionIndexCount);
158 return true;
161 bool ParseDeltaSetIndexMap(const Font* font, const uint8_t* data, const size_t length) {
162 Buffer subtable(data, length);
164 uint16_t entryFormat;
165 uint16_t mapCount;
167 if (!subtable.ReadU16(&entryFormat) ||
168 !subtable.ReadU16(&mapCount)) {
169 return OTS_FAILURE_MSG("Failed to read delta set index map header");
172 const uint16_t MAP_ENTRY_SIZE_MASK = 0x0030;
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");
179 return true;
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);
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");
193 if (dataOffset > length) {
194 return OTS_FAILURE_MSG("Invalid serialized data offset");
197 tupleVariationCount &= 0x0FFF; // mask off flags
199 const uint16_t EMBEDDED_PEAK_TUPLE = 0x8000;
200 const uint16_t INTERMEDIATE_REGION = 0x4000;
201 const uint16_t TUPLE_INDEX_MASK = 0x0FFF;
203 for (unsigned i = 0; i < tupleVariationCount; i++) {
204 uint16_t variationDataSize;
205 uint16_t tupleIndex;
207 if (!subtable.ReadU16(&variationDataSize) ||
208 !subtable.ReadU16(&tupleIndex)) {
209 return OTS_FAILURE_MSG("Failed to read tuple variation header");
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");
218 if (coordinate < -0x4000 || coordinate > 0x4000) {
219 return OTS_FAILURE_MSG("Tuple coordinate not in the range [-1.0, 1.0]: %g", coordinate / 16384.);
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");
231 if (coordinate < -0x4000 || coordinate > 0x4000) {
232 return OTS_FAILURE_MSG("Tuple coordinate not in the range [-1.0, 1.0]: %g", coordinate / 16384.);
234 startTuple.push_back(coordinate);
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");
243 if (coordinate < -0x4000 || coordinate > 0x4000) {
244 return OTS_FAILURE_MSG("Tuple coordinate not in the range [-1.0, 1.0]: %g", coordinate / 16384.);
246 endTuple.push_back(coordinate);
249 for (unsigned axis = 0; axis < axisCount; axis++) {
250 if (startTuple[axis] > endTuple[axis]) {
251 return OTS_FAILURE_MSG("Invalid intermediate range");
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");
264 // TODO: we don't attempt to interpret the serialized data block
266 return true;
269 } // namespace ots
271 #undef TABLE_NAME