summaryrefslogtreecommitdiffstats
path: root/gfx/ots/src/gsub.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/ots/src/gsub.cc')
-rw-r--r--gfx/ots/src/gsub.cc209
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