--- a/gfx/ots/README.mozilla
+++ b/gfx/ots/README.mozilla
@@ -1,12 +1,12 @@
This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/.
Our reference repository is https://github.com/khaledhosny/ots/.
-Current revision: 5f685b8e1fce77347c87f6d98511d53debbe64b2 (5.2.0)
+Current revision: 57ef618b11aa0409637af04988ccce7e6b92ed0f (5.2.0)
Upstream files included: LICENSE, src/, include/, tests/*.cc
Additional files: README.mozilla, src/moz.build
Additional patch: ots-visibility.patch (bug 711079).
-Additional patch: ots-config.patch (config.h not needed in mozilla build)
+Additional patch: ots-lz4.patch
--- a/gfx/ots/include/opentype-sanitiser.h
+++ b/gfx/ots/include/opentype-sanitiser.h
@@ -171,17 +171,17 @@ class OTSStream {
#ifdef __GCC__
#define MSGFUNC_FMT_ATTR __attribute__((format(printf, 2, 3)))
#else
#define MSGFUNC_FMT_ATTR
#endif
enum TableAction {
TABLE_ACTION_DEFAULT, // Use OTS's default action for that table
- TABLE_ACTION_SANITIZE, // Sanitize the table, potentially droping it
+ TABLE_ACTION_SANITIZE, // Sanitize the table, potentially dropping it
TABLE_ACTION_PASSTHRU, // Serialize the table unchanged
TABLE_ACTION_DROP // Drop the table
};
class OTS_API OTSContext {
public:
OTSContext() {}
virtual ~OTSContext() {}
deleted file mode 100644
--- a/gfx/ots/ots-config.patch
+++ /dev/null
@@ -1,22 +0,0 @@
-diff --git a/gfx/ots/src/ots.h b/gfx/ots/src/ots.h
---- a/gfx/ots/src/ots.h
-+++ b/gfx/ots/src/ots.h
-@@ -1,16 +1,17 @@
- // Copyright (c) 2009-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.
-
- #ifndef OTS_H_
- #define OTS_H_
-
--#include "config.h"
-+// Not needed in the gecko build
-+// #include "config.h"
-
- #include <stddef.h>
- #include <cstdarg>
- #include <cstddef>
- #include <cstdio>
- #include <cstdlib>
- #include <cstring>
- #include <limits>
new file mode 100644
--- /dev/null
+++ b/gfx/ots/ots-lz4.patch
@@ -0,0 +1,70 @@
+diff --git a/gfx/ots/src/glat.cc b/gfx/ots/src/glat.cc
+--- a/gfx/ots/src/glat.cc
++++ b/gfx/ots/src/glat.cc
+@@ -5,7 +5,7 @@
+ #include "glat.h"
+
+ #include "gloc.h"
+-#include "lz4.h"
++#include "mozilla/Compression.h"
+ #include <list>
+
+ namespace ots {
+@@ -201,13 +201,15 @@ bool OpenTypeGLAT_v3::Parse(const uint8_t* data, size_t length,
+ return DropGraphite("Illegal nested compression");
+ }
+ std::vector<uint8_t> decompressed(this->compHead & FULL_SIZE, 0);
+- int ret = LZ4_decompress_safe(
+- reinterpret_cast<const char*>(data + table.offset()),
+- reinterpret_cast<char*>(decompressed.data()),
+- table.remaining(),
+- decompressed.size());
+- if (ret < 0) {
+- return DropGraphite("Decompression failed with error code %d", ret);
++ size_t outputSize = 0;
++ if (!mozilla::Compression::LZ4::decompress(
++ reinterpret_cast<const char*>(data + table.offset()),
++ table.remaining(),
++ reinterpret_cast<char*>(decompressed.data()),
++ decompressed.size(),
++ &outputSize) ||
++ outputSize != (this->compHead & FULL_SIZE)) {
++ return DropGraphite("Decompression failed");
+ }
+ return this->Parse(decompressed.data(), decompressed.size(), true);
+ }
+diff --git a/gfx/ots/src/silf.cc b/gfx/ots/src/silf.cc
+--- a/gfx/ots/src/silf.cc
++++ b/gfx/ots/src/silf.cc
+@@ -5,7 +5,7 @@
+ #include "silf.h"
+
+ #include "name.h"
+-#include "lz4.h"
++#include "mozilla/Compression.h"
+ #include <cmath>
+
+ namespace ots {
+@@ -39,13 +39,15 @@ bool OpenTypeSILF::Parse(const uint8_t* data, size_t length,
+ return DropGraphite("Illegal nested compression");
+ }
+ std::vector<uint8_t> decompressed(this->compHead & FULL_SIZE, 0);
+- int ret = LZ4_decompress_safe(
+- reinterpret_cast<const char*>(data + table.offset()),
+- reinterpret_cast<char*>(decompressed.data()),
+- table.remaining(),
+- decompressed.size());
+- if (ret < 0) {
+- return DropGraphite("Decompression failed with error code %d", ret);
++ size_t outputSize = 0;
++ if (!mozilla::Compression::LZ4::decompress(
++ reinterpret_cast<const char*>(data + table.offset()),
++ table.remaining(),
++ reinterpret_cast<char*>(decompressed.data()),
++ decompressed.size(),
++ &outputSize) ||
++ outputSize != (this->compHead & FULL_SIZE)) {
++ return DropGraphite("Decompression failed");
+ }
+ return this->Parse(decompressed.data(), decompressed.size(), true);
+ }
--- a/gfx/ots/ots-visibility.patch
+++ b/gfx/ots/ots-visibility.patch
@@ -1,16 +1,12 @@
diff --git a/gfx/ots/include/opentype-sanitiser.h b/gfx/ots/include/opentype-sanitiser.h
--- a/gfx/ots/include/opentype-sanitiser.h
+++ b/gfx/ots/include/opentype-sanitiser.h
-@@ -1,15 +1,35 @@
- // Copyright (c) 2009 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
-
+@@ -5,6 +5,26 @@
#ifndef OPENTYPE_SANITISER_H_
#define OPENTYPE_SANITISER_H_
+#if defined(_WIN32) || defined(__CYGWIN__)
+ #define OTS_DLL_IMPORT __declspec(dllimport)
+ #define OTS_DLL_EXPORT __declspec(dllexport)
+#else
+ #if __GNUC__ >= 4
@@ -27,32 +23,17 @@ diff --git a/gfx/ots/include/opentype-sa
+ #endif
+#else
+ #define OTS_API
+#endif
+
#if defined(_WIN32)
#include <stdlib.h>
typedef signed char int8_t;
- typedef unsigned char uint8_t;
- typedef short int16_t;
- typedef unsigned short uint16_t;
- typedef int int32_t;
- typedef unsigned int uint32_t;
-@@ -187,17 +207,17 @@ class OTSStream {
-
- enum TableAction {
- TABLE_ACTION_DEFAULT, // Use OTS's default action for that table
- TABLE_ACTION_SANITIZE, // Sanitize the table, potentially droping it
- TABLE_ACTION_PASSTHRU, // Serialize the table unchanged
+@@ -161,7 +181,7 @@ enum TableAction {
TABLE_ACTION_DROP // Drop the table
};
-class OTSContext {
+class OTS_API OTSContext {
public:
OTSContext() {}
virtual ~OTSContext() {}
-
- // Process a given OpenType file and write out a sanitized version
- // output: a pointer to an object implementing the OTSStream interface. The
- // sanitisied output will be written to this. In the even of a failure,
- // partial output may have been written.
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/feat.cc
@@ -0,0 +1,193 @@
+// Copyright (c) 2009-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.
+
+#include "feat.h"
+
+#include "name.h"
+
+namespace ots {
+
+bool OpenTypeFEAT::Parse(const uint8_t* data, size_t length) {
+ if (GetFont()->dropped_graphite) {
+ return Drop("Skipping Graphite table");
+ }
+ Buffer table(data, length);
+
+ if (!table.ReadU32(&this->version)) {
+ return DropGraphite("Failed to read version");
+ }
+ if (this->version >> 16 != 1 && this->version >> 16 != 2) {
+ return DropGraphite("Unsupported table version: %u", this->version >> 16);
+ }
+ if (!table.ReadU16(&this->numFeat)) {
+ return DropGraphite("Failed to read numFeat");
+ }
+ if (!table.ReadU16(&this->reserved)) {
+ return DropGraphite("Failed to read reserved");
+ }
+ if (this->reserved != 0) {
+ Warning("Nonzero reserved");
+ }
+ if (!table.ReadU32(&this->reserved2)) {
+ return DropGraphite("Failed to read valid reserved2");
+ }
+ if (this->reserved2 != 0) {
+ Warning("Nonzero reserved2");
+ }
+
+ std::unordered_set<size_t> unverified;
+ //this->features.resize(this->numFeat, this);
+ for (unsigned i = 0; i < this->numFeat; ++i) {
+ this->features.emplace_back(this);
+ FeatureDefn& feature = this->features[i];
+ if (!feature.ParsePart(table)) {
+ return DropGraphite("Failed to read features[%u]", i);
+ }
+ this->feature_ids.insert(feature.id);
+ for (unsigned j = 0; j < feature.numSettings; ++j) {
+ size_t offset = feature.offset + j * 4;
+ if (offset < feature.offset || offset > length) {
+ return DropGraphite("Invalid FeatSettingDefn offset %zu/%zu",
+ offset, length);
+ }
+ unverified.insert(offset);
+ // need to verify that this FeatureDefn points to valid
+ // FeatureSettingDefn
+ }
+ }
+
+ while (table.remaining()) {
+ bool used = unverified.erase(table.offset());
+ FeatureSettingDefn featSetting(this);
+ if (!featSetting.ParsePart(table, used)) {
+ return DropGraphite("Failed to read a FeatureSettingDefn");
+ }
+ featSettings.push_back(featSetting);
+ }
+
+ if (!unverified.empty()) {
+ return DropGraphite("%zu incorrect offsets into featSettings",
+ unverified.size());
+ }
+ if (table.remaining()) {
+ return Warning("%zu bytes unparsed", table.remaining());
+ }
+ return true;
+}
+
+bool OpenTypeFEAT::Serialize(OTSStream* out) {
+ if (!out->WriteU32(this->version) ||
+ !out->WriteU16(this->numFeat) ||
+ !out->WriteU16(this->reserved) ||
+ !out->WriteU32(this->reserved2) ||
+ !SerializeParts(this->features, out) ||
+ !SerializeParts(this->featSettings, out)) {
+ return Error("Failed to write table");
+ }
+ return true;
+}
+
+bool OpenTypeFEAT::IsValidFeatureId(uint32_t id) const {
+ return feature_ids.count(id);
+}
+
+bool OpenTypeFEAT::FeatureDefn::ParsePart(Buffer& table) {
+ OpenTypeNAME* name = static_cast<OpenTypeNAME*>(
+ parent->GetFont()->GetTypedTable(OTS_TAG_NAME));
+ if (!name) {
+ return parent->Error("FeatureDefn: Required name table is missing");
+ }
+
+ if (parent->version >> 16 >= 2 && !table.ReadU32(&this->id)) {
+ return parent->Error("FeatureDefn: Failed to read id");
+ }
+ if (parent->version >> 16 == 1) {
+ uint16_t id;
+ if (!table.ReadU16(&id)) {
+ return parent->Error("FeatureDefn: Failed to read id");
+ }
+ this->id = id;
+ }
+ if (!table.ReadU16(&this->numSettings)) {
+ return parent->Error("FeatureDefn: Failed to read numSettings");
+ }
+ if (parent->version >> 16 >= 2) {
+ if (!table.ReadU16(&this->reserved)) {
+ return parent->Error("FeatureDefn: Failed to read reserved");
+ }
+ if (this->reserved != 0) {
+ parent->Warning("FeatureDefn: Nonzero reserved");
+ }
+ }
+ if (!table.ReadU32(&this->offset)) {
+ return parent->Error("FeatureDefn: Failed to read offset");
+ } // validity of offset verified in OpenTypeFEAT::Parse
+ if (!table.ReadU16(&this->flags)) {
+ return parent->Error("FeatureDefn: Failed to read flags");
+ }
+ if ((this->flags & RESERVED) != 0) {
+ this->flags &= ~RESERVED;
+ parent->Warning("FeatureDefn: Nonzero (flags & 0x%x) repaired", RESERVED);
+ }
+ if (this->flags & HAS_DEFAULT_SETTING &&
+ (this->flags & DEFAULT_SETTING) >= this->numSettings) {
+ return parent->Error("FeatureDefn: (flags & 0x%x) is set but (flags & 0x%x "
+ "is not a valid setting index", HAS_DEFAULT_SETTING,
+ DEFAULT_SETTING);
+ }
+ if (!table.ReadU16(&this->label)) {
+ return parent->Error("FeatureDefn: Failed to read label");
+ }
+ if (!name->IsValidNameId(this->label)) {
+ if (this->id == 1 && name->IsValidNameId(this->label, true)) {
+ parent->Warning("FeatureDefn: Missing NameRecord repaired for feature"
+ " with id=%u, label=%u", this->id, this->label);
+ }
+ else {
+ return parent->Error("FeatureDefn: Invalid label");
+ }
+ }
+ return true;
+}
+
+bool OpenTypeFEAT::FeatureDefn::SerializePart(OTSStream* out) const {
+ if ((parent->version >> 16 >= 2 && !out->WriteU32(this->id)) ||
+ (parent->version >> 16 == 1 &&
+ !out->WriteU16(static_cast<uint16_t>(this->id))) ||
+ !out->WriteU16(this->numSettings) ||
+ (parent->version >> 16 >= 2 && !out->WriteU16(this->reserved)) ||
+ !out->WriteU32(this->offset) ||
+ !out->WriteU16(this->flags) ||
+ !out->WriteU16(this->label)) {
+ return parent->Error("FeatureDefn: Failed to write");
+ }
+ return true;
+}
+
+bool OpenTypeFEAT::FeatureSettingDefn::ParsePart(Buffer& table, bool used) {
+ OpenTypeNAME* name = static_cast<OpenTypeNAME*>(
+ parent->GetFont()->GetTypedTable(OTS_TAG_NAME));
+ if (!name) {
+ return parent->Error("FeatureSettingDefn: Required name table is missing");
+ }
+
+ if (!table.ReadS16(&this->value)) {
+ return parent->Error("FeatureSettingDefn: Failed to read value");
+ }
+ if (!table.ReadU16(&this->label) ||
+ (used && !name->IsValidNameId(this->label))) {
+ return parent->Error("FeatureSettingDefn: Failed to read valid label");
+ }
+ return true;
+}
+
+bool OpenTypeFEAT::FeatureSettingDefn::SerializePart(OTSStream* out) const {
+ if (!out->WriteS16(this->value) ||
+ !out->WriteU16(this->label)) {
+ return parent->Error("FeatureSettingDefn: Failed to write");
+ }
+ return true;
+}
+
+} // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/feat.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2009-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.
+
+#ifndef OTS_FEAT_H_
+#define OTS_FEAT_H_
+
+#include <vector>
+#include <unordered_set>
+
+#include "ots.h"
+#include "graphite.h"
+
+namespace ots {
+
+class OpenTypeFEAT : public Table {
+ public:
+ explicit OpenTypeFEAT(Font* font, uint32_t tag)
+ : Table(font, tag, tag) { }
+
+ bool Parse(const uint8_t* data, size_t length);
+ bool Serialize(OTSStream* out);
+ bool IsValidFeatureId(uint32_t id) const;
+
+ private:
+ struct FeatureDefn : public TablePart<OpenTypeFEAT> {
+ explicit FeatureDefn(OpenTypeFEAT* parent)
+ : TablePart<OpenTypeFEAT>(parent) { }
+ bool ParsePart(Buffer& table);
+ bool SerializePart(OTSStream* out) const;
+ uint32_t id;
+ uint16_t numSettings;
+ uint16_t reserved;
+ uint32_t offset;
+ uint16_t flags;
+ static const uint16_t HAS_DEFAULT_SETTING = 0x4000;
+ static const uint16_t RESERVED = 0x3F00;
+ static const uint16_t DEFAULT_SETTING = 0x00FF;
+ uint16_t label;
+ };
+ struct FeatureSettingDefn : public TablePart<OpenTypeFEAT> {
+ explicit FeatureSettingDefn(OpenTypeFEAT* parent)
+ : TablePart<OpenTypeFEAT>(parent) { }
+ bool ParsePart(Buffer& table) { return ParsePart(table, true); }
+ bool ParsePart(Buffer& table, bool used);
+ bool SerializePart(OTSStream* out) const;
+ int16_t value;
+ uint16_t label;
+ };
+ uint32_t version;
+ uint16_t numFeat;
+ uint16_t reserved;
+ uint32_t reserved2;
+ std::vector<FeatureDefn> features;
+ std::vector<FeatureSettingDefn> featSettings;
+ std::unordered_set<uint32_t> feature_ids;
+};
+
+} // namespace ots
+
+#endif // OTS_FEAT_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/glat.cc
@@ -0,0 +1,447 @@
+// Copyright (c) 2009-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.
+
+#include "glat.h"
+
+#include "gloc.h"
+#include "mozilla/Compression.h"
+#include <list>
+
+namespace ots {
+
+// -----------------------------------------------------------------------------
+// OpenTypeGLAT_v1
+// -----------------------------------------------------------------------------
+
+bool OpenTypeGLAT_v1::Parse(const uint8_t* data, size_t length) {
+ Buffer table(data, length);
+ OpenTypeGLOC* gloc = static_cast<OpenTypeGLOC*>(
+ GetFont()->GetTypedTable(OTS_TAG_GLOC));
+ if (!gloc) {
+ return DropGraphite("Required Gloc table is missing");
+ }
+
+ if (!table.ReadU32(&this->version) || this->version >> 16 != 1) {
+ return DropGraphite("Failed to read version");
+ }
+
+ const std::vector<uint32_t>& locations = gloc->GetLocations();
+ if (locations.empty()) {
+ return DropGraphite("No locations from Gloc table");
+ }
+ std::list<uint32_t> unverified(locations.begin(), locations.end());
+ while (table.remaining()) {
+ GlatEntry entry(this);
+ if (table.offset() > unverified.front()) {
+ return DropGraphite("Offset check failed for a GlatEntry");
+ }
+ if (table.offset() == unverified.front()) {
+ unverified.pop_front();
+ }
+ if (unverified.empty()) {
+ return DropGraphite("Expected more locations");
+ }
+ if (!entry.ParsePart(table)) {
+ return DropGraphite("Failed to read a GlatEntry");
+ }
+ this->entries.push_back(entry);
+ }
+
+ if (unverified.size() != 1 || unverified.front() != table.offset()) {
+ return DropGraphite("%zu location(s) could not be verified", unverified.size());
+ }
+ if (table.remaining()) {
+ return Warning("%zu bytes unparsed", table.remaining());
+ }
+ return true;
+}
+
+bool OpenTypeGLAT_v1::Serialize(OTSStream* out) {
+ if (!out->WriteU32(this->version) ||
+ !SerializeParts(this->entries, out)) {
+ return Error("Failed to write table");
+ }
+ return true;
+}
+
+bool OpenTypeGLAT_v1::GlatEntry::ParsePart(Buffer& table) {
+ if (!table.ReadU8(&this->attNum)) {
+ return parent->Error("GlatEntry: Failed to read attNum");
+ }
+ if (!table.ReadU8(&this->num)) {
+ return parent->Error("GlatEntry: Failed to read num");
+ }
+
+ //this->attributes.resize(this->num);
+ for (unsigned i = 0; i < this->num; ++i) {
+ this->attributes.emplace_back();
+ if (!table.ReadS16(&this->attributes[i])) {
+ return parent->Error("GlatEntry: Failed to read attribute %u", i);
+ }
+ }
+ return true;
+}
+
+bool OpenTypeGLAT_v1::GlatEntry::SerializePart(OTSStream* out) const {
+ if (!out->WriteU8(this->attNum) ||
+ !out->WriteU8(this->num) ||
+ !SerializeParts(this->attributes, out)) {
+ return parent->Error("GlatEntry: Failed to write");
+ }
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+// OpenTypeGLAT_v2
+// -----------------------------------------------------------------------------
+
+bool OpenTypeGLAT_v2::Parse(const uint8_t* data, size_t length) {
+ Buffer table(data, length);
+ OpenTypeGLOC* gloc = static_cast<OpenTypeGLOC*>(
+ GetFont()->GetTypedTable(OTS_TAG_GLOC));
+ if (!gloc) {
+ return DropGraphite("Required Gloc table is missing");
+ }
+
+ if (!table.ReadU32(&this->version) || this->version >> 16 != 1) {
+ return DropGraphite("Failed to read version");
+ }
+
+ const std::vector<uint32_t>& locations = gloc->GetLocations();
+ if (locations.empty()) {
+ return DropGraphite("No locations from Gloc table");
+ }
+ std::list<uint32_t> unverified(locations.begin(), locations.end());
+ while (table.remaining()) {
+ GlatEntry entry(this);
+ if (table.offset() > unverified.front()) {
+ return DropGraphite("Offset check failed for a GlatEntry");
+ }
+ if (table.offset() == unverified.front()) {
+ unverified.pop_front();
+ }
+ if (unverified.empty()) {
+ return DropGraphite("Expected more locations");
+ }
+ if (!entry.ParsePart(table)) {
+ return DropGraphite("Failed to read a GlatEntry");
+ }
+ this->entries.push_back(entry);
+ }
+
+ if (unverified.size() != 1 || unverified.front() != table.offset()) {
+ return DropGraphite("%zu location(s) could not be verified", unverified.size());
+ }
+ if (table.remaining()) {
+ return Warning("%zu bytes unparsed", table.remaining());
+ }
+ return true;
+}
+
+bool OpenTypeGLAT_v2::Serialize(OTSStream* out) {
+ if (!out->WriteU32(this->version) ||
+ !SerializeParts(this->entries, out)) {
+ return Error("Failed to write table");
+ }
+ return true;
+}
+
+bool OpenTypeGLAT_v2::GlatEntry::ParsePart(Buffer& table) {
+ if (!table.ReadS16(&this->attNum)) {
+ return parent->Error("GlatEntry: Failed to read attNum");
+ }
+ if (!table.ReadS16(&this->num) || this->num < 0) {
+ return parent->Error("GlatEntry: Failed to read valid num");
+ }
+
+ //this->attributes.resize(this->num);
+ for (unsigned i = 0; i < this->num; ++i) {
+ this->attributes.emplace_back();
+ if (!table.ReadS16(&this->attributes[i])) {
+ return parent->Error("GlatEntry: Failed to read attribute %u", i);
+ }
+ }
+ return true;
+}
+
+bool OpenTypeGLAT_v2::GlatEntry::SerializePart(OTSStream* out) const {
+ if (!out->WriteS16(this->attNum) ||
+ !out->WriteS16(this->num) ||
+ !SerializeParts(this->attributes, out)) {
+ return parent->Error("GlatEntry: Failed to write");
+ }
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+// OpenTypeGLAT_v3
+// -----------------------------------------------------------------------------
+
+bool OpenTypeGLAT_v3::Parse(const uint8_t* data, size_t length,
+ bool prevent_decompression) {
+ Buffer table(data, length);
+ OpenTypeGLOC* gloc = static_cast<OpenTypeGLOC*>(
+ GetFont()->GetTypedTable(OTS_TAG_GLOC));
+ if (!gloc) {
+ return DropGraphite("Required Gloc table is missing");
+ }
+
+ if (!table.ReadU32(&this->version) || this->version >> 16 != 3) {
+ return DropGraphite("Failed to read version");
+ }
+ if (!table.ReadU32(&this->compHead)) {
+ return DropGraphite("Failed to read compression header");
+ }
+ switch ((this->compHead & SCHEME) >> 27) {
+ case 0: // uncompressed
+ break;
+ case 1: { // lz4
+ if (prevent_decompression) {
+ return DropGraphite("Illegal nested compression");
+ }
+ std::vector<uint8_t> decompressed(this->compHead & FULL_SIZE, 0);
+ size_t outputSize = 0;
+ if (!mozilla::Compression::LZ4::decompress(
+ reinterpret_cast<const char*>(data + table.offset()),
+ table.remaining(),
+ reinterpret_cast<char*>(decompressed.data()),
+ decompressed.size(),
+ &outputSize) ||
+ outputSize != (this->compHead & FULL_SIZE)) {
+ return DropGraphite("Decompression failed");
+ }
+ return this->Parse(decompressed.data(), decompressed.size(), true);
+ }
+ default:
+ return DropGraphite("Unknown compression scheme");
+ }
+ if (this->compHead & RESERVED) {
+ Warning("Nonzero reserved");
+ }
+
+ const std::vector<uint32_t>& locations = gloc->GetLocations();
+ if (locations.empty()) {
+ return DropGraphite("No locations from Gloc table");
+ }
+ std::list<uint32_t> unverified(locations.begin(), locations.end());
+ //this->entries.resize(locations.size() - 1, this);
+ for (size_t i = 0; i < locations.size() - 1; ++i) {
+ this->entries.emplace_back(this);
+ if (table.offset() != unverified.front()) {
+ return DropGraphite("Offset check failed for a GlyphAttrs");
+ }
+ unverified.pop_front();
+ if (!this->entries[i].ParsePart(table,
+ unverified.front() - table.offset())) {
+ // unverified.front() is guaranteed to exist because of the number of
+ // iterations of this loop
+ return DropGraphite("Failed to read a GlyphAttrs");
+ }
+ }
+
+ if (unverified.size() != 1 || unverified.front() != table.offset()) {
+ return DropGraphite("%zu location(s) could not be verified", unverified.size());
+ }
+ if (table.remaining()) {
+ return Warning("%zu bytes unparsed", table.remaining());
+ }
+ return true;
+}
+
+bool OpenTypeGLAT_v3::Serialize(OTSStream* out) {
+ if (!out->WriteU32(this->version) ||
+ !out->WriteU32(this->compHead) ||
+ !SerializeParts(this->entries, out)) {
+ return Error("Failed to write table");
+ }
+ return true;
+}
+
+bool OpenTypeGLAT_v3::GlyphAttrs::ParsePart(Buffer& table, const size_t size) {
+ size_t init_offset = table.offset();
+ if (parent->compHead & OCTABOXES && !octabox.ParsePart(table)) {
+ // parent->flags & 0b1: octaboxes are present flag
+ return parent->Error("GlyphAttrs: Failed to read octabox");
+ }
+
+ while (table.offset() < init_offset + size) {
+ GlatEntry entry(parent);
+ if (!entry.ParsePart(table)) {
+ return parent->Error("GlyphAttrs: Failed to read a GlatEntry");
+ }
+ this->entries.push_back(entry);
+ }
+ return true;
+}
+
+bool OpenTypeGLAT_v3::GlyphAttrs::SerializePart(OTSStream* out) const {
+ if ((parent->compHead & OCTABOXES && !octabox.SerializePart(out)) ||
+ !SerializeParts(this->entries, out)) {
+ return parent->Error("GlyphAttrs: Failed to write");
+ }
+ return true;
+}
+
+bool OpenTypeGLAT_v3::GlyphAttrs::
+OctaboxMetrics::ParsePart(Buffer& table) {
+ if (!table.ReadU16(&this->subbox_bitmap)) {
+ return parent->Error("OctaboxMetrics: Failed to read subbox_bitmap");
+ }
+ if (!table.ReadU8(&this->diag_neg_min)) {
+ return parent->Error("OctaboxMetrics: Failed to read diag_neg_min");
+ }
+ if (!table.ReadU8(&this->diag_neg_max) ||
+ this->diag_neg_max < this->diag_neg_min) {
+ return parent->Error("OctaboxMetrics: Failed to read valid diag_neg_max");
+ }
+ if (!table.ReadU8(&this->diag_pos_min)) {
+ return parent->Error("OctaboxMetrics: Failed to read diag_pos_min");
+ }
+ if (!table.ReadU8(&this->diag_pos_max) ||
+ this->diag_pos_max < this->diag_pos_min) {
+ return parent->Error("OctaboxMetrics: Failed to read valid diag_pos_max");
+ }
+
+ unsigned subboxes_len = 0; // count of 1's in this->subbox_bitmap
+ for (uint16_t i = this->subbox_bitmap; i; i >>= 1) {
+ if (i & 0b1) {
+ ++subboxes_len;
+ }
+ }
+ //this->subboxes.resize(subboxes_len, parent);
+ for (unsigned i = 0; i < subboxes_len; i++) {
+ this->subboxes.emplace_back(parent);
+ if (!this->subboxes[i].ParsePart(table)) {
+ return parent->Error("OctaboxMetrics: Failed to read subbox[%u]", i);
+ }
+ }
+ return true;
+}
+
+bool OpenTypeGLAT_v3::GlyphAttrs::
+OctaboxMetrics::SerializePart(OTSStream* out) const {
+ if (!out->WriteU16(this->subbox_bitmap) ||
+ !out->WriteU8(this->diag_neg_min) ||
+ !out->WriteU8(this->diag_neg_max) ||
+ !out->WriteU8(this->diag_pos_min) ||
+ !out->WriteU8(this->diag_pos_max) ||
+ !SerializeParts(this->subboxes, out)) {
+ return parent->Error("OctaboxMetrics: Failed to write");
+ }
+ return true;
+}
+
+bool OpenTypeGLAT_v3::GlyphAttrs::OctaboxMetrics::
+SubboxEntry::ParsePart(Buffer& table) {
+ if (!table.ReadU8(&this->left)) {
+ return parent->Error("SubboxEntry: Failed to read left");
+ }
+ if (!table.ReadU8(&this->right) || this->right < this->left) {
+ return parent->Error("SubboxEntry: Failed to read valid right");
+ }
+ if (!table.ReadU8(&this->bottom)) {
+ return parent->Error("SubboxEntry: Failed to read bottom");
+ }
+ if (!table.ReadU8(&this->top) || this->top < this->bottom) {
+ return parent->Error("SubboxEntry: Failed to read valid top");
+ }
+ if (!table.ReadU8(&this->diag_pos_min)) {
+ return parent->Error("SubboxEntry: Failed to read diag_pos_min");
+ }
+ if (!table.ReadU8(&this->diag_pos_max) ||
+ this->diag_pos_max < this->diag_pos_min) {
+ return parent->Error("SubboxEntry: Failed to read valid diag_pos_max");
+ }
+ if (!table.ReadU8(&this->diag_neg_min)) {
+ return parent->Error("SubboxEntry: Failed to read diag_neg_min");
+ }
+ if (!table.ReadU8(&this->diag_neg_max) ||
+ this->diag_neg_max < this->diag_neg_min) {
+ return parent->Error("SubboxEntry: Failed to read valid diag_neg_max");
+ }
+ return true;
+}
+
+bool OpenTypeGLAT_v3::GlyphAttrs::OctaboxMetrics::
+SubboxEntry::SerializePart(OTSStream* out) const {
+ if (!out->WriteU8(this->left) ||
+ !out->WriteU8(this->right) ||
+ !out->WriteU8(this->bottom) ||
+ !out->WriteU8(this->top) ||
+ !out->WriteU8(this->diag_pos_min) ||
+ !out->WriteU8(this->diag_pos_max) ||
+ !out->WriteU8(this->diag_neg_min) ||
+ !out->WriteU8(this->diag_neg_max)) {
+ return parent->Error("SubboxEntry: Failed to write");
+ }
+ return true;
+}
+
+bool OpenTypeGLAT_v3::GlyphAttrs::
+GlatEntry::ParsePart(Buffer& table) {
+ if (!table.ReadS16(&this->attNum)) {
+ return parent->Error("GlatEntry: Failed to read attNum");
+ }
+ if (!table.ReadS16(&this->num) || this->num < 0) {
+ return parent->Error("GlatEntry: Failed to read valid num");
+ }
+
+ //this->attributes.resize(this->num);
+ for (unsigned i = 0; i < this->num; ++i) {
+ this->attributes.emplace_back();
+ if (!table.ReadS16(&this->attributes[i])) {
+ return parent->Error("GlatEntry: Failed to read attribute %u", i);
+ }
+ }
+ return true;
+}
+
+bool OpenTypeGLAT_v3::GlyphAttrs::
+GlatEntry::SerializePart(OTSStream* out) const {
+ if (!out->WriteS16(this->attNum) ||
+ !out->WriteS16(this->num) ||
+ !SerializeParts(this->attributes, out)) {
+ return parent->Error("GlatEntry: Failed to write");
+ }
+ return true;
+}
+
+// -----------------------------------------------------------------------------
+// OpenTypeGLAT
+// -----------------------------------------------------------------------------
+
+bool OpenTypeGLAT::Parse(const uint8_t* data, size_t length) {
+ if (GetFont()->dropped_graphite) {
+ return Drop("Skipping Graphite table");
+ }
+ Buffer table(data, length);
+ uint32_t version;
+ if (!table.ReadU32(&version)) {
+ return DropGraphite("Failed to read version");
+ }
+ switch (version >> 16) {
+ case 1:
+ this->handler = new OpenTypeGLAT_v1(this->font, this->tag);
+ break;
+ case 2:
+ this->handler = new OpenTypeGLAT_v2(this->font, this->tag);
+ break;
+ case 3: {
+ this->handler = new OpenTypeGLAT_v3(this->font, this->tag);
+ break;
+ }
+ default:
+ return DropGraphite("Unsupported table version: %u", version >> 16);
+ }
+ return this->handler->Parse(data, length);
+}
+
+bool OpenTypeGLAT::Serialize(OTSStream* out) {
+ if (!this->handler) {
+ return Error("No Glat table parsed");
+ }
+ return this->handler->Serialize(out);
+}
+
+} // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/glat.h
@@ -0,0 +1,172 @@
+// Copyright (c) 2009-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.
+
+#ifndef OTS_GLAT_H_
+#define OTS_GLAT_H_
+
+#include <vector>
+
+#include "ots.h"
+#include "graphite.h"
+
+namespace ots {
+
+// -----------------------------------------------------------------------------
+// OpenTypeGLAT_Basic Interface
+// -----------------------------------------------------------------------------
+
+class OpenTypeGLAT_Basic : public Table {
+ public:
+ explicit OpenTypeGLAT_Basic(Font* font, uint32_t tag)
+ : Table(font, tag, tag) { }
+
+ virtual bool Parse(const uint8_t* data, size_t length) = 0;
+ virtual bool Serialize(OTSStream* out) = 0;
+};
+
+// -----------------------------------------------------------------------------
+// OpenTypeGLAT_v1
+// -----------------------------------------------------------------------------
+
+class OpenTypeGLAT_v1 : public OpenTypeGLAT_Basic {
+ public:
+ explicit OpenTypeGLAT_v1(Font* font, uint32_t tag)
+ : OpenTypeGLAT_Basic(font, tag) { }
+
+ bool Parse(const uint8_t* data, size_t length);
+ bool Serialize(OTSStream* out);
+
+ private:
+ struct GlatEntry : public TablePart<OpenTypeGLAT_v1> {
+ explicit GlatEntry(OpenTypeGLAT_v1* parent)
+ : TablePart<OpenTypeGLAT_v1>(parent) { }
+ bool ParsePart(Buffer& table);
+ bool SerializePart(OTSStream* out) const;
+ uint8_t attNum;
+ uint8_t num;
+ std::vector<int16_t> attributes;
+ };
+ uint32_t version;
+ std::vector<GlatEntry> entries;
+};
+
+// -----------------------------------------------------------------------------
+// OpenTypeGLAT_v2
+// -----------------------------------------------------------------------------
+
+class OpenTypeGLAT_v2 : public OpenTypeGLAT_Basic {
+ public:
+ explicit OpenTypeGLAT_v2(Font* font, uint32_t tag)
+ : OpenTypeGLAT_Basic(font, tag) { }
+
+ bool Parse(const uint8_t* data, size_t length);
+ bool Serialize(OTSStream* out);
+
+ private:
+ struct GlatEntry : public TablePart<OpenTypeGLAT_v2> {
+ explicit GlatEntry(OpenTypeGLAT_v2* parent)
+ : TablePart<OpenTypeGLAT_v2>(parent) { }
+ bool ParsePart(Buffer& table);
+ bool SerializePart(OTSStream* out) const;
+ int16_t attNum;
+ int16_t num;
+ std::vector<int16_t> attributes;
+ };
+ uint32_t version;
+ std::vector<GlatEntry> entries;
+};
+
+// -----------------------------------------------------------------------------
+// OpenTypeGLAT_v3
+// -----------------------------------------------------------------------------
+
+class OpenTypeGLAT_v3 : public OpenTypeGLAT_Basic {
+ public:
+ explicit OpenTypeGLAT_v3(Font* font, uint32_t tag)
+ : OpenTypeGLAT_Basic(font, tag) { }
+
+ bool Parse(const uint8_t* data, size_t length) {
+ return this->Parse(data, length, false);
+ }
+ bool Serialize(OTSStream* out);
+
+ private:
+ bool Parse(const uint8_t* data, size_t length, bool prevent_decompression);
+ struct GlyphAttrs : public TablePart<OpenTypeGLAT_v3> {
+ explicit GlyphAttrs(OpenTypeGLAT_v3* parent)
+ : TablePart<OpenTypeGLAT_v3>(parent), octabox(parent) { }
+ bool ParsePart(Buffer& table) { return false; }
+ bool ParsePart(Buffer& table, const size_t size);
+ bool SerializePart(OTSStream* out) const;
+ struct OctaboxMetrics : public TablePart<OpenTypeGLAT_v3> {
+ explicit OctaboxMetrics(OpenTypeGLAT_v3* parent)
+ : TablePart<OpenTypeGLAT_v3>(parent) { }
+ bool ParsePart(Buffer& table);
+ bool SerializePart(OTSStream* out) const;
+ struct SubboxEntry : public TablePart<OpenTypeGLAT_v3> {
+ explicit SubboxEntry(OpenTypeGLAT_v3* parent)
+ : TablePart<OpenTypeGLAT_v3>(parent) { }
+ bool ParsePart(Buffer& table);
+ bool SerializePart(OTSStream* out) const;
+ uint8_t left;
+ uint8_t right;
+ uint8_t bottom;
+ uint8_t top;
+ uint8_t diag_pos_min;
+ uint8_t diag_pos_max;
+ uint8_t diag_neg_min;
+ uint8_t diag_neg_max;
+ };
+ uint16_t subbox_bitmap;
+ uint8_t diag_neg_min;
+ uint8_t diag_neg_max;
+ uint8_t diag_pos_min;
+ uint8_t diag_pos_max;
+ std::vector<SubboxEntry> subboxes;
+ };
+ struct GlatEntry : public TablePart<OpenTypeGLAT_v3> {
+ explicit GlatEntry(OpenTypeGLAT_v3* parent)
+ : TablePart<OpenTypeGLAT_v3>(parent) { }
+ bool ParsePart(Buffer& table);
+ bool SerializePart(OTSStream* out) const;
+ int16_t attNum;
+ int16_t num;
+ std::vector<int16_t> attributes;
+ };
+ OctaboxMetrics octabox;
+ std::vector<GlatEntry> entries;
+ };
+ uint32_t version;
+ uint32_t compHead; // compression header
+ static const uint32_t SCHEME = 0xF8000000;
+ static const uint32_t FULL_SIZE = 0x07FFFFFF;
+ static const uint32_t RESERVED = 0x07FFFFFE;
+ static const uint32_t OCTABOXES = 0x00000001;
+ std::vector<GlyphAttrs> entries;
+};
+
+// -----------------------------------------------------------------------------
+// OpenTypeGLAT
+// -----------------------------------------------------------------------------
+
+class OpenTypeGLAT : public Table {
+ public:
+ explicit OpenTypeGLAT(Font* font, uint32_t tag)
+ : Table(font, tag, tag), font(font), tag(tag) { }
+ OpenTypeGLAT(const OpenTypeGLAT& other) = delete;
+ OpenTypeGLAT& operator=(const OpenTypeGLAT& other) = delete;
+ ~OpenTypeGLAT() { delete handler; }
+
+ bool Parse(const uint8_t* data, size_t length);
+ bool Serialize(OTSStream* out);
+
+ private:
+ Font* font;
+ uint32_t tag;
+ OpenTypeGLAT_Basic* handler = nullptr;
+};
+
+} // namespace ots
+
+#endif // OTS_GLAT_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/gloc.cc
@@ -0,0 +1,108 @@
+// Copyright (c) 2009-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.
+
+#include "gloc.h"
+
+#include "name.h"
+
+namespace ots {
+
+bool OpenTypeGLOC::Parse(const uint8_t* data, size_t length) {
+ if (GetFont()->dropped_graphite) {
+ return Drop("Skipping Graphite table");
+ }
+ Buffer table(data, length);
+ OpenTypeNAME* name = static_cast<OpenTypeNAME*>(
+ GetFont()->GetTypedTable(OTS_TAG_NAME));
+ if (!name) {
+ return DropGraphite("Required name table is missing");
+ }
+
+ if (!table.ReadU32(&this->version)) {
+ return DropGraphite("Failed to read version");
+ }
+ if (this->version >> 16 != 1) {
+ return DropGraphite("Unsupported table version: %u", this->version >> 16);
+ }
+ if (!table.ReadU16(&this->flags) || this->flags > 0b11) {
+ return DropGraphite("Failed to read valid flags");
+ }
+ if (!table.ReadU16(&this->numAttribs)) {
+ return DropGraphite("Failed to read numAttribs");
+ }
+
+ if (this->flags & ATTRIB_IDS && this->numAttribs * sizeof(uint16_t) >
+ table.remaining()) {
+ return DropGraphite("Failed to calulate length of locations");
+ }
+ size_t locations_len = (table.remaining() -
+ (this->flags & ATTRIB_IDS ? this->numAttribs * sizeof(uint16_t) : 0)) /
+ (this->flags & LONG_FORMAT ? sizeof(uint32_t) : sizeof(uint16_t));
+ //this->locations.resize(locations_len);
+ if (this->flags & LONG_FORMAT) {
+ unsigned long last_location = 0;
+ for (size_t i = 0; i < locations_len; ++i) {
+ this->locations.emplace_back();
+ uint32_t& location = this->locations[i];
+ if (!table.ReadU32(&location) || location < last_location) {
+ return DropGraphite("Failed to read valid locations[%lu]", i);
+ }
+ last_location = location;
+ }
+ } else { // short (16-bit) offsets
+ unsigned last_location = 0;
+ for (size_t i = 0; i < locations_len; ++i) {
+ uint16_t location;
+ if (!table.ReadU16(&location) || location < last_location) {
+ return DropGraphite("Failed to read valid locations[%lu]", i);
+ }
+ last_location = location;
+ this->locations.push_back(static_cast<uint32_t>(location));
+ }
+ }
+ if (this->locations.empty()) {
+ return DropGraphite("No locations");
+ }
+
+ if (this->flags & ATTRIB_IDS) { // attribIds array present
+ //this->attribIds.resize(numAttribs);
+ for (unsigned i = 0; i < this->numAttribs; ++i) {
+ this->attribIds.emplace_back();
+ if (!table.ReadU16(&this->attribIds[i]) ||
+ !name->IsValidNameId(this->attribIds[i])) {
+ return DropGraphite("Failed to read valid attribIds[%u]", i);
+ }
+ }
+ }
+
+ if (table.remaining()) {
+ return Warning("%zu bytes unparsed", table.remaining());
+ }
+ return true;
+}
+
+bool OpenTypeGLOC::Serialize(OTSStream* out) {
+ if (!out->WriteU32(this->version) ||
+ !out->WriteU16(this->flags) ||
+ !out->WriteU16(this->numAttribs) ||
+ (this->flags & LONG_FORMAT ? !SerializeParts(this->locations, out) :
+ ![&] {
+ for (uint32_t location : this->locations) {
+ if (!out->WriteU16(static_cast<uint16_t>(location))) {
+ return false;
+ }
+ }
+ return true;
+ }()) ||
+ (this->flags & ATTRIB_IDS && !SerializeParts(this->attribIds, out))) {
+ return Error("Failed to write table");
+ }
+ return true;
+}
+
+const std::vector<uint32_t>& OpenTypeGLOC::GetLocations() {
+ return this->locations;
+}
+
+} // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/gloc.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2009-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.
+
+#ifndef OTS_GLOC_H_
+#define OTS_GLOC_H_
+
+#include <vector>
+
+#include "ots.h"
+#include "graphite.h"
+
+namespace ots {
+
+class OpenTypeGLOC : public Table {
+ public:
+ explicit OpenTypeGLOC(Font* font, uint32_t tag)
+ : Table(font, tag, tag) { }
+
+ bool Parse(const uint8_t* data, size_t length);
+ bool Serialize(OTSStream* out);
+ const std::vector<uint32_t>& GetLocations();
+
+ private:
+ uint32_t version;
+ uint16_t flags;
+ static const uint16_t LONG_FORMAT = 0b1;
+ static const uint16_t ATTRIB_IDS = 0b10;
+ uint16_t numAttribs;
+ std::vector<uint32_t> locations;
+ std::vector<uint16_t> attribIds;
+};
+
+} // namespace ots
+
+#endif // OTS_GLOC_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/graphite.h
@@ -0,0 +1,95 @@
+// Copyright (c) 2009-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.
+
+#ifndef OTS_GRAPHITE_H_
+#define OTS_GRAPHITE_H_
+
+#include <vector>
+#include <type_traits>
+
+namespace ots {
+
+template<typename ParentType>
+class TablePart {
+ public:
+ TablePart(ParentType* parent) : parent(parent) { }
+ virtual bool ParsePart(Buffer& table) = 0;
+ virtual bool SerializePart(OTSStream* out) const = 0;
+ protected:
+ ParentType* parent;
+};
+
+template<typename T>
+bool SerializeParts(const std::vector<T>& vec, OTSStream* out) {
+ for (const T& part : vec) {
+ if (!part.SerializePart(out)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+template<typename T>
+bool SerializeParts(const std::vector<std::vector<T>>& vec, OTSStream* out) {
+ for (const std::vector<T>& part : vec) {
+ if (!SerializeParts(part, out)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+inline bool SerializeParts(const std::vector<uint8_t>& vec, OTSStream* out) {
+ for (uint8_t part : vec) {
+ if (!out->WriteU8(part)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+inline bool SerializeParts(const std::vector<uint16_t>& vec, OTSStream* out) {
+ for (uint16_t part : vec) {
+ if (!out->WriteU16(part)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+inline bool SerializeParts(const std::vector<int16_t>& vec, OTSStream* out) {
+ for (int16_t part : vec) {
+ if (!out->WriteS16(part)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+inline bool SerializeParts(const std::vector<uint32_t>& vec, OTSStream* out) {
+ for (uint32_t part : vec) {
+ if (!out->WriteU32(part)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+inline bool SerializeParts(const std::vector<int32_t>& vec, OTSStream* out) {
+ for (int32_t part : vec) {
+ if (!out->WriteS32(part)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+template<typename T>
+size_t datasize(std::vector<T> vec) {
+ return sizeof(T) * vec.size();
+}
+
+} // namespace ots
+
+#endif // OTS_GRAPHITE_H_
--- a/gfx/ots/src/moz.build
+++ b/gfx/ots/src/moz.build
@@ -5,59 +5,66 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXPORTS += [
'../include/opentype-sanitiser.h',
'../include/ots-memory-stream.h',
]
SOURCES += [
- # don't unify sources that use a (file-specific) DROP_THIS_TABLE macro
- 'gasp.cc',
+ # needs to be separate because gpos.cc also defines kMaxClassDefValue
'gdef.cc',
- 'gpos.cc',
- 'gsub.cc',
- 'hdmx.cc',
- 'kern.cc',
- 'ltsh.cc',
- 'math.cc',
- 'vdmx.cc',
- 'vorg.cc',
]
UNIFIED_SOURCES += [
'cff.cc',
'cff_type2_charstring.cc',
'cmap.cc',
'cvt.cc',
+ 'feat.cc',
'fpgm.cc',
+ 'gasp.cc',
+ 'glat.cc',
+ 'gloc.cc',
'glyf.cc',
+ 'gpos.cc',
+ 'gsub.cc',
+ 'hdmx.cc',
'head.cc',
'hhea.cc',
'hmtx.cc',
+ 'kern.cc',
'layout.cc',
'loca.cc',
+ 'ltsh.cc',
+ 'math.cc',
'maxp.cc',
'metrics.cc',
'name.cc',
'os2.cc',
'ots.cc',
'post.cc',
'prep.cc',
+ 'sile.cc',
+ 'silf.cc',
+ 'sill.cc',
+ 'vdmx.cc',
'vhea.cc',
'vmtx.cc',
+ 'vorg.cc',
]
# We allow warnings for third-party code that can be updated from upstream.
ALLOW_COMPILER_WARNINGS = True
FINAL_LIBRARY = 'gkmedias'
DEFINES['PACKAGE_VERSION'] = '"moz"'
DEFINES['PACKAGE_BUGREPORT'] = '"http://bugzilla.mozilla.org/"'
+DEFINES['OTS_GRAPHITE'] = 1
USE_LIBS += [
'brotli',
'woff2',
]
LOCAL_INCLUDES += [
'/modules/woff2/src',
--- a/gfx/ots/src/name.cc
+++ b/gfx/ots/src/name.cc
@@ -144,16 +144,17 @@ bool OpenTypeNAME::Parse(const uint8_t*
}
if (!this->names.empty() && !(this->names.back() < rec)) {
Warning("name records are not sorted.");
sort_required = true;
}
this->names.push_back(rec);
+ this->name_ids.insert(rec.name_id);
}
if (format == 1) {
// extended name table format with language tags
uint16_t lang_tag_count;
if (!table.ReadU16(&lang_tag_count)) {
return Error("Failed to read langTagCount");
}
@@ -300,9 +301,55 @@ bool OpenTypeNAME::Serialize(OTSStream*
if (!out->Write(string_data.data(), string_data.size())) {
return Error("Faile to write string data");
}
return true;
}
+bool OpenTypeNAME::IsValidNameId(uint16_t nameID, bool addIfMissing) {
+ if (addIfMissing && !this->name_ids.count(nameID)) {
+ bool added_unicode = false;
+ bool added_macintosh = false;
+ bool added_windows = false;
+ const size_t names_size = this->names.size(); // original size
+ for (size_t i = 0; i < names_size; ++i) switch (names[i].platform_id) {
+ case 0:
+ if (!added_unicode) {
+ // If there is an existing NameRecord with platform_id == 0 (Unicode),
+ // then add a NameRecord for the the specified nameID with arguments
+ // 0 (Unicode), 0 (v1.0), 0 (unspecified language).
+ this->names.emplace_back(0, 0, 0, nameID);
+ this->names.back().text = "NoName";
+ added_unicode = true;
+ }
+ break;
+ case 1:
+ if (!added_macintosh) {
+ // If there is an existing NameRecord with platform_id == 1 (Macintosh),
+ // then add a NameRecord for the specified nameID with arguments
+ // 1 (Macintosh), 0 (Roman), 0 (English).
+ this->names.emplace_back(1, 0, 0, nameID);
+ this->names.back().text = "NoName";
+ added_macintosh = true;
+ }
+ break;
+ case 3:
+ if (!added_windows) {
+ // If there is an existing NameRecord with platform_id == 3 (Windows),
+ // then add a NameRecord for the specified nameID with arguments
+ // 3 (Windows), 1 (UCS), 1033 (US English).
+ this->names.emplace_back(3, 1, 1033, nameID);
+ this->names.back().text = "NoName";
+ added_windows = true;
+ }
+ break;
+ }
+ if (added_unicode || added_macintosh || added_windows) {
+ std::sort(this->names.begin(), this->names.end());
+ this->name_ids.insert(nameID);
+ }
+ }
+ return this->name_ids.count(nameID);
+}
+
} // namespace
--- a/gfx/ots/src/name.h
+++ b/gfx/ots/src/name.h
@@ -4,16 +4,17 @@
#ifndef OTS_NAME_H_
#define OTS_NAME_H_
#include <new>
#include <string>
#include <utility>
#include <vector>
+#include <unordered_set>
#include "ots.h"
namespace ots {
struct NameRecord {
NameRecord() {
}
@@ -45,17 +46,19 @@ struct NameRecord {
class OpenTypeNAME : public Table {
public:
explicit OpenTypeNAME(Font *font, uint32_t tag)
: Table(font, tag, tag) { }
bool Parse(const uint8_t *data, size_t length);
bool Serialize(OTSStream *out);
+ bool IsValidNameId(uint16_t nameID, bool addIfMissing = false);
private:
std::vector<NameRecord> names;
std::vector<std::string> lang_tags;
+ std::unordered_set<uint16_t> name_ids;
};
} // namespace ots
#endif // OTS_NAME_H_
--- a/gfx/ots/src/ots.cc
+++ b/gfx/ots/src/ots.cc
@@ -42,16 +42,26 @@
#include "ots.h"
#include "post.h"
#include "prep.h"
#include "vdmx.h"
#include "vhea.h"
#include "vmtx.h"
#include "vorg.h"
+// Graphite tables
+#ifdef OTS_GRAPHITE
+#include "feat.h"
+#include "glat.h"
+#include "gloc.h"
+#include "sile.h"
+#include "silf.h"
+#include "sill.h"
+#endif
+
namespace ots {
struct Arena {
public:
~Arena() {
for (std::vector<uint8_t*>::iterator
i = hunks_.begin(); i != hunks_.end(); ++i) {
delete[] *i;
@@ -119,16 +129,25 @@ const struct {
// We need to parse GDEF table in advance of parsing GSUB/GPOS tables
// because they could refer GDEF table.
{ OTS_TAG_GDEF, false },
{ OTS_TAG_GPOS, false },
{ OTS_TAG_GSUB, false },
{ OTS_TAG_VHEA, false },
{ OTS_TAG_VMTX, false },
{ OTS_TAG_MATH, false },
+ // Graphite tables
+#ifdef OTS_GRAPHITE
+ { OTS_TAG_GLOC, false },
+ { OTS_TAG_GLAT, false },
+ { OTS_TAG_FEAT, false },
+ { OTS_TAG_SILF, false },
+ { OTS_TAG_SILE, false },
+ { OTS_TAG_SILL, false },
+#endif
{ 0, false },
};
bool ProcessGeneric(ots::FontFile *header,
ots::Font *font,
uint32_t signature,
ots::OTSStream *output,
const uint8_t *data, size_t length,
@@ -864,16 +883,25 @@ bool Font::ParseTable(const TableEntry&
case OTS_TAG_NAME: table = new OpenTypeNAME(this, tag); break;
case OTS_TAG_OS2: table = new OpenTypeOS2(this, tag); break;
case OTS_TAG_POST: table = new OpenTypePOST(this, tag); break;
case OTS_TAG_PREP: table = new OpenTypePREP(this, tag); break;
case OTS_TAG_VDMX: table = new OpenTypeVDMX(this, tag); break;
case OTS_TAG_VORG: table = new OpenTypeVORG(this, tag); break;
case OTS_TAG_VHEA: table = new OpenTypeVHEA(this, tag); break;
case OTS_TAG_VMTX: table = new OpenTypeVMTX(this, tag); break;
+ // Graphite tables
+#ifdef OTS_GRAPHITE
+ case OTS_TAG_FEAT: table = new OpenTypeFEAT(this, tag); break;
+ case OTS_TAG_GLAT: table = new OpenTypeGLAT(this, tag); break;
+ case OTS_TAG_GLOC: table = new OpenTypeGLOC(this, tag); break;
+ case OTS_TAG_SILE: table = new OpenTypeSILE(this, tag); break;
+ case OTS_TAG_SILF: table = new OpenTypeSILF(this, tag); break;
+ case OTS_TAG_SILL: table = new OpenTypeSILL(this, tag); break;
+#endif
default: break;
}
}
if (table) {
const uint8_t* table_data;
size_t table_length;
@@ -905,16 +933,31 @@ Table* Font::GetTable(uint32_t tag) cons
Table* Font::GetTypedTable(uint32_t tag) const {
Table* t = GetTable(tag);
if (t && t->Type() == tag)
return t;
return NULL;
}
+void Font::DropGraphite() {
+ file->context->Message(0, "Dropping all Graphite tables");
+ for (const std::pair<uint32_t, Table*> entry : m_tables) {
+ if (entry.first == OTS_TAG_FEAT ||
+ entry.first == OTS_TAG_GLAT ||
+ entry.first == OTS_TAG_GLOC ||
+ entry.first == OTS_TAG_SILE ||
+ entry.first == OTS_TAG_SILF ||
+ entry.first == OTS_TAG_SILL) {
+ entry.second->Drop("Discarding Graphite table");
+ }
+ }
+ dropped_graphite = true;
+}
+
bool Table::ShouldSerialize() {
return m_shouldSerialize;
}
void Table::Message(int level, const char *format, va_list va) {
char msg[206] = { OTS_UNTAG(m_tag), ':', ' ' };
std::vsnprintf(msg + 6, 200, format, va);
m_font->file->context->Message(level, msg);
@@ -945,16 +988,26 @@ bool Table::Drop(const char *format, ...
va_start(va, format);
Message(0, format, va);
m_font->file->context->Message(0, "Table discarded");
va_end(va);
return true;
}
+bool Table::DropGraphite(const char *format, ...) {
+ va_list va;
+ va_start(va, format);
+ Message(0, format, va);
+ va_end(va);
+
+ m_font->DropGraphite();
+ return true;
+}
+
bool TablePassthru::Parse(const uint8_t *data, size_t length) {
m_data = data;
m_length = length;
return true;
}
bool TablePassthru::Serialize(OTSStream *out) {
if (!out->Write(m_data, m_length)) {
--- a/gfx/ots/src/ots.h
+++ b/gfx/ots/src/ots.h
@@ -1,17 +1,18 @@
// Copyright (c) 2009-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.
#ifndef OTS_H_
#define OTS_H_
-// Not needed in the gecko build
-// #include "config.h"
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
#include <stddef.h>
#include <cstdarg>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <limits>
@@ -183,35 +184,41 @@ template<typename T> T Round2(T value) {
return (value + 1) & ~1;
}
bool IsValidVersionTag(uint32_t tag);
#define OTS_TAG_CFF OTS_TAG('C','F','F',' ')
#define OTS_TAG_CMAP OTS_TAG('c','m','a','p')
#define OTS_TAG_CVT OTS_TAG('c','v','t',' ')
+#define OTS_TAG_FEAT OTS_TAG('F','e','a','t')
#define OTS_TAG_FPGM OTS_TAG('f','p','g','m')
#define OTS_TAG_GASP OTS_TAG('g','a','s','p')
#define OTS_TAG_GDEF OTS_TAG('G','D','E','F')
+#define OTS_TAG_GLAT OTS_TAG('G','l','a','t')
+#define OTS_TAG_GLOC OTS_TAG('G','l','o','c')
#define OTS_TAG_GLYF OTS_TAG('g','l','y','f')
#define OTS_TAG_GPOS OTS_TAG('G','P','O','S')
#define OTS_TAG_GSUB OTS_TAG('G','S','U','B')
#define OTS_TAG_HDMX OTS_TAG('h','d','m','x')
#define OTS_TAG_HEAD OTS_TAG('h','e','a','d')
#define OTS_TAG_HHEA OTS_TAG('h','h','e','a')
#define OTS_TAG_HMTX OTS_TAG('h','m','t','x')
#define OTS_TAG_KERN OTS_TAG('k','e','r','n')
#define OTS_TAG_LOCA OTS_TAG('l','o','c','a')
#define OTS_TAG_LTSH OTS_TAG('L','T','S','H')
#define OTS_TAG_MATH OTS_TAG('M','A','T','H')
#define OTS_TAG_MAXP OTS_TAG('m','a','x','p')
#define OTS_TAG_NAME OTS_TAG('n','a','m','e')
#define OTS_TAG_OS2 OTS_TAG('O','S','/','2')
#define OTS_TAG_POST OTS_TAG('p','o','s','t')
#define OTS_TAG_PREP OTS_TAG('p','r','e','p')
+#define OTS_TAG_SILE OTS_TAG('S','i','l','e')
+#define OTS_TAG_SILF OTS_TAG('S','i','l','f')
+#define OTS_TAG_SILL OTS_TAG('S','i','l','l')
#define OTS_TAG_VDMX OTS_TAG('V','D','M','X')
#define OTS_TAG_VHEA OTS_TAG('v','h','e','a')
#define OTS_TAG_VMTX OTS_TAG('v','m','t','x')
#define OTS_TAG_VORG OTS_TAG('V','O','R','G')
struct Font;
struct FontFile;
struct TableEntry;
@@ -239,16 +246,17 @@ class Table {
// TablePassthru (indicating unparsed data).
uint32_t Type() { return m_type; }
Font* GetFont() { return m_font; }
bool Error(const char *format, ...);
bool Warning(const char *format, ...);
bool Drop(const char *format, ...);
+ bool DropGraphite(const char *format, ...);
private:
void Message(int level, const char *format, va_list va);
uint32_t m_tag;
uint32_t m_type;
Font *m_font;
bool m_shouldSerialize;
@@ -272,35 +280,40 @@ class TablePassthru : public Table {
struct Font {
explicit Font(FontFile *f)
: file(f),
version(0),
num_tables(0),
search_range(0),
entry_selector(0),
- range_shift(0) {
+ range_shift(0),
+ dropped_graphite(false) {
}
bool ParseTable(const TableEntry& tableinfo, const uint8_t* data,
Arena &arena);
Table* GetTable(uint32_t tag) const;
// This checks that the returned Table is actually of the correct subclass
// for |tag|, so it can safely be downcast to the corresponding OpenTypeXXXX;
// if not (i.e. if the table was treated as Passthru), it will return NULL.
Table* GetTypedTable(uint32_t tag) const;
+ // Drop all Graphite tables and don't parse new ones.
+ void DropGraphite();
+
FontFile *file;
uint32_t version;
uint16_t num_tables;
uint16_t search_range;
uint16_t entry_selector;
uint16_t range_shift;
+ bool dropped_graphite;
private:
std::map<uint32_t, Table*> m_tables;
};
struct TableEntry {
uint32_t tag;
uint32_t offset;
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/sile.cc
@@ -0,0 +1,74 @@
+// Copyright (c) 2009-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.
+
+#include "sile.h"
+
+namespace ots {
+
+bool OpenTypeSILE::Parse(const uint8_t* data, size_t length) {
+ if (GetFont()->dropped_graphite) {
+ return Drop("Skipping Graphite table");
+ }
+ Buffer table(data, length);
+
+ if (!table.ReadU32(&this->version) || this->version >> 16 != 1) {
+ return DropGraphite("Failed to read valid version");
+ }
+ if (!table.ReadU32(&this->checksum)) {
+ return DropGraphite("Failed to read checksum");
+ }
+ if (!table.ReadU32(&this->createTime[0]) ||
+ !table.ReadU32(&this->createTime[1])) {
+ return DropGraphite("Failed to read createTime");
+ }
+ if (!table.ReadU32(&this->modifyTime[0]) ||
+ !table.ReadU32(&this->modifyTime[1])) {
+ return DropGraphite("Failed to read modifyTime");
+ }
+
+ if (!table.ReadU16(&this->fontNameLength)) {
+ return DropGraphite("Failed to read fontNameLength");
+ }
+ //this->fontName.resize(this->fontNameLength);
+ for (unsigned i = 0; i < this->fontNameLength; ++i) {
+ this->fontName.emplace_back();
+ if (!table.ReadU16(&this->fontName[i])) {
+ return DropGraphite("Failed to read fontName[%u]", i);
+ }
+ }
+
+ if (!table.ReadU16(&this->fontFileLength)) {
+ return DropGraphite("Failed to read fontFileLength");
+ }
+ //this->baseFile.resize(this->fontFileLength);
+ for (unsigned i = 0; i < this->fontFileLength; ++i) {
+ this->baseFile.emplace_back();
+ if (!table.ReadU16(&this->baseFile[i])) {
+ return DropGraphite("Failed to read baseFile[%u]", i);
+ }
+ }
+
+ if (table.remaining()) {
+ return Warning("%zu bytes unparsed", table.remaining());
+ }
+ return true;
+}
+
+bool OpenTypeSILE::Serialize(OTSStream* out) {
+ if (!out->WriteU32(this->version) ||
+ !out->WriteU32(this->checksum) ||
+ !out->WriteU32(this->createTime[0]) ||
+ !out->WriteU32(this->createTime[1]) ||
+ !out->WriteU32(this->modifyTime[0]) ||
+ !out->WriteU32(this->modifyTime[1]) ||
+ !out->WriteU16(this->fontNameLength) ||
+ !SerializeParts(this->fontName, out) ||
+ !out->WriteU16(this->fontFileLength) ||
+ !SerializeParts(this->baseFile, out)) {
+ return Error("Failed to write table");
+ }
+ return true;
+}
+
+} // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/sile.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2009-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.
+
+#ifndef OTS_SILE_H_
+#define OTS_SILE_H_
+
+#include "ots.h"
+#include "graphite.h"
+
+#include <vector>
+
+namespace ots {
+
+class OpenTypeSILE : public Table {
+ public:
+ explicit OpenTypeSILE(Font* font, uint32_t tag)
+ : Table(font, tag, tag) { }
+
+ bool Parse(const uint8_t* data, size_t length);
+ bool Serialize(OTSStream* out);
+
+ private:
+ uint32_t version;
+ uint32_t checksum;
+ uint32_t createTime[2];
+ uint32_t modifyTime[2];
+ uint16_t fontNameLength;
+ std::vector<uint16_t> fontName;
+ uint16_t fontFileLength;
+ std::vector<uint16_t> baseFile;
+};
+
+} // namespace ots
+
+#endif // OTS_SILE_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/silf.cc
@@ -0,0 +1,950 @@
+// Copyright (c) 2009-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.
+
+#include "silf.h"
+
+#include "name.h"
+#include "mozilla/Compression.h"
+#include <cmath>
+
+namespace ots {
+
+bool OpenTypeSILF::Parse(const uint8_t* data, size_t length,
+ bool prevent_decompression) {
+ if (GetFont()->dropped_graphite) {
+ return Drop("Skipping Graphite table");
+ }
+ Buffer table(data, length);
+
+ if (!table.ReadU32(&this->version)) {
+ return DropGraphite("Failed to read version");
+ }
+ if (this->version >> 16 != 1 &&
+ this->version >> 16 != 2 &&
+ this->version >> 16 != 3 &&
+ this->version >> 16 != 4 &&
+ this->version >> 16 != 5) {
+ return DropGraphite("Unsupported table version: %u", this->version >> 16);
+ }
+ if (this->version >> 16 >= 3 && !table.ReadU32(&this->compHead)) {
+ return DropGraphite("Failed to read compHead");
+ }
+ if (this->version >> 16 >= 5) {
+ switch ((this->compHead & SCHEME) >> 27) {
+ case 0: // uncompressed
+ break;
+ case 1: { // lz4
+ if (prevent_decompression) {
+ return DropGraphite("Illegal nested compression");
+ }
+ std::vector<uint8_t> decompressed(this->compHead & FULL_SIZE, 0);
+ size_t outputSize = 0;
+ if (!mozilla::Compression::LZ4::decompress(
+ reinterpret_cast<const char*>(data + table.offset()),
+ table.remaining(),
+ reinterpret_cast<char*>(decompressed.data()),
+ decompressed.size(),
+ &outputSize) ||
+ outputSize != (this->compHead & FULL_SIZE)) {
+ return DropGraphite("Decompression failed");
+ }
+ return this->Parse(decompressed.data(), decompressed.size(), true);
+ }
+ default:
+ return DropGraphite("Unknown compression scheme");
+ }
+ }
+ if (!table.ReadU16(&this->numSub)) {
+ return DropGraphite("Failed to read numSub");
+ }
+ if (this->version >> 16 >= 2 && !table.ReadU16(&this->reserved)) {
+ return DropGraphite("Failed to read reserved");
+ }
+ if (this->version >> 16 >= 2 && this->reserved != 0) {
+ Warning("Nonzero reserved");
+ }
+
+ unsigned long last_offset = 0;
+ //this->offset.resize(this->numSub);
+ for (unsigned i = 0; i < this->numSub; ++i) {
+ this->offset.emplace_back();
+ if (!table.ReadU32(&this->offset[i]) || this->offset[i] < last_offset) {
+ return DropGraphite("Failed to read offset[%u]", i);
+ }
+ last_offset = this->offset[i];
+ }
+
+ for (unsigned i = 0; i < this->numSub; ++i) {
+ if (table.offset() != this->offset[i]) {
+ return DropGraphite("Offset check failed for tables[%lu]", i);
+ }
+ SILSub subtable(this);
+ if (!subtable.ParsePart(table)) {
+ return DropGraphite("Failed to read tables[%u]", i);
+ }
+ tables.push_back(subtable);
+ }
+
+ if (table.remaining()) {
+ return Warning("%zu bytes unparsed", table.remaining());
+ }
+ return true;
+}
+
+bool OpenTypeSILF::Serialize(OTSStream* out) {
+ if (!out->WriteU32(this->version) ||
+ (this->version >> 16 >= 3 && !out->WriteU32(this->compHead)) ||
+ !out->WriteU16(this->numSub) ||
+ (this->version >> 16 >= 2 && !out->WriteU16(this->reserved)) ||
+ !SerializeParts(this->offset, out) ||
+ !SerializeParts(this->tables, out)) {
+ return Error("Failed to write table");
+ }
+ return true;
+}
+
+bool OpenTypeSILF::SILSub::ParsePart(Buffer& table) {
+ size_t init_offset = table.offset();
+ if (parent->version >> 16 >= 3) {
+ if (!table.ReadU32(&this->ruleVersion)) {
+ return parent->Error("SILSub: Failed to read ruleVersion");
+ }
+ if (!table.ReadU16(&this->passOffset)) {
+ return parent->Error("SILSub: Failed to read passOffset");
+ }
+ if (!table.ReadU16(&this->pseudosOffset)) {
+ return parent->Error("SILSub: Failed to read pseudosOffset");
+ }
+ }
+ if (!table.ReadU16(&this->maxGlyphID)) {
+ return parent->Error("SILSub: Failed to read maxGlyphID");
+ }
+ if (!table.ReadS16(&this->extraAscent)) {
+ return parent->Error("SILSub: Failed to read extraAscent");
+ }
+ if (!table.ReadS16(&this->extraDescent)) {
+ return parent->Error("SILSub: Failed to read extraDescent");
+ }
+ if (!table.ReadU8(&this->numPasses)) {
+ return parent->Error("SILSub: Failed to read numPasses");
+ }
+ if (!table.ReadU8(&this->iSubst) || this->iSubst > this->numPasses) {
+ return parent->Error("SILSub: Failed to read valid iSubst");
+ }
+ if (!table.ReadU8(&this->iPos) || this->iPos > this->numPasses) {
+ return parent->Error("SILSub: Failed to read valid iPos");
+ }
+ if (!table.ReadU8(&this->iJust) || this->iJust > this->numPasses) {
+ return parent->Error("SILSub: Failed to read valid iJust");
+ }
+ if (!table.ReadU8(&this->iBidi) ||
+ !(iBidi == 0xFF || this->iBidi <= this->iPos)) {
+ return parent->Error("SILSub: Failed to read valid iBidi");
+ }
+ if (!table.ReadU8(&this->flags)) {
+ return parent->Error("SILSub: Failed to read flags");
+ // checks omitted
+ }
+ if (!table.ReadU8(&this->maxPreContext)) {
+ return parent->Error("SILSub: Failed to read maxPreContext");
+ }
+ if (!table.ReadU8(&this->maxPostContext)) {
+ return parent->Error("SILSub: Failed to read maxPostContext");
+ }
+ if (!table.ReadU8(&this->attrPseudo)) {
+ return parent->Error("SILSub: Failed to read attrPseudo");
+ }
+ if (!table.ReadU8(&this->attrBreakWeight)) {
+ return parent->Error("SILSub: Failed to read attrBreakWeight");
+ }
+ if (!table.ReadU8(&this->attrDirectionality)) {
+ return parent->Error("SILSub: Failed to read attrDirectionality");
+ }
+ if (parent->version >> 16 >= 2) {
+ if (!table.ReadU8(&this->attrMirroring)) {
+ return parent->Error("SILSub: Failed to read attrMirroring");
+ }
+ if (parent->version >> 16 < 4 && this->attrMirroring != 0) {
+ parent->Warning("SILSub: Nonzero attrMirroring (reserved before v4)");
+ }
+ if (!table.ReadU8(&this->attrSkipPasses)) {
+ return parent->Error("SILSub: Failed to read attrSkipPasses");
+ }
+ if (parent->version >> 16 < 4 && this->attrSkipPasses != 0) {
+ parent->Warning("SILSub: Nonzero attrSkipPasses (reserved2 before v4)");
+ }
+
+ if (!table.ReadU8(&this->numJLevels)) {
+ return parent->Error("SILSub: Failed to read numJLevels");
+ }
+ //this->jLevels.resize(this->numJLevels, parent);
+ for (unsigned i = 0; i < this->numJLevels; ++i) {
+ this->jLevels.emplace_back(parent);
+ if (!this->jLevels[i].ParsePart(table)) {
+ return parent->Error("SILSub: Failed to read jLevels[%u]", i);
+ }
+ }
+ }
+
+ if (!table.ReadU16(&this->numLigComp)) {
+ return parent->Error("SILSub: Failed to read numLigComp");
+ }
+ if (!table.ReadU8(&this->numUserDefn)) {
+ return parent->Error("SILSub: Failed to read numUserDefn");
+ }
+ if (!table.ReadU8(&this->maxCompPerLig)) {
+ return parent->Error("SILSub: Failed to read maxCompPerLig");
+ }
+ if (!table.ReadU8(&this->direction)) {
+ return parent->Error("SILSub: Failed to read direction");
+ }
+ if (!table.ReadU8(&this->attCollisions)) {
+ return parent->Error("SILSub: Failed to read attCollisions");
+ }
+ if (parent->version >> 16 < 5 && this->attCollisions != 0) {
+ parent->Warning("SILSub: Nonzero attCollisions (reserved before v5)");
+ }
+ if (!table.ReadU8(&this->reserved4)) {
+ return parent->Error("SILSub: Failed to read reserved4");
+ }
+ if (this->reserved4 != 0) {
+ parent->Warning("SILSub: Nonzero reserved4");
+ }
+ if (!table.ReadU8(&this->reserved5)) {
+ return parent->Error("SILSub: Failed to read reserved5");
+ }
+ if (this->reserved5 != 0) {
+ parent->Warning("SILSub: Nonzero reserved5");
+ }
+ if (parent->version >> 16 >= 2) {
+ if (!table.ReadU8(&this->reserved6)) {
+ return parent->Error("SILSub: Failed to read reserved6");
+ }
+ if (this->reserved6 != 0) {
+ parent->Warning("SILSub: Nonzero reserved6");
+ }
+
+ if (!table.ReadU8(&this->numCritFeatures)) {
+ return parent->Error("SILSub: Failed to read numCritFeatures");
+ }
+ //this->critFeatures.resize(this->numCritFeatures);
+ for (unsigned i = 0; i < this->numCritFeatures; ++i) {
+ this->critFeatures.emplace_back();
+ if (!table.ReadU16(&this->critFeatures[i])) {
+ return parent->Error("SILSub: Failed to read critFeatures[%u]", i);
+ }
+ }
+
+ if (!table.ReadU8(&this->reserved7)) {
+ return parent->Error("SILSub: Failed to read reserved7");
+ }
+ if (this->reserved7 != 0) {
+ parent->Warning("SILSub: Nonzero reserved7");
+ }
+ }
+
+ if (!table.ReadU8(&this->numScriptTag)) {
+ return parent->Error("SILSub: Failed to read numScriptTag");
+ }
+ //this->scriptTag.resize(this->numScriptTag);
+ for (unsigned i = 0; i < this->numScriptTag; ++i) {
+ this->scriptTag.emplace_back();
+ if (!table.ReadU32(&this->scriptTag[i])) {
+ return parent->Error("SILSub: Failed to read scriptTag[%u]", i);
+ }
+ }
+
+ if (!table.ReadU16(&this->lbGID) || this->lbGID > this->maxGlyphID) {
+ return parent->Error("SILSub: Failed to read valid lbGID");
+ }
+
+ if (parent->version >> 16 >= 3 &&
+ table.offset() != init_offset + this->passOffset) {
+ return parent->Error("SILSub: passOffset check failed");
+ }
+ unsigned long last_oPass = 0;
+ //this->oPasses.resize(static_cast<unsigned>(this->numPasses) + 1);
+ for (unsigned i = 0; i <= this->numPasses; ++i) {
+ this->oPasses.emplace_back();
+ if (!table.ReadU32(&this->oPasses[i]) || this->oPasses[i] < last_oPass) {
+ return false;
+ }
+ last_oPass = this->oPasses[i];
+ }
+
+ if (parent->version >> 16 >= 3 &&
+ table.offset() != init_offset + this->pseudosOffset) {
+ return parent->Error("SILSub: pseudosOffset check failed");
+ }
+ if (!table.ReadU16(&this->numPseudo)) {
+ return parent->Error("SILSub: Failed to read numPseudo");
+ }
+ if (!table.ReadU16(&this->searchPseudo) || this->searchPseudo !=
+ (this->numPseudo == 0 ? 0 : // protect against log2(0)
+ (unsigned)std::pow(2, std::floor(std::log2(this->numPseudo))))) {
+ return parent->Error("SILSub: Failed to read valid searchPseudo");
+ }
+ if (!table.ReadU16(&this->pseudoSelector) || this->pseudoSelector !=
+ (this->numPseudo == 0 ? 0 : // protect against log2(0)
+ (unsigned)std::floor(std::log2(this->numPseudo)))) {
+ return parent->Error("SILSub: Failed to read valid pseudoSelector");
+ }
+ if (!table.ReadU16(&this->pseudoShift) ||
+ this->pseudoShift != this->numPseudo - this->searchPseudo) {
+ return parent->Error("SILSub: Failed to read valid pseudoShift");
+ }
+
+ //this->pMaps.resize(this->numPseudo, parent);
+ for (unsigned i = 0; i < numPseudo; i++) {
+ this->pMaps.emplace_back(parent);
+ if (!this->pMaps[i].ParsePart(table)) {
+ return parent->Error("SILSub: Failed to read pMaps[%u]", i);
+ }
+ }
+
+ if (!this->classes.ParsePart(table)) {
+ return parent->Error("SILSub: Failed to read classes");
+ }
+
+ //this->passes.resize(this->numPasses, parent);
+ for (unsigned i = 0; i < this->numPasses; ++i) {
+ this->passes.emplace_back(parent);
+ if (table.offset() != init_offset + this->oPasses[i]) {
+ return parent->Error("SILSub: Offset check failed for passes[%u]", i);
+ }
+ if (!this->passes[i].ParsePart(table, init_offset, this->oPasses[i+1])) {
+ return parent->Error("SILSub: Failed to read passes[%u]", i);
+ }
+ }
+ return true;
+}
+
+bool OpenTypeSILF::SILSub::SerializePart(OTSStream* out) const {
+ if ((parent->version >> 16 >= 3 &&
+ (!out->WriteU32(this->ruleVersion) ||
+ !out->WriteU16(this->passOffset) ||
+ !out->WriteU16(this->pseudosOffset))) ||
+ !out->WriteU16(this->maxGlyphID) ||
+ !out->WriteS16(this->extraAscent) ||
+ !out->WriteS16(this->extraDescent) ||
+ !out->WriteU8(this->numPasses) ||
+ !out->WriteU8(this->iSubst) ||
+ !out->WriteU8(this->iPos) ||
+ !out->WriteU8(this->iJust) ||
+ !out->WriteU8(this->iBidi) ||
+ !out->WriteU8(this->flags) ||
+ !out->WriteU8(this->maxPreContext) ||
+ !out->WriteU8(this->maxPostContext) ||
+ !out->WriteU8(this->attrPseudo) ||
+ !out->WriteU8(this->attrBreakWeight) ||
+ !out->WriteU8(this->attrDirectionality) ||
+ (parent->version >> 16 >= 2 &&
+ (!out->WriteU8(this->attrMirroring) ||
+ !out->WriteU8(this->attrSkipPasses) ||
+ !out->WriteU8(this->numJLevels) ||
+ !SerializeParts(this->jLevels, out))) ||
+ !out->WriteU16(this->numLigComp) ||
+ !out->WriteU8(this->numUserDefn) ||
+ !out->WriteU8(this->maxCompPerLig) ||
+ !out->WriteU8(this->direction) ||
+ !out->WriteU8(this->attCollisions) ||
+ !out->WriteU8(this->reserved4) ||
+ !out->WriteU8(this->reserved5) ||
+ (parent->version >> 16 >= 2 &&
+ (!out->WriteU8(this->reserved6) ||
+ !out->WriteU8(this->numCritFeatures) ||
+ !SerializeParts(this->critFeatures, out) ||
+ !out->WriteU8(this->reserved7))) ||
+ !out->WriteU8(this->numScriptTag) ||
+ !SerializeParts(this->scriptTag, out) ||
+ !out->WriteU16(this->lbGID) ||
+ !SerializeParts(this->oPasses, out) ||
+ !out->WriteU16(this->numPseudo) ||
+ !out->WriteU16(this->searchPseudo) ||
+ !out->WriteU16(this->pseudoSelector) ||
+ !out->WriteU16(this->pseudoShift) ||
+ !SerializeParts(this->pMaps, out) ||
+ !this->classes.SerializePart(out) ||
+ !SerializeParts(this->passes, out)) {
+ return parent->Error("SILSub: Failed to write");
+ }
+ return true;
+}
+
+bool OpenTypeSILF::SILSub::
+JustificationLevel::ParsePart(Buffer& table) {
+ if (!table.ReadU8(&this->attrStretch)) {
+ return parent->Error("JustificationLevel: Failed to read attrStretch");
+ }
+ if (!table.ReadU8(&this->attrShrink)) {
+ return parent->Error("JustificationLevel: Failed to read attrShrink");
+ }
+ if (!table.ReadU8(&this->attrStep)) {
+ return parent->Error("JustificationLevel: Failed to read attrStep");
+ }
+ if (!table.ReadU8(&this->attrWeight)) {
+ return parent->Error("JustificationLevel: Failed to read attrWeight");
+ }
+ if (!table.ReadU8(&this->runto)) {
+ return parent->Error("JustificationLevel: Failed to read runto");
+ }
+ if (!table.ReadU8(&this->reserved)) {
+ return parent->Error("JustificationLevel: Failed to read reserved");
+ }
+ if (this->reserved != 0) {
+ parent->Warning("JustificationLevel: Nonzero reserved");
+ }
+ if (!table.ReadU8(&this->reserved2)) {
+ return parent->Error("JustificationLevel: Failed to read reserved2");
+ }
+ if (this->reserved2 != 0) {
+ parent->Warning("JustificationLevel: Nonzero reserved2");
+ }
+ if (!table.ReadU8(&this->reserved3)) {
+ return parent->Error("JustificationLevel: Failed to read reserved3");
+ }
+ if (this->reserved3 != 0) {
+ parent->Warning("JustificationLevel: Nonzero reserved3");
+ }
+ return true;
+}
+
+bool OpenTypeSILF::SILSub::
+JustificationLevel::SerializePart(OTSStream* out) const {
+ if (!out->WriteU8(this->attrStretch) ||
+ !out->WriteU8(this->attrShrink) ||
+ !out->WriteU8(this->attrStep) ||
+ !out->WriteU8(this->attrWeight) ||
+ !out->WriteU8(this->runto) ||
+ !out->WriteU8(this->reserved) ||
+ !out->WriteU8(this->reserved2) ||
+ !out->WriteU8(this->reserved3)) {
+ return parent->Error("JustificationLevel: Failed to write");
+ }
+ return true;
+}
+
+bool OpenTypeSILF::SILSub::
+PseudoMap::ParsePart(Buffer& table) {
+ if (parent->version >> 16 >= 2 && !table.ReadU32(&this->unicode)) {
+ return parent->Error("PseudoMap: Failed to read unicode");
+ }
+ if (parent->version >> 16 == 1) {
+ uint16_t unicode;
+ if (!table.ReadU16(&unicode)) {
+ return parent->Error("PseudoMap: Failed to read unicode");
+ }
+ this->unicode = unicode;
+ }
+ if (!table.ReadU16(&this->nPseudo)) {
+ return parent->Error("PseudoMap: Failed to read nPseudo");
+ }
+ return true;
+}
+
+bool OpenTypeSILF::SILSub::
+PseudoMap::SerializePart(OTSStream* out) const {
+ if ((parent->version >> 16 >= 2 && !out->WriteU32(this->unicode)) ||
+ (parent->version >> 16 == 1 &&
+ !out->WriteU16(static_cast<uint16_t>(this->unicode))) ||
+ !out->WriteU16(this->nPseudo)) {
+ return parent->Error("PseudoMap: Failed to write");
+ }
+ return true;
+}
+
+bool OpenTypeSILF::SILSub::
+ClassMap::ParsePart(Buffer& table) {
+ size_t init_offset = table.offset();
+ if (!table.ReadU16(&this->numClass)) {
+ return parent->Error("ClassMap: Failed to read numClass");
+ }
+ if (!table.ReadU16(&this->numLinear) || this->numLinear > this->numClass) {
+ return parent->Error("ClassMap: Failed to read valid numLinear");
+ }
+
+ //this->oClass.resize(static_cast<unsigned long>(this->numClass) + 1);
+ if (parent->version >> 16 >= 4) {
+ unsigned long last_oClass = 0;
+ for (unsigned long i = 0; i <= this->numClass; ++i) {
+ this->oClass.emplace_back();
+ if (!table.ReadU32(&this->oClass[i]) || this->oClass[i] < last_oClass) {
+ return parent->Error("ClassMap: Failed to read oClass[%lu]", i);
+ }
+ last_oClass = this->oClass[i];
+ }
+ }
+ if (parent->version >> 16 < 4) {
+ unsigned last_oClass = 0;
+ for (unsigned long i = 0; i <= this->numClass; ++i) {
+ uint16_t offset;
+ if (!table.ReadU16(&offset) || offset < last_oClass) {
+ return parent->Error("ClassMap: Failed to read oClass[%lu]", i);
+ }
+ last_oClass = offset;
+ this->oClass.push_back(static_cast<uint32_t>(offset));
+ }
+ }
+
+ if (table.offset() - init_offset > this->oClass[this->numLinear]) {
+ return parent->Error("ClassMap: Failed to calculate length of glyphs");
+ }
+ unsigned long glyphs_len = (this->oClass[this->numLinear] -
+ (table.offset() - init_offset))/2;
+ //this->glyphs.resize(glyphs_len);
+ for (unsigned long i = 0; i < glyphs_len; ++i) {
+ this->glyphs.emplace_back();
+ if (!table.ReadU16(&this->glyphs[i])) {
+ return parent->Error("ClassMap: Failed to read glyphs[%lu]", i);
+ }
+ }
+
+ unsigned lookups_len = this->numClass - this->numLinear;
+ // this->numLinear <= this->numClass
+ //this->lookups.resize(lookups_len, parent);
+ for (unsigned i = 0; i < lookups_len; ++i) {
+ this->lookups.emplace_back(parent);
+ if (table.offset() != init_offset + oClass[this->numLinear + i]) {
+ return parent->Error("ClassMap: Offset check failed for lookups[%u]", i);
+ }
+ if (!this->lookups[i].ParsePart(table)) {
+ return parent->Error("ClassMap: Failed to read lookups[%u]", i);
+ }
+ }
+ return true;
+}
+
+bool OpenTypeSILF::SILSub::
+ClassMap::SerializePart(OTSStream* out) const {
+ if (!out->WriteU16(this->numClass) ||
+ !out->WriteU16(this->numLinear) ||
+ (parent->version >> 16 >= 4 && !SerializeParts(this->oClass, out)) ||
+ (parent->version >> 16 < 4 &&
+ ![&] {
+ for (uint32_t offset : this->oClass) {
+ if (!out->WriteU16(static_cast<uint16_t>(offset))) {
+ return false;
+ }
+ }
+ return true;
+ }()) ||
+ !SerializeParts(this->glyphs, out) ||
+ !SerializeParts(this->lookups, out)) {
+ return parent->Error("ClassMap: Failed to write");
+ }
+ return true;
+}
+
+bool OpenTypeSILF::SILSub::ClassMap::
+LookupClass::ParsePart(Buffer& table) {
+ if (!table.ReadU16(&this->numIDs)) {
+ return parent->Error("LookupClass: Failed to read numIDs");
+ }
+ if (!table.ReadU16(&this->searchRange) || this->searchRange !=
+ (this->numIDs == 0 ? 0 : // protect against log2(0)
+ (unsigned)std::pow(2, std::floor(std::log2(this->numIDs))))) {
+ return parent->Error("LookupClass: Failed to read valid searchRange");
+ }
+ if (!table.ReadU16(&this->entrySelector) || this->entrySelector !=
+ (this->numIDs == 0 ? 0 : // protect against log2(0)
+ (unsigned)std::floor(std::log2(this->numIDs)))) {
+ return parent->Error("LookupClass: Failed to read valid entrySelector");
+ }
+ if (!table.ReadU16(&this->rangeShift) ||
+ this->rangeShift != this->numIDs - this->searchRange) {
+ return parent->Error("LookupClass: Failed to read valid rangeShift");
+ }
+
+ //this->lookups.resize(this->numIDs, parent);
+ for (unsigned i = 0; i < numIDs; ++i) {
+ this->lookups.emplace_back(parent);
+ if (!this->lookups[i].ParsePart(table)) {
+ return parent->Error("LookupClass: Failed to read lookups[%u]", i);
+ }
+ }
+ return true;
+}
+
+bool OpenTypeSILF::SILSub::ClassMap::
+LookupClass::SerializePart(OTSStream* out) const {
+ if (!out->WriteU16(this->numIDs) ||
+ !out->WriteU16(this->searchRange) ||
+ !out->WriteU16(this->entrySelector) ||
+ !out->WriteU16(this->rangeShift) ||
+ !SerializeParts(this->lookups, out)) {
+ return parent->Error("LookupClass: Failed to write");
+ }
+ return true;
+}
+
+bool OpenTypeSILF::SILSub::ClassMap::LookupClass::
+LookupPair::ParsePart(Buffer& table) {
+ if (!table.ReadU16(&this->glyphId)) {
+ return parent->Error("LookupPair: Failed to read glyphId");
+ }
+ if (!table.ReadU16(&this->index)) {
+ return parent->Error("LookupPair: Failed to read index");
+ }
+ return true;
+}
+
+bool OpenTypeSILF::SILSub::ClassMap::LookupClass::
+LookupPair::SerializePart(OTSStream* out) const {
+ if (!out->WriteU16(this->glyphId) ||
+ !out->WriteU16(this->index)) {
+ return parent->Error("LookupPair: Failed to write");
+ }
+ return true;
+}
+
+bool OpenTypeSILF::SILSub::
+SILPass::ParsePart(Buffer& table, const size_t SILSub_init_offset,
+ const size_t next_pass_offset) {
+ size_t init_offset = table.offset();
+ if (!table.ReadU8(&this->flags)) {
+ return parent->Error("SILPass: Failed to read flags");
+ // checks omitted
+ }
+ if (!table.ReadU8(&this->maxRuleLoop)) {
+ return parent->Error("SILPass: Failed to read valid maxRuleLoop");
+ }
+ if (!table.ReadU8(&this->maxRuleContext)) {
+ return parent->Error("SILPass: Failed to read maxRuleContext");
+ }
+ if (!table.ReadU8(&this->maxBackup)) {
+ return parent->Error("SILPass: Failed to read maxBackup");
+ }
+ if (!table.ReadU16(&this->numRules)) {
+ return parent->Error("SILPass: Failed to read numRules");
+ }
+ if (parent->version >> 16 >= 2) {
+ if (!table.ReadU16(&this->fsmOffset)) {
+ return parent->Error("SILPass: Failed to read fsmOffset");
+ }
+ if (parent->version >> 16 == 2 && this->fsmOffset != 0) {
+ parent->Warning("SILPass: Nonzero fsmOffset (reserved in SILSub v2)");
+ }
+ if (!table.ReadU32(&this->pcCode) ||
+ (parent->version >= 3 && this->pcCode < this->fsmOffset)) {
+ return parent->Error("SILPass: Failed to read pcCode");
+ }
+ }
+ if (!table.ReadU32(&this->rcCode) ||
+ (parent->version >> 16 >= 2 && this->rcCode < this->pcCode)) {
+ return parent->Error("SILPass: Failed to read valid rcCode");
+ }
+ if (!table.ReadU32(&this->aCode) || this->aCode < this->rcCode) {
+ return parent->Error("SILPass: Failed to read valid aCode");
+ }
+ if (!table.ReadU32(&this->oDebug) ||
+ (this->oDebug && this->oDebug < this->aCode)) {
+ return parent->Error("SILPass: Failed to read valid oDebug");
+ }
+ if (parent->version >> 16 >= 3 &&
+ table.offset() != init_offset + this->fsmOffset) {
+ return parent->Error("SILPass: fsmOffset check failed");
+ }
+ if (!table.ReadU16(&this->numRows) ||
+ (this->oDebug && this->numRows < this->numRules)) {
+ return parent->Error("SILPass: Failed to read valid numRows");
+ }
+ if (!table.ReadU16(&this->numTransitional)) {
+ return parent->Error("SILPass: Failed to read numTransitional");
+ }
+ if (!table.ReadU16(&this->numSuccess)) {
+ return parent->Error("SILPass: Failed to read numSuccess");
+ }
+ if (!table.ReadU16(&this->numColumns)) {
+ return parent->Error("SILPass: Failed to read numColumns");
+ }
+ if (!table.ReadU16(&this->numRange)) {
+ return parent->Error("SILPass: Failed to read numRange");
+ }
+ if (!table.ReadU16(&this->searchRange) || this->searchRange !=
+ (this->numRange == 0 ? 0 : // protect against log2(0)
+ (unsigned)std::pow(2, std::floor(std::log2(this->numRange))))) {
+ return parent->Error("SILPass: Failed to read valid searchRange");
+ }
+ if (!table.ReadU16(&this->entrySelector) || this->entrySelector !=
+ (this->numRange == 0 ? 0 : // protect against log2(0)
+ (unsigned)std::floor(std::log2(this->numRange)))) {
+ return parent->Error("SILPass: Failed to read valid entrySelector");
+ }
+ if (!table.ReadU16(&this->rangeShift) ||
+ this->rangeShift != this->numRange - this->searchRange) {
+ return parent->Error("SILPass: Failed to read valid rangeShift");
+ }
+
+ //this->ranges.resize(this->numRange, parent);
+ for (unsigned i = 0 ; i < this->numRange; ++i) {
+ this->ranges.emplace_back(parent);
+ if (!this->ranges[i].ParsePart(table)) {
+ return parent->Error("SILPass: Failed to read ranges[%u]", i);
+ }
+ }
+ unsigned ruleMap_len = 0; // maximum value in oRuleMap
+ //this->oRuleMap.resize(static_cast<unsigned long>(this->numSuccess) + 1);
+ for (unsigned long i = 0; i <= this->numSuccess; ++i) {
+ this->oRuleMap.emplace_back();
+ if (!table.ReadU16(&this->oRuleMap[i])) {
+ return parent->Error("SILPass: Failed to read oRuleMap[%u]", i);
+ }
+ if (oRuleMap[i] > ruleMap_len) {
+ ruleMap_len = oRuleMap[i];
+ }
+ }
+
+ //this->ruleMap.resize(ruleMap_len);
+ for (unsigned i = 0; i < ruleMap_len; ++i) {
+ this->ruleMap.emplace_back();
+ if (!table.ReadU16(&this->ruleMap[i])) {
+ return parent->Error("SILPass: Failed to read ruleMap[%u]", i);
+ }
+ }
+
+ if (!table.ReadU8(&this->minRulePreContext)) {
+ return parent->Error("SILPass: Failed to read minRulePreContext");
+ }
+ if (!table.ReadU8(&this->maxRulePreContext) ||
+ this->maxRulePreContext < this->minRulePreContext) {
+ return parent->Error("SILPass: Failed to read valid maxRulePreContext");
+ }
+
+ unsigned startStates_len = this->maxRulePreContext - this->minRulePreContext
+ + 1;
+ // this->minRulePreContext <= this->maxRulePreContext
+ //this->startStates.resize(startStates_len);
+ for (unsigned i = 0; i < startStates_len; ++i) {
+ this->startStates.emplace_back();
+ if (!table.ReadS16(&this->startStates[i])) {
+ return parent->Error("SILPass: Failed to read startStates[%u]", i);
+ }
+ }
+
+ //this->ruleSortKeys.resize(this->numRules);
+ for (unsigned i = 0; i < this->numRules; ++i) {
+ this->ruleSortKeys.emplace_back();
+ if (!table.ReadU16(&this->ruleSortKeys[i])) {
+ return parent->Error("SILPass: Failed to read ruleSortKeys[%u]", i);
+ }
+ }
+
+ //this->rulePreContext.resize(this->numRules);
+ for (unsigned i = 0; i < this->numRules; ++i) {
+ this->rulePreContext.emplace_back();
+ if (!table.ReadU8(&this->rulePreContext[i])) {
+ return parent->Error("SILPass: Failed to read rulePreContext[%u]", i);
+ }
+ }
+
+ if (parent->version >> 16 >= 2) {
+ if (!table.ReadU8(&this->collisionThreshold)) {
+ return parent->Error("SILPass: Failed to read collisionThreshold");
+ }
+ if (parent->version >> 16 < 5 && this->collisionThreshold != 0) {
+ parent->Warning("SILPass: Nonzero collisionThreshold"
+ " (reserved before v5)");
+ }
+ if (!table.ReadU16(&this->pConstraint)) {
+ return parent->Error("SILPass: Failed to read pConstraint");
+ }
+ }
+
+ unsigned long ruleConstraints_len = this->aCode - this->rcCode;
+ // this->rcCode <= this->aCode
+ //this->oConstraints.resize(static_cast<unsigned long>(this->numRules) + 1);
+ for (unsigned long i = 0; i <= this->numRules; ++i) {
+ this->oConstraints.emplace_back();
+ if (!table.ReadU16(&this->oConstraints[i]) ||
+ this->oConstraints[i] > ruleConstraints_len) {
+ return parent->Error("SILPass: Failed to read valid oConstraints[%lu]",
+ i);
+ }
+ }
+
+ if (!this->oDebug && this->aCode > next_pass_offset) {
+ return parent->Error("SILPass: Failed to calculate length of actions");
+ }
+ unsigned long actions_len = this->oDebug ? this->oDebug - this->aCode :
+ next_pass_offset - this->aCode;
+ // if this->oDebug, then this->aCode <= this->oDebug
+ //this->oActions.resize(static_cast<unsigned long>(this->numRules) + 1);
+ for (unsigned long i = 0; i <= this->numRules; ++i) {
+ this->oActions.emplace_back();
+ if (!table.ReadU16(&this->oActions[i]) ||
+ (this->oActions[i] > actions_len)) {
+ return parent->Error("SILPass: Failed to read valid oActions[%lu]", i);
+ }
+ }
+
+ //this->stateTrans.resize(this->numTransitional);
+ for (unsigned i = 0; i < this->numTransitional; ++i) {
+ this->stateTrans.emplace_back();
+ //this->stateTrans[i].resize(this->numColumns);
+ for (unsigned j = 0; j < this->numColumns; ++j) {
+ this->stateTrans[i].emplace_back();
+ if (!table.ReadU16(&stateTrans[i][j])) {
+ return parent->Error("SILPass: Failed to read stateTrans[%u][%u]",
+ i, j);
+ }
+ }
+ }
+
+ if (parent->version >> 16 >= 2) {
+ if (!table.ReadU8(&this->reserved2)) {
+ return parent->Error("SILPass: Failed to read reserved2");
+ }
+ if (this->reserved2 != 0) {
+ parent->Warning("SILPass: Nonzero reserved2");
+ }
+
+ if (table.offset() != SILSub_init_offset + this->pcCode) {
+ return parent->Error("SILPass: pcCode check failed");
+ }
+ //this->passConstraints.resize(this->pConstraint);
+ for (unsigned i = 0; i < this->pConstraint; ++i) {
+ this->passConstraints.emplace_back();
+ if (!table.ReadU8(&this->passConstraints[i])) {
+ return parent->Error("SILPass: Failed to read passConstraints[%u]", i);
+ }
+ }
+ }
+
+ if (table.offset() != SILSub_init_offset + this->rcCode) {
+ return parent->Error("SILPass: rcCode check failed");
+ }
+ //this->ruleConstraints.resize(ruleConstraints_len); // calculated above
+ for (unsigned long i = 0; i < ruleConstraints_len; ++i) {
+ this->ruleConstraints.emplace_back();
+ if (!table.ReadU8(&this->ruleConstraints[i])) {
+ return parent->Error("SILPass: Failed to read ruleConstraints[%u]", i);
+ }
+ }
+
+ if (table.offset() != SILSub_init_offset + this->aCode) {
+ return parent->Error("SILPass: aCode check failed");
+ }
+ //this->actions.resize(actions_len); // calculated above
+ for (unsigned long i = 0; i < actions_len; ++i) {
+ this->actions.emplace_back();
+ if (!table.ReadU8(&this->actions[i])) {
+ return parent->Error("SILPass: Failed to read actions[%u]", i);
+ }
+ }
+
+ if (this->oDebug) {
+ OpenTypeNAME* name = static_cast<OpenTypeNAME*>(
+ parent->GetFont()->GetTypedTable(OTS_TAG_NAME));
+ if (!name) {
+ return parent->Error("SILPass: Required name table is missing");
+ }
+
+ if (table.offset() != SILSub_init_offset + this->oDebug) {
+ return parent->Error("SILPass: oDebug check failed");
+ }
+ //this->dActions.resize(this->numRules);
+ for (unsigned i = 0; i < this->numRules; ++i) {
+ this->dActions.emplace_back();
+ if (!table.ReadU16(&this->dActions[i]) ||
+ !name->IsValidNameId(this->dActions[i])) {
+ return parent->Error("SILPass: Failed to read valid dActions[%u]", i);
+ }
+ }
+
+ unsigned dStates_len = this->numRows - this->numRules;
+ // this->numRules <= this->numRows
+ //this->dStates.resize(dStates_len);
+ for (unsigned i = 0; i < dStates_len; ++i) {
+ this->dStates.emplace_back();
+ if (!table.ReadU16(&this->dStates[i]) ||
+ !name->IsValidNameId(this->dStates[i])) {
+ return parent->Error("SILPass: Failed to read valid dStates[%u]", i);
+ }
+ }
+
+ //this->dCols.resize(this->numRules);
+ for (unsigned i = 0; i < this->numRules; ++i) {
+ this->dCols.emplace_back();
+ if (!table.ReadU16(&this->dCols[i]) ||
+ !name->IsValidNameId(this->dCols[i])) {
+ return parent->Error("SILPass: Failed to read valid dCols[%u]");
+ }
+ }
+ }
+ return true;
+}
+
+bool OpenTypeSILF::SILSub::
+SILPass::SerializePart(OTSStream* out) const {
+ if (!out->WriteU8(this->flags) ||
+ !out->WriteU8(this->maxRuleLoop) ||
+ !out->WriteU8(this->maxRuleContext) ||
+ !out->WriteU8(this->maxBackup) ||
+ !out->WriteU16(this->numRules) ||
+ (parent->version >> 16 >= 2 &&
+ (!out->WriteU16(this->fsmOffset) ||
+ !out->WriteU32(this->pcCode))) ||
+ !out->WriteU32(this->rcCode) ||
+ !out->WriteU32(this->aCode) ||
+ !out->WriteU32(this->oDebug) ||
+ !out->WriteU16(this->numRows) ||
+ !out->WriteU16(this->numTransitional) ||
+ !out->WriteU16(this->numSuccess) ||
+ !out->WriteU16(this->numColumns) ||
+ !out->WriteU16(this->numRange) ||
+ !out->WriteU16(this->searchRange) ||
+ !out->WriteU16(this->entrySelector) ||
+ !out->WriteU16(this->rangeShift) ||
+ !SerializeParts(this->ranges, out) ||
+ !SerializeParts(this->oRuleMap, out) ||
+ !SerializeParts(this->ruleMap, out) ||
+ !out->WriteU8(this->minRulePreContext) ||
+ !out->WriteU8(this->maxRulePreContext) ||
+ !SerializeParts(this->startStates, out) ||
+ !SerializeParts(this->ruleSortKeys, out) ||
+ !SerializeParts(this->rulePreContext, out) ||
+ (parent->version >> 16 >= 2 &&
+ (!out->WriteU8(this->collisionThreshold) ||
+ !out->WriteU16(this->pConstraint))) ||
+ !SerializeParts(this->oConstraints, out) ||
+ !SerializeParts(this->oActions, out) ||
+ !SerializeParts(this->stateTrans, out) ||
+ (parent->version >> 16 >= 2 &&
+ (!out->WriteU8(this->reserved2) ||
+ !SerializeParts(this->passConstraints, out))) ||
+ !SerializeParts(this->ruleConstraints, out) ||
+ !SerializeParts(this->actions, out) ||
+ !SerializeParts(this->dActions, out) ||
+ !SerializeParts(this->dStates, out) ||
+ !SerializeParts(this->dCols, out)) {
+ return parent->Error("SILPass: Failed to write");
+ }
+ return true;
+}
+
+bool OpenTypeSILF::SILSub::SILPass::
+PassRange::ParsePart(Buffer& table) {
+ if (!table.ReadU16(&this->firstId)) {
+ return parent->Error("PassRange: Failed to read firstId");
+ }
+ if (!table.ReadU16(&this->lastId)) {
+ return parent->Error("PassRange: Failed to read lastId");
+ }
+ if (!table.ReadU16(&this->colId)) {
+ return parent->Error("PassRange: Failed to read colId");
+ }
+ return true;
+}
+
+bool OpenTypeSILF::SILSub::SILPass::
+PassRange::SerializePart(OTSStream* out) const {
+ if (!out->WriteU16(this->firstId) ||
+ !out->WriteU16(this->lastId) ||
+ !out->WriteU16(this->colId)) {
+ return parent->Error("PassRange: Failed to write");
+ }
+ return true;
+}
+
+} // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/silf.h
@@ -0,0 +1,196 @@
+// Copyright (c) 2009-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.
+
+#ifndef OTS_SILF_H_
+#define OTS_SILF_H_
+
+#include <vector>
+
+#include "ots.h"
+#include "graphite.h"
+
+namespace ots {
+
+class OpenTypeSILF : public Table {
+ public:
+ explicit OpenTypeSILF(Font* font, uint32_t tag)
+ : Table(font, tag, tag) { }
+
+ bool Parse(const uint8_t* data, size_t length) {
+ return this->Parse(data, length, false);
+ }
+ bool Serialize(OTSStream* out);
+
+ private:
+ bool Parse(const uint8_t* data, size_t length, bool prevent_decompression);
+ struct SILSub : public TablePart<OpenTypeSILF> {
+ explicit SILSub(OpenTypeSILF* parent)
+ : TablePart<OpenTypeSILF>(parent), classes(parent) { }
+ bool ParsePart(Buffer& table);
+ bool SerializePart(OTSStream* out) const;
+ struct JustificationLevel : public TablePart<OpenTypeSILF> {
+ explicit JustificationLevel(OpenTypeSILF* parent)
+ : TablePart<OpenTypeSILF>(parent) { }
+ bool ParsePart(Buffer& table);
+ bool SerializePart(OTSStream* out) const;
+ uint8_t attrStretch;
+ uint8_t attrShrink;
+ uint8_t attrStep;
+ uint8_t attrWeight;
+ uint8_t runto;
+ uint8_t reserved;
+ uint8_t reserved2;
+ uint8_t reserved3;
+ };
+ struct PseudoMap : public TablePart<OpenTypeSILF> {
+ explicit PseudoMap(OpenTypeSILF* parent)
+ : TablePart<OpenTypeSILF>(parent) { }
+ bool ParsePart(Buffer& table);
+ bool SerializePart(OTSStream* out) const;
+ uint32_t unicode;
+ uint16_t nPseudo;
+ };
+ struct ClassMap : public TablePart<OpenTypeSILF> {
+ explicit ClassMap(OpenTypeSILF* parent)
+ : TablePart<OpenTypeSILF>(parent) { }
+ bool ParsePart(Buffer& table);
+ bool SerializePart(OTSStream* out) const;
+ struct LookupClass : public TablePart<OpenTypeSILF> {
+ explicit LookupClass(OpenTypeSILF* parent)
+ : TablePart<OpenTypeSILF>(parent) { }
+ bool ParsePart(Buffer& table);
+ bool SerializePart(OTSStream* out) const;
+ struct LookupPair : public TablePart<OpenTypeSILF> {
+ explicit LookupPair(OpenTypeSILF* parent)
+ : TablePart<OpenTypeSILF>(parent) { }
+ bool ParsePart(Buffer& table);
+ bool SerializePart(OTSStream* out) const;
+ uint16_t glyphId;
+ uint16_t index;
+ };
+ uint16_t numIDs;
+ uint16_t searchRange;
+ uint16_t entrySelector;
+ uint16_t rangeShift;
+ std::vector<LookupPair> lookups;
+ };
+ uint16_t numClass;
+ uint16_t numLinear;
+ std::vector<uint32_t> oClass; // uint16_t before v4
+ std::vector<uint16_t> glyphs;
+ std::vector<LookupClass> lookups;
+ };
+ struct SILPass : public TablePart<OpenTypeSILF> {
+ explicit SILPass(OpenTypeSILF* parent)
+ : TablePart<OpenTypeSILF>(parent) { }
+ bool ParsePart(Buffer& table) { return false; }
+ bool ParsePart(Buffer& table, const size_t SILSub_init_offset,
+ const size_t next_pass_offset);
+ bool SerializePart(OTSStream* out) const;
+ struct PassRange : public TablePart<OpenTypeSILF> {
+ explicit PassRange(OpenTypeSILF* parent)
+ : TablePart<OpenTypeSILF>(parent) { }
+ bool ParsePart(Buffer& table);
+ bool SerializePart(OTSStream* out) const;
+ uint16_t firstId;
+ uint16_t lastId;
+ uint16_t colId;
+ };
+ uint8_t flags;
+ uint8_t maxRuleLoop;
+ uint8_t maxRuleContext;
+ uint8_t maxBackup;
+ uint16_t numRules;
+ uint16_t fsmOffset;
+ uint32_t pcCode;
+ uint32_t rcCode;
+ uint32_t aCode;
+ uint32_t oDebug;
+ uint16_t numRows;
+ uint16_t numTransitional;
+ uint16_t numSuccess;
+ uint16_t numColumns;
+ uint16_t numRange;
+ uint16_t searchRange;
+ uint16_t entrySelector;
+ uint16_t rangeShift;
+ std::vector<PassRange> ranges;
+ std::vector<uint16_t> oRuleMap;
+ std::vector<uint16_t> ruleMap;
+ uint8_t minRulePreContext;
+ uint8_t maxRulePreContext;
+ std::vector<int16_t> startStates;
+ std::vector<uint16_t> ruleSortKeys;
+ std::vector<uint8_t> rulePreContext;
+ uint8_t collisionThreshold; // reserved before v5
+ uint16_t pConstraint;
+ std::vector<uint16_t> oConstraints;
+ std::vector<uint16_t> oActions;
+ std::vector<std::vector<uint16_t>> stateTrans;
+ uint8_t reserved2;
+ std::vector<uint8_t> passConstraints;
+ std::vector<uint8_t> ruleConstraints;
+ std::vector<uint8_t> actions;
+ std::vector<uint16_t> dActions;
+ std::vector<uint16_t> dStates;
+ std::vector<uint16_t> dCols;
+ };
+ uint32_t ruleVersion;
+ uint16_t passOffset;
+ uint16_t pseudosOffset;
+ uint16_t maxGlyphID;
+ int16_t extraAscent;
+ int16_t extraDescent;
+ uint8_t numPasses;
+ uint8_t iSubst;
+ uint8_t iPos;
+ uint8_t iJust;
+ uint8_t iBidi;
+ uint8_t flags;
+ uint8_t maxPreContext;
+ uint8_t maxPostContext;
+ uint8_t attrPseudo;
+ uint8_t attrBreakWeight;
+ uint8_t attrDirectionality;
+ uint8_t attrMirroring; // reserved before v4
+ uint8_t attrSkipPasses; // reserved2 before v4
+ uint8_t numJLevels;
+ std::vector<JustificationLevel> jLevels;
+ uint16_t numLigComp;
+ uint8_t numUserDefn;
+ uint8_t maxCompPerLig;
+ uint8_t direction;
+ uint8_t attCollisions; // reserved3 before v5
+ uint8_t reserved4;
+ uint8_t reserved5;
+ uint8_t reserved6;
+ uint8_t numCritFeatures;
+ std::vector<uint16_t> critFeatures;
+ uint8_t reserved7;
+ uint8_t numScriptTag;
+ std::vector<uint32_t> scriptTag;
+ uint16_t lbGID;
+ std::vector<uint32_t> oPasses;
+ uint16_t numPseudo;
+ uint16_t searchPseudo;
+ uint16_t pseudoSelector;
+ uint16_t pseudoShift;
+ std::vector<PseudoMap> pMaps;
+ ClassMap classes;
+ std::vector<SILPass> passes;
+ };
+ uint32_t version;
+ uint32_t compHead; // compression header
+ static const uint32_t SCHEME = 0xF8000000;
+ static const uint32_t FULL_SIZE = 0x07FFFFFF;
+ static const uint32_t COMPILER_VERSION = 0x07FFFFFF;
+ uint16_t numSub;
+ uint16_t reserved;
+ std::vector<uint32_t> offset;
+ std::vector<SILSub> tables;
+};
+
+} // namespace ots
+
+#endif // OTS_SILF_H_
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/sill.cc
@@ -0,0 +1,151 @@
+// Copyright (c) 2009-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.
+
+#include "sill.h"
+
+#include "feat.h"
+#include <cmath>
+#include <unordered_set>
+
+namespace ots {
+
+bool OpenTypeSILL::Parse(const uint8_t* data, size_t length) {
+ if (GetFont()->dropped_graphite) {
+ return Drop("Skipping Graphite table");
+ }
+ Buffer table(data, length);
+
+ if (!table.ReadU32(&this->version) || this->version >> 16 != 1) {
+ return Drop("Failed to read valid version");
+ }
+ if (!table.ReadU16(&this->numLangs)) {
+ return Drop("Failed to read numLangs");
+ }
+ if (!table.ReadU16(&this->searchRange) || this->searchRange !=
+ (this->numLangs == 0 ? 0 : // protect against log2(0)
+ (unsigned)std::pow(2, std::floor(std::log2(this->numLangs))))) {
+ return Drop("Failed to read valid searchRange");
+ }
+ if (!table.ReadU16(&this->entrySelector) || this->entrySelector !=
+ (this->numLangs == 0 ? 0 : // protect against log2(0)
+ (unsigned)std::floor(std::log2(this->numLangs)))) {
+ return Drop("Failed to read valid entrySelector");
+ }
+ if (!table.ReadU16(&this->rangeShift) ||
+ this->rangeShift != this->numLangs - this->searchRange) {
+ return Drop("Failed to read valid rangeShift");
+ }
+
+ std::unordered_set<size_t> unverified;
+ //this->entries.resize(static_cast<unsigned long>(this->numLangs) + 1, this);
+ for (unsigned long i = 0; i <= this->numLangs; ++i) {
+ this->entries.emplace_back(this);
+ LanguageEntry& entry = this->entries[i];
+ if (!entry.ParsePart(table)) {
+ return Drop("Failed to read entries[%u]", i);
+ }
+ for (unsigned j = 0; j < entry.numSettings; ++j) {
+ size_t offset = entry.offset + j * 8;
+ if (offset < entry.offset || offset > length) {
+ return DropGraphite("Invalid LangFeatureSetting offset %zu/%zu",
+ offset, length);
+ }
+ unverified.insert(offset);
+ // need to verify that this LanguageEntry points to valid
+ // LangFeatureSetting
+ }
+ }
+
+ while (table.remaining()) {
+ unverified.erase(table.offset());
+ LangFeatureSetting setting(this);
+ if (!setting.ParsePart(table)) {
+ return Drop("Failed to read a LangFeatureSetting");
+ }
+ settings.push_back(setting);
+ }
+
+ if (!unverified.empty()) {
+ return Drop("%zu incorrect offsets into settings", unverified.size());
+ }
+ if (table.remaining()) {
+ return Warning("%zu bytes unparsed", table.remaining());
+ }
+ return true;
+}
+
+bool OpenTypeSILL::Serialize(OTSStream* out) {
+ if (!out->WriteU32(this->version) ||
+ !out->WriteU16(this->numLangs) ||
+ !out->WriteU16(this->searchRange) ||
+ !out->WriteU16(this->entrySelector) ||
+ !out->WriteU16(this->rangeShift) ||
+ !SerializeParts(this->entries, out) ||
+ !SerializeParts(this->settings, out)) {
+ return Error("Failed to write table");
+ }
+ return true;
+}
+
+bool OpenTypeSILL::LanguageEntry::ParsePart(Buffer& table) {
+ if (!table.ReadU8(&this->langcode[0]) ||
+ !table.ReadU8(&this->langcode[1]) ||
+ !table.ReadU8(&this->langcode[2]) ||
+ !table.ReadU8(&this->langcode[3])) {
+ return parent->Error("LanguageEntry: Failed to read langcode");
+ }
+ if (!table.ReadU16(&this->numSettings)) {
+ return parent->Error("LanguageEntry: Failed to read numSettings");
+ }
+ if (!table.ReadU16(&this->offset)) {
+ return parent->Error("LanguageEntry: Failed to read offset");
+ }
+ return true;
+}
+
+bool OpenTypeSILL::LanguageEntry::SerializePart(OTSStream* out) const {
+ if (!out->WriteU8(this->langcode[0]) ||
+ !out->WriteU8(this->langcode[1]) ||
+ !out->WriteU8(this->langcode[2]) ||
+ !out->WriteU8(this->langcode[3]) ||
+ !out->WriteU16(this->numSettings) ||
+ !out->WriteU16(this->offset)) {
+ return parent->Error("LanguageEntry: Failed to write");
+ }
+ return true;
+}
+
+bool OpenTypeSILL::LangFeatureSetting::ParsePart(Buffer& table) {
+ OpenTypeFEAT* feat = static_cast<OpenTypeFEAT*>(
+ parent->GetFont()->GetTypedTable(OTS_TAG_FEAT));
+ if (!feat) {
+ return parent->Error("FeatureDefn: Required Feat table is missing");
+ }
+
+ if (!table.ReadU32(&this->featureId) ||
+ !feat->IsValidFeatureId(this->featureId)) {
+ return parent->Error("LangFeatureSetting: Failed to read valid featureId");
+ }
+ if (!table.ReadS16(&this->value)) {
+ return parent->Error("LangFeatureSetting: Failed to read value");
+ }
+ if (!table.ReadU16(&this->reserved)) {
+ return parent->Error("LangFeatureSetting: Failed to read reserved");
+ }
+ if (this->reserved != 0) {
+ parent->Warning("LangFeatureSetting: Nonzero reserved");
+ }
+ return true;
+}
+
+bool OpenTypeSILL::LangFeatureSetting::SerializePart(OTSStream* out) const {
+ if (!out->WriteU32(this->featureId) ||
+ !out->WriteS16(this->value) ||
+ !out->WriteU16(this->reserved)) {
+ return parent->Error("LangFeatureSetting: Failed to read reserved");
+ }
+ return true;
+}
+
+} // namespace ots
new file mode 100644
--- /dev/null
+++ b/gfx/ots/src/sill.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2009-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.
+
+#ifndef OTS_SILL_H_
+#define OTS_SILL_H_
+
+#include "ots.h"
+#include "graphite.h"
+
+#include <vector>
+
+namespace ots {
+
+class OpenTypeSILL : public Table {
+ public:
+ explicit OpenTypeSILL(Font* font, uint32_t tag)
+ : Table(font, tag, tag) { }
+
+ bool Parse(const uint8_t* data, size_t length);
+ bool Serialize(OTSStream* out);
+
+ private:
+ struct LanguageEntry : public TablePart<OpenTypeSILL> {
+ explicit LanguageEntry(OpenTypeSILL* parent)
+ : TablePart<OpenTypeSILL>(parent) { }
+ bool ParsePart(Buffer &table);
+ bool SerializePart(OTSStream* out) const;
+ uint8_t langcode[4];
+ uint16_t numSettings;
+ uint16_t offset;
+ };
+ struct LangFeatureSetting : public TablePart<OpenTypeSILL> {
+ explicit LangFeatureSetting(OpenTypeSILL* parent)
+ : TablePart<OpenTypeSILL>(parent) { }
+ bool ParsePart(Buffer &table);
+ bool SerializePart(OTSStream* out) const;
+ uint32_t featureId;
+ int16_t value;
+ uint16_t reserved;
+ };
+ uint32_t version;
+ uint16_t numLangs;
+ uint16_t searchRange;
+ uint16_t entrySelector;
+ uint16_t rangeShift;
+ std::vector<LanguageEntry> entries;
+ std::vector<LangFeatureSetting> settings;
+};
+
+} // namespace ots
+
+#endif // OTS_SILL_H_
--- a/gfx/ots/sync.sh
+++ b/gfx/ots/sync.sh
@@ -29,10 +29,10 @@ echo "Updating README.mozilla..."
REVISION=`cd $1; git log | head -1 | sed "s/commit //"`
VERSION=`cd $1; git describe | cut -d '-' -f 1 | sed 's/v//'`
sed -e "s/\(Current revision: \).*/\1$REVISION \($VERSION\)/" README.mozilla > README.tmp
mv README.tmp README.mozilla
echo "Applying ots-visibility.patch..."
patch -p3 < ots-visibility.patch
-echo "Applying ots-config.patch..."
-patch -p3 < ots-config.patch
+echo "Applying ots-lz4.patch..."
+patch -p3 < ots-lz4.patch
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -192,21 +192,16 @@ public:
(mKeepVariationTables &&
(aTag == TRUETYPE_TAG('a', 'v', 'a', 'r') ||
aTag == TRUETYPE_TAG('c', 'v', 'a', 'r') ||
aTag == TRUETYPE_TAG('f', 'v', 'a', 'r') ||
aTag == TRUETYPE_TAG('g', 'v', 'a', 'r') ||
aTag == TRUETYPE_TAG('H', 'V', 'A', 'R') ||
aTag == TRUETYPE_TAG('M', 'V', 'A', 'R') ||
aTag == TRUETYPE_TAG('V', 'V', 'A', 'R'))) ||
- aTag == TRUETYPE_TAG('S', 'i', 'l', 'f') ||
- aTag == TRUETYPE_TAG('S', 'i', 'l', 'l') ||
- aTag == TRUETYPE_TAG('G', 'l', 'o', 'c') ||
- aTag == TRUETYPE_TAG('G', 'l', 'a', 't') ||
- aTag == TRUETYPE_TAG('F', 'e', 'a', 't') ||
aTag == TRUETYPE_TAG('S', 'V', 'G', ' ') ||
aTag == TRUETYPE_TAG('C', 'O', 'L', 'R') ||
aTag == TRUETYPE_TAG('C', 'P', 'A', 'L')) {
return ots::TABLE_ACTION_PASSTHRU;
}
return ots::TABLE_ACTION_DEFAULT;
}