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 #include "variations.h"
11 #define TABLE_NAME "gvar"
15 // -----------------------------------------------------------------------------
17 // -----------------------------------------------------------------------------
19 static bool ParseSharedTuples(const Font
* font
, const uint8_t* data
, size_t length
,
20 size_t sharedTupleCount
, size_t axisCount
) {
21 Buffer
subtable(data
, length
);
22 for (unsigned i
= 0; i
< sharedTupleCount
; i
++) {
23 for (unsigned j
= 0; j
< axisCount
; j
++) {
25 if (!subtable
.ReadS16(&coordinate
)) {
26 return OTS_FAILURE_MSG("Failed to read shared tuple coordinate");
33 static bool ParseGlyphVariationDataArray(const Font
* font
, const uint8_t* data
, size_t length
,
34 uint16_t flags
, size_t glyphCount
, size_t axisCount
,
35 size_t sharedTupleCount
,
36 const uint8_t* glyphVariationData
,
37 size_t glyphVariationDataLength
) {
38 Buffer
subtable(data
, length
);
40 bool glyphVariationDataOffsetsAreLong
= (flags
& 0x0001u
);
41 uint32_t prevOffset
= 0;
42 for (size_t i
= 0; i
< glyphCount
+ 1; i
++) {
44 if (glyphVariationDataOffsetsAreLong
) {
45 if (!subtable
.ReadU32(&offset
)) {
46 return OTS_FAILURE_MSG("Failed to read GlyphVariationData offset");
50 if (!subtable
.ReadU16(&halfOffset
)) {
51 return OTS_FAILURE_MSG("Failed to read GlyphVariationData offset");
53 offset
= halfOffset
* 2;
56 if (i
> 0 && offset
> prevOffset
) {
57 if (prevOffset
> glyphVariationDataLength
) {
58 return OTS_FAILURE_MSG("Invalid GlyphVariationData offset");
60 if (!ParseVariationData(font
, glyphVariationData
+ prevOffset
,
61 glyphVariationDataLength
- prevOffset
,
62 axisCount
, sharedTupleCount
)) {
63 return OTS_FAILURE_MSG("Failed to parse GlyphVariationData");
72 bool OpenTypeGVAR::Parse(const uint8_t* data
, size_t length
) {
73 Buffer
table(data
, length
);
75 uint16_t majorVersion
;
76 uint16_t minorVersion
;
78 uint16_t sharedTupleCount
;
79 uint32_t sharedTuplesOffset
;
82 uint32_t glyphVariationDataArrayOffset
;
84 if (!table
.ReadU16(&majorVersion
) ||
85 !table
.ReadU16(&minorVersion
) ||
86 !table
.ReadU16(&axisCount
) ||
87 !table
.ReadU16(&sharedTupleCount
) ||
88 !table
.ReadU32(&sharedTuplesOffset
) ||
89 !table
.ReadU16(&glyphCount
) ||
90 !table
.ReadU16(&flags
) ||
91 !table
.ReadU32(&glyphVariationDataArrayOffset
)) {
92 return DropVariations("Failed to read table header");
94 if (majorVersion
!= 1) {
95 return DropVariations("Unknown table version");
98 // check axisCount == fvar->axisCount
99 OpenTypeFVAR
* fvar
= static_cast<OpenTypeFVAR
*>(
100 GetFont()->GetTypedTable(OTS_TAG_FVAR
));
102 return DropVariations("Required fvar table is missing");
104 if (axisCount
!= fvar
->AxisCount()) {
105 return DropVariations("Axis count mismatch");
108 // check glyphCount == maxp->num_glyphs
109 OpenTypeMAXP
* maxp
= static_cast<OpenTypeMAXP
*>(
110 GetFont()->GetTypedTable(OTS_TAG_MAXP
));
112 return DropVariations("Required maxp table is missing");
114 if (glyphCount
!= maxp
->num_glyphs
) {
115 return DropVariations("Glyph count mismatch");
118 if (sharedTupleCount
> 0) {
119 if (sharedTuplesOffset
< table
.offset() || sharedTuplesOffset
> length
) {
120 return DropVariations("Invalid sharedTuplesOffset");
122 if (!ParseSharedTuples(GetFont(),
123 data
+ sharedTuplesOffset
, length
- sharedTuplesOffset
,
124 sharedTupleCount
, axisCount
)) {
125 return DropVariations("Failed to parse shared tuples");
129 if (glyphVariationDataArrayOffset
) {
130 if (glyphVariationDataArrayOffset
> length
) {
131 return DropVariations("Invalid glyphVariationDataArrayOffset");
133 if (!ParseGlyphVariationDataArray(GetFont(),
134 data
+ table
.offset(), length
- table
.offset(),
135 flags
, glyphCount
, axisCount
, sharedTupleCount
,
136 data
+ glyphVariationDataArrayOffset
,
137 length
- glyphVariationDataArrayOffset
)) {
138 return DropVariations("Failed to read glyph variation data array");
143 this->m_length
= length
;
148 bool OpenTypeGVAR::Serialize(OTSStream
* out
) {
149 if (!out
->Write(this->m_data
, this->m_length
)) {
150 return Error("Failed to write gvar table");