Bug 1369672 - Update OTS to support Graphite table sanitization. r=jfkthame

MozReview-Commit-ID: 4WU4nQcsQgt

--HG--
extra : rebase_source : 8a27c738aaccb5bd47bf057de181c4abe210ba93
This commit is contained in:
Kevin Hsieh 2017-08-11 16:36:12 -07:00
Родитель c1383cebf3
Коммит 572c3c94d2
25 изменённых файлов: 2785 добавлений и 66 удалений

Просмотреть файл

@ -2,11 +2,11 @@ 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

Просмотреть файл

@ -176,7 +176,7 @@ 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_SANITIZE, // Sanitize the table, potentially dropping it
TABLE_ACTION_PASSTHRU, // Serialize the table unchanged
TABLE_ACTION_DROP // Drop the table
};

Просмотреть файл

@ -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>

70
gfx/ots/ots-lz4.patch Normal file
Просмотреть файл

@ -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);
}

Просмотреть файл

@ -1,11 +1,7 @@
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_
@ -32,17 +28,7 @@ diff --git a/gfx/ots/include/opentype-sanitiser.h b/gfx/ots/include/opentype-san
#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
};
@ -51,8 +37,3 @@ diff --git a/gfx/ots/include/opentype-sanitiser.h b/gfx/ots/include/opentype-san
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.

193
gfx/ots/src/feat.cc Normal file
Просмотреть файл

@ -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

61
gfx/ots/src/feat.h Normal file
Просмотреть файл

@ -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_

447
gfx/ots/src/glat.cc Normal file
Просмотреть файл

@ -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

172
gfx/ots/src/glat.h Normal file
Просмотреть файл

@ -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_

108
gfx/ots/src/gloc.cc Normal file
Просмотреть файл

@ -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

36
gfx/ots/src/gloc.h Normal file
Просмотреть файл

@ -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_

95
gfx/ots/src/graphite.h Normal file
Просмотреть файл

@ -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_

Просмотреть файл

@ -10,17 +10,8 @@ EXPORTS += [
]
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 += [
@ -28,13 +19,23 @@ UNIFIED_SOURCES += [
'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',
@ -42,8 +43,13 @@ UNIFIED_SOURCES += [
'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.
@ -53,6 +59,7 @@ FINAL_LIBRARY = 'gkmedias'
DEFINES['PACKAGE_VERSION'] = '"moz"'
DEFINES['PACKAGE_BUGREPORT'] = '"http://bugzilla.mozilla.org/"'
DEFINES['OTS_GRAPHITE'] = 1
USE_LIBS += [
'brotli',

Просмотреть файл

@ -149,6 +149,7 @@ bool OpenTypeNAME::Parse(const uint8_t* data, size_t length) {
}
this->names.push_back(rec);
this->name_ids.insert(rec.name_id);
}
if (format == 1) {
@ -305,4 +306,50 @@ bool OpenTypeNAME::Serialize(OTSStream* out) {
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

Просмотреть файл

@ -9,6 +9,7 @@
#include <string>
#include <utility>
#include <vector>
#include <unordered_set>
#include "ots.h"
@ -50,10 +51,12 @@ class OpenTypeNAME : public Table {
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

Просмотреть файл

@ -47,6 +47,16 @@
#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 {
@ -124,6 +134,15 @@ const struct {
{ 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 },
};
@ -869,6 +888,15 @@ bool Font::ParseTable(const TableEntry& table_entry, const uint8_t* data,
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;
}
}
@ -910,6 +938,21 @@ Table* Font::GetTypedTable(uint32_t tag) const {
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;
}
@ -950,6 +993,16 @@ bool Table::Drop(const char *format, ...) {
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;

Просмотреть файл

@ -5,8 +5,9 @@
#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>
@ -188,9 +189,12 @@ 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')
@ -207,6 +211,9 @@ bool IsValidVersionTag(uint32_t tag);
#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')
@ -244,6 +251,7 @@ class Table {
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);
@ -277,7 +285,8 @@ struct Font {
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,
@ -289,6 +298,9 @@ struct Font {
// 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;
@ -296,6 +308,7 @@ struct Font {
uint16_t search_range;
uint16_t entry_selector;
uint16_t range_shift;
bool dropped_graphite;
private:
std::map<uint32_t, Table*> m_tables;

74
gfx/ots/src/sile.cc Normal file
Просмотреть файл

@ -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

36
gfx/ots/src/sile.h Normal file
Просмотреть файл

@ -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_

950
gfx/ots/src/silf.cc Normal file
Просмотреть файл

@ -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

196
gfx/ots/src/silf.h Normal file
Просмотреть файл

@ -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_

151
gfx/ots/src/sill.cc Normal file
Просмотреть файл

@ -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

53
gfx/ots/src/sill.h Normal file
Просмотреть файл

@ -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_

Просмотреть файл

@ -34,5 +34,5 @@ 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

Просмотреть файл

@ -197,11 +197,6 @@ public:
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')) {