diff options
Diffstat (limited to 'gfx/ots/src/gsub.cc')
-rw-r--r-- | gfx/ots/src/gsub.cc | 209 |
1 files changed, 105 insertions, 104 deletions
diff --git a/gfx/ots/src/gsub.cc b/gfx/ots/src/gsub.cc index 9baf2e88b..c90fb48f3 100644 --- a/gfx/ots/src/gsub.cc +++ b/gfx/ots/src/gsub.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2011-2017 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. @@ -17,8 +17,10 @@ namespace { -// The GSUB header size -const size_t kGsubHeaderSize = 4 + 3 * 2; +// The GSUB header size for table version 1.0 +const size_t kGsubHeaderSize_1_0 = 4 + 3 * 2; +// GSUB header size v1.1 +const size_t kGsubHeaderSize_1_1 = 4 + 3 * 2 + 4; enum GSUB_TYPE { GSUB_TYPE_SINGLE = 1, @@ -82,7 +84,12 @@ bool ParseSingleSubstitution(const ots::Font *font, return OTS_FAILURE_MSG("Failed to read single subst table header"); } - const uint16_t num_glyphs = font->maxp->num_glyphs; + ots::OpenTypeMAXP *maxp = static_cast<ots::OpenTypeMAXP*>( + font->GetTypedTable(OTS_TAG_MAXP)); + if (!maxp) { + return OTS_FAILURE_MSG("Required maxp table missing"); + } + const uint16_t num_glyphs = maxp->num_glyphs; if (format == 1) { // Parse SingleSubstFormat1 int16_t delta_glyph_id = 0; @@ -170,7 +177,12 @@ bool ParseMutipleSubstitution(const ots::Font *font, return OTS_FAILURE_MSG("Bad multiple subst table format %d", format); } - const uint16_t num_glyphs = font->maxp->num_glyphs; + ots::OpenTypeMAXP *maxp = static_cast<ots::OpenTypeMAXP*>( + font->GetTypedTable(OTS_TAG_MAXP)); + if (!maxp) { + return OTS_FAILURE_MSG("Required maxp table missing"); + } + const uint16_t num_glyphs = maxp->num_glyphs; const unsigned sequence_end = static_cast<unsigned>(6) + sequence_count * 2; if (sequence_end > std::numeric_limits<uint16_t>::max()) { @@ -245,7 +257,12 @@ bool ParseAlternateSubstitution(const ots::Font *font, return OTS_FAILURE_MSG("Bad alternate subst table format %d", format); } - const uint16_t num_glyphs = font->maxp->num_glyphs; + ots::OpenTypeMAXP *maxp = static_cast<ots::OpenTypeMAXP*>( + font->GetTypedTable(OTS_TAG_MAXP)); + if (!maxp) { + return OTS_FAILURE_MSG("Required maxp table missing"); + } + const uint16_t num_glyphs = maxp->num_glyphs; const unsigned alternate_set_end = static_cast<unsigned>(6) + alternate_set_count * 2; if (alternate_set_end > std::numeric_limits<uint16_t>::max()) { @@ -362,7 +379,12 @@ bool ParseLigatureSubstitution(const ots::Font *font, return OTS_FAILURE_MSG("Bad ligature substitution table format %d", format); } - const uint16_t num_glyphs = font->maxp->num_glyphs; + ots::OpenTypeMAXP *maxp = static_cast<ots::OpenTypeMAXP*>( + font->GetTypedTable(OTS_TAG_MAXP)); + if (!maxp) { + return OTS_FAILURE_MSG("Required maxp table missing"); + } + const uint16_t num_glyphs = maxp->num_glyphs; const unsigned ligature_set_end = static_cast<unsigned>(6) + lig_set_count * 2; if (ligature_set_end > std::numeric_limits<uint16_t>::max()) { @@ -398,8 +420,18 @@ bool ParseLigatureSubstitution(const ots::Font *font, // Contextual Substitution Subtable bool ParseContextSubstitution(const ots::Font *font, const uint8_t *data, const size_t length) { - return ots::ParseContextSubtable(font, data, length, font->maxp->num_glyphs, - font->gsub->num_lookups); + ots::OpenTypeMAXP *maxp = static_cast<ots::OpenTypeMAXP*>( + font->GetTypedTable(OTS_TAG_MAXP)); + if (!maxp) { + return OTS_FAILURE_MSG("Required maxp table missing"); + } + ots::OpenTypeGSUB *gsub = static_cast<ots::OpenTypeGSUB*>( + font->GetTypedTable(OTS_TAG_GSUB)); + if (!gsub) { + return OTS_FAILURE_MSG("Internal error!"); + } + return ots::ParseContextSubtable(font, data, length, maxp->num_glyphs, + gsub->num_lookups); } // Lookup Type 6: @@ -407,9 +439,19 @@ bool ParseContextSubstitution(const ots::Font *font, bool ParseChainingContextSubstitution(const ots::Font *font, const uint8_t *data, const size_t length) { + ots::OpenTypeMAXP *maxp = static_cast<ots::OpenTypeMAXP*>( + font->GetTypedTable(OTS_TAG_MAXP)); + if (!maxp) { + return OTS_FAILURE_MSG("Required maxp table missing"); + } + ots::OpenTypeGSUB *gsub = static_cast<ots::OpenTypeGSUB*>( + font->GetTypedTable(OTS_TAG_GSUB)); + if (!gsub) { + return OTS_FAILURE_MSG("Internal error!"); + } return ots::ParseChainingContextSubtable(font, data, length, - font->maxp->num_glyphs, - font->gsub->num_lookups); + maxp->num_glyphs, + gsub->num_lookups); } // Lookup Type 7: @@ -434,7 +476,12 @@ bool ParseReverseChainingContextSingleSubstitution( return OTS_FAILURE_MSG("Failed to read reverse chaining header"); } - const uint16_t num_glyphs = font->maxp->num_glyphs; + ots::OpenTypeMAXP *maxp = static_cast<ots::OpenTypeMAXP*>( + font->GetTypedTable(OTS_TAG_MAXP)); + if (!maxp) { + return OTS_FAILURE_MSG("Required maxp table missing"); + } + const uint16_t num_glyphs = maxp->num_glyphs; uint16_t backtrack_glyph_count = 0; if (!subtable.ReadU16(&backtrack_glyph_count)) { @@ -530,143 +577,97 @@ bool ParseReverseChainingContextSingleSubstitution( namespace ots { -// As far as I checked, following fonts contain invalid values in GSUB table. -// OTS will drop their GSUB table. -// -// # too large substitute (value is 0xFFFF) -// kaiu.ttf -// mingliub2.ttf -// mingliub1.ttf -// mingliub0.ttf -// GraublauWeb.otf -// GraublauWebBold.otf -// -// # too large alternate (value is 0xFFFF) -// ManchuFont.ttf -// -// # bad offset to lang sys table (NULL offset) -// DejaVuMonoSansBold.ttf -// DejaVuMonoSansBoldOblique.ttf -// DejaVuMonoSansOblique.ttf -// DejaVuSansMono-BoldOblique.ttf -// DejaVuSansMono-Oblique.ttf -// DejaVuSansMono-Bold.ttf -// -// # bad start coverage index -// GenBasBI.ttf -// GenBasI.ttf -// AndBasR.ttf -// GenBkBasI.ttf -// CharisSILR.ttf -// CharisSILBI.ttf -// CharisSILI.ttf -// CharisSILB.ttf -// DoulosSILR.ttf -// CharisSILBI.ttf -// GenBkBasB.ttf -// GenBkBasR.ttf -// GenBkBasBI.ttf -// GenBasB.ttf -// GenBasR.ttf -// -// # glyph range is overlapping -// KacstTitleL.ttf -// KacstDecorative.ttf -// KacstTitle.ttf -// KacstArt.ttf -// KacstPoster.ttf -// KacstQurn.ttf -// KacstDigital.ttf -// KacstBook.ttf -// KacstFarsi.ttf - -bool ots_gsub_parse(Font *font, const uint8_t *data, size_t length) { - // Parsing gsub table requires |font->maxp->num_glyphs| - if (!font->maxp) { - return OTS_FAILURE_MSG("Missing maxp table in font, needed by GSUB"); - } - +bool OpenTypeGSUB::Parse(const uint8_t *data, size_t length) { + // Parsing gsub table requires |maxp->num_glyphs| + Font *font = GetFont(); Buffer table(data, length); - OpenTypeGSUB *gsub = new OpenTypeGSUB; - font->gsub = gsub; - - uint32_t version = 0; + uint16_t version_major = 0, version_minor = 0; uint16_t offset_script_list = 0; uint16_t offset_feature_list = 0; uint16_t offset_lookup_list = 0; - if (!table.ReadU32(&version) || + uint32_t offset_feature_variations = 0; + if (!table.ReadU16(&version_major) || + !table.ReadU16(&version_minor) || !table.ReadU16(&offset_script_list) || !table.ReadU16(&offset_feature_list) || !table.ReadU16(&offset_lookup_list)) { - return OTS_FAILURE_MSG("Incomplete table"); + return Error("Incomplete table"); } - if (version != 0x00010000) { - return OTS_FAILURE_MSG("Bad version"); + if (version_major != 1 || version_minor > 1) { + return Error("Bad version"); } + if (version_minor > 0) { + if (!table.ReadU32(&offset_feature_variations)) { + return Error("Incomplete table"); + } + } + + const size_t header_size = + (version_minor == 0) ? kGsubHeaderSize_1_0 : kGsubHeaderSize_1_1; + if (offset_lookup_list) { - if (offset_lookup_list < kGsubHeaderSize || offset_lookup_list >= length) { - return OTS_FAILURE_MSG("Bad lookup list offset in table header"); + if (offset_lookup_list < header_size || offset_lookup_list >= length) { + return Error("Bad lookup list offset in table header"); } if (!ParseLookupListTable(font, data + offset_lookup_list, length - offset_lookup_list, &kGsubLookupSubtableParser, - &gsub->num_lookups)) { - return OTS_FAILURE_MSG("Failed to parse lookup list table"); + &this->num_lookups)) { + return Error("Failed to parse lookup list table"); } } uint16_t num_features = 0; if (offset_feature_list) { - if (offset_feature_list < kGsubHeaderSize || offset_feature_list >= length) { - return OTS_FAILURE_MSG("Bad feature list offset in table header"); + if (offset_feature_list < header_size || offset_feature_list >= length) { + return Error("Bad feature list offset in table header"); } if (!ParseFeatureListTable(font, data + offset_feature_list, - length - offset_feature_list, gsub->num_lookups, + length - offset_feature_list, this->num_lookups, &num_features)) { - return OTS_FAILURE_MSG("Failed to parse feature list table"); + return Error("Failed to parse feature list table"); } } if (offset_script_list) { - if (offset_script_list < kGsubHeaderSize || offset_script_list >= length) { - return OTS_FAILURE_MSG("Bad script list offset in table header"); + if (offset_script_list < header_size || offset_script_list >= length) { + return Error("Bad script list offset in table header"); } if (!ParseScriptListTable(font, data + offset_script_list, length - offset_script_list, num_features)) { - return OTS_FAILURE_MSG("Failed to parse script list table"); + return Error("Failed to parse script list table"); } } - gsub->data = data; - gsub->length = length; - return true; -} - -bool ots_gsub_should_serialise(Font *font) { - return font->gsub != NULL && font->gsub->data != NULL; -} + if (offset_feature_variations) { + if (offset_feature_variations < header_size || offset_feature_variations >= length) { + return Error("Bad feature variations offset in table header"); + } -bool ots_gsub_serialise(OTSStream *out, Font *font) { - if (!out->Write(font->gsub->data, font->gsub->length)) { - return OTS_FAILURE_MSG("Failed to write GSUB table"); + if (!ParseFeatureVariationsTable(font, data + offset_feature_variations, + length - offset_feature_variations, + this->num_lookups)) { + return Error("Failed to parse feature variations table"); + } } + this->m_data = data; + this->m_length = length; return true; } -void ots_gsub_reuse(Font *font, Font *other) { - font->gsub = other->gsub; - font->gsub_reused = true; -} +bool OpenTypeGSUB::Serialize(OTSStream *out) { + if (!out->Write(this->m_data, this->m_length)) { + return Error("Failed to write GSUB table"); + } -void ots_gsub_free(Font *font) { - delete font->gsub; + return true; } } // namespace ots |