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.
9 // OpenType Variations Common Table Formats
11 #define TABLE_NAME "Variations" // XXX: use individual table names
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
);
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) {
30 const ots::OpenTypeFVAR
* fvar
=
31 static_cast<ots::OpenTypeFVAR
*>(font
->GetTypedTable(OTS_TAG_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");
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
);
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
++) {
90 if (!subtable
.ReadU16(®ionIndex
) || 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");
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
);
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");
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
,
136 return OTS_FAILURE_MSG("Failed to parse variation region list");
139 for (unsigned i
= 0; i
< itemVariationDataCount
; i
++) {
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
,
150 ®ionIndexCount
)) {
151 return OTS_FAILURE_MSG("Failed to parse variation data subtable");
153 if (regionIndexCounts
) {
154 regionIndexCounts
->push_back(regionIndexCount
);
161 bool ParseDeltaSetIndexMap(const Font
* font
, const uint8_t* data
, const size_t length
) {
162 Buffer
subtable(data
, length
);
164 uint16_t entryFormat
;
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");
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
;
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
;
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
++) {
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
++) {
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
++) {
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