diff options
Diffstat (limited to 'gfx/ots/src/gvar.cc')
-rw-r--r-- | gfx/ots/src/gvar.cc | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/gfx/ots/src/gvar.cc b/gfx/ots/src/gvar.cc new file mode 100644 index 000000000..324a0fc83 --- /dev/null +++ b/gfx/ots/src/gvar.cc @@ -0,0 +1,158 @@ +// Copyright (c) 2018 The OTS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gvar.h" + +#include "fvar.h" +#include "maxp.h" +#include "variations.h" + +#define TABLE_NAME "gvar" + +namespace ots { + +// ----------------------------------------------------------------------------- +// OpenTypeGVAR +// ----------------------------------------------------------------------------- + +static bool ParseSharedTuples(const Font* font, const uint8_t* data, size_t length, + size_t sharedTupleCount, size_t axisCount) { + Buffer subtable(data, length); + for (unsigned i = 0; i < sharedTupleCount; i++) { + for (unsigned j = 0; j < axisCount; j++) { + int16_t coordinate; + if (!subtable.ReadS16(&coordinate)) { + return OTS_FAILURE_MSG("Failed to read shared tuple coordinate"); + } + } + } + return true; +} + +static bool ParseGlyphVariationDataArray(const Font* font, const uint8_t* data, size_t length, + uint16_t flags, size_t glyphCount, size_t axisCount, + size_t sharedTupleCount, + const uint8_t* glyphVariationData, + size_t glyphVariationDataLength) { + Buffer subtable(data, length); + + bool glyphVariationDataOffsetsAreLong = (flags & 0x0001u); + uint32_t prevOffset = 0; + for (size_t i = 0; i < glyphCount + 1; i++) { + uint32_t offset; + if (glyphVariationDataOffsetsAreLong) { + if (!subtable.ReadU32(&offset)) { + return OTS_FAILURE_MSG("Failed to read GlyphVariationData offset"); + } + } else { + uint16_t halfOffset; + if (!subtable.ReadU16(&halfOffset)) { + return OTS_FAILURE_MSG("Failed to read GlyphVariationData offset"); + } + offset = halfOffset * 2; + } + + if (i > 0 && offset > prevOffset) { + if (prevOffset > glyphVariationDataLength) { + return OTS_FAILURE_MSG("Invalid GlyphVariationData offset"); + } + if (!ParseVariationData(font, glyphVariationData + prevOffset, + glyphVariationDataLength - prevOffset, + axisCount, sharedTupleCount)) { + return OTS_FAILURE_MSG("Failed to parse GlyphVariationData"); + } + } + prevOffset = offset; + } + + return true; +} + +bool OpenTypeGVAR::Parse(const uint8_t* data, size_t length) { + Buffer table(data, length); + + uint16_t majorVersion; + uint16_t minorVersion; + uint16_t axisCount; + uint16_t sharedTupleCount; + uint32_t sharedTuplesOffset; + uint16_t glyphCount; + uint16_t flags; + uint32_t glyphVariationDataArrayOffset; + + if (!table.ReadU16(&majorVersion) || + !table.ReadU16(&minorVersion) || + !table.ReadU16(&axisCount) || + !table.ReadU16(&sharedTupleCount) || + !table.ReadU32(&sharedTuplesOffset) || + !table.ReadU16(&glyphCount) || + !table.ReadU16(&flags) || + !table.ReadU32(&glyphVariationDataArrayOffset)) { + return DropVariations("Failed to read table header"); + } + if (majorVersion != 1) { + return DropVariations("Unknown table version"); + } + + // check axisCount == fvar->axisCount + OpenTypeFVAR* fvar = static_cast<OpenTypeFVAR*>( + GetFont()->GetTypedTable(OTS_TAG_FVAR)); + if (!fvar) { + return DropVariations("Required fvar table is missing"); + } + if (axisCount != fvar->AxisCount()) { + return DropVariations("Axis count mismatch"); + } + + // check glyphCount == maxp->num_glyphs + OpenTypeMAXP* maxp = static_cast<OpenTypeMAXP*>( + GetFont()->GetTypedTable(OTS_TAG_MAXP)); + if (!maxp) { + return DropVariations("Required maxp table is missing"); + } + if (glyphCount != maxp->num_glyphs) { + return DropVariations("Glyph count mismatch"); + } + + if (sharedTupleCount > 0) { + if (sharedTuplesOffset < table.offset() || sharedTuplesOffset > length) { + return DropVariations("Invalid sharedTuplesOffset"); + } + if (!ParseSharedTuples(GetFont(), + data + sharedTuplesOffset, length - sharedTuplesOffset, + sharedTupleCount, axisCount)) { + return DropVariations("Failed to parse shared tuples"); + } + } + + if (glyphVariationDataArrayOffset) { + if (glyphVariationDataArrayOffset > length) { + return DropVariations("Invalid glyphVariationDataArrayOffset"); + } + if (!ParseGlyphVariationDataArray(GetFont(), + data + table.offset(), length - table.offset(), + flags, glyphCount, axisCount, sharedTupleCount, + data + glyphVariationDataArrayOffset, + length - glyphVariationDataArrayOffset)) { + return DropVariations("Failed to read glyph variation data array"); + } + } + + this->m_data = data; + this->m_length = length; + + return true; +} + +bool OpenTypeGVAR::Serialize(OTSStream* out) { + if (!out->Write(this->m_data, this->m_length)) { + return Error("Failed to write gvar table"); + } + + return true; +} + +} // namespace ots + +#undef TABLE_NAME |