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(&regionIndex) || 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                                 &regionCount)) {
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                                     &regionIndexCount)) {
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