159 lines
5.0 KiB
C++
159 lines
5.0 KiB
C++
// 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
|