gvar.cc (6796B)
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 "gvar.h" 6 7 #include "fvar.h" 8 #include "maxp.h" 9 #include "variations.h" 10 #include "ots-memory-stream.h" 11 12 #define TABLE_NAME "gvar" 13 14 namespace ots { 15 16 // ----------------------------------------------------------------------------- 17 // OpenTypeGVAR 18 // ----------------------------------------------------------------------------- 19 20 static bool ParseSharedTuples(const Font* font, const uint8_t* data, size_t length, 21 size_t sharedTupleCount, size_t axisCount) { 22 Buffer subtable(data, length); 23 for (unsigned i = 0; i < sharedTupleCount; i++) { 24 for (unsigned j = 0; j < axisCount; j++) { 25 int16_t coordinate; 26 if (!subtable.ReadS16(&coordinate)) { 27 return OTS_FAILURE_MSG("Failed to read shared tuple coordinate"); 28 } 29 } 30 } 31 return true; 32 } 33 34 static bool ParseGlyphVariationDataArray(const Font* font, const uint8_t* data, size_t length, 35 uint16_t flags, size_t glyphCount, size_t axisCount, 36 size_t sharedTupleCount, 37 const uint8_t* glyphVariationData, 38 size_t glyphVariationDataLength) { 39 Buffer subtable(data, length); 40 41 bool glyphVariationDataOffsetsAreLong = (flags & 0x0001u); 42 uint32_t prevOffset = 0; 43 for (size_t i = 0; i < glyphCount + 1; i++) { 44 uint32_t offset; 45 if (glyphVariationDataOffsetsAreLong) { 46 if (!subtable.ReadU32(&offset)) { 47 return OTS_FAILURE_MSG("Failed to read GlyphVariationData offset"); 48 } 49 } else { 50 uint16_t halfOffset; 51 if (!subtable.ReadU16(&halfOffset)) { 52 return OTS_FAILURE_MSG("Failed to read GlyphVariationData offset"); 53 } 54 offset = halfOffset * 2; 55 } 56 57 if (i > 0 && offset > prevOffset) { 58 if (prevOffset > glyphVariationDataLength) { 59 return OTS_FAILURE_MSG("Invalid GlyphVariationData offset"); 60 } 61 if (!ParseVariationData(font, glyphVariationData + prevOffset, 62 glyphVariationDataLength - prevOffset, 63 axisCount, sharedTupleCount)) { 64 return OTS_FAILURE_MSG("Failed to parse GlyphVariationData"); 65 } 66 } 67 prevOffset = offset; 68 } 69 70 return true; 71 } 72 73 bool OpenTypeGVAR::Parse(const uint8_t* data, size_t length) { 74 Buffer table(data, length); 75 76 uint16_t majorVersion; 77 uint16_t minorVersion; 78 uint16_t axisCount; 79 uint16_t sharedTupleCount; 80 uint32_t sharedTuplesOffset; 81 uint16_t glyphCount; 82 uint16_t flags; 83 uint32_t glyphVariationDataArrayOffset; 84 85 if (!table.ReadU16(&majorVersion) || 86 !table.ReadU16(&minorVersion) || 87 !table.ReadU16(&axisCount) || 88 !table.ReadU16(&sharedTupleCount) || 89 !table.ReadU32(&sharedTuplesOffset) || 90 !table.ReadU16(&glyphCount) || 91 !table.ReadU16(&flags) || 92 !table.ReadU32(&glyphVariationDataArrayOffset)) { 93 return DropVariations("Failed to read table header"); 94 } 95 if (majorVersion != 1) { 96 return DropVariations("Unknown table version"); 97 } 98 99 // check axisCount == fvar->axisCount 100 OpenTypeFVAR* fvar = static_cast<OpenTypeFVAR*>( 101 GetFont()->GetTypedTable(OTS_TAG_FVAR)); 102 if (!fvar) { 103 return DropVariations("Required fvar table is missing"); 104 } 105 if (axisCount != fvar->AxisCount()) { 106 return DropVariations("Axis count mismatch"); 107 } 108 109 // check glyphCount == maxp->num_glyphs 110 OpenTypeMAXP* maxp = static_cast<OpenTypeMAXP*>( 111 GetFont()->GetTypedTable(OTS_TAG_MAXP)); 112 if (!maxp) { 113 return DropVariations("Required maxp table is missing"); 114 } 115 if (glyphCount != maxp->num_glyphs) { 116 return DropVariations("Glyph count mismatch"); 117 } 118 119 if (sharedTupleCount > 0) { 120 if (sharedTuplesOffset < table.offset() || sharedTuplesOffset > length) { 121 return DropVariations("Invalid sharedTuplesOffset"); 122 } 123 if (!ParseSharedTuples(GetFont(), 124 data + sharedTuplesOffset, length - sharedTuplesOffset, 125 sharedTupleCount, axisCount)) { 126 return DropVariations("Failed to parse shared tuples"); 127 } 128 } 129 130 if (glyphVariationDataArrayOffset) { 131 if (glyphVariationDataArrayOffset > length) { 132 return DropVariations("Invalid glyphVariationDataArrayOffset"); 133 } 134 if (!ParseGlyphVariationDataArray(GetFont(), 135 data + table.offset(), length - table.offset(), 136 flags, glyphCount, axisCount, sharedTupleCount, 137 data + glyphVariationDataArrayOffset, 138 length - glyphVariationDataArrayOffset)) { 139 return DropVariations("Failed to read glyph variation data array"); 140 } 141 } 142 143 this->m_data = data; 144 this->m_length = length; 145 146 return true; 147 } 148 149 #ifdef OTS_SYNTHESIZE_MISSING_GVAR 150 bool OpenTypeGVAR::InitEmpty() { 151 // Generate an empty but well-formed 'gvar' table for the font. 152 const ots::Font* font = GetFont(); 153 154 OpenTypeFVAR* fvar = static_cast<OpenTypeFVAR*>(font->GetTypedTable(OTS_TAG_FVAR)); 155 if (!fvar) { 156 return DropVariations("Required fvar table missing"); 157 } 158 159 OpenTypeMAXP* maxp = static_cast<OpenTypeMAXP*>(font->GetTypedTable(OTS_TAG_MAXP)); 160 if (!maxp) { 161 return DropVariations("Required maxp table missing"); 162 } 163 164 uint16_t majorVersion = 1; 165 uint16_t minorVersion = 0; 166 uint16_t axisCount = fvar->AxisCount(); 167 uint16_t sharedTupleCount = 0; 168 uint32_t sharedTuplesOffset = 0; 169 uint16_t glyphCount = maxp->num_glyphs; 170 uint16_t flags = 0; 171 uint32_t glyphVariationDataArrayOffset = 0; 172 173 size_t length = 6 * sizeof(uint16_t) + 2 * sizeof(uint32_t) // basic header fields 174 + (glyphCount + 1) * sizeof(uint16_t); // glyphVariationDataOffsets[] array 175 176 uint8_t* data = new uint8_t[length]; 177 MemoryStream stream(data, length); 178 if (!stream.WriteU16(majorVersion) || 179 !stream.WriteU16(minorVersion) || 180 !stream.WriteU16(axisCount) || 181 !stream.WriteU16(sharedTupleCount) || 182 !stream.WriteU32(sharedTuplesOffset) || 183 !stream.WriteU16(glyphCount) || 184 !stream.WriteU16(flags) || 185 !stream.WriteU32(glyphVariationDataArrayOffset) || 186 !stream.Pad((glyphCount + 1) * sizeof(uint16_t))) { 187 delete[] data; 188 return DropVariations("Failed to generate dummy gvar table"); 189 } 190 191 this->m_data = data; 192 this->m_length = length; 193 this->m_ownsData = true; 194 195 return true; 196 } 197 #endif 198 199 bool OpenTypeGVAR::Serialize(OTSStream* out) { 200 if (!out->Write(this->m_data, this->m_length)) { 201 return Error("Failed to write gvar table"); 202 } 203 204 return true; 205 } 206 207 } // namespace ots 208 209 #undef TABLE_NAME