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
ParseVariationRegionList(const ots::Font * font,const uint8_t * data,const size_t length,uint16_t * regionCount)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
ParseVariationDataSubtable(const ots::Font * font,const uint8_t * data,const size_t length,const uint16_t regionCount,uint16_t * regionIndexCount)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 shortDeltaCount;
71
72 if (!subtable.ReadU16(&itemCount) ||
73 !subtable.ReadU16(&shortDeltaCount) ||
74 !subtable.ReadU16(regionIndexCount)) {
75 return OTS_FAILURE_MSG("Failed to read variation data subtable header");
76 }
77
78 for (unsigned i = 0; i < *regionIndexCount; i++) {
79 uint16_t regionIndex;
80 if (!subtable.ReadU16(®ionIndex) || regionIndex >= regionCount) {
81 return OTS_FAILURE_MSG("Bad region index");
82 }
83 }
84
85 if (!subtable.Skip(size_t(itemCount) * (size_t(shortDeltaCount) + size_t(*regionIndexCount)))) {
86 return OTS_FAILURE_MSG("Failed to read delta data");
87 }
88
89 return true;
90 }
91
92 } // namespace
93
94 namespace ots {
95
96 bool
ParseItemVariationStore(const Font * font,const uint8_t * data,const size_t length,std::vector<uint16_t> * regionIndexCounts)97 ParseItemVariationStore(const Font* font,
98 const uint8_t* data, const size_t length,
99 std::vector<uint16_t>* regionIndexCounts) {
100 Buffer subtable(data, length);
101
102 uint16_t format;
103 uint32_t variationRegionListOffset;
104 uint16_t itemVariationDataCount;
105
106 if (!subtable.ReadU16(&format) ||
107 !subtable.ReadU32(&variationRegionListOffset) ||
108 !subtable.ReadU16(&itemVariationDataCount)) {
109 return OTS_FAILURE_MSG("Failed to read item variation store header");
110 }
111
112 if (format != 1) {
113 return OTS_FAILURE_MSG("Unknown item variation store format");
114 }
115
116 if (variationRegionListOffset < subtable.offset() + 4 * itemVariationDataCount ||
117 variationRegionListOffset > length) {
118 return OTS_FAILURE_MSG("Invalid variation region list offset");
119 }
120
121 uint16_t regionCount;
122 if (!ParseVariationRegionList(font,
123 data + variationRegionListOffset,
124 length - variationRegionListOffset,
125 ®ionCount)) {
126 return OTS_FAILURE_MSG("Failed to parse variation region list");
127 }
128
129 for (unsigned i = 0; i < itemVariationDataCount; i++) {
130 uint32_t offset;
131 if (!subtable.ReadU32(&offset)) {
132 return OTS_FAILURE_MSG("Failed to read variation data subtable offset");
133 }
134 if (offset >= length) {
135 return OTS_FAILURE_MSG("Bad offset to variation data subtable");
136 }
137 uint16_t regionIndexCount = 0;
138 if (!ParseVariationDataSubtable(font, data + offset, length - offset,
139 regionCount,
140 ®ionIndexCount)) {
141 return OTS_FAILURE_MSG("Failed to parse variation data subtable");
142 }
143 if (regionIndexCounts) {
144 regionIndexCounts->push_back(regionIndexCount);
145 }
146 }
147
148 return true;
149 }
150
ParseDeltaSetIndexMap(const Font * font,const uint8_t * data,const size_t length)151 bool ParseDeltaSetIndexMap(const Font* font, const uint8_t* data, const size_t length) {
152 Buffer subtable(data, length);
153
154 uint16_t entryFormat;
155 uint16_t mapCount;
156
157 if (!subtable.ReadU16(&entryFormat) ||
158 !subtable.ReadU16(&mapCount)) {
159 return OTS_FAILURE_MSG("Failed to read delta set index map header");
160 }
161
162 const uint16_t MAP_ENTRY_SIZE_MASK = 0x0030;
163
164 const uint16_t entrySize = (((entryFormat & MAP_ENTRY_SIZE_MASK) >> 4) + 1);
165 if (!subtable.Skip(entrySize * mapCount)) {
166 return OTS_FAILURE_MSG("Failed to read delta set index map data");
167 }
168
169 return true;
170 }
171
ParseVariationData(const Font * font,const uint8_t * data,size_t length,size_t axisCount,size_t sharedTupleCount)172 bool ParseVariationData(const Font* font, const uint8_t* data, size_t length,
173 size_t axisCount, size_t sharedTupleCount) {
174 Buffer subtable(data, length);
175
176 uint16_t tupleVariationCount;
177 uint16_t dataOffset;
178 if (!subtable.ReadU16(&tupleVariationCount) ||
179 !subtable.ReadU16(&dataOffset)) {
180 return OTS_FAILURE_MSG("Failed to read variation data header");
181 }
182
183 if (dataOffset > length) {
184 return OTS_FAILURE_MSG("Invalid serialized data offset");
185 }
186
187 tupleVariationCount &= 0x0FFF; // mask off flags
188
189 const uint16_t EMBEDDED_PEAK_TUPLE = 0x8000;
190 const uint16_t INTERMEDIATE_REGION = 0x4000;
191 const uint16_t TUPLE_INDEX_MASK = 0x0FFF;
192
193 for (unsigned i = 0; i < tupleVariationCount; i++) {
194 uint16_t variationDataSize;
195 uint16_t tupleIndex;
196
197 if (!subtable.ReadU16(&variationDataSize) ||
198 !subtable.ReadU16(&tupleIndex)) {
199 return OTS_FAILURE_MSG("Failed to read tuple variation header");
200 }
201
202 if (tupleIndex & EMBEDDED_PEAK_TUPLE) {
203 for (unsigned axis = 0; axis < axisCount; axis++) {
204 int16_t coordinate;
205 if (!subtable.ReadS16(&coordinate)) {
206 return OTS_FAILURE_MSG("Failed to read tuple coordinate");
207 }
208 if (coordinate < -0x4000 || coordinate > 0x4000) {
209 return OTS_FAILURE_MSG("Invalid tuple coordinate");
210 }
211 }
212 }
213
214 if (tupleIndex & INTERMEDIATE_REGION) {
215 std::vector<int16_t> startTuple(axisCount);
216 for (unsigned axis = 0; axis < axisCount; axis++) {
217 int16_t coordinate;
218 if (!subtable.ReadS16(&coordinate)) {
219 return OTS_FAILURE_MSG("Failed to read tuple coordinate");
220 }
221 if (coordinate < -0x4000 || coordinate > 0x4000) {
222 return OTS_FAILURE_MSG("Invalid tuple coordinate");
223 }
224 startTuple.push_back(coordinate);
225 }
226
227 std::vector<int16_t> endTuple(axisCount);
228 for (unsigned axis = 0; axis < axisCount; axis++) {
229 int16_t coordinate;
230 if (!subtable.ReadS16(&coordinate)) {
231 return OTS_FAILURE_MSG("Failed to read tuple coordinate");
232 }
233 if (coordinate < -0x4000 || coordinate > 0x4000) {
234 return OTS_FAILURE_MSG("Invalid tuple coordinate");
235 }
236 endTuple.push_back(coordinate);
237 }
238
239 for (unsigned axis = 0; axis < axisCount; axis++) {
240 if (startTuple[axis] > endTuple[axis]) {
241 return OTS_FAILURE_MSG("Invalid intermediate range");
242 }
243 }
244 }
245
246 if (!(tupleIndex & EMBEDDED_PEAK_TUPLE)) {
247 tupleIndex &= TUPLE_INDEX_MASK;
248 if (tupleIndex >= sharedTupleCount) {
249 return OTS_FAILURE_MSG("Tuple index out of range");
250 }
251 }
252 }
253
254 // TODO: we don't attempt to interpret the serialized data block
255
256 return true;
257 }
258
259 } // namespace ots
260
261 #undef TABLE_NAME
262