Bug 1193050 - Update OTS to latest upstream version. r=jfkthame

This commit is contained in:
Frédéric Wang 2015-10-02 05:21:45 +02:00
parent dff0918eb8
commit 13da0bff4d
40 changed files with 1442 additions and 1269 deletions

View File

@ -2,7 +2,7 @@ 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: e779d45e7a96d3b97ed3d2b76db7478cb86fdd8b
Current revision: e8039a2b0f1a8ac1d2b21c088d1cbf0cd53cfe94
Upstream files included: LICENSE, src/, include/

View File

@ -49,6 +49,9 @@ typedef unsigned __int64 uint64_t;
#include <cstddef>
#include <cstring>
#define OTS_TAG(c1,c2,c3,c4) ((uint32_t)((((uint8_t)(c1))<<24)|(((uint8_t)(c2))<<16)|(((uint8_t)(c3))<<8)|((uint8_t)(c4))))
#define OTS_UNTAG(tag) ((uint8_t)((tag)>>24)), ((uint8_t)((tag)>>16)), ((uint8_t)((tag)>>8)), ((uint8_t)(tag))
namespace ots {
// -----------------------------------------------------------------------------
@ -57,9 +60,7 @@ namespace ots {
// -----------------------------------------------------------------------------
class OTSStream {
public:
OTSStream() {
ResetChecksum();
}
OTSStream() : chksum_(0) {}
virtual ~OTSStream() {}
@ -71,20 +72,15 @@ class OTSStream {
const size_t orig_length = length;
size_t offset = 0;
if (chksum_buffer_offset_) {
const size_t l =
std::min(length, static_cast<size_t>(4) - chksum_buffer_offset_);
std::memcpy(chksum_buffer_ + chksum_buffer_offset_, data, l);
chksum_buffer_offset_ += l;
offset += l;
length -= l;
}
if (chksum_buffer_offset_ == 4) {
uint32_t tmp;
std::memcpy(&tmp, chksum_buffer_, 4);
size_t chksum_offset = Tell() & 3;
if (chksum_offset) {
const size_t l = std::min(length, static_cast<size_t>(4) - chksum_offset);
uint32_t tmp = 0;
std::memcpy(reinterpret_cast<uint8_t *>(&tmp) + chksum_offset, data, l);
chksum_ += ntohl(tmp);
chksum_buffer_offset_ = 0;
length -= l;
offset += l;
}
while (length >= 4) {
@ -97,11 +93,11 @@ class OTSStream {
}
if (length) {
if (chksum_buffer_offset_ != 0) return false; // not reached
if (length > 4) return false; // not reached
std::memcpy(chksum_buffer_,
reinterpret_cast<const uint8_t*>(data) + offset, length);
chksum_buffer_offset_ = length;
uint32_t tmp = 0;
std::memcpy(&tmp,
reinterpret_cast<const uint8_t*>(data) + offset, length);
chksum_ += ntohl(tmp);
}
return WriteRaw(data, orig_length);
@ -113,7 +109,7 @@ class OTSStream {
virtual bool Pad(size_t bytes) {
static const uint32_t kZero = 0;
while (bytes >= 4) {
if (!WriteTag(kZero)) return false;
if (!Write(&kZero, 4)) return false;
bytes -= 4;
}
while (bytes) {
@ -157,46 +153,17 @@ class OTSStream {
return Write(&v, sizeof(v));
}
bool WriteTag(uint32_t v) {
return Write(&v, sizeof(v));
}
void ResetChecksum() {
assert((Tell() & 3) == 0);
chksum_ = 0;
chksum_buffer_offset_ = 0;
}
uint32_t chksum() const {
assert(chksum_buffer_offset_ == 0);
return chksum_;
}
struct ChecksumState {
uint32_t chksum;
uint8_t chksum_buffer[4];
unsigned chksum_buffer_offset;
};
ChecksumState SaveChecksumState() const {
ChecksumState s;
s.chksum = chksum_;
s.chksum_buffer_offset = chksum_buffer_offset_;
std::memcpy(s.chksum_buffer, chksum_buffer_, 4);
return s;
}
void RestoreChecksum(const ChecksumState &s) {
assert(chksum_buffer_offset_ == 0);
chksum_ += s.chksum;
chksum_buffer_offset_ = s.chksum_buffer_offset;
std::memcpy(chksum_buffer_, s.chksum_buffer, 4);
}
protected:
uint32_t chksum_;
uint8_t chksum_buffer_[4];
unsigned chksum_buffer_offset_;
};
#ifdef __GCC__
@ -223,7 +190,10 @@ class OTS_API OTSContext {
// partial output may have been written.
// input: the OpenType file
// length: the size, in bytes, of |input|
bool Process(OTSStream *output, const uint8_t *input, size_t length);
// index: if the input is a font collection and index is specified, then
// the corresponding font will be returned, otherwise the whole
// collection. Ignored for non-collection fonts.
bool Process(OTSStream *output, const uint8_t *input, size_t length, uint32_t index = -1);
// This function will be called when OTS is reporting an error.
// level: the severity of the generated message:
@ -233,8 +203,7 @@ class OTS_API OTSContext {
// This function will be called when OTS needs to decide what to do for a
// font table.
// tag: table tag as an integer in big-endian byte order, independent of
// platform endianness
// tag: table tag as a platform-native unsigned integer
virtual TableAction GetTableAction(uint32_t tag) { return ots::TABLE_ACTION_DEFAULT; }
};

View File

@ -375,11 +375,17 @@ bool ParsePrivateDictData(
operands.pop_back();
switch (op) {
// array
// hints
case 6: // BlueValues
case 7: // OtherBlues
case 8: // FamilyBlues
case 9: // FamilyOtherBlues
if (operands.empty() || (operands.size() % 2) != 0) {
return OTS_FAILURE();
}
break;
// array
case (12U << 8) + 12: // StemSnapH (delta)
case (12U << 8) + 13: // StemSnapV (delta)
if (operands.empty()) {
@ -898,14 +904,14 @@ bool ParseDictData(const uint8_t *data, size_t table_length,
namespace ots {
bool ots_cff_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
bool ots_cff_parse(Font *font, const uint8_t *data, size_t length) {
Buffer table(data, length);
file->cff = new OpenTypeCFF;
file->cff->data = data;
file->cff->length = length;
file->cff->font_dict_length = 0;
file->cff->local_subrs = NULL;
font->cff = new OpenTypeCFF;
font->cff->data = data;
font->cff->length = length;
font->cff->font_dict_length = 0;
font->cff->local_subrs = NULL;
// parse "6. Header" in the Adobe Compact Font Format Specification
uint8_t major = 0;
@ -943,7 +949,7 @@ bool ots_cff_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if (!ParseIndex(&table, &name_index)) {
return OTS_FAILURE();
}
if (!ParseNameData(&table, name_index, &(file->cff->name))) {
if (!ParseNameData(&table, name_index, &(font->cff->name))) {
return OTS_FAILURE();
}
@ -967,14 +973,14 @@ bool ots_cff_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return OTS_FAILURE();
}
const uint16_t num_glyphs = file->maxp->num_glyphs;
const uint16_t num_glyphs = font->maxp->num_glyphs;
const size_t sid_max = string_index.count + kNStdString;
// string_index.count == 0 is allowed.
// parse "9. Top DICT Data"
if (!ParseDictData(data, length, top_dict_index,
num_glyphs, sid_max,
DICT_DATA_TOPLEVEL, file->cff)) {
DICT_DATA_TOPLEVEL, font->cff)) {
return OTS_FAILURE();
}
@ -987,21 +993,21 @@ bool ots_cff_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
// Check if all fd_index in FDSelect are valid.
std::map<uint16_t, uint8_t>::const_iterator iter;
std::map<uint16_t, uint8_t>::const_iterator end = file->cff->fd_select.end();
for (iter = file->cff->fd_select.begin(); iter != end; ++iter) {
if (iter->second >= file->cff->font_dict_length) {
std::map<uint16_t, uint8_t>::const_iterator end = font->cff->fd_select.end();
for (iter = font->cff->fd_select.begin(); iter != end; ++iter) {
if (iter->second >= font->cff->font_dict_length) {
return OTS_FAILURE();
}
}
// Check if all charstrings (font hinting code for each glyph) are valid.
for (size_t i = 0; i < file->cff->char_strings_array.size(); ++i) {
if (!ValidateType2CharStringIndex(file,
*(file->cff->char_strings_array.at(i)),
for (size_t i = 0; i < font->cff->char_strings_array.size(); ++i) {
if (!ValidateType2CharStringIndex(font,
*(font->cff->char_strings_array.at(i)),
global_subrs_index,
file->cff->fd_select,
file->cff->local_subrs_per_font,
file->cff->local_subrs,
font->cff->fd_select,
font->cff->local_subrs_per_font,
font->cff->local_subrs,
&table)) {
return OTS_FAILURE_MSG("Failed validating charstring set %d", (int) i);
}
@ -1010,29 +1016,34 @@ bool ots_cff_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return true;
}
bool ots_cff_should_serialise(OpenTypeFile *file) {
return file->cff != NULL;
bool ots_cff_should_serialise(Font *font) {
return font->cff != NULL;
}
bool ots_cff_serialise(OTSStream *out, OpenTypeFile *file) {
bool ots_cff_serialise(OTSStream *out, Font *font) {
// TODO(yusukes): would be better to transcode the data,
// rather than simple memcpy.
if (!out->Write(file->cff->data, file->cff->length)) {
if (!out->Write(font->cff->data, font->cff->length)) {
return OTS_FAILURE();
}
return true;
}
void ots_cff_free(OpenTypeFile *file) {
if (file->cff) {
for (size_t i = 0; i < file->cff->char_strings_array.size(); ++i) {
delete (file->cff->char_strings_array)[i];
void ots_cff_reuse(Font *font, Font *other) {
font->cff = other->cff;
font->cff_reused = true;
}
void ots_cff_free(Font *font) {
if (font->cff) {
for (size_t i = 0; i < font->cff->char_strings_array.size(); ++i) {
delete (font->cff->char_strings_array)[i];
}
for (size_t i = 0; i < file->cff->local_subrs_per_font.size(); ++i) {
delete (file->cff->local_subrs_per_font)[i];
for (size_t i = 0; i < font->cff->local_subrs_per_font.size(); ++i) {
delete (font->cff->local_subrs_per_font)[i];
}
delete file->cff->local_subrs;
delete file->cff;
delete font->cff->local_subrs;
delete font->cff;
}
}

View File

@ -30,7 +30,7 @@ const size_t kMaxSubrNesting = 10;
// will fail with the dummy value.
const int32_t dummy_result = INT_MAX;
bool ExecuteType2CharString(ots::OpenTypeFile *file,
bool ExecuteType2CharString(ots::Font *font,
size_t call_depth,
const ots::CFFIndex& global_subrs_index,
const ots::CFFIndex& local_subrs_index,
@ -225,7 +225,7 @@ bool ReadNextNumberFromType2CharString(ots::Buffer *char_string,
// succeeds. If the |op| is kCallSubr or kCallGSubr, the function recursively
// calls ExecuteType2CharString() function. The arguments other than |op| and
// |argument_stack| are passed for that reason.
bool ExecuteType2CharStringOperator(ots::OpenTypeFile *file,
bool ExecuteType2CharStringOperator(ots::Font *font,
int32_t op,
size_t call_depth,
const ots::CFFIndex& global_subrs_index,
@ -290,7 +290,7 @@ bool ExecuteType2CharStringOperator(ots::OpenTypeFile *file,
}
ots::Buffer char_string_to_jump(cff_table->buffer() + offset, length);
return ExecuteType2CharString(file,
return ExecuteType2CharString(font,
call_depth + 1,
global_subrs_index,
local_subrs_index,
@ -729,7 +729,7 @@ bool ExecuteType2CharStringOperator(ots::OpenTypeFile *file,
// in_out_found_width: true is set if |char_string| contains 'width' byte (which
// is 0 or 1 byte.)
// in_out_num_stems: total number of hstems and vstems processed so far.
bool ExecuteType2CharString(ots::OpenTypeFile *file,
bool ExecuteType2CharString(ots::Font *font,
size_t call_depth,
const ots::CFFIndex& global_subrs_index,
const ots::CFFIndex& local_subrs_index,
@ -779,7 +779,7 @@ bool ExecuteType2CharString(ots::OpenTypeFile *file,
}
// An operator is found. Execute it.
if (!ExecuteType2CharStringOperator(file,
if (!ExecuteType2CharStringOperator(font,
operator_or_operand,
call_depth,
global_subrs_index,
@ -845,21 +845,19 @@ bool SelectLocalSubr(const std::map<uint16_t, uint8_t> &fd_select,
namespace ots {
bool ValidateType2CharStringIndex(
ots::OpenTypeFile *file,
ots::Font *font,
const CFFIndex& char_strings_index,
const CFFIndex& global_subrs_index,
const std::map<uint16_t, uint8_t> &fd_select,
const std::vector<CFFIndex *> &local_subrs_per_font,
const CFFIndex *local_subrs,
Buffer* cff_table) {
const uint16_t num_offsets =
static_cast<uint16_t>(char_strings_index.offsets.size());
if (num_offsets != char_strings_index.offsets.size() || num_offsets == 0) {
if (char_strings_index.offsets.size() == 0) {
return OTS_FAILURE(); // no charstring.
}
// For each glyph, validate the corresponding charstring.
for (uint16_t i = 1; i < num_offsets; ++i) {
for (unsigned i = 1; i < char_strings_index.offsets.size(); ++i) {
// Prepare a Buffer object, |char_string|, which contains the charstring
// for the |i|-th glyph.
const size_t length =
@ -875,7 +873,7 @@ bool ValidateType2CharStringIndex(
Buffer char_string(cff_table->buffer() + offset, length);
// Get a local subrs for the glyph.
const uint16_t glyph_index = i - 1; // index in the map is 0-origin.
const unsigned glyph_index = i - 1; // index in the map is 0-origin.
const CFFIndex *local_subrs_to_use = NULL;
if (!SelectLocalSubr(fd_select,
local_subrs_per_font,
@ -895,7 +893,7 @@ bool ValidateType2CharStringIndex(
bool found_endchar = false;
bool found_width = false;
size_t num_stems = 0;
if (!ExecuteType2CharString(file,
if (!ExecuteType2CharString(font,
0 /* initial call_depth is zero */,
global_subrs_index, *local_subrs_to_use,
cff_table, &char_string, &argument_stack,

View File

@ -35,7 +35,7 @@ namespace ots {
// cff_table: A buffer which contains actual byte code of charstring, global
// subroutines and local subroutines.
bool ValidateType2CharStringIndex(
OpenTypeFile *file,
Font *font,
const CFFIndex &char_strings_index,
const CFFIndex &global_subrs_index,
const std::map<uint16_t, uint8_t> &fd_select,

View File

@ -61,7 +61,7 @@ const uint32_t kIVSEnd = 0xE01EF;
const uint32_t kUVSUpperLimit = 0xFFFFFF;
// Parses Format 4 tables
bool ParseFormat4(ots::OpenTypeFile *file, int platform, int encoding,
bool ParseFormat4(ots::Font *font, int platform, int encoding,
const uint8_t *data, size_t length, uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
@ -69,7 +69,7 @@ bool ParseFormat4(ots::OpenTypeFile *file, int platform, int encoding,
// whole thing and recompacting it, we validate it and include it verbatim
// in the output.
if (!file->os2) {
if (!font->os2) {
return OTS_FAILURE_MSG("Required OS/2 table missing");
}
@ -195,15 +195,15 @@ bool ParseFormat4(ots::OpenTypeFile *file, int platform, int encoding,
// On many fonts, the value of {first, last}_char_index are incorrect.
// Fix them.
if (file->os2->first_char_index != 0xFFFF &&
if (font->os2->first_char_index != 0xFFFF &&
ranges[i].start_range != 0xFFFF &&
file->os2->first_char_index > ranges[i].start_range) {
file->os2->first_char_index = ranges[i].start_range;
font->os2->first_char_index > ranges[i].start_range) {
font->os2->first_char_index = ranges[i].start_range;
}
if (file->os2->last_char_index != 0xFFFF &&
if (font->os2->last_char_index != 0xFFFF &&
ranges[i].end_range != 0xFFFF &&
file->os2->last_char_index < ranges[i].end_range) {
file->os2->last_char_index = ranges[i].end_range;
font->os2->last_char_index < ranges[i].end_range) {
font->os2->last_char_index = ranges[i].end_range;
}
}
@ -249,14 +249,14 @@ bool ParseFormat4(ots::OpenTypeFile *file, int platform, int encoding,
// We accept the table.
// TODO(yusukes): transcode the subtable.
if (platform == 3 && encoding == 0) {
file->cmap->subtable_3_0_4_data = data;
file->cmap->subtable_3_0_4_length = length;
font->cmap->subtable_3_0_4_data = data;
font->cmap->subtable_3_0_4_length = length;
} else if (platform == 3 && encoding == 1) {
file->cmap->subtable_3_1_4_data = data;
file->cmap->subtable_3_1_4_length = length;
font->cmap->subtable_3_1_4_data = data;
font->cmap->subtable_3_1_4_length = length;
} else if (platform == 0 && encoding == 3) {
file->cmap->subtable_0_3_4_data = data;
file->cmap->subtable_0_3_4_length = length;
font->cmap->subtable_0_3_4_data = data;
font->cmap->subtable_0_3_4_length = length;
} else {
return OTS_FAILURE_MSG("Unknown cmap subtable type (platform=%d, encoding=%d)", platform, encoding);
}
@ -264,7 +264,7 @@ bool ParseFormat4(ots::OpenTypeFile *file, int platform, int encoding,
return true;
}
bool Parse31012(ots::OpenTypeFile *file,
bool Parse31012(ots::Font *font,
const uint8_t *data, size_t length, uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
@ -287,11 +287,11 @@ bool Parse31012(ots::OpenTypeFile *file,
return OTS_FAILURE_MSG("can't read number of format 12 subtable groups");
}
if (num_groups == 0 || num_groups > kMaxCMAPGroups) {
return OTS_FAILURE_MSG("bad format 12 subtable group count %d", num_groups);
return OTS_FAILURE_MSG("Bad format 12 subtable group count %d", num_groups);
}
std::vector<ots::OpenTypeCMAPSubtableRange> &groups
= file->cmap->subtable_3_10_12;
= font->cmap->subtable_3_10_12;
groups.resize(num_groups);
for (unsigned i = 0; i < num_groups; ++i) {
@ -350,7 +350,7 @@ bool Parse31012(ots::OpenTypeFile *file,
return true;
}
bool Parse31013(ots::OpenTypeFile *file,
bool Parse31013(ots::Font *font,
const uint8_t *data, size_t length, uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
@ -376,11 +376,11 @@ bool Parse31013(ots::OpenTypeFile *file,
// We limit the number of groups in the same way as in 3.10.12 tables. See
// the comment there in
if (num_groups == 0 || num_groups > kMaxCMAPGroups) {
return OTS_FAILURE_MSG("Bad number of groups (%d) in a cmap subtable", num_groups);
return OTS_FAILURE_MSG("Bad format 13 subtable group count %d", num_groups);
}
std::vector<ots::OpenTypeCMAPSubtableRange> &groups
= file->cmap->subtable_3_10_13;
= font->cmap->subtable_3_10_13;
groups.resize(num_groups);
for (unsigned i = 0; i < num_groups; ++i) {
@ -416,7 +416,7 @@ bool Parse31013(ots::OpenTypeFile *file,
return true;
}
bool Parse0514(ots::OpenTypeFile *file,
bool Parse0514(ots::Font *font,
const uint8_t *data, size_t length, uint16_t num_glyphs) {
// Unicode Variation Selector table
ots::Buffer subtable(data, length);
@ -434,11 +434,11 @@ bool Parse0514(ots::OpenTypeFile *file,
return OTS_FAILURE_MSG("Can't read number of records in cmap subtable");
}
if (num_records == 0 || num_records > kMaxCMAPSelectorRecords) {
return OTS_FAILURE_MSG("Bad number of records (%d) in cmap subtable", num_records);
return OTS_FAILURE_MSG("Bad format 14 subtable records count %d", num_records);
}
std::vector<ots::OpenTypeCMAPSubtableVSRecord>& records
= file->cmap->subtable_0_5_14;
= font->cmap->subtable_0_5_14;
records.resize(num_records);
for (unsigned i = 0; i < num_records; ++i) {
@ -483,8 +483,8 @@ bool Parse0514(ots::OpenTypeFile *file,
if (!subtable.ReadU32(&num_ranges)) {
return OTS_FAILURE_MSG("Can't read number of ranges in record %d", i);
}
if (!num_ranges || num_ranges > kMaxCMAPGroups) {
return OTS_FAILURE_MSG("number of ranges too high (%d > %d) in record %d", num_ranges, kMaxCMAPGroups, i);
if (num_ranges == 0 || num_ranges > kMaxCMAPGroups) {
return OTS_FAILURE_MSG("Bad number of ranges (%d) in record %d", num_ranges, i);
}
uint32_t last_unicode_value = 0;
@ -517,8 +517,8 @@ bool Parse0514(ots::OpenTypeFile *file,
if (!subtable.ReadU32(&num_mappings)) {
return OTS_FAILURE_MSG("Can't read number of mappings in variation selector record %d", i);
}
if (!num_mappings || num_mappings > kMaxCMAPGroups) {
return OTS_FAILURE_MSG("Number of mappings too high (%d) in variation selector record %d", num_mappings, i);
if (num_mappings == 0) {
return OTS_FAILURE_MSG("Bad number of mappings (%d) in variation selector record %d", num_mappings, i);
}
uint32_t last_unicode_value = 0;
@ -546,11 +546,11 @@ bool Parse0514(ots::OpenTypeFile *file,
if (subtable.offset() != length) {
return OTS_FAILURE_MSG("Bad subtable offset (%ld != %ld)", subtable.offset(), length);
}
file->cmap->subtable_0_5_14_length = subtable.offset();
font->cmap->subtable_0_5_14_length = subtable.offset();
return true;
}
bool Parse100(ots::OpenTypeFile *file, const uint8_t *data, size_t length) {
bool Parse100(ots::Font *font, const uint8_t *data, size_t length) {
// Mac Roman table
ots::Buffer subtable(data, length);
@ -566,13 +566,13 @@ bool Parse100(ots::OpenTypeFile *file, const uint8_t *data, size_t length) {
OTS_WARNING("language id should be zero: %u", language);
}
file->cmap->subtable_1_0_0.reserve(kFormat0ArraySize);
font->cmap->subtable_1_0_0.reserve(kFormat0ArraySize);
for (size_t i = 0; i < kFormat0ArraySize; ++i) {
uint8_t glyph_id = 0;
if (!subtable.ReadU8(&glyph_id)) {
return OTS_FAILURE_MSG("Can't read glyph id at array[%ld] in cmap subtable", i);
}
file->cmap->subtable_1_0_0.push_back(glyph_id);
font->cmap->subtable_1_0_0.push_back(glyph_id);
}
return true;
@ -582,9 +582,9 @@ bool Parse100(ots::OpenTypeFile *file, const uint8_t *data, size_t length) {
namespace ots {
bool ots_cmap_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
bool ots_cmap_parse(Font *font, const uint8_t *data, size_t length) {
Buffer table(data, length);
file->cmap = new OpenTypeCMAP;
font->cmap = new OpenTypeCMAP;
uint16_t version = 0;
uint16_t num_tables = 0;
@ -738,10 +738,10 @@ bool ots_cmap_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
// we grab the number of glyphs in the file from the maxp table to make sure
// that the character map isn't referencing anything beyound this range.
if (!file->maxp) {
if (!font->maxp) {
return OTS_FAILURE_MSG("No maxp table in font! Needed by cmap.");
}
const uint16_t num_glyphs = file->maxp->num_glyphs;
const uint16_t num_glyphs = font->maxp->num_glyphs;
// We only support a subset of the possible character map tables. Microsoft
// 'strongly recommends' that everyone supports the Unicode BMP table with
@ -778,27 +778,27 @@ bool ots_cmap_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
// table actually points to MS symbol data and thus should be parsed as
// 3-0-4 table (e.g., marqueem.ttf and quixotic.ttf). This error will be
// recovered in ots_cmap_serialise().
if (!ParseFormat4(file, 3, 1, data + subtable_headers[i].offset,
if (!ParseFormat4(font, 3, 1, data + subtable_headers[i].offset,
subtable_headers[i].length, num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse format 4 cmap subtable %d", i);
}
} else if ((subtable_headers[i].encoding == 3) &&
(subtable_headers[i].format == 4)) {
// parse and output the 0-3-4 table as 0-3-4 table.
if (!ParseFormat4(file, 0, 3, data + subtable_headers[i].offset,
if (!ParseFormat4(font, 0, 3, data + subtable_headers[i].offset,
subtable_headers[i].length, num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse format 4 cmap subtable %d", i);
}
} else if ((subtable_headers[i].encoding == 3) &&
(subtable_headers[i].format == 12)) {
// parse and output the 0-3-12 table as 3-10-12 table.
if (!Parse31012(file, data + subtable_headers[i].offset,
if (!Parse31012(font, data + subtable_headers[i].offset,
subtable_headers[i].length, num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse format 12 cmap subtable %d", i);
}
} else if ((subtable_headers[i].encoding == 5) &&
(subtable_headers[i].format == 14)) {
if (!Parse0514(file, data + subtable_headers[i].offset,
if (!Parse0514(font, data + subtable_headers[i].offset,
subtable_headers[i].length, num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse format 14 cmap subtable %d", i);
}
@ -809,7 +809,7 @@ bool ots_cmap_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if ((subtable_headers[i].encoding == 0) &&
(subtable_headers[i].format == 0)) {
// parse and output the 1-0-0 table.
if (!Parse100(file, data + subtable_headers[i].offset,
if (!Parse100(font, data + subtable_headers[i].offset,
subtable_headers[i].length)) {
return OTS_FAILURE();
}
@ -822,7 +822,7 @@ bool ots_cmap_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
case 1:
if (subtable_headers[i].format == 4) {
// parse 3-0-4 or 3-1-4 table.
if (!ParseFormat4(file, subtable_headers[i].platform,
if (!ParseFormat4(font, subtable_headers[i].platform,
subtable_headers[i].encoding,
data + subtable_headers[i].offset,
subtable_headers[i].length, num_glyphs)) {
@ -832,14 +832,14 @@ bool ots_cmap_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
break;
case 10:
if (subtable_headers[i].format == 12) {
file->cmap->subtable_3_10_12.clear();
if (!Parse31012(file, data + subtable_headers[i].offset,
font->cmap->subtable_3_10_12.clear();
if (!Parse31012(font, data + subtable_headers[i].offset,
subtable_headers[i].length, num_glyphs)) {
return OTS_FAILURE();
}
} else if (subtable_headers[i].format == 13) {
file->cmap->subtable_3_10_13.clear();
if (!Parse31013(file, data + subtable_headers[i].offset,
font->cmap->subtable_3_10_13.clear();
if (!Parse31013(font, data + subtable_headers[i].offset,
subtable_headers[i].length, num_glyphs)) {
return OTS_FAILURE();
}
@ -852,20 +852,20 @@ bool ots_cmap_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return true;
}
bool ots_cmap_should_serialise(OpenTypeFile *file) {
return file->cmap != NULL;
bool ots_cmap_should_serialise(Font *font) {
return font->cmap != NULL;
}
bool ots_cmap_serialise(OTSStream *out, OpenTypeFile *file) {
const bool have_034 = file->cmap->subtable_0_3_4_data != NULL;
const bool have_0514 = file->cmap->subtable_0_5_14.size() != 0;
const bool have_100 = file->cmap->subtable_1_0_0.size() != 0;
const bool have_304 = file->cmap->subtable_3_0_4_data != NULL;
bool ots_cmap_serialise(OTSStream *out, Font *font) {
const bool have_034 = font->cmap->subtable_0_3_4_data != NULL;
const bool have_0514 = font->cmap->subtable_0_5_14.size() != 0;
const bool have_100 = font->cmap->subtable_1_0_0.size() != 0;
const bool have_304 = font->cmap->subtable_3_0_4_data != NULL;
// MS Symbol and MS Unicode tables should not co-exist.
// See the comment above in 0-0-4 parser.
const bool have_314 = (!have_304) && file->cmap->subtable_3_1_4_data;
const bool have_31012 = file->cmap->subtable_3_10_12.size() != 0;
const bool have_31013 = file->cmap->subtable_3_10_13.size() != 0;
const bool have_314 = (!have_304) && font->cmap->subtable_3_1_4_data;
const bool have_31012 = font->cmap->subtable_3_10_12.size() != 0;
const bool have_31013 = font->cmap->subtable_3_10_13.size() != 0;
const uint16_t num_subtables = static_cast<uint16_t>(have_034) +
static_cast<uint16_t>(have_0514) +
static_cast<uint16_t>(have_100) +
@ -893,8 +893,8 @@ bool ots_cmap_serialise(OTSStream *out, OpenTypeFile *file) {
const off_t offset_034 = out->Tell();
if (have_034) {
if (!out->Write(file->cmap->subtable_0_3_4_data,
file->cmap->subtable_0_3_4_length)) {
if (!out->Write(font->cmap->subtable_0_3_4_data,
font->cmap->subtable_0_3_4_length)) {
return OTS_FAILURE();
}
}
@ -902,10 +902,10 @@ bool ots_cmap_serialise(OTSStream *out, OpenTypeFile *file) {
const off_t offset_0514 = out->Tell();
if (have_0514) {
const std::vector<ots::OpenTypeCMAPSubtableVSRecord> &records
= file->cmap->subtable_0_5_14;
= font->cmap->subtable_0_5_14;
const unsigned num_records = records.size();
if (!out->WriteU16(14) ||
!out->WriteU32(file->cmap->subtable_0_5_14_length) ||
!out->WriteU32(font->cmap->subtable_0_5_14_length) ||
!out->WriteU32(num_records)) {
return OTS_FAILURE();
}
@ -957,23 +957,23 @@ bool ots_cmap_serialise(OTSStream *out, OpenTypeFile *file) {
!out->WriteU16(0)) { // language
return OTS_FAILURE();
}
if (!out->Write(&(file->cmap->subtable_1_0_0[0]), kFormat0ArraySize)) {
if (!out->Write(&(font->cmap->subtable_1_0_0[0]), kFormat0ArraySize)) {
return OTS_FAILURE();
}
}
const off_t offset_304 = out->Tell();
if (have_304) {
if (!out->Write(file->cmap->subtable_3_0_4_data,
file->cmap->subtable_3_0_4_length)) {
if (!out->Write(font->cmap->subtable_3_0_4_data,
font->cmap->subtable_3_0_4_length)) {
return OTS_FAILURE();
}
}
const off_t offset_314 = out->Tell();
if (have_314) {
if (!out->Write(file->cmap->subtable_3_1_4_data,
file->cmap->subtable_3_1_4_length)) {
if (!out->Write(font->cmap->subtable_3_1_4_data,
font->cmap->subtable_3_1_4_length)) {
return OTS_FAILURE();
}
}
@ -981,7 +981,7 @@ bool ots_cmap_serialise(OTSStream *out, OpenTypeFile *file) {
const off_t offset_31012 = out->Tell();
if (have_31012) {
std::vector<OpenTypeCMAPSubtableRange> &groups
= file->cmap->subtable_3_10_12;
= font->cmap->subtable_3_10_12;
const unsigned num_groups = groups.size();
if (!out->WriteU16(12) ||
!out->WriteU16(0) ||
@ -1003,7 +1003,7 @@ bool ots_cmap_serialise(OTSStream *out, OpenTypeFile *file) {
const off_t offset_31013 = out->Tell();
if (have_31013) {
std::vector<OpenTypeCMAPSubtableRange> &groups
= file->cmap->subtable_3_10_13;
= font->cmap->subtable_3_10_13;
const unsigned num_groups = groups.size();
if (!out->WriteU16(13) ||
!out->WriteU16(0) ||
@ -1023,10 +1023,6 @@ bool ots_cmap_serialise(OTSStream *out, OpenTypeFile *file) {
}
const off_t table_end = out->Tell();
// We might have hanging bytes from the above's checksum which the OTSStream
// then merges into the table of offsets.
OTSStream::ChecksumState saved_checksum = out->SaveChecksumState();
out->ResetChecksum();
// Now seek back and write the table of offsets
if (!out->Seek(record_offset)) {
@ -1092,13 +1088,17 @@ bool ots_cmap_serialise(OTSStream *out, OpenTypeFile *file) {
if (!out->Seek(table_end)) {
return OTS_FAILURE();
}
out->RestoreChecksum(saved_checksum);
return true;
}
void ots_cmap_free(OpenTypeFile *file) {
delete file->cmap;
void ots_cmap_reuse(Font *font, Font *other) {
font->cmap = other->cmap;
font->cmap_reused = true;
}
void ots_cmap_free(Font *font) {
delete font->cmap;
}
} // namespace ots

View File

@ -11,11 +11,11 @@
namespace ots {
bool ots_cvt_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
bool ots_cvt_parse(Font *font, const uint8_t *data, size_t length) {
Buffer table(data, length);
OpenTypeCVT *cvt = new OpenTypeCVT;
file->cvt = cvt;
font->cvt = cvt;
if (length >= 128 * 1024u) {
return OTS_FAILURE_MSG("Length (%d) > 120K"); // almost all cvt tables are less than 4k bytes.
@ -34,15 +34,15 @@ bool ots_cvt_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return true;
}
bool ots_cvt_should_serialise(OpenTypeFile *file) {
if (!file->glyf) {
bool ots_cvt_should_serialise(Font *font) {
if (!font->glyf) {
return false; // this table is not for CFF fonts.
}
return file->cvt != NULL;
return font->cvt != NULL;
}
bool ots_cvt_serialise(OTSStream *out, OpenTypeFile *file) {
const OpenTypeCVT *cvt = file->cvt;
bool ots_cvt_serialise(OTSStream *out, Font *font) {
const OpenTypeCVT *cvt = font->cvt;
if (!out->Write(cvt->data, cvt->length)) {
return OTS_FAILURE_MSG("Failed to write CVT table");
@ -51,8 +51,13 @@ bool ots_cvt_serialise(OTSStream *out, OpenTypeFile *file) {
return true;
}
void ots_cvt_free(OpenTypeFile *file) {
delete file->cvt;
void ots_cvt_reuse(Font *font, Font *other) {
font->cvt = other->cvt;
font->cvt_reused = true;
}
void ots_cvt_free(Font *font) {
delete font->cvt;
}
} // namespace ots

View File

@ -11,11 +11,11 @@
namespace ots {
bool ots_fpgm_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
bool ots_fpgm_parse(Font *font, const uint8_t *data, size_t length) {
Buffer table(data, length);
OpenTypeFPGM *fpgm = new OpenTypeFPGM;
file->fpgm = fpgm;
font->fpgm = fpgm;
if (length >= 128 * 1024u) {
return OTS_FAILURE_MSG("length (%ld) > 120", length); // almost all fpgm tables are less than 5k bytes.
@ -30,13 +30,13 @@ bool ots_fpgm_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return true;
}
bool ots_fpgm_should_serialise(OpenTypeFile *file) {
if (!file->glyf) return false; // this table is not for CFF fonts.
return file->fpgm != NULL;
bool ots_fpgm_should_serialise(Font *font) {
if (!font->glyf) return false; // this table is not for CFF fonts.
return font->fpgm != NULL;
}
bool ots_fpgm_serialise(OTSStream *out, OpenTypeFile *file) {
const OpenTypeFPGM *fpgm = file->fpgm;
bool ots_fpgm_serialise(OTSStream *out, Font *font) {
const OpenTypeFPGM *fpgm = font->fpgm;
if (!out->Write(fpgm->data, fpgm->length)) {
return OTS_FAILURE_MSG("Failed to write fpgm");
@ -45,8 +45,13 @@ bool ots_fpgm_serialise(OTSStream *out, OpenTypeFile *file) {
return true;
}
void ots_fpgm_free(OpenTypeFile *file) {
delete file->fpgm;
void ots_fpgm_reuse(Font *font, Font *other) {
font->fpgm = other->fpgm;
font->fpgm_reused = true;
}
void ots_fpgm_free(Font *font) {
delete font->fpgm;
}
} // namespace ots

View File

@ -11,19 +11,19 @@
#define DROP_THIS_TABLE(...) \
do { \
OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
OTS_FAILURE_MSG_(font->file, TABLE_NAME ": " __VA_ARGS__); \
OTS_FAILURE_MSG("Table discarded"); \
delete file->gasp; \
file->gasp = 0; \
delete font->gasp; \
font->gasp = 0; \
} while (0)
namespace ots {
bool ots_gasp_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
bool ots_gasp_parse(Font *font, const uint8_t *data, size_t length) {
Buffer table(data, length);
OpenTypeGASP *gasp = new OpenTypeGASP;
file->gasp = gasp;
font->gasp = gasp;
uint16_t num_ranges = 0;
if (!table.ReadU16(&gasp->version) ||
@ -80,12 +80,12 @@ bool ots_gasp_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return true;
}
bool ots_gasp_should_serialise(OpenTypeFile *file) {
return file->gasp != NULL;
bool ots_gasp_should_serialise(Font *font) {
return font->gasp != NULL;
}
bool ots_gasp_serialise(OTSStream *out, OpenTypeFile *file) {
const OpenTypeGASP *gasp = file->gasp;
bool ots_gasp_serialise(OTSStream *out, Font *font) {
const OpenTypeGASP *gasp = font->gasp;
const uint16_t num_ranges = static_cast<uint16_t>(gasp->gasp_ranges.size());
if (num_ranges != gasp->gasp_ranges.size() ||
@ -104,8 +104,13 @@ bool ots_gasp_serialise(OTSStream *out, OpenTypeFile *file) {
return true;
}
void ots_gasp_free(OpenTypeFile *file) {
delete file->gasp;
void ots_gasp_reuse(Font *font, Font *other) {
font->gasp = other->gasp;
font->gasp_reused = true;
}
void ots_gasp_free(Font *font) {
delete font->gasp;
}
} // namespace ots

View File

@ -28,13 +28,13 @@ const uint16_t kMaxGlyphClassDefValue = 4;
// ParseLigCaretListTable() for the reason.
const uint16_t kMaxCaretValueFormat = 2;
bool ParseGlyphClassDefTable(ots::OpenTypeFile *file, const uint8_t *data,
bool ParseGlyphClassDefTable(ots::Font *font, const uint8_t *data,
size_t length, const uint16_t num_glyphs) {
return ots::ParseClassDefTable(file, data, length, num_glyphs,
return ots::ParseClassDefTable(font, data, length, num_glyphs,
kMaxGlyphClassDefValue);
}
bool ParseAttachListTable(ots::OpenTypeFile *file, const uint8_t *data,
bool ParseAttachListTable(ots::Font *font, const uint8_t *data,
size_t length, const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
@ -70,7 +70,7 @@ bool ParseAttachListTable(ots::OpenTypeFile *file, const uint8_t *data,
}
// Parse coverage table
if (!ots::ParseCoverageTable(file, data + offset_coverage,
if (!ots::ParseCoverageTable(font, data + offset_coverage,
length - offset_coverage, num_glyphs)) {
return OTS_FAILURE_MSG("Bad coverage table");
}
@ -102,7 +102,7 @@ bool ParseAttachListTable(ots::OpenTypeFile *file, const uint8_t *data,
return true;
}
bool ParseLigCaretListTable(ots::OpenTypeFile *file, const uint8_t *data,
bool ParseLigCaretListTable(ots::Font *font, const uint8_t *data,
size_t length, const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
uint16_t offset_coverage = 0;
@ -136,7 +136,7 @@ bool ParseLigCaretListTable(ots::OpenTypeFile *file, const uint8_t *data,
}
// Parse coverage table
if (!ots::ParseCoverageTable(file, data + offset_coverage,
if (!ots::ParseCoverageTable(font, data + offset_coverage,
length - offset_coverage, num_glyphs)) {
return OTS_FAILURE_MSG("Can't parse caret coverage table");
}
@ -187,12 +187,12 @@ bool ParseLigCaretListTable(ots::OpenTypeFile *file, const uint8_t *data,
return true;
}
bool ParseMarkAttachClassDefTable(ots::OpenTypeFile *file, const uint8_t *data,
bool ParseMarkAttachClassDefTable(ots::Font *font, const uint8_t *data,
size_t length, const uint16_t num_glyphs) {
return ots::ParseClassDefTable(file, data, length, num_glyphs, kMaxClassDefValue);
return ots::ParseClassDefTable(font, data, length, num_glyphs, kMaxClassDefValue);
}
bool ParseMarkGlyphSetsDefTable(ots::OpenTypeFile *file, const uint8_t *data,
bool ParseMarkGlyphSetsDefTable(ots::Font *font, const uint8_t *data,
size_t length, const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
uint16_t format = 0;
@ -218,47 +218,38 @@ bool ParseMarkGlyphSetsDefTable(ots::OpenTypeFile *file, const uint8_t *data,
offset_coverage < mark_sets_end) {
return OTS_FAILURE_MSG("Bad coverage location %d for mark set %d", offset_coverage, i);
}
if (!ots::ParseCoverageTable(file, data + offset_coverage,
if (!ots::ParseCoverageTable(font, data + offset_coverage,
length - offset_coverage, num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse coverage table for mark set %d", i);
}
}
file->gdef->num_mark_glyph_sets = mark_set_count;
font->gdef->num_mark_glyph_sets = mark_set_count;
return true;
}
} // namespace
#define DROP_THIS_TABLE(msg_) \
do { \
OTS_FAILURE_MSG(msg_ ", table discarded"); \
file->gdef->data = 0; \
file->gdef->length = 0; \
} while (0)
namespace ots {
bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
// Grab the number of glyphs in the file from the maxp table to check
bool ots_gdef_parse(Font *font, const uint8_t *data, size_t length) {
// Grab the number of glyphs in the font from the maxp table to check
// GlyphIDs in GDEF table.
if (!file->maxp) {
if (!font->maxp) {
return OTS_FAILURE_MSG("No maxp table in font, needed by GDEF");
}
const uint16_t num_glyphs = file->maxp->num_glyphs;
const uint16_t num_glyphs = font->maxp->num_glyphs;
Buffer table(data, length);
OpenTypeGDEF *gdef = new OpenTypeGDEF;
file->gdef = gdef;
font->gdef = gdef;
uint32_t version = 0;
if (!table.ReadU32(&version)) {
DROP_THIS_TABLE("Incomplete table");
return true;
return OTS_FAILURE_MSG("Incomplete table");
}
if (version < 0x00010000 || version == 0x00010001) {
DROP_THIS_TABLE("Bad version");
return true;
return OTS_FAILURE_MSG("Bad version");
}
if (version >= 0x00010002) {
@ -273,14 +264,12 @@ bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
!table.ReadU16(&offset_attach_list) ||
!table.ReadU16(&offset_lig_caret_list) ||
!table.ReadU16(&offset_mark_attach_class_def)) {
DROP_THIS_TABLE("Incomplete table");
return true;
return OTS_FAILURE_MSG("Incomplete table");
}
uint16_t offset_mark_glyph_sets_def = 0;
if (gdef->version_2) {
if (!table.ReadU16(&offset_mark_glyph_sets_def)) {
DROP_THIS_TABLE("Incomplete table");
return true;
return OTS_FAILURE_MSG("Incomplete table");
}
}
@ -292,14 +281,12 @@ bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if (offset_glyph_class_def) {
if (offset_glyph_class_def >= length ||
offset_glyph_class_def < gdef_header_end) {
DROP_THIS_TABLE("Invalid offset to glyph classes");
return true;
return OTS_FAILURE_MSG("Invalid offset to glyph classes");
}
if (!ParseGlyphClassDefTable(file, data + offset_glyph_class_def,
if (!ParseGlyphClassDefTable(font, data + offset_glyph_class_def,
length - offset_glyph_class_def,
num_glyphs)) {
DROP_THIS_TABLE("Invalid glyph classes");
return true;
return OTS_FAILURE_MSG("Invalid glyph classes");
}
gdef->has_glyph_class_def = true;
}
@ -307,28 +294,24 @@ bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if (offset_attach_list) {
if (offset_attach_list >= length ||
offset_attach_list < gdef_header_end) {
DROP_THIS_TABLE("Invalid offset to attachment list");
return true;
return OTS_FAILURE_MSG("Invalid offset to attachment list");
}
if (!ParseAttachListTable(file, data + offset_attach_list,
if (!ParseAttachListTable(font, data + offset_attach_list,
length - offset_attach_list,
num_glyphs)) {
DROP_THIS_TABLE("Invalid attachment list");
return true;
return OTS_FAILURE_MSG("Invalid attachment list");
}
}
if (offset_lig_caret_list) {
if (offset_lig_caret_list >= length ||
offset_lig_caret_list < gdef_header_end) {
DROP_THIS_TABLE("Invalid offset to ligature caret list");
return true;
return OTS_FAILURE_MSG("Invalid offset to ligature caret list");
}
if (!ParseLigCaretListTable(file, data + offset_lig_caret_list,
if (!ParseLigCaretListTable(font, data + offset_lig_caret_list,
length - offset_lig_caret_list,
num_glyphs)) {
DROP_THIS_TABLE("Invalid ligature caret list");
return true;
return OTS_FAILURE_MSG("Invalid ligature caret list");
}
}
@ -337,12 +320,11 @@ bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
offset_mark_attach_class_def < gdef_header_end) {
return OTS_FAILURE_MSG("Invalid offset to mark attachment list");
}
if (!ParseMarkAttachClassDefTable(file,
if (!ParseMarkAttachClassDefTable(font,
data + offset_mark_attach_class_def,
length - offset_mark_attach_class_def,
num_glyphs)) {
DROP_THIS_TABLE("Invalid mark attachment list");
return true;
return OTS_FAILURE_MSG("Invalid mark attachment list");
}
gdef->has_mark_attachment_class_def = true;
}
@ -352,12 +334,11 @@ bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
offset_mark_glyph_sets_def < gdef_header_end) {
return OTS_FAILURE_MSG("invalid offset to mark glyph sets");
}
if (!ParseMarkGlyphSetsDefTable(file,
if (!ParseMarkGlyphSetsDefTable(font,
data + offset_mark_glyph_sets_def,
length - offset_mark_glyph_sets_def,
num_glyphs)) {
DROP_THIS_TABLE("Invalid mark glyph sets");
return true;
return OTS_FAILURE_MSG("Invalid mark glyph sets");
}
gdef->has_mark_glyph_sets_def = true;
}
@ -366,23 +347,27 @@ bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return true;
}
bool ots_gdef_should_serialise(OpenTypeFile *file) {
return file->gdef != NULL && file->gdef->data != NULL;
bool ots_gdef_should_serialise(Font *font) {
return font->gdef != NULL && font->gdef->data != NULL;
}
bool ots_gdef_serialise(OTSStream *out, OpenTypeFile *file) {
if (!out->Write(file->gdef->data, file->gdef->length)) {
bool ots_gdef_serialise(OTSStream *out, Font *font) {
if (!out->Write(font->gdef->data, font->gdef->length)) {
return OTS_FAILURE_MSG("Failed to write GDEF table");
}
return true;
}
void ots_gdef_free(OpenTypeFile *file) {
delete file->gdef;
void ots_gdef_reuse(Font *font, Font *other) {
font->gdef = other->gdef;
font->gdef_reused = true;
}
void ots_gdef_free(Font *font) {
delete font->gdef;
}
} // namespace ots
#undef TABLE_NAME
#undef DROP_THIS_TABLE

View File

@ -18,7 +18,7 @@
namespace {
bool ParseFlagsForSimpleGlyph(ots::OpenTypeFile *file,
bool ParseFlagsForSimpleGlyph(ots::Font *font,
ots::Buffer *table,
uint32_t gly_length,
uint32_t num_flags,
@ -64,7 +64,7 @@ bool ParseFlagsForSimpleGlyph(ots::OpenTypeFile *file,
}
if ((flag & (1u << 6)) || (flag & (1u << 7))) { // reserved flags
return OTS_FAILURE_MSG("Bad flag value (%d)", flag);
return OTS_FAILURE_MSG("Bad glyph flag value (%d), reserved flags must be set to zero", flag);
}
*xy_coordinates_length += delta;
@ -75,11 +75,11 @@ bool ParseFlagsForSimpleGlyph(ots::OpenTypeFile *file,
return true;
}
bool ParseSimpleGlyph(ots::OpenTypeFile *file, const uint8_t *data,
bool ParseSimpleGlyph(ots::Font *font, const uint8_t *data,
ots::Buffer *table, int16_t num_contours,
uint32_t gly_offset, uint32_t gly_length,
uint32_t *new_size) {
ots::OpenTypeGLYF *glyf = file->glyf;
ots::OpenTypeGLYF *glyf = font->glyf;
// read the end-points array
uint16_t num_flags = 0;
@ -102,8 +102,8 @@ bool ParseSimpleGlyph(ots::OpenTypeFile *file, const uint8_t *data,
if (!table->ReadU16(&bytecode_length)) {
return OTS_FAILURE_MSG("Can't read bytecode length");
}
if ((file->maxp->version_1) &&
(file->maxp->max_size_glyf_instructions < bytecode_length)) {
if ((font->maxp->version_1) &&
(font->maxp->max_size_glyf_instructions < bytecode_length)) {
return OTS_FAILURE_MSG("Bytecode length too high %d", bytecode_length);
}
@ -125,7 +125,7 @@ bool ParseSimpleGlyph(ots::OpenTypeFile *file, const uint8_t *data,
for (uint32_t flags_count_logical = 0;
flags_count_logical < num_flags;
++flags_count_logical, ++flags_count_physical) {
if (!ParseFlagsForSimpleGlyph(file,
if (!ParseFlagsForSimpleGlyph(font,
table,
gly_length,
num_flags,
@ -162,18 +162,18 @@ bool ParseSimpleGlyph(ots::OpenTypeFile *file, const uint8_t *data,
namespace ots {
bool ots_glyf_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
bool ots_glyf_parse(Font *font, const uint8_t *data, size_t length) {
Buffer table(data, length);
if (!file->maxp || !file->loca || !file->head) {
if (!font->maxp || !font->loca || !font->head) {
return OTS_FAILURE_MSG("Missing maxp or loca or head table needed by glyf table");
}
OpenTypeGLYF *glyf = new OpenTypeGLYF;
file->glyf = glyf;
font->glyf = glyf;
const unsigned num_glyphs = file->maxp->num_glyphs;
std::vector<uint32_t> &offsets = file->loca->offsets;
const unsigned num_glyphs = font->maxp->num_glyphs;
std::vector<uint32_t> &offsets = font->loca->offsets;
if (offsets.size() != num_glyphs + 1) {
return OTS_FAILURE_MSG("Invalide glyph offsets size %ld != %d", offsets.size(), num_glyphs + 1);
@ -235,7 +235,7 @@ bool ots_glyf_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
unsigned new_size = 0;
if (num_contours >= 0) {
// this is a simple glyph and might contain bytecode
if (!ParseSimpleGlyph(file, data, &table,
if (!ParseSimpleGlyph(font, data, &table,
num_contours, gly_offset, gly_length, &new_size)) {
return OTS_FAILURE_MSG("Failed to parse glyph %d", i);
}
@ -264,21 +264,21 @@ bool ots_glyf_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
const uint16_t max16 = std::numeric_limits<uint16_t>::max();
if ((*std::max_element(resulting_offsets.begin(),
resulting_offsets.end()) >= (max16 * 2u)) &&
(file->head->index_to_loc_format != 1)) {
(font->head->index_to_loc_format != 1)) {
OTS_WARNING("2-bytes indexing is not possible (due to the padding above)");
file->head->index_to_loc_format = 1;
font->head->index_to_loc_format = 1;
}
file->loca->offsets = resulting_offsets;
font->loca->offsets = resulting_offsets;
return true;
}
bool ots_glyf_should_serialise(OpenTypeFile *file) {
return file->glyf != NULL;
bool ots_glyf_should_serialise(Font *font) {
return font->glyf != NULL;
}
bool ots_glyf_serialise(OTSStream *out, OpenTypeFile *file) {
const OpenTypeGLYF *glyf = file->glyf;
bool ots_glyf_serialise(OTSStream *out, Font *font) {
const OpenTypeGLYF *glyf = font->glyf;
for (unsigned i = 0; i < glyf->iov.size(); ++i) {
if (!out->Write(glyf->iov[i].first, glyf->iov[i].second)) {
@ -289,8 +289,13 @@ bool ots_glyf_serialise(OTSStream *out, OpenTypeFile *file) {
return true;
}
void ots_glyf_free(OpenTypeFile *file) {
delete file->glyf;
void ots_glyf_reuse(Font *font, Font *other) {
font->glyf = other->glyf;
font->glyf_reused = true;
}
void ots_glyf_free(Font *font) {
delete font->glyf;
}
} // namespace ots

View File

@ -38,23 +38,23 @@ const uint16_t kMaxAnchorFormat = 3;
const uint16_t kMaxClassDefValue = 0xFFFF;
// Lookup type parsers.
bool ParseSingleAdjustment(const ots::OpenTypeFile *file,
bool ParseSingleAdjustment(const ots::Font *font,
const uint8_t *data, const size_t length);
bool ParsePairAdjustment(const ots::OpenTypeFile *file,
bool ParsePairAdjustment(const ots::Font *font,
const uint8_t *data, const size_t length);
bool ParseCursiveAttachment(const ots::OpenTypeFile *file,
bool ParseCursiveAttachment(const ots::Font *font,
const uint8_t *data, const size_t length);
bool ParseMarkToBaseAttachment(const ots::OpenTypeFile *file,
bool ParseMarkToBaseAttachment(const ots::Font *font,
const uint8_t *data, const size_t length);
bool ParseMarkToLigatureAttachment(const ots::OpenTypeFile *file,
bool ParseMarkToLigatureAttachment(const ots::Font *font,
const uint8_t *data, const size_t length);
bool ParseMarkToMarkAttachment(const ots::OpenTypeFile *file,
bool ParseMarkToMarkAttachment(const ots::Font *font,
const uint8_t *data, const size_t length);
bool ParseContextPositioning(const ots::OpenTypeFile *file,
bool ParseContextPositioning(const ots::Font *font,
const uint8_t *data, const size_t length);
bool ParseChainedContextPositioning(const ots::OpenTypeFile *file,
bool ParseChainedContextPositioning(const ots::Font *font,
const uint8_t *data, const size_t length);
bool ParseExtensionPositioning(const ots::OpenTypeFile *file,
bool ParseExtensionPositioning(const ots::Font *font,
const uint8_t *data, const size_t length);
const ots::LookupSubtableParser::TypeParser kGposTypeParsers[] = {
@ -76,7 +76,7 @@ const ots::LookupSubtableParser kGposLookupSubtableParser = {
// Shared Tables: ValueRecord, Anchor Table, and MarkArray
bool ParseValueRecord(const ots::OpenTypeFile *file,
bool ParseValueRecord(const ots::Font *font,
ots::Buffer* subtable, const uint8_t *data,
const size_t length, const uint16_t value_format) {
// Check existence of adjustment fields.
@ -102,7 +102,7 @@ bool ParseValueRecord(const ots::OpenTypeFile *file,
if (offset >= length) {
return OTS_FAILURE_MSG("Value record offset too high %d >= %ld", offset, length);
}
if (!ots::ParseDeviceTable(file, data + offset, length - offset)) {
if (!ots::ParseDeviceTable(font, data + offset, length - offset)) {
return OTS_FAILURE_MSG("Failed to parse device table in value record");
}
}
@ -111,7 +111,7 @@ bool ParseValueRecord(const ots::OpenTypeFile *file,
return true;
}
bool ParseAnchorTable(const ots::OpenTypeFile *file,
bool ParseAnchorTable(const ots::Font *font,
const uint8_t *data, const size_t length) {
ots::Buffer subtable(data, length);
@ -146,7 +146,7 @@ bool ParseAnchorTable(const ots::OpenTypeFile *file,
if (offset_x_device < format_end || offset_x_device >= length) {
return OTS_FAILURE_MSG("Bad x device table offset %d", offset_x_device);
}
if (!ots::ParseDeviceTable(file, data + offset_x_device,
if (!ots::ParseDeviceTable(font, data + offset_x_device,
length - offset_x_device)) {
return OTS_FAILURE_MSG("Failed to parse device table in anchor table");
}
@ -155,7 +155,7 @@ bool ParseAnchorTable(const ots::OpenTypeFile *file,
if (offset_y_device < format_end || offset_y_device >= length) {
return OTS_FAILURE_MSG("Bad y device table offset %d", offset_y_device);
}
if (!ots::ParseDeviceTable(file, data + offset_y_device,
if (!ots::ParseDeviceTable(font, data + offset_y_device,
length - offset_y_device)) {
return OTS_FAILURE_MSG("Failed to parse device table in anchor table");
}
@ -164,7 +164,7 @@ bool ParseAnchorTable(const ots::OpenTypeFile *file,
return true;
}
bool ParseMarkArrayTable(const ots::OpenTypeFile *file,
bool ParseMarkArrayTable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t class_count) {
ots::Buffer subtable(data, length);
@ -192,7 +192,7 @@ bool ParseMarkArrayTable(const ots::OpenTypeFile *file,
offset_mark_anchor >= length) {
return OTS_FAILURE_MSG("Bad mark anchor offset %d for mark table %d", offset_mark_anchor, i);
}
if (!ParseAnchorTable(file, data + offset_mark_anchor,
if (!ParseAnchorTable(font, data + offset_mark_anchor,
length - offset_mark_anchor)) {
return OTS_FAILURE_MSG("Faled to parse anchor table for mark table %d", i);
}
@ -203,7 +203,7 @@ bool ParseMarkArrayTable(const ots::OpenTypeFile *file,
// Lookup Type 1:
// Single Adjustment Positioning Subtable
bool ParseSingleAdjustment(const ots::OpenTypeFile *file, const uint8_t *data,
bool ParseSingleAdjustment(const ots::Font *font, const uint8_t *data,
const size_t length) {
ots::Buffer subtable(data, length);
@ -218,7 +218,7 @@ bool ParseSingleAdjustment(const ots::OpenTypeFile *file, const uint8_t *data,
if (format == 1) {
// Format 1 exactly one value record.
if (!ParseValueRecord(file, &subtable, data, length, value_format)) {
if (!ParseValueRecord(font, &subtable, data, length, value_format)) {
return OTS_FAILURE_MSG("Failed to parse format 1 single adjustment table");
}
} else if (format == 2) {
@ -227,7 +227,7 @@ bool ParseSingleAdjustment(const ots::OpenTypeFile *file, const uint8_t *data,
return OTS_FAILURE_MSG("Failed to parse format 2 single adjustment table");
}
for (unsigned i = 0; i < value_count; ++i) {
if (!ParseValueRecord(file, &subtable, data, length, value_format)) {
if (!ParseValueRecord(font, &subtable, data, length, value_format)) {
return OTS_FAILURE_MSG("Failed to parse value record %d in format 2 single adjustment table", i);
}
}
@ -239,16 +239,16 @@ bool ParseSingleAdjustment(const ots::OpenTypeFile *file, const uint8_t *data,
return OTS_FAILURE_MSG("Bad coverage offset %d in single adjustment table", offset_coverage);
}
if (!ots::ParseCoverageTable(file, data + offset_coverage,
if (!ots::ParseCoverageTable(font, data + offset_coverage,
length - offset_coverage,
file->maxp->num_glyphs)) {
font->maxp->num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse coverage table in single adjustment table");
}
return true;
}
bool ParsePairSetTable(const ots::OpenTypeFile *file,
bool ParsePairSetTable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t value_format1,
const uint16_t value_format2,
@ -268,17 +268,17 @@ bool ParsePairSetTable(const ots::OpenTypeFile *file,
if (glyph_id >= num_glyphs) {
return OTS_FAILURE_MSG("glyph id %d too high >= %d", glyph_id, num_glyphs);
}
if (!ParseValueRecord(file, &subtable, data, length, value_format1)) {
if (!ParseValueRecord(font, &subtable, data, length, value_format1)) {
return OTS_FAILURE_MSG("Failed to parse value record in format 1 pair set table");
}
if (!ParseValueRecord(file, &subtable, data, length, value_format2)) {
if (!ParseValueRecord(font, &subtable, data, length, value_format2)) {
return OTS_FAILURE_MSG("Failed to parse value record in format 2 pair set table");
}
}
return true;
}
bool ParsePairPosFormat1(const ots::OpenTypeFile *file,
bool ParsePairPosFormat1(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t value_format1,
const uint16_t value_format2,
@ -308,7 +308,7 @@ bool ParsePairPosFormat1(const ots::OpenTypeFile *file,
return OTS_FAILURE_MSG("Bad pair set offset %d for pair set %d", pair_set_offset, i);
}
// Check pair set tables
if (!ParsePairSetTable(file, data + pair_set_offset, length - pair_set_offset,
if (!ParsePairSetTable(font, data + pair_set_offset, length - pair_set_offset,
value_format1, value_format2,
num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse pair set table %d", i);
@ -318,7 +318,7 @@ bool ParsePairPosFormat1(const ots::OpenTypeFile *file,
return true;
}
bool ParsePairPosFormat2(const ots::OpenTypeFile *file,
bool ParsePairPosFormat2(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t value_format1,
const uint16_t value_format2,
@ -345,11 +345,11 @@ bool ParsePairPosFormat2(const ots::OpenTypeFile *file,
for (unsigned i = 0; i < class1_count; ++i) {
// Check class 2 records.
for (unsigned j = 0; j < class2_count; ++j) {
if (value_format1 && !ParseValueRecord(file, &subtable, data, length,
if (value_format1 && !ParseValueRecord(font, &subtable, data, length,
value_format1)) {
return OTS_FAILURE_MSG("Failed to parse value record 1 %d and %d", j, i);
}
if (value_format2 && !ParseValueRecord(file, &subtable, data, length,
if (value_format2 && !ParseValueRecord(font, &subtable, data, length,
value_format2)) {
return OTS_FAILURE_MSG("Falied to parse value record 2 %d and %d", j, i);
}
@ -361,12 +361,12 @@ bool ParsePairPosFormat2(const ots::OpenTypeFile *file,
offset_class_def2 < subtable.offset() || offset_class_def2 >= length) {
return OTS_FAILURE_MSG("Bad class definition table offsets %d or %d", offset_class_def1, offset_class_def2);
}
if (!ots::ParseClassDefTable(file, data + offset_class_def1,
if (!ots::ParseClassDefTable(font, data + offset_class_def1,
length - offset_class_def1,
num_glyphs, kMaxClassDefValue)) {
return OTS_FAILURE_MSG("Failed to parse class definition table 1");
}
if (!ots::ParseClassDefTable(file, data + offset_class_def2,
if (!ots::ParseClassDefTable(font, data + offset_class_def2,
length - offset_class_def2,
num_glyphs, kMaxClassDefValue)) {
return OTS_FAILURE_MSG("Failed to parse class definition table 2");
@ -377,7 +377,7 @@ bool ParsePairPosFormat2(const ots::OpenTypeFile *file,
// Lookup Type 2:
// Pair Adjustment Positioning Subtable
bool ParsePairAdjustment(const ots::OpenTypeFile *file, const uint8_t *data,
bool ParsePairAdjustment(const ots::Font *font, const uint8_t *data,
const size_t length) {
ots::Buffer subtable(data, length);
@ -393,13 +393,13 @@ bool ParsePairAdjustment(const ots::OpenTypeFile *file, const uint8_t *data,
}
if (format == 1) {
if (!ParsePairPosFormat1(file, data, length, value_format1, value_format2,
file->maxp->num_glyphs)) {
if (!ParsePairPosFormat1(font, data, length, value_format1, value_format2,
font->maxp->num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse pair pos format 1");
}
} else if (format == 2) {
if (!ParsePairPosFormat2(file, data, length, value_format1, value_format2,
file->maxp->num_glyphs)) {
if (!ParsePairPosFormat2(font, data, length, value_format1, value_format2,
font->maxp->num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse pair format 2");
}
} else {
@ -409,9 +409,9 @@ bool ParsePairAdjustment(const ots::OpenTypeFile *file, const uint8_t *data,
if (offset_coverage < subtable.offset() || offset_coverage >= length) {
return OTS_FAILURE_MSG("Bad pair pos offset coverage %d", offset_coverage);
}
if (!ots::ParseCoverageTable(file, data + offset_coverage,
if (!ots::ParseCoverageTable(font, data + offset_coverage,
length - offset_coverage,
file->maxp->num_glyphs)) {
font->maxp->num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse coverage table");
}
@ -420,7 +420,7 @@ bool ParsePairAdjustment(const ots::OpenTypeFile *file, const uint8_t *data,
// Lookup Type 3
// Cursive Attachment Positioning Subtable
bool ParseCursiveAttachment(const ots::OpenTypeFile *file, const uint8_t *data,
bool ParseCursiveAttachment(const ots::Font *font, const uint8_t *data,
const size_t length) {
ots::Buffer subtable(data, length);
@ -456,7 +456,7 @@ bool ParseCursiveAttachment(const ots::OpenTypeFile *file, const uint8_t *data,
offset_entry_anchor >= length) {
return OTS_FAILURE_MSG("Bad entry anchor offset %d in entry exit record %d", offset_entry_anchor, i);
}
if (!ParseAnchorTable(file, data + offset_entry_anchor,
if (!ParseAnchorTable(font, data + offset_entry_anchor,
length - offset_entry_anchor)) {
return OTS_FAILURE_MSG("Failed to parse entry anchor table in entry exit record %d", i);
}
@ -466,7 +466,7 @@ bool ParseCursiveAttachment(const ots::OpenTypeFile *file, const uint8_t *data,
offset_exit_anchor >= length) {
return OTS_FAILURE_MSG("Bad exit anchor offset %d in entry exit record %d", offset_exit_anchor, i);
}
if (!ParseAnchorTable(file, data + offset_exit_anchor,
if (!ParseAnchorTable(font, data + offset_exit_anchor,
length - offset_exit_anchor)) {
return OTS_FAILURE_MSG("Failed to parse exit anchor table in entry exit record %d", i);
}
@ -476,16 +476,16 @@ bool ParseCursiveAttachment(const ots::OpenTypeFile *file, const uint8_t *data,
if (offset_coverage < subtable.offset() || offset_coverage >= length) {
return OTS_FAILURE_MSG("Bad coverage offset in cursive attachment %d", offset_coverage);
}
if (!ots::ParseCoverageTable(file, data + offset_coverage,
if (!ots::ParseCoverageTable(font, data + offset_coverage,
length - offset_coverage,
file->maxp->num_glyphs)) {
font->maxp->num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse coverage table in cursive attachment");
}
return true;
}
bool ParseAnchorArrayTable(const ots::OpenTypeFile *file,
bool ParseAnchorArrayTable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t class_count) {
ots::Buffer subtable(data, length);
@ -511,7 +511,7 @@ bool ParseAnchorArrayTable(const ots::OpenTypeFile *file,
if (offset_record < anchor_array_end || offset_record >= length) {
return OTS_FAILURE_MSG("Bad record offset %d in class %d, record %d", offset_record, j, i);
}
if (!ParseAnchorTable(file, data + offset_record,
if (!ParseAnchorTable(font, data + offset_record,
length - offset_record)) {
return OTS_FAILURE_MSG("Failed to parse anchor table for class %d, record %d", j, i);
}
@ -521,7 +521,7 @@ bool ParseAnchorArrayTable(const ots::OpenTypeFile *file,
return true;
}
bool ParseLigatureArrayTable(const ots::OpenTypeFile *file,
bool ParseLigatureArrayTable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t class_count) {
ots::Buffer subtable(data, length);
@ -538,7 +538,7 @@ bool ParseLigatureArrayTable(const ots::OpenTypeFile *file,
if (offset_ligature_attach < 2 || offset_ligature_attach >= length) {
return OTS_FAILURE_MSG("Bad ligature attachment offset %d in ligature %d", offset_ligature_attach, i);
}
if (!ParseAnchorArrayTable(file, data + offset_ligature_attach,
if (!ParseAnchorArrayTable(font, data + offset_ligature_attach,
length - offset_ligature_attach, class_count)) {
return OTS_FAILURE_MSG("Failed to parse anchor table for ligature %d", i);
}
@ -547,7 +547,7 @@ bool ParseLigatureArrayTable(const ots::OpenTypeFile *file,
}
// Common parser for Lookup Type 4, 5 and 6.
bool ParseMarkToAttachmentSubtables(const ots::OpenTypeFile *file,
bool ParseMarkToAttachmentSubtables(const ots::Font *font,
const uint8_t *data, const size_t length,
const GPOS_TYPE type) {
ots::Buffer subtable(data, length);
@ -578,24 +578,24 @@ bool ParseMarkToAttachmentSubtables(const ots::OpenTypeFile *file,
if (offset_coverage1 < header_end || offset_coverage1 >= length) {
return OTS_FAILURE_MSG("Bad coverage 1 offset %d", offset_coverage1);
}
if (!ots::ParseCoverageTable(file, data + offset_coverage1,
if (!ots::ParseCoverageTable(font, data + offset_coverage1,
length - offset_coverage1,
file->maxp->num_glyphs)) {
font->maxp->num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse converge 1 table");
}
if (offset_coverage2 < header_end || offset_coverage2 >= length) {
return OTS_FAILURE_MSG("Bad coverage 2 offset %d", offset_coverage2);
}
if (!ots::ParseCoverageTable(file, data + offset_coverage2,
if (!ots::ParseCoverageTable(font, data + offset_coverage2,
length - offset_coverage2,
file->maxp->num_glyphs)) {
font->maxp->num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse coverage table 2");
}
if (offset_mark_array < header_end || offset_mark_array >= length) {
return OTS_FAILURE_MSG("Bad mark array offset %d", offset_mark_array);
}
if (!ParseMarkArrayTable(file, data + offset_mark_array,
if (!ParseMarkArrayTable(font, data + offset_mark_array,
length - offset_mark_array, class_count)) {
return OTS_FAILURE_MSG("Failed to parse mark array");
}
@ -606,13 +606,13 @@ bool ParseMarkToAttachmentSubtables(const ots::OpenTypeFile *file,
}
if (type == GPOS_TYPE_MARK_TO_BASE_ATTACHMENT ||
type == GPOS_TYPE_MARK_TO_MARK_ATTACHMENT) {
if (!ParseAnchorArrayTable(file, data + offset_type_specific_array,
if (!ParseAnchorArrayTable(font, data + offset_type_specific_array,
length - offset_type_specific_array,
class_count)) {
return OTS_FAILURE_MSG("Failed to parse anchor array");
}
} else if (type == GPOS_TYPE_MARK_TO_LIGATURE_ATTACHMENT) {
if (!ParseLigatureArrayTable(file, data + offset_type_specific_array,
if (!ParseLigatureArrayTable(font, data + offset_type_specific_array,
length - offset_type_specific_array,
class_count)) {
return OTS_FAILURE_MSG("Failed to parse ligature array");
@ -626,62 +626,55 @@ bool ParseMarkToAttachmentSubtables(const ots::OpenTypeFile *file,
// Lookup Type 4:
// MarkToBase Attachment Positioning Subtable
bool ParseMarkToBaseAttachment(const ots::OpenTypeFile *file,
bool ParseMarkToBaseAttachment(const ots::Font *font,
const uint8_t *data, const size_t length) {
return ParseMarkToAttachmentSubtables(file, data, length,
return ParseMarkToAttachmentSubtables(font, data, length,
GPOS_TYPE_MARK_TO_BASE_ATTACHMENT);
}
// Lookup Type 5:
// MarkToLigature Attachment Positioning Subtable
bool ParseMarkToLigatureAttachment(const ots::OpenTypeFile *file,
bool ParseMarkToLigatureAttachment(const ots::Font *font,
const uint8_t *data, const size_t length) {
return ParseMarkToAttachmentSubtables(file, data, length,
return ParseMarkToAttachmentSubtables(font, data, length,
GPOS_TYPE_MARK_TO_LIGATURE_ATTACHMENT);
}
// Lookup Type 6:
// MarkToMark Attachment Positioning Subtable
bool ParseMarkToMarkAttachment(const ots::OpenTypeFile *file,
bool ParseMarkToMarkAttachment(const ots::Font *font,
const uint8_t *data, const size_t length) {
return ParseMarkToAttachmentSubtables(file, data, length,
return ParseMarkToAttachmentSubtables(font, data, length,
GPOS_TYPE_MARK_TO_MARK_ATTACHMENT);
}
// Lookup Type 7:
// Contextual Positioning Subtables
bool ParseContextPositioning(const ots::OpenTypeFile *file,
bool ParseContextPositioning(const ots::Font *font,
const uint8_t *data, const size_t length) {
return ots::ParseContextSubtable(file, data, length, file->maxp->num_glyphs,
file->gpos->num_lookups);
return ots::ParseContextSubtable(font, data, length, font->maxp->num_glyphs,
font->gpos->num_lookups);
}
// Lookup Type 8:
// Chaining Contexual Positioning Subtable
bool ParseChainedContextPositioning(const ots::OpenTypeFile *file,
bool ParseChainedContextPositioning(const ots::Font *font,
const uint8_t *data, const size_t length) {
return ots::ParseChainingContextSubtable(file, data, length,
file->maxp->num_glyphs,
file->gpos->num_lookups);
return ots::ParseChainingContextSubtable(font, data, length,
font->maxp->num_glyphs,
font->gpos->num_lookups);
}
// Lookup Type 9:
// Extension Positioning
bool ParseExtensionPositioning(const ots::OpenTypeFile *file,
bool ParseExtensionPositioning(const ots::Font *font,
const uint8_t *data, const size_t length) {
return ots::ParseExtensionSubtable(file, data, length,
return ots::ParseExtensionSubtable(font, data, length,
&kGposLookupSubtableParser);
}
} // namespace
#define DROP_THIS_TABLE(msg_) \
do { \
OTS_FAILURE_MSG(msg_ ", table discarded"); \
file->gpos->data = 0; \
file->gpos->length = 0; \
} while (0)
namespace ots {
// As far as I checked, following fonts contain invalid GPOS table and
@ -730,16 +723,16 @@ namespace ots {
// # Contour point indexes aren't sorted
// Arial Unicode.ttf
bool ots_gpos_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
bool ots_gpos_parse(Font *font, const uint8_t *data, size_t length) {
// Parsing GPOS table requires num_glyphs which is contained in maxp table.
if (!file->maxp) {
if (!font->maxp) {
return OTS_FAILURE_MSG("missing maxp table needed in GPOS");
}
Buffer table(data, length);
OpenTypeGPOS *gpos = new OpenTypeGPOS;
file->gpos = gpos;
font->gpos = gpos;
uint32_t version = 0;
uint16_t offset_script_list = 0;
@ -749,55 +742,47 @@ bool ots_gpos_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
!table.ReadU16(&offset_script_list) ||
!table.ReadU16(&offset_feature_list) ||
!table.ReadU16(&offset_lookup_list)) {
DROP_THIS_TABLE("Incomplete table");
return true;
return OTS_FAILURE_MSG("Incomplete table");
}
if (version != 0x00010000) {
DROP_THIS_TABLE("Bad version");
return true;
return OTS_FAILURE_MSG("Bad version");
}
if (offset_lookup_list) {
if (offset_lookup_list < kGposHeaderSize || offset_lookup_list >= length) {
DROP_THIS_TABLE("Bad lookup list offset in table header");
return true;
return OTS_FAILURE_MSG("Bad lookup list offset in table header");
}
if (!ParseLookupListTable(file, data + offset_lookup_list,
if (!ParseLookupListTable(font, data + offset_lookup_list,
length - offset_lookup_list,
&kGposLookupSubtableParser,
&gpos->num_lookups)) {
DROP_THIS_TABLE("Failed to parse lookup list table");
return true;
return OTS_FAILURE_MSG("Failed to parse lookup list table");
}
}
uint16_t num_features = 0;
if (offset_feature_list) {
if (offset_feature_list < kGposHeaderSize || offset_feature_list >= length) {
DROP_THIS_TABLE("Bad feature list offset in table header");
return true;
return OTS_FAILURE_MSG("Bad feature list offset in table header");
}
if (!ParseFeatureListTable(file, data + offset_feature_list,
if (!ParseFeatureListTable(font, data + offset_feature_list,
length - offset_feature_list, gpos->num_lookups,
&num_features)) {
DROP_THIS_TABLE("Failed to parse feature list table");
return true;
return OTS_FAILURE_MSG("Failed to parse feature list table");
}
}
if (offset_script_list) {
if (offset_script_list < kGposHeaderSize || offset_script_list >= length) {
DROP_THIS_TABLE("Bad script list offset in table header");
return true;
return OTS_FAILURE_MSG("Bad script list offset in table header");
}
if (!ParseScriptListTable(file, data + offset_script_list,
if (!ParseScriptListTable(font, data + offset_script_list,
length - offset_script_list, num_features)) {
DROP_THIS_TABLE("Failed to parse script list table");
return true;
return OTS_FAILURE_MSG("Failed to parse script list table");
}
}
@ -806,23 +791,27 @@ bool ots_gpos_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return true;
}
bool ots_gpos_should_serialise(OpenTypeFile *file) {
return file->gpos != NULL && file->gpos->data != NULL;
bool ots_gpos_should_serialise(Font *font) {
return font->gpos != NULL && font->gpos->data != NULL;
}
bool ots_gpos_serialise(OTSStream *out, OpenTypeFile *file) {
if (!out->Write(file->gpos->data, file->gpos->length)) {
bool ots_gpos_serialise(OTSStream *out, Font *font) {
if (!out->Write(font->gpos->data, font->gpos->length)) {
return OTS_FAILURE_MSG("Failed to write GPOS table");
}
return true;
}
void ots_gpos_free(OpenTypeFile *file) {
delete file->gpos;
void ots_gpos_reuse(Font *font, Font *other) {
font->gpos = other->gpos;
font->gpos_reused = true;
}
void ots_gpos_free(Font *font) {
delete font->gpos;
}
} // namespace ots
#undef TABLE_NAME
#undef DROP_THIS_TABLE

View File

@ -33,23 +33,23 @@ enum GSUB_TYPE {
};
// Lookup type parsers.
bool ParseSingleSubstitution(const ots::OpenTypeFile *file,
bool ParseSingleSubstitution(const ots::Font *font,
const uint8_t *data, const size_t length);
bool ParseMutipleSubstitution(const ots::OpenTypeFile *file,
bool ParseMutipleSubstitution(const ots::Font *font,
const uint8_t *data, const size_t length);
bool ParseAlternateSubstitution(const ots::OpenTypeFile *file,
bool ParseAlternateSubstitution(const ots::Font *font,
const uint8_t *data, const size_t length);
bool ParseLigatureSubstitution(const ots::OpenTypeFile *file,
bool ParseLigatureSubstitution(const ots::Font *font,
const uint8_t *data, const size_t length);
bool ParseContextSubstitution(const ots::OpenTypeFile *file,
bool ParseContextSubstitution(const ots::Font *font,
const uint8_t *data, const size_t length);
bool ParseChainingContextSubstitution(const ots::OpenTypeFile *file,
bool ParseChainingContextSubstitution(const ots::Font *font,
const uint8_t *data,
const size_t length);
bool ParseExtensionSubstitution(const ots::OpenTypeFile *file,
bool ParseExtensionSubstitution(const ots::Font *font,
const uint8_t *data, const size_t length);
bool ParseReverseChainingContextSingleSubstitution(
const ots::OpenTypeFile *file, const uint8_t *data, const size_t length);
const ots::Font *font, const uint8_t *data, const size_t length);
const ots::LookupSubtableParser::TypeParser kGsubTypeParsers[] = {
{GSUB_TYPE_SINGLE, ParseSingleSubstitution},
@ -70,7 +70,7 @@ const ots::LookupSubtableParser kGsubLookupSubtableParser = {
// Lookup Type 1:
// Single Substitution Subtable
bool ParseSingleSubstitution(const ots::OpenTypeFile *file,
bool ParseSingleSubstitution(const ots::Font *font,
const uint8_t *data, const size_t length) {
ots::Buffer subtable(data, length);
@ -82,7 +82,7 @@ bool ParseSingleSubstitution(const ots::OpenTypeFile *file,
return OTS_FAILURE_MSG("Failed to read single subst table header");
}
const uint16_t num_glyphs = file->maxp->num_glyphs;
const uint16_t num_glyphs = font->maxp->num_glyphs;
if (format == 1) {
// Parse SingleSubstFormat1
int16_t delta_glyph_id = 0;
@ -117,7 +117,7 @@ bool ParseSingleSubstitution(const ots::OpenTypeFile *file,
if (offset_coverage < subtable.offset() || offset_coverage >= length) {
return OTS_FAILURE_MSG("Bad coverage offset %x", offset_coverage);
}
if (!ots::ParseCoverageTable(file, data + offset_coverage,
if (!ots::ParseCoverageTable(font, data + offset_coverage,
length - offset_coverage, num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse coverage table");
}
@ -125,7 +125,7 @@ bool ParseSingleSubstitution(const ots::OpenTypeFile *file,
return true;
}
bool ParseSequenceTable(const ots::OpenTypeFile *file,
bool ParseSequenceTable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
@ -152,7 +152,7 @@ bool ParseSequenceTable(const ots::OpenTypeFile *file,
// Lookup Type 2:
// Multiple Substitution Subtable
bool ParseMutipleSubstitution(const ots::OpenTypeFile *file,
bool ParseMutipleSubstitution(const ots::Font *font,
const uint8_t *data, const size_t length) {
ots::Buffer subtable(data, length);
@ -170,7 +170,7 @@ bool ParseMutipleSubstitution(const ots::OpenTypeFile *file,
return OTS_FAILURE_MSG("Bad multiple subst table format %d", format);
}
const uint16_t num_glyphs = file->maxp->num_glyphs;
const uint16_t num_glyphs = font->maxp->num_glyphs;
const unsigned sequence_end = static_cast<unsigned>(6) +
sequence_count * 2;
if (sequence_end > std::numeric_limits<uint16_t>::max()) {
@ -184,7 +184,7 @@ bool ParseMutipleSubstitution(const ots::OpenTypeFile *file,
if (offset_sequence < sequence_end || offset_sequence >= length) {
return OTS_FAILURE_MSG("Bad sequence offset %d for sequence %d", offset_sequence, i);
}
if (!ParseSequenceTable(file, data + offset_sequence, length - offset_sequence,
if (!ParseSequenceTable(font, data + offset_sequence, length - offset_sequence,
num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse sequence table %d", i);
}
@ -193,7 +193,7 @@ bool ParseMutipleSubstitution(const ots::OpenTypeFile *file,
if (offset_coverage < sequence_end || offset_coverage >= length) {
return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage);
}
if (!ots::ParseCoverageTable(file, data + offset_coverage,
if (!ots::ParseCoverageTable(font, data + offset_coverage,
length - offset_coverage, num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse coverage table");
}
@ -201,7 +201,7 @@ bool ParseMutipleSubstitution(const ots::OpenTypeFile *file,
return true;
}
bool ParseAlternateSetTable(const ots::OpenTypeFile *file,
bool ParseAlternateSetTable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
@ -227,7 +227,7 @@ bool ParseAlternateSetTable(const ots::OpenTypeFile *file,
// Lookup Type 3:
// Alternate Substitution Subtable
bool ParseAlternateSubstitution(const ots::OpenTypeFile *file,
bool ParseAlternateSubstitution(const ots::Font *font,
const uint8_t *data, const size_t length) {
ots::Buffer subtable(data, length);
@ -245,7 +245,7 @@ bool ParseAlternateSubstitution(const ots::OpenTypeFile *file,
return OTS_FAILURE_MSG("Bad alternate subst table format %d", format);
}
const uint16_t num_glyphs = file->maxp->num_glyphs;
const uint16_t num_glyphs = font->maxp->num_glyphs;
const unsigned alternate_set_end = static_cast<unsigned>(6) +
alternate_set_count * 2;
if (alternate_set_end > std::numeric_limits<uint16_t>::max()) {
@ -260,7 +260,7 @@ bool ParseAlternateSubstitution(const ots::OpenTypeFile *file,
offset_alternate_set >= length) {
return OTS_FAILURE_MSG("Bad alternate set offset %d for set %d", offset_alternate_set, i);
}
if (!ParseAlternateSetTable(file, data + offset_alternate_set,
if (!ParseAlternateSetTable(font, data + offset_alternate_set,
length - offset_alternate_set,
num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse alternate set");
@ -270,7 +270,7 @@ bool ParseAlternateSubstitution(const ots::OpenTypeFile *file,
if (offset_coverage < alternate_set_end || offset_coverage >= length) {
return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage);
}
if (!ots::ParseCoverageTable(file, data + offset_coverage,
if (!ots::ParseCoverageTable(font, data + offset_coverage,
length - offset_coverage, num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse coverage table");
}
@ -278,7 +278,7 @@ bool ParseAlternateSubstitution(const ots::OpenTypeFile *file,
return true;
}
bool ParseLigatureTable(const ots::OpenTypeFile *file,
bool ParseLigatureTable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
@ -310,7 +310,7 @@ bool ParseLigatureTable(const ots::OpenTypeFile *file,
return true;
}
bool ParseLigatureSetTable(const ots::OpenTypeFile *file,
bool ParseLigatureSetTable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
@ -333,7 +333,7 @@ bool ParseLigatureSetTable(const ots::OpenTypeFile *file,
if (offset_ligature < ligature_end || offset_ligature >= length) {
return OTS_FAILURE_MSG("Bad ligature offset %d for ligature %d", offset_ligature, i);
}
if (!ParseLigatureTable(file, data + offset_ligature, length - offset_ligature,
if (!ParseLigatureTable(font, data + offset_ligature, length - offset_ligature,
num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse ligature %d", i);
}
@ -344,7 +344,7 @@ bool ParseLigatureSetTable(const ots::OpenTypeFile *file,
// Lookup Type 4:
// Ligature Substitution Subtable
bool ParseLigatureSubstitution(const ots::OpenTypeFile *file,
bool ParseLigatureSubstitution(const ots::Font *font,
const uint8_t *data, const size_t length) {
ots::Buffer subtable(data, length);
@ -362,7 +362,7 @@ bool ParseLigatureSubstitution(const ots::OpenTypeFile *file,
return OTS_FAILURE_MSG("Bad ligature substitution table format %d", format);
}
const uint16_t num_glyphs = file->maxp->num_glyphs;
const uint16_t num_glyphs = font->maxp->num_glyphs;
const unsigned ligature_set_end = static_cast<unsigned>(6) +
lig_set_count * 2;
if (ligature_set_end > std::numeric_limits<uint16_t>::max()) {
@ -377,7 +377,7 @@ bool ParseLigatureSubstitution(const ots::OpenTypeFile *file,
offset_ligature_set >= length) {
return OTS_FAILURE_MSG("Bad ligature set offset %d for set %d", offset_ligature_set, i);
}
if (!ParseLigatureSetTable(file, data + offset_ligature_set,
if (!ParseLigatureSetTable(font, data + offset_ligature_set,
length - offset_ligature_set, num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse ligature set %d", i);
}
@ -386,7 +386,7 @@ bool ParseLigatureSubstitution(const ots::OpenTypeFile *file,
if (offset_coverage < ligature_set_end || offset_coverage >= length) {
return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage);
}
if (!ots::ParseCoverageTable(file, data + offset_coverage,
if (!ots::ParseCoverageTable(font, data + offset_coverage,
length - offset_coverage, num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse coverage table");
}
@ -396,34 +396,34 @@ bool ParseLigatureSubstitution(const ots::OpenTypeFile *file,
// Lookup Type 5:
// Contextual Substitution Subtable
bool ParseContextSubstitution(const ots::OpenTypeFile *file,
bool ParseContextSubstitution(const ots::Font *font,
const uint8_t *data, const size_t length) {
return ots::ParseContextSubtable(file, data, length, file->maxp->num_glyphs,
file->gsub->num_lookups);
return ots::ParseContextSubtable(font, data, length, font->maxp->num_glyphs,
font->gsub->num_lookups);
}
// Lookup Type 6:
// Chaining Contextual Substitution Subtable
bool ParseChainingContextSubstitution(const ots::OpenTypeFile *file,
bool ParseChainingContextSubstitution(const ots::Font *font,
const uint8_t *data,
const size_t length) {
return ots::ParseChainingContextSubtable(file, data, length,
file->maxp->num_glyphs,
file->gsub->num_lookups);
return ots::ParseChainingContextSubtable(font, data, length,
font->maxp->num_glyphs,
font->gsub->num_lookups);
}
// Lookup Type 7:
// Extension Substition
bool ParseExtensionSubstitution(const ots::OpenTypeFile *file,
bool ParseExtensionSubstitution(const ots::Font *font,
const uint8_t *data, const size_t length) {
return ots::ParseExtensionSubtable(file, data, length,
return ots::ParseExtensionSubtable(font, data, length,
&kGsubLookupSubtableParser);
}
// Lookup Type 8:
// Reverse Chaining Contexual Single Substitution Subtable
bool ParseReverseChainingContextSingleSubstitution(
const ots::OpenTypeFile *file, const uint8_t *data, const size_t length) {
const ots::Font *font, const uint8_t *data, const size_t length) {
ots::Buffer subtable(data, length);
uint16_t format = 0;
@ -434,7 +434,7 @@ bool ParseReverseChainingContextSingleSubstitution(
return OTS_FAILURE_MSG("Failed to read reverse chaining header");
}
const uint16_t num_glyphs = file->maxp->num_glyphs;
const uint16_t num_glyphs = font->maxp->num_glyphs;
uint16_t backtrack_glyph_count = 0;
if (!subtable.ReadU16(&backtrack_glyph_count)) {
@ -496,7 +496,7 @@ bool ParseReverseChainingContextSingleSubstitution(
if (offset_coverage < substitute_end || offset_coverage >= length) {
return OTS_FAILURE_MSG("Bad coverage offset %d in reverse chaining table", offset_coverage);
}
if (!ots::ParseCoverageTable(file, data + offset_coverage,
if (!ots::ParseCoverageTable(font, data + offset_coverage,
length - offset_coverage, num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse coverage table in reverse chaining table");
}
@ -506,7 +506,7 @@ bool ParseReverseChainingContextSingleSubstitution(
offsets_backtrack[i] >= length) {
return OTS_FAILURE_MSG("Bad backtrack offset %d for backtrack %d in reverse chaining table", offsets_backtrack[i], i);
}
if (!ots::ParseCoverageTable(file, data + offsets_backtrack[i],
if (!ots::ParseCoverageTable(font, data + offsets_backtrack[i],
length - offsets_backtrack[i], num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse coverage table for backtrack %d in reverse chaining table", i);
}
@ -517,7 +517,7 @@ bool ParseReverseChainingContextSingleSubstitution(
offsets_lookahead[i] >= length) {
return OTS_FAILURE_MSG("Bad lookahead offset %d for lookahead %d in reverse chaining table", offsets_lookahead[i], i);
}
if (!ots::ParseCoverageTable(file, data + offsets_lookahead[i],
if (!ots::ParseCoverageTable(font, data + offsets_lookahead[i],
length - offsets_lookahead[i], num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse lookahead coverage table %d in reverse chaining table", i);
}
@ -528,13 +528,6 @@ bool ParseReverseChainingContextSingleSubstitution(
} // namespace
#define DROP_THIS_TABLE(msg_) \
do { \
OTS_FAILURE_MSG(msg_ ", table discarded"); \
file->gsub->data = 0; \
file->gsub->length = 0; \
} while (0)
namespace ots {
// As far as I checked, following fonts contain invalid values in GSUB table.
@ -587,16 +580,16 @@ namespace ots {
// KacstBook.ttf
// KacstFarsi.ttf
bool ots_gsub_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
// Parsing gsub table requires |file->maxp->num_glyphs|
if (!file->maxp) {
bool ots_gsub_parse(Font *font, const uint8_t *data, size_t length) {
// Parsing gsub table requires |font->maxp->num_glyphs|
if (!font->maxp) {
return OTS_FAILURE_MSG("Missing maxp table in font, needed by GSUB");
}
Buffer table(data, length);
OpenTypeGSUB *gsub = new OpenTypeGSUB;
file->gsub = gsub;
font->gsub = gsub;
uint32_t version = 0;
uint16_t offset_script_list = 0;
@ -606,55 +599,47 @@ bool ots_gsub_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
!table.ReadU16(&offset_script_list) ||
!table.ReadU16(&offset_feature_list) ||
!table.ReadU16(&offset_lookup_list)) {
DROP_THIS_TABLE("Incomplete table");
return true;
return OTS_FAILURE_MSG("Incomplete table");
}
if (version != 0x00010000) {
DROP_THIS_TABLE("Bad version");
return true;
return OTS_FAILURE_MSG("Bad version");
}
if (offset_lookup_list) {
if (offset_lookup_list < kGsubHeaderSize || offset_lookup_list >= length) {
DROP_THIS_TABLE("Bad lookup list offset in table header");
return true;
return OTS_FAILURE_MSG("Bad lookup list offset in table header");
}
if (!ParseLookupListTable(file, data + offset_lookup_list,
if (!ParseLookupListTable(font, data + offset_lookup_list,
length - offset_lookup_list,
&kGsubLookupSubtableParser,
&gsub->num_lookups)) {
DROP_THIS_TABLE("Failed to parse lookup list table");
return true;
return OTS_FAILURE_MSG("Failed to parse lookup list table");
}
}
uint16_t num_features = 0;
if (offset_feature_list) {
if (offset_feature_list < kGsubHeaderSize || offset_feature_list >= length) {
DROP_THIS_TABLE("Bad feature list offset in table header");
return true;
return OTS_FAILURE_MSG("Bad feature list offset in table header");
}
if (!ParseFeatureListTable(file, data + offset_feature_list,
if (!ParseFeatureListTable(font, data + offset_feature_list,
length - offset_feature_list, gsub->num_lookups,
&num_features)) {
DROP_THIS_TABLE("Failed to parse feature list table");
return true;
return OTS_FAILURE_MSG("Failed to parse feature list table");
}
}
if (offset_script_list) {
if (offset_script_list < kGsubHeaderSize || offset_script_list >= length) {
DROP_THIS_TABLE("Bad script list offset in table header");
return true;
return OTS_FAILURE_MSG("Bad script list offset in table header");
}
if (!ParseScriptListTable(file, data + offset_script_list,
if (!ParseScriptListTable(font, data + offset_script_list,
length - offset_script_list, num_features)) {
DROP_THIS_TABLE("Failed to parse script list table");
return true;
return OTS_FAILURE_MSG("Failed to parse script list table");
}
}
@ -663,23 +648,27 @@ bool ots_gsub_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return true;
}
bool ots_gsub_should_serialise(OpenTypeFile *file) {
return file->gsub != NULL && file->gsub->data != NULL;
bool ots_gsub_should_serialise(Font *font) {
return font->gsub != NULL && font->gsub->data != NULL;
}
bool ots_gsub_serialise(OTSStream *out, OpenTypeFile *file) {
if (!out->Write(file->gsub->data, file->gsub->length)) {
bool ots_gsub_serialise(OTSStream *out, Font *font) {
if (!out->Write(font->gsub->data, font->gsub->length)) {
return OTS_FAILURE_MSG("Failed to write GSUB table");
}
return true;
}
void ots_gsub_free(OpenTypeFile *file) {
delete file->gsub;
void ots_gsub_reuse(Font *font, Font *other) {
font->gsub = other->gsub;
font->gsub_reused = true;
}
void ots_gsub_free(Font *font) {
delete font->gsub;
}
} // namespace ots
#undef TABLE_NAME
#undef DROP_THIS_TABLE

View File

@ -13,24 +13,24 @@
#define DROP_THIS_TABLE(...) \
do { \
OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
OTS_FAILURE_MSG_(font->file, TABLE_NAME ": " __VA_ARGS__); \
OTS_FAILURE_MSG("Table discarded"); \
delete file->hdmx; \
file->hdmx = 0; \
delete font->hdmx; \
font->hdmx = 0; \
} while (0)
namespace ots {
bool ots_hdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
bool ots_hdmx_parse(Font *font, const uint8_t *data, size_t length) {
Buffer table(data, length);
file->hdmx = new OpenTypeHDMX;
OpenTypeHDMX * const hdmx = file->hdmx;
font->hdmx = new OpenTypeHDMX;
OpenTypeHDMX * const hdmx = font->hdmx;
if (!file->head || !file->maxp) {
if (!font->head || !font->maxp) {
return OTS_FAILURE_MSG("Missing maxp or head tables in font, needed by hdmx");
}
if ((file->head->flags & 0x14) == 0) {
if ((font->head->flags & 0x14) == 0) {
// http://www.microsoft.com/typography/otspec/recom.htm
DROP_THIS_TABLE("the table should not be present when bit 2 and 4 of the "
"head->flags are not set");
@ -51,7 +51,7 @@ bool ots_hdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
DROP_THIS_TABLE("bad num_recs: %d", num_recs);
return true;
}
const int32_t actual_size_device_record = file->maxp->num_glyphs + 2;
const int32_t actual_size_device_record = font->maxp->num_glyphs + 2;
if (hdmx->size_device_record < actual_size_device_record) {
DROP_THIS_TABLE("bad hdmx->size_device_record: %d", hdmx->size_device_record);
return true;
@ -78,8 +78,8 @@ bool ots_hdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
}
last_pixel_size = rec.pixel_size;
rec.widths.reserve(file->maxp->num_glyphs);
for (unsigned j = 0; j < file->maxp->num_glyphs; ++j) {
rec.widths.reserve(font->maxp->num_glyphs);
for (unsigned j = 0; j < font->maxp->num_glyphs; ++j) {
uint8_t width;
if (!table.ReadU8(&width)) {
return OTS_FAILURE_MSG("Failed to read glyph width %d in record %d", j, i);
@ -98,14 +98,14 @@ bool ots_hdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return true;
}
bool ots_hdmx_should_serialise(OpenTypeFile *file) {
if (!file->hdmx) return false;
if (!file->glyf) return false; // this table is not for CFF fonts.
bool ots_hdmx_should_serialise(Font *font) {
if (!font->hdmx) return false;
if (!font->glyf) return false; // this table is not for CFF fonts.
return true;
}
bool ots_hdmx_serialise(OTSStream *out, OpenTypeFile *file) {
OpenTypeHDMX * const hdmx = file->hdmx;
bool ots_hdmx_serialise(OTSStream *out, Font *font) {
OpenTypeHDMX * const hdmx = font->hdmx;
const int16_t num_recs = static_cast<int16_t>(hdmx->records.size());
if (hdmx->records.size() >
@ -132,8 +132,13 @@ bool ots_hdmx_serialise(OTSStream *out, OpenTypeFile *file) {
return true;
}
void ots_hdmx_free(OpenTypeFile *file) {
delete file->hdmx;
void ots_hdmx_reuse(Font *font, Font *other) {
font->hdmx = other->hdmx;
font->hdmx_reused = true;
}
void ots_hdmx_free(Font *font) {
delete font->hdmx;
}
} // namespace ots

View File

@ -13,13 +13,14 @@
namespace ots {
bool ots_head_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
bool ots_head_parse(Font* font, const uint8_t *data, size_t length) {
Buffer table(data, length);
file->head = new OpenTypeHEAD;
OpenTypeHEAD *head = new OpenTypeHEAD;
font->head = head;
uint32_t version = 0;
if (!table.ReadU32(&version) ||
!table.ReadU32(&file->head->revision)) {
!table.ReadU32(&head->revision)) {
return OTS_FAILURE_MSG("Failed to read head header");
}
@ -33,64 +34,63 @@ bool ots_head_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
}
uint32_t magic;
if (!table.ReadTag(&magic) ||
std::memcmp(&magic, "\x5F\x0F\x3C\xF5", 4)) {
if (!table.ReadU32(&magic) || magic != 0x5F0F3CF5) {
return OTS_FAILURE_MSG("Failed to read font magic number");
}
if (!table.ReadU16(&file->head->flags)) {
if (!table.ReadU16(&head->flags)) {
return OTS_FAILURE_MSG("Failed to read head flags");
}
// We allow bits 0..4, 11..13
file->head->flags &= 0x381f;
head->flags &= 0x381f;
if (!table.ReadU16(&file->head->ppem)) {
if (!table.ReadU16(&head->ppem)) {
return OTS_FAILURE_MSG("Failed to read pixels per em");
}
// ppem must be in range
if (file->head->ppem < 16 ||
file->head->ppem > 16384) {
return OTS_FAILURE_MSG("Bad ppm of %d", file->head->ppem);
if (head->ppem < 16 ||
head->ppem > 16384) {
return OTS_FAILURE_MSG("Bad ppm of %d", head->ppem);
}
// ppem must be a power of two
#if 0
// We don't call ots_failure() for now since lots of TrueType fonts are
// not following this rule. Putting OTS_WARNING here is too noisy.
if ((file->head->ppem - 1) & file->head->ppem) {
return OTS_FAILURE_MSG("ppm not a power of two: %d", file->head->ppem);
if ((head->ppem - 1) & head->ppem) {
return OTS_FAILURE_MSG("ppm not a power of two: %d", head->ppem);
}
#endif
if (!table.ReadR64(&file->head->created) ||
!table.ReadR64(&file->head->modified)) {
if (!table.ReadR64(&head->created) ||
!table.ReadR64(&head->modified)) {
return OTS_FAILURE_MSG("Can't read font dates");
}
if (!table.ReadS16(&file->head->xmin) ||
!table.ReadS16(&file->head->ymin) ||
!table.ReadS16(&file->head->xmax) ||
!table.ReadS16(&file->head->ymax)) {
if (!table.ReadS16(&head->xmin) ||
!table.ReadS16(&head->ymin) ||
!table.ReadS16(&head->xmax) ||
!table.ReadS16(&head->ymax)) {
return OTS_FAILURE_MSG("Failed to read font bounding box");
}
if (file->head->xmin > file->head->xmax) {
return OTS_FAILURE_MSG("Bad x dimension in the font bounding box (%d, %d)", file->head->xmin, file->head->xmax);
if (head->xmin > head->xmax) {
return OTS_FAILURE_MSG("Bad x dimension in the font bounding box (%d, %d)", head->xmin, head->xmax);
}
if (file->head->ymin > file->head->ymax) {
return OTS_FAILURE_MSG("Bad y dimension in the font bounding box (%d, %d)", file->head->ymin, file->head->ymax);
if (head->ymin > head->ymax) {
return OTS_FAILURE_MSG("Bad y dimension in the font bounding box (%d, %d)", head->ymin, head->ymax);
}
if (!table.ReadU16(&file->head->mac_style)) {
if (!table.ReadU16(&head->mac_style)) {
return OTS_FAILURE_MSG("Failed to read font style");
}
// We allow bits 0..6
file->head->mac_style &= 0x7f;
head->mac_style &= 0x7f;
if (!table.ReadU16(&file->head->min_ppem)) {
if (!table.ReadU16(&head->min_ppem)) {
return OTS_FAILURE_MSG("Failed to read font minimum ppm");
}
@ -99,12 +99,12 @@ bool ots_head_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return OTS_FAILURE_MSG("Failed to skip font direction hint");
}
if (!table.ReadS16(&file->head->index_to_loc_format)) {
if (!table.ReadS16(&head->index_to_loc_format)) {
return OTS_FAILURE_MSG("Failed to read index to loc format");
}
if (file->head->index_to_loc_format < 0 ||
file->head->index_to_loc_format > 1) {
return OTS_FAILURE_MSG("Bad index to loc format %d", file->head->index_to_loc_format);
if (head->index_to_loc_format < 0 ||
head->index_to_loc_format > 1) {
return OTS_FAILURE_MSG("Bad index to loc format %d", head->index_to_loc_format);
}
int16_t glyph_data_format;
@ -116,27 +116,28 @@ bool ots_head_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return true;
}
bool ots_head_should_serialise(OpenTypeFile *file) {
return file->head != NULL;
bool ots_head_should_serialise(Font *font) {
return font->head != NULL;
}
bool ots_head_serialise(OTSStream *out, OpenTypeFile *file) {
bool ots_head_serialise(OTSStream *out, Font *font) {
const OpenTypeHEAD *head = font->head;
if (!out->WriteU32(0x00010000) ||
!out->WriteU32(file->head->revision) ||
!out->WriteU32(head->revision) ||
!out->WriteU32(0) || // check sum not filled in yet
!out->WriteU32(0x5F0F3CF5) ||
!out->WriteU16(file->head->flags) ||
!out->WriteU16(file->head->ppem) ||
!out->WriteR64(file->head->created) ||
!out->WriteR64(file->head->modified) ||
!out->WriteS16(file->head->xmin) ||
!out->WriteS16(file->head->ymin) ||
!out->WriteS16(file->head->xmax) ||
!out->WriteS16(file->head->ymax) ||
!out->WriteU16(file->head->mac_style) ||
!out->WriteU16(file->head->min_ppem) ||
!out->WriteU16(head->flags) ||
!out->WriteU16(head->ppem) ||
!out->WriteR64(head->created) ||
!out->WriteR64(head->modified) ||
!out->WriteS16(head->xmin) ||
!out->WriteS16(head->ymin) ||
!out->WriteS16(head->xmax) ||
!out->WriteS16(head->ymax) ||
!out->WriteU16(head->mac_style) ||
!out->WriteU16(head->min_ppem) ||
!out->WriteS16(2) ||
!out->WriteS16(file->head->index_to_loc_format) ||
!out->WriteS16(head->index_to_loc_format) ||
!out->WriteS16(0)) {
return OTS_FAILURE_MSG("Failed to write head table");
}
@ -144,8 +145,13 @@ bool ots_head_serialise(OTSStream *out, OpenTypeFile *file) {
return true;
}
void ots_head_free(OpenTypeFile *file) {
delete file->head;
void ots_head_reuse(Font *font, Font *other) {
font->head = other->head;
font->head_reused = true;
}
void ots_head_free(Font *font) {
delete font->head;
}
} // namespace

View File

@ -14,10 +14,10 @@
namespace ots {
bool ots_hhea_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
bool ots_hhea_parse(Font *font, const uint8_t *data, size_t length) {
Buffer table(data, length);
OpenTypeHHEA *hhea = new OpenTypeHHEA;
file->hhea = hhea;
font->hhea = hhea;
if (!table.ReadU32(&hhea->header.version)) {
return OTS_FAILURE_MSG("Failed to read hhea version");
@ -26,26 +26,31 @@ bool ots_hhea_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return OTS_FAILURE_MSG("Bad hhea version of %d", hhea->header.version);
}
if (!ParseMetricsHeader(file, &table, &hhea->header)) {
if (!ParseMetricsHeader(font, &table, &hhea->header)) {
return OTS_FAILURE_MSG("Failed to parse horizontal metrics");
}
return true;
}
bool ots_hhea_should_serialise(OpenTypeFile *file) {
return file->hhea != NULL;
bool ots_hhea_should_serialise(Font *font) {
return font->hhea != NULL;
}
bool ots_hhea_serialise(OTSStream *out, OpenTypeFile *file) {
if (!SerialiseMetricsHeader(file, out, &file->hhea->header)) {
bool ots_hhea_serialise(OTSStream *out, Font *font) {
if (!SerialiseMetricsHeader(font, out, &font->hhea->header)) {
return OTS_FAILURE_MSG("Failed to serialise horizontal metrics");
}
return true;
}
void ots_hhea_free(OpenTypeFile *file) {
delete file->hhea;
void ots_hhea_reuse(Font *font, Font *other) {
font->hhea = other->hhea;
font->hhea_reused = true;
}
void ots_hhea_free(Font *font) {
delete font->hhea;
}
} // namespace ots

View File

@ -14,36 +14,41 @@
namespace ots {
bool ots_hmtx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
bool ots_hmtx_parse(Font *font, const uint8_t *data, size_t length) {
Buffer table(data, length);
OpenTypeHMTX *hmtx = new OpenTypeHMTX;
file->hmtx = hmtx;
font->hmtx = hmtx;
if (!file->hhea || !file->maxp) {
if (!font->hhea || !font->maxp) {
return OTS_FAILURE_MSG("Missing hhea or maxp tables in font, needed by hmtx");
}
if (!ParseMetricsTable(file, &table, file->maxp->num_glyphs,
&file->hhea->header, &hmtx->metrics)) {
if (!ParseMetricsTable(font, &table, font->maxp->num_glyphs,
&font->hhea->header, &hmtx->metrics)) {
return OTS_FAILURE_MSG("Failed to parse hmtx metrics");
}
return true;
}
bool ots_hmtx_should_serialise(OpenTypeFile *file) {
return file->hmtx != NULL;
bool ots_hmtx_should_serialise(Font *font) {
return font->hmtx != NULL;
}
bool ots_hmtx_serialise(OTSStream *out, OpenTypeFile *file) {
if (!SerialiseMetricsTable(file, out, &file->hmtx->metrics)) {
bool ots_hmtx_serialise(OTSStream *out, Font *font) {
if (!SerialiseMetricsTable(font, out, &font->hmtx->metrics)) {
return OTS_FAILURE_MSG("Failed to serialise htmx metrics");
}
return true;
}
void ots_hmtx_free(OpenTypeFile *file) {
delete file->hmtx;
void ots_hmtx_reuse(Font *font, Font *other) {
font->hmtx = other->hmtx;
font->hmtx_reused = true;
}
void ots_hmtx_free(Font *font) {
delete font->hmtx;
}
} // namespace ots

View File

@ -12,17 +12,17 @@
#define DROP_THIS_TABLE(msg_) \
do { \
OTS_FAILURE_MSG(msg_ ", table discarded"); \
delete file->kern; \
file->kern = 0; \
delete font->kern; \
font->kern = 0; \
} while (0)
namespace ots {
bool ots_kern_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
bool ots_kern_parse(Font *font, const uint8_t *data, size_t length) {
Buffer table(data, length);
OpenTypeKERN *kern = new OpenTypeKERN;
file->kern = kern;
font->kern = kern;
uint16_t num_tables = 0;
if (!table.ReadU16(&kern->version) ||
@ -70,7 +70,7 @@ bool ots_kern_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
continue;
}
if (subtable.coverage & 0xF0) {
DROP_THIS_TABLE("Reserved fields should zero-filled.");
DROP_THIS_TABLE("Reserved fields should zero-filled");
return true;
}
const uint32_t format = (subtable.coverage & 0xFF00) >> 8;
@ -89,7 +89,7 @@ bool ots_kern_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
}
if (!num_pairs) {
DROP_THIS_TABLE("Zero length subtable is found.");
DROP_THIS_TABLE("Zero length subtable is found");
return true;
}
@ -98,7 +98,7 @@ bool ots_kern_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
const size_t kFormat0PairSize = 6; // left, right, and value. 2 bytes each.
if (num_pairs > (65536 / kFormat0PairSize)) {
// Some fonts (e.g. calibri.ttf, pykes_peak_zero.ttf) have pairs >= 10923.
DROP_THIS_TABLE("Too large subtable.");
DROP_THIS_TABLE("Too large subtable");
return true;
}
unsigned max_pow2 = 0;
@ -135,7 +135,7 @@ bool ots_kern_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
if (j != 0 && current_pair <= last_pair) {
// Many free fonts don't follow this rule, so we don't call OTS_FAILURE
// in order to support these fonts.
DROP_THIS_TABLE("Kerning pairs are not sorted.");
DROP_THIS_TABLE("Kerning pairs are not sorted");
return true;
}
last_pair = current_pair;
@ -146,20 +146,20 @@ bool ots_kern_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
}
if (!kern->subtables.size()) {
DROP_THIS_TABLE("All subtables are removed.");
DROP_THIS_TABLE("All subtables are removed");
return true;
}
return true;
}
bool ots_kern_should_serialise(OpenTypeFile *file) {
if (!file->glyf) return false; // this table is not for CFF fonts.
return file->kern != NULL;
bool ots_kern_should_serialise(Font *font) {
if (!font->glyf) return false; // this table is not for CFF fonts.
return font->kern != NULL;
}
bool ots_kern_serialise(OTSStream *out, OpenTypeFile *file) {
const OpenTypeKERN *kern = file->kern;
bool ots_kern_serialise(OTSStream *out, Font *font) {
const OpenTypeKERN *kern = font->kern;
const uint16_t num_subtables = static_cast<uint16_t>(kern->subtables.size());
if (num_subtables != kern->subtables.size() ||
@ -193,8 +193,13 @@ bool ots_kern_serialise(OTSStream *out, OpenTypeFile *file) {
return true;
}
void ots_kern_free(OpenTypeFile *file) {
delete file->kern;
void ots_kern_reuse(Font *font, Font *other) {
font->kern = other->kern;
font->kern_reused = true;
}
void ots_kern_free(Font *font) {
delete font->kern;
}
} // namespace ots

View File

@ -46,7 +46,7 @@ struct FeatureRecord {
uint16_t offset;
};
bool ParseLangSysTable(const ots::OpenTypeFile *file,
bool ParseLangSysTable(const ots::Font *font,
ots::Buffer *subtable, const uint32_t tag,
const uint16_t num_features) {
uint16_t offset_lookup_order = 0;
@ -55,33 +55,33 @@ bool ParseLangSysTable(const ots::OpenTypeFile *file,
if (!subtable->ReadU16(&offset_lookup_order) ||
!subtable->ReadU16(&req_feature_index) ||
!subtable->ReadU16(&feature_count)) {
return OTS_FAILURE_MSG("Failed to read langsys header for tag %4.4s", (char *)&tag);
return OTS_FAILURE_MSG("Failed to read langsys header for tag %c%c%c%c", OTS_UNTAG(tag));
}
// |offset_lookup_order| is reserved and should be NULL.
if (offset_lookup_order != 0) {
return OTS_FAILURE_MSG("Bad lookup offset order %d for langsys tag %4.4s", offset_lookup_order, (char *)&tag);
return OTS_FAILURE_MSG("Bad lookup offset order %d for langsys tag %c%c%c%c", offset_lookup_order, OTS_UNTAG(tag));
}
if (req_feature_index != kNoRequiredFeatureIndexDefined &&
req_feature_index >= num_features) {
return OTS_FAILURE_MSG("Bad required features index %d for langsys tag %4.4s", req_feature_index, (char *)&tag);
return OTS_FAILURE_MSG("Bad required features index %d for langsys tag %c%c%c%c", req_feature_index, OTS_UNTAG(tag));
}
if (feature_count > num_features) {
return OTS_FAILURE_MSG("Bad feature count %d for langsys tag %4.4s", feature_count, (char *)&tag);
return OTS_FAILURE_MSG("Bad feature count %d for langsys tag %c%c%c%c", feature_count, OTS_UNTAG(tag));
}
for (unsigned i = 0; i < feature_count; ++i) {
uint16_t feature_index = 0;
if (!subtable->ReadU16(&feature_index)) {
return OTS_FAILURE_MSG("Failed to read feature index %d for langsys tag %4.4s", i, (char *)&tag);
return OTS_FAILURE_MSG("Failed to read feature index %d for langsys tag %c%c%c%c", i, OTS_UNTAG(tag));
}
if (feature_index >= num_features) {
return OTS_FAILURE_MSG("Bad feature index %d for feature %d for langsys tag %4.4s", feature_index, i, (char *)&tag);
return OTS_FAILURE_MSG("Bad feature index %d for feature %d for langsys tag %c%c%c%c", feature_index, i, OTS_UNTAG(tag));
}
}
return true;
}
bool ParseScriptTable(const ots::OpenTypeFile *file,
bool ParseScriptTable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint32_t tag, const uint16_t num_features) {
ots::Buffer subtable(data, length);
@ -90,20 +90,20 @@ bool ParseScriptTable(const ots::OpenTypeFile *file,
uint16_t lang_sys_count = 0;
if (!subtable.ReadU16(&offset_default_lang_sys) ||
!subtable.ReadU16(&lang_sys_count)) {
return OTS_FAILURE_MSG("Failed to read script header for script tag %4.4s", (char *)&tag);
return OTS_FAILURE_MSG("Failed to read script header for script tag %c%c%c%c", OTS_UNTAG(tag));
}
// The spec requires a script table for 'DFLT' tag must contain non-NULL
// |offset_default_lang_sys| and |lang_sys_count| == 0
if (tag == kScriptTableTagDflt &&
(offset_default_lang_sys == 0 || lang_sys_count != 0)) {
return OTS_FAILURE_MSG("DFLT table doesn't satisfy the spec. for script tag %4.4s", (char *)&tag);
return OTS_FAILURE_MSG("DFLT table doesn't satisfy the spec. for script tag %c%c%c%c", OTS_UNTAG(tag));
}
const unsigned lang_sys_record_end =
6 * static_cast<unsigned>(lang_sys_count) + 4;
if (lang_sys_record_end > std::numeric_limits<uint16_t>::max()) {
return OTS_FAILURE_MSG("Bad end of langsys record %d for script tag %4.4s", lang_sys_record_end, (char *)&tag);
return OTS_FAILURE_MSG("Bad end of langsys record %d for script tag %c%c%c%c", lang_sys_record_end, OTS_UNTAG(tag));
}
std::vector<LangSysRecord> lang_sys_records;
@ -112,11 +112,11 @@ bool ParseScriptTable(const ots::OpenTypeFile *file,
for (unsigned i = 0; i < lang_sys_count; ++i) {
if (!subtable.ReadU32(&lang_sys_records[i].tag) ||
!subtable.ReadU16(&lang_sys_records[i].offset)) {
return OTS_FAILURE_MSG("Failed to read langsys record header %d for script tag %4.4s", i, (char *)&tag);
return OTS_FAILURE_MSG("Failed to read langsys record header %d for script tag %c%c%c%c", i, OTS_UNTAG(tag));
}
// The record array must store the records alphabetically by tag
if (last_tag != 0 && last_tag > lang_sys_records[i].tag) {
return OTS_FAILURE_MSG("Bad last tag %d for langsys record %d for script tag %4.4s", last_tag, i, (char *)&tag);
return OTS_FAILURE_MSG("Bad last tag %d for langsys record %d for script tag %c%c%c%c", last_tag, i, OTS_UNTAG(tag));
}
if (lang_sys_records[i].offset < lang_sys_record_end ||
lang_sys_records[i].offset >= length) {
@ -129,15 +129,15 @@ bool ParseScriptTable(const ots::OpenTypeFile *file,
// Check lang sys tables
for (unsigned i = 0; i < lang_sys_count; ++i) {
subtable.set_offset(lang_sys_records[i].offset);
if (!ParseLangSysTable(file, &subtable, lang_sys_records[i].tag, num_features)) {
return OTS_FAILURE_MSG("Failed to parse langsys table %d (%4.4s) for script tag %4.4s", i, (char *)&lang_sys_records[i].tag, (char *)&tag);
if (!ParseLangSysTable(font, &subtable, lang_sys_records[i].tag, num_features)) {
return OTS_FAILURE_MSG("Failed to parse langsys table %d (%c%c%c%c) for script tag %c%c%c%c", i, OTS_UNTAG(lang_sys_records[i].tag), OTS_UNTAG(tag));
}
}
return true;
}
bool ParseFeatureTable(const ots::OpenTypeFile *file,
bool ParseFeatureTable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_lookups) {
ots::Buffer subtable(data, length);
@ -174,7 +174,7 @@ bool ParseFeatureTable(const ots::OpenTypeFile *file,
return true;
}
bool ParseLookupTable(ots::OpenTypeFile *file, const uint8_t *data,
bool ParseLookupTable(ots::Font *font, const uint8_t *data,
const size_t length,
const ots::LookupSubtableParser* parser) {
ots::Buffer subtable(data, length);
@ -194,16 +194,16 @@ bool ParseLookupTable(ots::OpenTypeFile *file, const uint8_t *data,
// Check lookup flags.
if ((lookup_flag & kGdefRequiredFlags) &&
(!file->gdef || !file->gdef->has_glyph_class_def)) {
(!font->gdef || !font->gdef->has_glyph_class_def)) {
return OTS_FAILURE_MSG("Bad lookup flags %d", lookup_flag);
}
if ((lookup_flag & kMarkAttachmentTypeMask) &&
(!file->gdef || !file->gdef->has_mark_attachment_class_def)) {
(!font->gdef || !font->gdef->has_mark_attachment_class_def)) {
return OTS_FAILURE_MSG("lookup flag asks for mark attachment that is bad %d", lookup_flag);
}
bool use_mark_filtering_set = false;
if (lookup_flag & kUseMarkFilteringSetBit) {
if (!file->gdef || !file->gdef->has_mark_glyph_sets_def) {
if (!font->gdef || !font->gdef->has_mark_glyph_sets_def) {
return OTS_FAILURE_MSG("lookup flag asks for mark filtering that is bad %d", lookup_flag);
}
use_mark_filtering_set = true;
@ -238,15 +238,15 @@ bool ParseLookupTable(ots::OpenTypeFile *file, const uint8_t *data,
if (!subtable.ReadU16(&mark_filtering_set)) {
return OTS_FAILURE_MSG("Failed to read mark filtering set");
}
if (file->gdef->num_mark_glyph_sets == 0 ||
mark_filtering_set >= file->gdef->num_mark_glyph_sets) {
if (font->gdef->num_mark_glyph_sets == 0 ||
mark_filtering_set >= font->gdef->num_mark_glyph_sets) {
return OTS_FAILURE_MSG("Bad mark filtering set %d", mark_filtering_set);
}
}
// Parse lookup subtables for this lookup type.
for (unsigned i = 0; i < subtable_count; ++i) {
if (!parser->Parse(file, data + subtables[i], length - subtables[i],
if (!parser->Parse(font, data + subtables[i], length - subtables[i],
lookup_type)) {
return OTS_FAILURE_MSG("Failed to parse subtable %d", i);
}
@ -254,7 +254,7 @@ bool ParseLookupTable(ots::OpenTypeFile *file, const uint8_t *data,
return true;
}
bool ParseClassDefFormat1(const ots::OpenTypeFile *file,
bool ParseClassDefFormat1(const ots::Font *font,
const uint8_t *data, size_t length,
const uint16_t num_glyphs,
const uint16_t num_classes) {
@ -293,7 +293,7 @@ bool ParseClassDefFormat1(const ots::OpenTypeFile *file,
return true;
}
bool ParseClassDefFormat2(const ots::OpenTypeFile *file,
bool ParseClassDefFormat2(const ots::Font *font,
const uint8_t *data, size_t length,
const uint16_t num_glyphs,
const uint16_t num_classes) {
@ -334,7 +334,7 @@ bool ParseClassDefFormat2(const ots::OpenTypeFile *file,
return true;
}
bool ParseCoverageFormat1(const ots::OpenTypeFile *file,
bool ParseCoverageFormat1(const ots::Font *font,
const uint8_t *data, size_t length,
const uint16_t num_glyphs,
const uint16_t expected_num_glyphs) {
@ -369,7 +369,7 @@ bool ParseCoverageFormat1(const ots::OpenTypeFile *file,
return true;
}
bool ParseCoverageFormat2(const ots::OpenTypeFile *file,
bool ParseCoverageFormat2(const ots::Font *font,
const uint8_t *data, size_t length,
const uint16_t num_glyphs,
const uint16_t expected_num_glyphs) {
@ -423,7 +423,7 @@ bool ParseCoverageFormat2(const ots::OpenTypeFile *file,
// Parsers for Contextual subtables in GSUB/GPOS tables.
bool ParseLookupRecord(const ots::OpenTypeFile *file,
bool ParseLookupRecord(const ots::Font *font,
ots::Buffer *subtable, const uint16_t num_glyphs,
const uint16_t num_lookups) {
uint16_t sequence_index = 0;
@ -441,7 +441,7 @@ bool ParseLookupRecord(const ots::OpenTypeFile *file,
return true;
}
bool ParseRuleSubtable(const ots::OpenTypeFile *file,
bool ParseRuleSubtable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs,
const uint16_t num_lookups) {
@ -468,14 +468,14 @@ bool ParseRuleSubtable(const ots::OpenTypeFile *file,
}
for (unsigned i = 0; i < lookup_count; ++i) {
if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) {
return OTS_FAILURE_MSG("Failed to parse lookup record %d", i);
}
}
return true;
}
bool ParseRuleSetTable(const ots::OpenTypeFile *file,
bool ParseRuleSetTable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs,
const uint16_t num_lookups) {
@ -498,7 +498,7 @@ bool ParseRuleSetTable(const ots::OpenTypeFile *file,
if (offset_rule < rule_end || offset_rule >= length) {
return OTS_FAILURE_MSG("Bad rule offset %d in set %d", offset_rule, i);
}
if (!ParseRuleSubtable(file, data + offset_rule, length - offset_rule,
if (!ParseRuleSubtable(font, data + offset_rule, length - offset_rule,
num_glyphs, num_lookups)) {
return OTS_FAILURE_MSG("Failed to parse rule set %d", i);
}
@ -507,7 +507,7 @@ bool ParseRuleSetTable(const ots::OpenTypeFile *file,
return true;
}
bool ParseContextFormat1(const ots::OpenTypeFile *file,
bool ParseContextFormat1(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs,
const uint16_t num_lookups) {
@ -530,7 +530,7 @@ bool ParseContextFormat1(const ots::OpenTypeFile *file,
if (offset_coverage < rule_set_end || offset_coverage >= length) {
return OTS_FAILURE_MSG("Bad coverage offset %d in context format 1", offset_coverage);
}
if (!ots::ParseCoverageTable(file, data + offset_coverage,
if (!ots::ParseCoverageTable(font, data + offset_coverage,
length - offset_coverage, num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse coverage table in context format 1");
}
@ -543,7 +543,7 @@ bool ParseContextFormat1(const ots::OpenTypeFile *file,
if (offset_rule < rule_set_end || offset_rule >= length) {
return OTS_FAILURE_MSG("Bad rule offset %d in rule %d in context format 1", offset_rule, i);
}
if (!ParseRuleSetTable(file, data + offset_rule, length - offset_rule,
if (!ParseRuleSetTable(font, data + offset_rule, length - offset_rule,
num_glyphs, num_lookups)) {
return OTS_FAILURE_MSG("Failed to parse rule set %d in context format 1", i);
}
@ -552,7 +552,7 @@ bool ParseContextFormat1(const ots::OpenTypeFile *file,
return true;
}
bool ParseClassRuleTable(const ots::OpenTypeFile *file,
bool ParseClassRuleTable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs,
const uint16_t num_lookups) {
@ -577,14 +577,14 @@ bool ParseClassRuleTable(const ots::OpenTypeFile *file,
}
for (unsigned i = 0; i < lookup_count; ++i) {
if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) {
return OTS_FAILURE_MSG("Failed to parse lookup record %d in class rule table", i);
}
}
return true;
}
bool ParseClassSetTable(const ots::OpenTypeFile *file,
bool ParseClassSetTable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs,
const uint16_t num_lookups) {
@ -607,7 +607,7 @@ bool ParseClassSetTable(const ots::OpenTypeFile *file,
if (offset_class_rule < class_rule_end || offset_class_rule >= length) {
return OTS_FAILURE_MSG("Bad class rule offset %d in class %d", offset_class_rule, i);
}
if (!ParseClassRuleTable(file, data + offset_class_rule,
if (!ParseClassRuleTable(font, data + offset_class_rule,
length - offset_class_rule, num_glyphs,
num_lookups)) {
return OTS_FAILURE_MSG("Failed to parse class rule table %d", i);
@ -617,7 +617,7 @@ bool ParseClassSetTable(const ots::OpenTypeFile *file,
return true;
}
bool ParseContextFormat2(const ots::OpenTypeFile *file,
bool ParseContextFormat2(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs,
const uint16_t num_lookups) {
@ -641,7 +641,7 @@ bool ParseContextFormat2(const ots::OpenTypeFile *file,
if (offset_coverage < class_set_end || offset_coverage >= length) {
return OTS_FAILURE_MSG("Bad coverage offset %d in context format 2", offset_coverage);
}
if (!ots::ParseCoverageTable(file, data + offset_coverage,
if (!ots::ParseCoverageTable(font, data + offset_coverage,
length - offset_coverage, num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse coverage table in context format 2");
}
@ -649,7 +649,7 @@ bool ParseContextFormat2(const ots::OpenTypeFile *file,
if (offset_class_def < class_set_end || offset_class_def >= length) {
return OTS_FAILURE_MSG("bad class definition offset %d in context format 2", offset_class_def);
}
if (!ots::ParseClassDefTable(file, data + offset_class_def,
if (!ots::ParseClassDefTable(font, data + offset_class_def,
length - offset_class_def,
num_glyphs, kMaxClassDefValue)) {
return OTS_FAILURE_MSG("Failed to parse class definition table in context format 2");
@ -664,7 +664,7 @@ bool ParseContextFormat2(const ots::OpenTypeFile *file,
if (offset_class_rule < class_set_end || offset_class_rule >= length) {
return OTS_FAILURE_MSG("Bad class rule offset %d for rule %d in context format 2", offset_class_rule, i);
}
if (!ParseClassSetTable(file, data + offset_class_rule,
if (!ParseClassSetTable(font, data + offset_class_rule,
length - offset_class_rule, num_glyphs,
num_lookups)) {
return OTS_FAILURE_MSG("Failed to parse class set %d in context format 2", i);
@ -675,7 +675,7 @@ bool ParseContextFormat2(const ots::OpenTypeFile *file,
return true;
}
bool ParseContextFormat3(const ots::OpenTypeFile *file,
bool ParseContextFormat3(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs,
const uint16_t num_lookups) {
@ -706,14 +706,14 @@ bool ParseContextFormat3(const ots::OpenTypeFile *file,
if (offset_coverage < lookup_record_end || offset_coverage >= length) {
return OTS_FAILURE_MSG("Bad coverage offset %d for glyph %d in context format 3", offset_coverage, i);
}
if (!ots::ParseCoverageTable(file, data + offset_coverage,
if (!ots::ParseCoverageTable(font, data + offset_coverage,
length - offset_coverage, num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse coverage table for glyph %d in context format 3", i);
}
}
for (unsigned i = 0; i < lookup_count; ++i) {
if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) {
return OTS_FAILURE_MSG("Failed to parse lookup record %d in context format 3", i);
}
}
@ -723,7 +723,7 @@ bool ParseContextFormat3(const ots::OpenTypeFile *file,
// Parsers for Chaning Contextual subtables in GSUB/GPOS tables.
bool ParseChainRuleSubtable(const ots::OpenTypeFile *file,
bool ParseChainRuleSubtable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs,
const uint16_t num_lookups) {
@ -785,7 +785,7 @@ bool ParseChainRuleSubtable(const ots::OpenTypeFile *file,
return OTS_FAILURE_MSG("Failed to read lookup count in chain rule subtable");
}
for (unsigned i = 0; i < lookup_count; ++i) {
if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) {
return OTS_FAILURE_MSG("Failed to parse lookup record %d in chain rule subtable", i);
}
}
@ -793,7 +793,7 @@ bool ParseChainRuleSubtable(const ots::OpenTypeFile *file,
return true;
}
bool ParseChainRuleSetTable(const ots::OpenTypeFile *file,
bool ParseChainRuleSetTable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs,
const uint16_t num_lookups) {
@ -816,7 +816,7 @@ bool ParseChainRuleSetTable(const ots::OpenTypeFile *file,
if (offset_chain_rule < chain_rule_end || offset_chain_rule >= length) {
return OTS_FAILURE_MSG("Bad chain rule offset %d for chain rule %d in chain rule set", offset_chain_rule, i);
}
if (!ParseChainRuleSubtable(file, data + offset_chain_rule,
if (!ParseChainRuleSubtable(font, data + offset_chain_rule,
length - offset_chain_rule,
num_glyphs, num_lookups)) {
return OTS_FAILURE_MSG("Failed to parse chain rule %d in chain rule set", i);
@ -826,7 +826,7 @@ bool ParseChainRuleSetTable(const ots::OpenTypeFile *file,
return true;
}
bool ParseChainContextFormat1(const ots::OpenTypeFile *file,
bool ParseChainContextFormat1(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs,
const uint16_t num_lookups) {
@ -849,7 +849,7 @@ bool ParseChainContextFormat1(const ots::OpenTypeFile *file,
if (offset_coverage < chain_rule_set_end || offset_coverage >= length) {
return OTS_FAILURE_MSG("Bad coverage offset %d in chain context format 1", chain_rule_set_end);
}
if (!ots::ParseCoverageTable(file, data + offset_coverage,
if (!ots::ParseCoverageTable(font, data + offset_coverage,
length - offset_coverage, num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse coverage table for chain context format 1");
}
@ -863,7 +863,7 @@ bool ParseChainContextFormat1(const ots::OpenTypeFile *file,
offset_chain_rule_set >= length) {
return OTS_FAILURE_MSG("Bad chain rule set offset %d for chain rule set %d in chain context format 1", offset_chain_rule_set, i);
}
if (!ParseChainRuleSetTable(file, data + offset_chain_rule_set,
if (!ParseChainRuleSetTable(font, data + offset_chain_rule_set,
length - offset_chain_rule_set,
num_glyphs, num_lookups)) {
return OTS_FAILURE_MSG("Failed to parse chain rule set %d in chain context format 1", i);
@ -873,7 +873,7 @@ bool ParseChainContextFormat1(const ots::OpenTypeFile *file,
return true;
}
bool ParseChainClassRuleSubtable(const ots::OpenTypeFile *file,
bool ParseChainClassRuleSubtable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs,
const uint16_t num_lookups) {
@ -920,7 +920,7 @@ bool ParseChainClassRuleSubtable(const ots::OpenTypeFile *file,
return OTS_FAILURE_MSG("Failed to read lookup count in chain class rule subtable");
}
for (unsigned i = 0; i < lookup_count; ++i) {
if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) {
return OTS_FAILURE_MSG("Failed to parse lookup record %d in chain class rule subtable", i);
}
}
@ -928,7 +928,7 @@ bool ParseChainClassRuleSubtable(const ots::OpenTypeFile *file,
return true;
}
bool ParseChainClassSetTable(const ots::OpenTypeFile *file,
bool ParseChainClassSetTable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs,
const uint16_t num_lookups) {
@ -952,7 +952,7 @@ bool ParseChainClassSetTable(const ots::OpenTypeFile *file,
offset_chain_class_rule >= length) {
return OTS_FAILURE_MSG("Bad chain class rule offset %d for chain class %d in chain class set", offset_chain_class_rule, i);
}
if (!ParseChainClassRuleSubtable(file, data + offset_chain_class_rule,
if (!ParseChainClassRuleSubtable(font, data + offset_chain_class_rule,
length - offset_chain_class_rule,
num_glyphs, num_lookups)) {
return OTS_FAILURE_MSG("Failed to parse chain class rule %d in chain class set", i);
@ -962,7 +962,7 @@ bool ParseChainClassSetTable(const ots::OpenTypeFile *file,
return true;
}
bool ParseChainContextFormat2(const ots::OpenTypeFile *file,
bool ParseChainContextFormat2(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs,
const uint16_t num_lookups) {
@ -991,7 +991,7 @@ bool ParseChainContextFormat2(const ots::OpenTypeFile *file,
if (offset_coverage < chain_class_set_end || offset_coverage >= length) {
return OTS_FAILURE_MSG("Bad coverage offset %d in chain context format 2", offset_coverage);
}
if (!ots::ParseCoverageTable(file, data + offset_coverage,
if (!ots::ParseCoverageTable(font, data + offset_coverage,
length - offset_coverage, num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse coverage table in chain context format 2");
}
@ -1002,7 +1002,7 @@ bool ParseChainContextFormat2(const ots::OpenTypeFile *file,
offset_backtrack_class_def >= length) {
return OTS_FAILURE_MSG("Bad backtrack class offset %d in chain context format 2", offset_backtrack_class_def);
}
if (!ots::ParseClassDefTable(file, data + offset_backtrack_class_def,
if (!ots::ParseClassDefTable(font, data + offset_backtrack_class_def,
length - offset_backtrack_class_def,
num_glyphs, kMaxClassDefValue)) {
return OTS_FAILURE_MSG("Failed to parse backtrack class defn table in chain context format 2");
@ -1013,7 +1013,7 @@ bool ParseChainContextFormat2(const ots::OpenTypeFile *file,
offset_input_class_def >= length) {
return OTS_FAILURE_MSG("Bad input class defn offset %d in chain context format 2", offset_input_class_def);
}
if (!ots::ParseClassDefTable(file, data + offset_input_class_def,
if (!ots::ParseClassDefTable(font, data + offset_input_class_def,
length - offset_input_class_def,
num_glyphs, kMaxClassDefValue)) {
return OTS_FAILURE_MSG("Failed to parse input class defn in chain context format 2");
@ -1024,7 +1024,7 @@ bool ParseChainContextFormat2(const ots::OpenTypeFile *file,
offset_lookahead_class_def >= length) {
return OTS_FAILURE_MSG("Bad lookahead class defn offset %d in chain context format 2", offset_lookahead_class_def);
}
if (!ots::ParseClassDefTable(file, data + offset_lookahead_class_def,
if (!ots::ParseClassDefTable(font, data + offset_lookahead_class_def,
length - offset_lookahead_class_def,
num_glyphs, kMaxClassDefValue)) {
return OTS_FAILURE_MSG("Failed to parse lookahead class defn in chain context format 2");
@ -1042,7 +1042,7 @@ bool ParseChainContextFormat2(const ots::OpenTypeFile *file,
offset_chain_class_set >= length) {
return OTS_FAILURE_MSG("Bad chain set class offset %d for chain set %d in chain context format 2", offset_chain_class_set, i);
}
if (!ParseChainClassSetTable(file, data + offset_chain_class_set,
if (!ParseChainClassSetTable(font, data + offset_chain_class_set,
length - offset_chain_class_set,
num_glyphs, num_lookups)) {
return OTS_FAILURE_MSG("Failed to parse chain class set table %d in chain context format 2", i);
@ -1053,7 +1053,7 @@ bool ParseChainContextFormat2(const ots::OpenTypeFile *file,
return true;
}
bool ParseChainContextFormat3(const ots::OpenTypeFile *file,
bool ParseChainContextFormat3(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs,
const uint16_t num_lookups) {
@ -1127,7 +1127,7 @@ bool ParseChainContextFormat3(const ots::OpenTypeFile *file,
return OTS_FAILURE_MSG("Failed to read lookup count in chain context format 3");
}
for (unsigned i = 0; i < lookup_count; ++i) {
if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
if (!ParseLookupRecord(font, &subtable, num_glyphs, num_lookups)) {
return OTS_FAILURE_MSG("Failed to parse lookup %d in chain context format 3", i);
}
}
@ -1145,7 +1145,7 @@ bool ParseChainContextFormat3(const ots::OpenTypeFile *file,
offsets_backtrack[i] >= length) {
return OTS_FAILURE_MSG("Bad backtrack offset of %d for backtrack %d in chain context format 3", offsets_backtrack[i], i);
}
if (!ots::ParseCoverageTable(file, data + offsets_backtrack[i],
if (!ots::ParseCoverageTable(font, data + offsets_backtrack[i],
length - offsets_backtrack[i], num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse backtrack coverage %d in chain context format 3", i);
}
@ -1154,7 +1154,7 @@ bool ParseChainContextFormat3(const ots::OpenTypeFile *file,
if (offsets_input[i] < lookup_record_end || offsets_input[i] >= length) {
return OTS_FAILURE_MSG("Bad input offset %d for input %d in chain context format 3", offsets_input[i], i);
}
if (!ots::ParseCoverageTable(file, data + offsets_input[i],
if (!ots::ParseCoverageTable(font, data + offsets_input[i],
length - offsets_input[i], num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse input coverage table %d in chain context format 3", i);
}
@ -1164,7 +1164,7 @@ bool ParseChainContextFormat3(const ots::OpenTypeFile *file,
offsets_lookahead[i] >= length) {
return OTS_FAILURE_MSG("Bad lookadhead offset %d for lookahead %d in chain context format 3", offsets_lookahead[i], i);
}
if (!ots::ParseCoverageTable(file, data + offsets_lookahead[i],
if (!ots::ParseCoverageTable(font, data + offsets_lookahead[i],
length - offsets_lookahead[i], num_glyphs)) {
return OTS_FAILURE_MSG("Failed to parse lookahead coverage table %d in chain context format 3", i);
}
@ -1177,12 +1177,12 @@ bool ParseChainContextFormat3(const ots::OpenTypeFile *file,
namespace ots {
bool LookupSubtableParser::Parse(const OpenTypeFile *file, const uint8_t *data,
bool LookupSubtableParser::Parse(const Font *font, const uint8_t *data,
const size_t length,
const uint16_t lookup_type) const {
for (unsigned i = 0; i < num_types; ++i) {
if (parsers[i].type == lookup_type && parsers[i].parse) {
if (!parsers[i].parse(file, data, length)) {
if (!parsers[i].parse(font, data, length)) {
return OTS_FAILURE_MSG("Failed to parse lookup subtable %d", i);
}
return true;
@ -1193,7 +1193,7 @@ bool LookupSubtableParser::Parse(const OpenTypeFile *file, const uint8_t *data,
// Parsing ScriptListTable requires number of features so we need to
// parse FeatureListTable before calling this function.
bool ParseScriptListTable(const ots::OpenTypeFile *file,
bool ParseScriptListTable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_features) {
Buffer subtable(data, length);
@ -1226,7 +1226,7 @@ bool ParseScriptListTable(const ots::OpenTypeFile *file,
}
last_tag = record.tag;
if (record.offset < script_record_end || record.offset >= length) {
return OTS_FAILURE_MSG("Bad record offset %d for script %4.4s entry %d in script list table", record.offset, (char *)&record.tag, i);
return OTS_FAILURE_MSG("Bad record offset %d for script %c%c%c%c entry %d in script list table", record.offset, OTS_UNTAG(record.tag), i);
}
script_list.push_back(record);
}
@ -1236,7 +1236,7 @@ bool ParseScriptListTable(const ots::OpenTypeFile *file,
// Check script records.
for (unsigned i = 0; i < script_count; ++i) {
if (!ParseScriptTable(file, data + script_list[i].offset,
if (!ParseScriptTable(font, data + script_list[i].offset,
length - script_list[i].offset,
script_list[i].tag, num_features)) {
return OTS_FAILURE_MSG("Failed to parse script table %d", i);
@ -1248,7 +1248,7 @@ bool ParseScriptListTable(const ots::OpenTypeFile *file,
// Parsing FeatureListTable requires number of lookups so we need to parse
// LookupListTable before calling this function.
bool ParseFeatureListTable(const ots::OpenTypeFile *file,
bool ParseFeatureListTable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_lookups,
uint16_t* num_features) {
@ -1282,12 +1282,12 @@ bool ParseFeatureListTable(const ots::OpenTypeFile *file,
last_tag = feature_records[i].tag;
if (feature_records[i].offset < feature_record_end ||
feature_records[i].offset >= length) {
return OTS_FAILURE_MSG("Bad feature offset %d for feature %d %4.4s", feature_records[i].offset, i, (char *)&feature_records[i].tag);
return OTS_FAILURE_MSG("Bad feature offset %d for feature %d %c%c%c%c", feature_records[i].offset, i, OTS_UNTAG(feature_records[i].tag));
}
}
for (unsigned i = 0; i < feature_count; ++i) {
if (!ParseFeatureTable(file, data + feature_records[i].offset,
if (!ParseFeatureTable(font, data + feature_records[i].offset,
length - feature_records[i].offset, num_lookups)) {
return OTS_FAILURE_MSG("Failed to parse feature table %d", i);
}
@ -1299,7 +1299,7 @@ bool ParseFeatureListTable(const ots::OpenTypeFile *file,
// For parsing GPOS/GSUB tables, this function should be called at first to
// obtain the number of lookups because parsing FeatureTableList requires
// the number.
bool ParseLookupListTable(OpenTypeFile *file, const uint8_t *data,
bool ParseLookupListTable(Font *font, const uint8_t *data,
const size_t length,
const LookupSubtableParser* parser,
uint16_t *num_lookups) {
@ -1331,7 +1331,7 @@ bool ParseLookupListTable(OpenTypeFile *file, const uint8_t *data,
}
for (unsigned i = 0; i < *num_lookups; ++i) {
if (!ParseLookupTable(file, data + lookups[i], length - lookups[i],
if (!ParseLookupTable(font, data + lookups[i], length - lookups[i],
parser)) {
return OTS_FAILURE_MSG("Failed to parse lookup %d", i);
}
@ -1340,7 +1340,7 @@ bool ParseLookupListTable(OpenTypeFile *file, const uint8_t *data,
return true;
}
bool ParseClassDefTable(const ots::OpenTypeFile *file,
bool ParseClassDefTable(const ots::Font *font,
const uint8_t *data, size_t length,
const uint16_t num_glyphs,
const uint16_t num_classes) {
@ -1351,15 +1351,15 @@ bool ParseClassDefTable(const ots::OpenTypeFile *file,
return OTS_FAILURE_MSG("Failed to read class defn format");
}
if (format == 1) {
return ParseClassDefFormat1(file, data, length, num_glyphs, num_classes);
return ParseClassDefFormat1(font, data, length, num_glyphs, num_classes);
} else if (format == 2) {
return ParseClassDefFormat2(file, data, length, num_glyphs, num_classes);
return ParseClassDefFormat2(font, data, length, num_glyphs, num_classes);
}
return OTS_FAILURE_MSG("Bad class defn format %d", format);
}
bool ParseCoverageTable(const ots::OpenTypeFile *file,
bool ParseCoverageTable(const ots::Font *font,
const uint8_t *data, size_t length,
const uint16_t num_glyphs,
const uint16_t expected_num_glyphs) {
@ -1370,15 +1370,15 @@ bool ParseCoverageTable(const ots::OpenTypeFile *file,
return OTS_FAILURE_MSG("Failed to read coverage table format");
}
if (format == 1) {
return ParseCoverageFormat1(file, data, length, num_glyphs, expected_num_glyphs);
return ParseCoverageFormat1(font, data, length, num_glyphs, expected_num_glyphs);
} else if (format == 2) {
return ParseCoverageFormat2(file, data, length, num_glyphs, expected_num_glyphs);
return ParseCoverageFormat2(font, data, length, num_glyphs, expected_num_glyphs);
}
return OTS_FAILURE_MSG("Bad coverage table format %d", format);
}
bool ParseDeviceTable(const ots::OpenTypeFile *file,
bool ParseDeviceTable(const ots::Font *font,
const uint8_t *data, size_t length) {
Buffer subtable(data, length);
@ -1408,7 +1408,7 @@ bool ParseDeviceTable(const ots::OpenTypeFile *file,
return true;
}
bool ParseContextSubtable(const ots::OpenTypeFile *file,
bool ParseContextSubtable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs,
const uint16_t num_lookups) {
@ -1420,15 +1420,15 @@ bool ParseContextSubtable(const ots::OpenTypeFile *file,
}
if (format == 1) {
if (!ParseContextFormat1(file, data, length, num_glyphs, num_lookups)) {
if (!ParseContextFormat1(font, data, length, num_glyphs, num_lookups)) {
return OTS_FAILURE_MSG("Failed to parse context format 1 subtable");
}
} else if (format == 2) {
if (!ParseContextFormat2(file, data, length, num_glyphs, num_lookups)) {
if (!ParseContextFormat2(font, data, length, num_glyphs, num_lookups)) {
return OTS_FAILURE_MSG("Failed to parse context format 2 subtable");
}
} else if (format == 3) {
if (!ParseContextFormat3(file, data, length, num_glyphs, num_lookups)) {
if (!ParseContextFormat3(font, data, length, num_glyphs, num_lookups)) {
return OTS_FAILURE_MSG("Failed to parse context format 3 subtable");
}
} else {
@ -1438,7 +1438,7 @@ bool ParseContextSubtable(const ots::OpenTypeFile *file,
return true;
}
bool ParseChainingContextSubtable(const ots::OpenTypeFile *file,
bool ParseChainingContextSubtable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs,
const uint16_t num_lookups) {
@ -1450,15 +1450,15 @@ bool ParseChainingContextSubtable(const ots::OpenTypeFile *file,
}
if (format == 1) {
if (!ParseChainContextFormat1(file, data, length, num_glyphs, num_lookups)) {
if (!ParseChainContextFormat1(font, data, length, num_glyphs, num_lookups)) {
return OTS_FAILURE_MSG("Failed to parse chaining context format 1 subtable");
}
} else if (format == 2) {
if (!ParseChainContextFormat2(file, data, length, num_glyphs, num_lookups)) {
if (!ParseChainContextFormat2(font, data, length, num_glyphs, num_lookups)) {
return OTS_FAILURE_MSG("Failed to parse chaining context format 2 subtable");
}
} else if (format == 3) {
if (!ParseChainContextFormat3(file, data, length, num_glyphs, num_lookups)) {
if (!ParseChainContextFormat3(font, data, length, num_glyphs, num_lookups)) {
return OTS_FAILURE_MSG("Failed to parse chaining context format 3 subtable");
}
} else {
@ -1468,7 +1468,7 @@ bool ParseChainingContextSubtable(const ots::OpenTypeFile *file,
return true;
}
bool ParseExtensionSubtable(const OpenTypeFile *file,
bool ParseExtensionSubtable(const Font *font,
const uint8_t *data, const size_t length,
const LookupSubtableParser* parser) {
Buffer subtable(data, length);
@ -1498,7 +1498,7 @@ bool ParseExtensionSubtable(const OpenTypeFile *file,
}
// Parse the extension subtable of |lookup_type|.
if (!parser->Parse(file, data + offset_extension, length - offset_extension,
if (!parser->Parse(font, data + offset_extension, length - offset_extension,
lookup_type)) {
return OTS_FAILURE_MSG("Failed to parse lookup from extension lookup");
}

View File

@ -16,57 +16,57 @@ namespace ots {
struct LookupSubtableParser {
struct TypeParser {
uint16_t type;
bool (*parse)(const OpenTypeFile *file, const uint8_t *data,
bool (*parse)(const Font *font, const uint8_t *data,
const size_t length);
};
size_t num_types;
uint16_t extension_type;
const TypeParser *parsers;
bool Parse(const OpenTypeFile *file, const uint8_t *data,
bool Parse(const Font *font, const uint8_t *data,
const size_t length, const uint16_t lookup_type) const;
};
bool ParseScriptListTable(const ots::OpenTypeFile *file,
bool ParseScriptListTable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_features);
bool ParseFeatureListTable(const ots::OpenTypeFile *file,
bool ParseFeatureListTable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_lookups,
uint16_t *num_features);
bool ParseLookupListTable(OpenTypeFile *file, const uint8_t *data,
bool ParseLookupListTable(Font *font, const uint8_t *data,
const size_t length,
const LookupSubtableParser* parser,
uint16_t* num_lookups);
bool ParseClassDefTable(const ots::OpenTypeFile *file,
bool ParseClassDefTable(const ots::Font *font,
const uint8_t *data, size_t length,
const uint16_t num_glyphs,
const uint16_t num_classes);
bool ParseCoverageTable(const ots::OpenTypeFile *file,
bool ParseCoverageTable(const ots::Font *font,
const uint8_t *data, size_t length,
const uint16_t num_glyphs,
const uint16_t expected_num_glyphs = 0);
bool ParseDeviceTable(const ots::OpenTypeFile *file,
bool ParseDeviceTable(const ots::Font *font,
const uint8_t *data, size_t length);
// Parser for 'Contextual' subtable shared by GSUB/GPOS tables.
bool ParseContextSubtable(const ots::OpenTypeFile *file,
bool ParseContextSubtable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs,
const uint16_t num_lookups);
// Parser for 'Chaining Contextual' subtable shared by GSUB/GPOS tables.
bool ParseChainingContextSubtable(const ots::OpenTypeFile *file,
bool ParseChainingContextSubtable(const ots::Font *font,
const uint8_t *data, const size_t length,
const uint16_t num_glyphs,
const uint16_t num_lookups);
bool ParseExtensionSubtable(const OpenTypeFile *file,
bool ParseExtensionSubtable(const Font *font,
const uint8_t *data, const size_t length,
const LookupSubtableParser* parser);

View File

@ -14,25 +14,25 @@
namespace ots {
bool ots_loca_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
bool ots_loca_parse(Font *font, const uint8_t *data, size_t length) {
Buffer table(data, length);
// We can't do anything useful in validating this data except to ensure that
// the values are monotonically increasing.
OpenTypeLOCA *loca = new OpenTypeLOCA;
file->loca = loca;
font->loca = loca;
if (!file->maxp || !file->head) {
if (!font->maxp || !font->head) {
return OTS_FAILURE_MSG("maxp or head tables missing from font, needed by loca");
}
const unsigned num_glyphs = file->maxp->num_glyphs;
const unsigned num_glyphs = font->maxp->num_glyphs;
unsigned last_offset = 0;
loca->offsets.resize(num_glyphs + 1);
// maxp->num_glyphs is uint16_t, thus the addition never overflows.
if (file->head->index_to_loc_format == 0) {
if (font->head->index_to_loc_format == 0) {
// Note that the <= here (and below) is correct. There is one more offset
// than the number of glyphs in order to give the length of the final
// glyph.
@ -64,13 +64,13 @@ bool ots_loca_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return true;
}
bool ots_loca_should_serialise(OpenTypeFile *file) {
return file->loca != NULL;
bool ots_loca_should_serialise(Font *font) {
return font->loca != NULL;
}
bool ots_loca_serialise(OTSStream *out, OpenTypeFile *file) {
const OpenTypeLOCA *loca = file->loca;
const OpenTypeHEAD *head = file->head;
bool ots_loca_serialise(OTSStream *out, Font *font) {
const OpenTypeLOCA *loca = font->loca;
const OpenTypeHEAD *head = font->head;
if (!head) {
return OTS_FAILURE_MSG("Missing head table in font needed by loca");
@ -95,8 +95,13 @@ bool ots_loca_serialise(OTSStream *out, OpenTypeFile *file) {
return true;
}
void ots_loca_free(OpenTypeFile *file) {
delete file->loca;
void ots_loca_reuse(Font *font, Font *other) {
font->loca = other->loca;
font->loca_reused = true;
}
void ots_loca_free(Font *font) {
delete font->loca;
}
} // namespace ots

View File

@ -13,23 +13,23 @@
#define DROP_THIS_TABLE(...) \
do { \
OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
OTS_FAILURE_MSG_(font->file, TABLE_NAME ": " __VA_ARGS__); \
OTS_FAILURE_MSG("Table discarded"); \
delete file->ltsh; \
file->ltsh = 0; \
delete font->ltsh; \
font->ltsh = 0; \
} while (0)
namespace ots {
bool ots_ltsh_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
bool ots_ltsh_parse(Font *font, const uint8_t *data, size_t length) {
Buffer table(data, length);
if (!file->maxp) {
if (!font->maxp) {
return OTS_FAILURE_MSG("Missing maxp table from font needed by ltsh");
}
OpenTypeLTSH *ltsh = new OpenTypeLTSH;
file->ltsh = ltsh;
font->ltsh = ltsh;
uint16_t num_glyphs = 0;
if (!table.ReadU16(&ltsh->version) ||
@ -42,7 +42,7 @@ bool ots_ltsh_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return true;
}
if (num_glyphs != file->maxp->num_glyphs) {
if (num_glyphs != font->maxp->num_glyphs) {
DROP_THIS_TABLE("bad num_glyphs: %u", num_glyphs);
return true;
}
@ -59,13 +59,13 @@ bool ots_ltsh_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return true;
}
bool ots_ltsh_should_serialise(OpenTypeFile *file) {
if (!file->glyf) return false; // this table is not for CFF fonts.
return file->ltsh != NULL;
bool ots_ltsh_should_serialise(Font *font) {
if (!font->glyf) return false; // this table is not for CFF fonts.
return font->ltsh != NULL;
}
bool ots_ltsh_serialise(OTSStream *out, OpenTypeFile *file) {
const OpenTypeLTSH *ltsh = file->ltsh;
bool ots_ltsh_serialise(OTSStream *out, Font *font) {
const OpenTypeLTSH *ltsh = font->ltsh;
const uint16_t num_ypels = static_cast<uint16_t>(ltsh->ypels.size());
if (num_ypels != ltsh->ypels.size() ||
@ -82,8 +82,13 @@ bool ots_ltsh_serialise(OTSStream *out, OpenTypeFile *file) {
return true;
}
void ots_ltsh_free(OpenTypeFile *file) {
delete file->ltsh;
void ots_ltsh_reuse(Font *font, Font *other) {
font->ltsh = other->ltsh;
font->ltsh_reused = true;
}
void ots_ltsh_free(Font *font) {
delete font->ltsh;
}
} // namespace ots

View File

@ -50,7 +50,7 @@ const unsigned kGlyphPartRecordSize = 5 * 2;
// Shared Table: MathValueRecord
bool ParseMathValueRecord(const ots::OpenTypeFile *file,
bool ParseMathValueRecord(const ots::Font *font,
ots::Buffer* subtable, const uint8_t *data,
const size_t length) {
// Check the Value field.
@ -67,7 +67,7 @@ bool ParseMathValueRecord(const ots::OpenTypeFile *file,
if (offset >= length) {
return OTS_FAILURE();
}
if (!ots::ParseDeviceTable(file, data + offset, length - offset)) {
if (!ots::ParseDeviceTable(font, data + offset, length - offset)) {
return OTS_FAILURE();
}
}
@ -75,7 +75,7 @@ bool ParseMathValueRecord(const ots::OpenTypeFile *file,
return true;
}
bool ParseMathConstantsTable(const ots::OpenTypeFile *file,
bool ParseMathConstantsTable(const ots::Font *font,
const uint8_t *data, size_t length) {
ots::Buffer subtable(data, length);
@ -146,7 +146,7 @@ bool ParseMathConstantsTable(const ots::OpenTypeFile *file,
//
// RadicalKernAfterDegree
for (unsigned i = 0; i < static_cast<unsigned>(51); ++i) {
if (!ParseMathValueRecord(file, &subtable, data, length)) {
if (!ParseMathValueRecord(font, &subtable, data, length)) {
return OTS_FAILURE();
}
}
@ -160,7 +160,7 @@ bool ParseMathConstantsTable(const ots::OpenTypeFile *file,
return true;
}
bool ParseMathValueRecordSequenceForGlyphs(const ots::OpenTypeFile *file,
bool ParseMathValueRecordSequenceForGlyphs(const ots::Font *font,
ots::Buffer* subtable,
const uint8_t *data,
const size_t length,
@ -183,7 +183,7 @@ bool ParseMathValueRecordSequenceForGlyphs(const ots::OpenTypeFile *file,
if (offset_coverage < sequence_end || offset_coverage >= length) {
return OTS_FAILURE();
}
if (!ots::ParseCoverageTable(file, data + offset_coverage,
if (!ots::ParseCoverageTable(font, data + offset_coverage,
length - offset_coverage,
num_glyphs, sequence_count)) {
return OTS_FAILURE();
@ -191,7 +191,7 @@ bool ParseMathValueRecordSequenceForGlyphs(const ots::OpenTypeFile *file,
// Check sequence.
for (unsigned i = 0; i < sequence_count; ++i) {
if (!ParseMathValueRecord(file, subtable, data, length)) {
if (!ParseMathValueRecord(font, subtable, data, length)) {
return OTS_FAILURE();
}
}
@ -199,25 +199,25 @@ bool ParseMathValueRecordSequenceForGlyphs(const ots::OpenTypeFile *file,
return true;
}
bool ParseMathItalicsCorrectionInfoTable(const ots::OpenTypeFile *file,
bool ParseMathItalicsCorrectionInfoTable(const ots::Font *font,
const uint8_t *data,
size_t length,
const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
return ParseMathValueRecordSequenceForGlyphs(file, &subtable, data, length,
return ParseMathValueRecordSequenceForGlyphs(font, &subtable, data, length,
num_glyphs);
}
bool ParseMathTopAccentAttachmentTable(const ots::OpenTypeFile *file,
bool ParseMathTopAccentAttachmentTable(const ots::Font *font,
const uint8_t *data,
size_t length,
const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
return ParseMathValueRecordSequenceForGlyphs(file, &subtable, data, length,
return ParseMathValueRecordSequenceForGlyphs(font, &subtable, data, length,
num_glyphs);
}
bool ParseMathKernTable(const ots::OpenTypeFile *file,
bool ParseMathKernTable(const ots::Font *font,
const uint8_t *data, size_t length) {
ots::Buffer subtable(data, length);
@ -229,14 +229,14 @@ bool ParseMathKernTable(const ots::OpenTypeFile *file,
// Check the Correction Heights.
for (unsigned i = 0; i < height_count; ++i) {
if (!ParseMathValueRecord(file, &subtable, data, length)) {
if (!ParseMathValueRecord(font, &subtable, data, length)) {
return OTS_FAILURE();
}
}
// Check the Kern Values.
for (unsigned i = 0; i <= height_count; ++i) {
if (!ParseMathValueRecord(file, &subtable, data, length)) {
if (!ParseMathValueRecord(font, &subtable, data, length)) {
return OTS_FAILURE();
}
}
@ -244,7 +244,7 @@ bool ParseMathKernTable(const ots::OpenTypeFile *file,
return true;
}
bool ParseMathKernInfoTable(const ots::OpenTypeFile *file,
bool ParseMathKernInfoTable(const ots::Font *font,
const uint8_t *data, size_t length,
const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
@ -267,7 +267,7 @@ bool ParseMathKernInfoTable(const ots::OpenTypeFile *file,
if (offset_coverage < sequence_end || offset_coverage >= length) {
return OTS_FAILURE();
}
if (!ots::ParseCoverageTable(file, data + offset_coverage, length - offset_coverage,
if (!ots::ParseCoverageTable(font, data + offset_coverage, length - offset_coverage,
num_glyphs, sequence_count)) {
return OTS_FAILURE();
}
@ -282,7 +282,7 @@ bool ParseMathKernInfoTable(const ots::OpenTypeFile *file,
}
if (offset_math_kern) {
if (offset_math_kern < sequence_end || offset_math_kern >= length ||
!ParseMathKernTable(file, data + offset_math_kern,
!ParseMathKernTable(font, data + offset_math_kern,
length - offset_math_kern)) {
return OTS_FAILURE();
}
@ -293,7 +293,7 @@ bool ParseMathKernInfoTable(const ots::OpenTypeFile *file,
return true;
}
bool ParseMathGlyphInfoTable(const ots::OpenTypeFile *file,
bool ParseMathGlyphInfoTable(const ots::Font *font,
const uint8_t *data, size_t length,
const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
@ -318,7 +318,7 @@ bool ParseMathGlyphInfoTable(const ots::OpenTypeFile *file,
if (offset_math_italics_correction_info >= length ||
offset_math_italics_correction_info < kMathGlyphInfoHeaderSize ||
!ParseMathItalicsCorrectionInfoTable(
file, data + offset_math_italics_correction_info,
font, data + offset_math_italics_correction_info,
length - offset_math_italics_correction_info,
num_glyphs)) {
return OTS_FAILURE();
@ -327,7 +327,7 @@ bool ParseMathGlyphInfoTable(const ots::OpenTypeFile *file,
if (offset_math_top_accent_attachment) {
if (offset_math_top_accent_attachment >= length ||
offset_math_top_accent_attachment < kMathGlyphInfoHeaderSize ||
!ParseMathTopAccentAttachmentTable(file, data +
!ParseMathTopAccentAttachmentTable(font, data +
offset_math_top_accent_attachment,
length -
offset_math_top_accent_attachment,
@ -338,7 +338,7 @@ bool ParseMathGlyphInfoTable(const ots::OpenTypeFile *file,
if (offset_extended_shaped_coverage) {
if (offset_extended_shaped_coverage >= length ||
offset_extended_shaped_coverage < kMathGlyphInfoHeaderSize ||
!ots::ParseCoverageTable(file, data + offset_extended_shaped_coverage,
!ots::ParseCoverageTable(font, data + offset_extended_shaped_coverage,
length - offset_extended_shaped_coverage,
num_glyphs)) {
return OTS_FAILURE();
@ -347,7 +347,7 @@ bool ParseMathGlyphInfoTable(const ots::OpenTypeFile *file,
if (offset_math_kern_info) {
if (offset_math_kern_info >= length ||
offset_math_kern_info < kMathGlyphInfoHeaderSize ||
!ParseMathKernInfoTable(file, data + offset_math_kern_info,
!ParseMathKernInfoTable(font, data + offset_math_kern_info,
length - offset_math_kern_info, num_glyphs)) {
return OTS_FAILURE();
}
@ -356,14 +356,14 @@ bool ParseMathGlyphInfoTable(const ots::OpenTypeFile *file,
return true;
}
bool ParseGlyphAssemblyTable(const ots::OpenTypeFile *file,
bool ParseGlyphAssemblyTable(const ots::Font *font,
const uint8_t *data,
size_t length, const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
// Check the header.
uint16_t part_count = 0;
if (!ParseMathValueRecord(file, &subtable, data, length) ||
if (!ParseMathValueRecord(font, &subtable, data, length) ||
!subtable.ReadU16(&part_count)) {
return OTS_FAILURE();
}
@ -394,7 +394,7 @@ bool ParseGlyphAssemblyTable(const ots::OpenTypeFile *file,
return true;
}
bool ParseMathGlyphConstructionTable(const ots::OpenTypeFile *file,
bool ParseMathGlyphConstructionTable(const ots::Font *font,
const uint8_t *data,
size_t length, const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
@ -419,7 +419,7 @@ bool ParseMathGlyphConstructionTable(const ots::OpenTypeFile *file,
offset_glyph_assembly < sequence_end) {
return OTS_FAILURE();
}
if (!ParseGlyphAssemblyTable(file, data + offset_glyph_assembly,
if (!ParseGlyphAssemblyTable(font, data + offset_glyph_assembly,
length - offset_glyph_assembly, num_glyphs)) {
return OTS_FAILURE();
}
@ -440,7 +440,7 @@ bool ParseMathGlyphConstructionTable(const ots::OpenTypeFile *file,
return true;
}
bool ParseMathGlyphConstructionSequence(const ots::OpenTypeFile *file,
bool ParseMathGlyphConstructionSequence(const ots::Font *font,
ots::Buffer* subtable,
const uint8_t *data,
size_t length,
@ -452,7 +452,7 @@ bool ParseMathGlyphConstructionSequence(const ots::OpenTypeFile *file,
if (offset_coverage < sequence_end || offset_coverage >= length) {
return OTS_FAILURE();
}
if (!ots::ParseCoverageTable(file, data + offset_coverage,
if (!ots::ParseCoverageTable(font, data + offset_coverage,
length - offset_coverage,
num_glyphs, glyph_count)) {
return OTS_FAILURE();
@ -466,7 +466,7 @@ bool ParseMathGlyphConstructionSequence(const ots::OpenTypeFile *file,
}
if (offset_glyph_construction < sequence_end ||
offset_glyph_construction >= length ||
!ParseMathGlyphConstructionTable(file, data + offset_glyph_construction,
!ParseMathGlyphConstructionTable(font, data + offset_glyph_construction,
length - offset_glyph_construction,
num_glyphs)) {
return OTS_FAILURE();
@ -476,7 +476,7 @@ bool ParseMathGlyphConstructionSequence(const ots::OpenTypeFile *file,
return true;
}
bool ParseMathVariantsTable(const ots::OpenTypeFile *file,
bool ParseMathVariantsTable(const ots::Font *font,
const uint8_t *data,
size_t length, const uint16_t num_glyphs) {
ots::Buffer subtable(data, length);
@ -500,11 +500,11 @@ bool ParseMathVariantsTable(const ots::OpenTypeFile *file,
return OTS_FAILURE();
}
if (!ParseMathGlyphConstructionSequence(file, &subtable, data, length, num_glyphs,
if (!ParseMathGlyphConstructionSequence(font, &subtable, data, length, num_glyphs,
offset_vert_glyph_coverage,
vert_glyph_count,
sequence_end) ||
!ParseMathGlyphConstructionSequence(file, &subtable, data, length, num_glyphs,
!ParseMathGlyphConstructionSequence(font, &subtable, data, length, num_glyphs,
offset_horiz_glyph_coverage,
horiz_glyph_count,
sequence_end)) {
@ -519,24 +519,24 @@ bool ParseMathVariantsTable(const ots::OpenTypeFile *file,
#define DROP_THIS_TABLE(msg_) \
do { \
OTS_FAILURE_MSG(msg_ ", table discarded"); \
file->math->data = 0; \
file->math->length = 0; \
font->math->data = 0; \
font->math->length = 0; \
} while (0)
namespace ots {
bool ots_math_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
// Grab the number of glyphs in the file from the maxp table to check
bool ots_math_parse(Font *font, const uint8_t *data, size_t length) {
// Grab the number of glyphs in the font from the maxp table to check
// GlyphIDs in MATH table.
if (!file->maxp) {
if (!font->maxp) {
return OTS_FAILURE();
}
const uint16_t num_glyphs = file->maxp->num_glyphs;
const uint16_t num_glyphs = font->maxp->num_glyphs;
Buffer table(data, length);
OpenTypeMATH* math = new OpenTypeMATH;
file->math = math;
font->math = math;
uint32_t version = 0;
if (!table.ReadU32(&version)) {
@ -566,17 +566,17 @@ bool ots_math_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return true;
}
if (!ParseMathConstantsTable(file, data + offset_math_constants,
if (!ParseMathConstantsTable(font, data + offset_math_constants,
length - offset_math_constants)) {
DROP_THIS_TABLE("failed to parse MathConstants table");
return true;
}
if (!ParseMathGlyphInfoTable(file, data + offset_math_glyph_info,
if (!ParseMathGlyphInfoTable(font, data + offset_math_glyph_info,
length - offset_math_glyph_info, num_glyphs)) {
DROP_THIS_TABLE("failed to parse MathGlyphInfo table");
return true;
}
if (!ParseMathVariantsTable(file, data + offset_math_variants,
if (!ParseMathVariantsTable(font, data + offset_math_variants,
length - offset_math_variants, num_glyphs)) {
DROP_THIS_TABLE("failed to parse MathVariants table");
return true;
@ -587,20 +587,25 @@ bool ots_math_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return true;
}
bool ots_math_should_serialise(OpenTypeFile *file) {
return file->math != NULL && file->math->data != NULL;
bool ots_math_should_serialise(Font *font) {
return font->math != NULL && font->math->data != NULL;
}
bool ots_math_serialise(OTSStream *out, OpenTypeFile *file) {
if (!out->Write(file->math->data, file->math->length)) {
bool ots_math_serialise(OTSStream *out, Font *font) {
if (!out->Write(font->math->data, font->math->length)) {
return OTS_FAILURE();
}
return true;
}
void ots_math_free(OpenTypeFile *file) {
delete file->math;
void ots_math_reuse(Font *font, Font *other) {
font->math = other->math;
font->math_reused = true;
}
void ots_math_free(Font *font) {
delete font->math;
}
} // namespace ots

View File

@ -11,11 +11,11 @@
namespace ots {
bool ots_maxp_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
bool ots_maxp_parse(Font *font, const uint8_t *data, size_t length) {
Buffer table(data, length);
OpenTypeMAXP *maxp = new OpenTypeMAXP;
file->maxp = maxp;
font->maxp = maxp;
uint32_t version = 0;
if (!table.ReadU32(&version)) {
@ -72,12 +72,12 @@ bool ots_maxp_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return true;
}
bool ots_maxp_should_serialise(OpenTypeFile *file) {
return file->maxp != NULL;
bool ots_maxp_should_serialise(Font *font) {
return font->maxp != NULL;
}
bool ots_maxp_serialise(OTSStream *out, OpenTypeFile *file) {
const OpenTypeMAXP *maxp = file->maxp;
bool ots_maxp_serialise(OTSStream *out, Font *font) {
const OpenTypeMAXP *maxp = font->maxp;
if (!out->WriteU32(maxp->version_1 ? 0x00010000 : 0x00005000) ||
!out->WriteU16(maxp->num_glyphs)) {
@ -111,8 +111,13 @@ bool ots_maxp_serialise(OTSStream *out, OpenTypeFile *file) {
return true;
}
void ots_maxp_free(OpenTypeFile *file) {
delete file->maxp;
void ots_maxp_reuse(Font *font, Font *other) {
font->maxp = other->maxp;
font->maxp_reused = true;
}
void ots_maxp_free(Font *font) {
delete font->maxp;
}
} // namespace ots

View File

@ -15,7 +15,7 @@
namespace ots {
bool ParseMetricsHeader(OpenTypeFile *file, Buffer *table,
bool ParseMetricsHeader(Font *font, Buffer *table,
OpenTypeMetricsHeader *header) {
if (!table->ReadS16(&header->ascent) ||
!table->ReadS16(&header->descent) ||
@ -39,12 +39,12 @@ bool ParseMetricsHeader(OpenTypeFile *file, Buffer *table,
header->linegap = 0;
}
if (!file->head) {
if (!font->head) {
return OTS_FAILURE_MSG("Missing head font table");
}
// if the font is non-slanted, caret_offset should be zero.
if (!(file->head->mac_style & 2) &&
if (!(font->head->mac_style & 2) &&
(header->caret_offset != 0)) {
OTS_WARNING("bad caret offset: %d", header->caret_offset);
header->caret_offset = 0;
@ -67,18 +67,18 @@ bool ParseMetricsHeader(OpenTypeFile *file, Buffer *table,
return OTS_FAILURE_MSG("Failed to read number of metrics");
}
if (!file->maxp) {
if (!font->maxp) {
return OTS_FAILURE_MSG("Missing maxp font table");
}
if (header->num_metrics > file->maxp->num_glyphs) {
if (header->num_metrics > font->maxp->num_glyphs) {
return OTS_FAILURE_MSG("Bad number of metrics %d", header->num_metrics);
}
return true;
}
bool SerialiseMetricsHeader(const ots::OpenTypeFile *file,
bool SerialiseMetricsHeader(const ots::Font *font,
OTSStream *out,
const OpenTypeMetricsHeader *header) {
if (!out->WriteU32(header->version) ||
@ -101,7 +101,7 @@ bool SerialiseMetricsHeader(const ots::OpenTypeFile *file,
return true;
}
bool ParseMetricsTable(const ots::OpenTypeFile *file,
bool ParseMetricsTable(const ots::Font *font,
Buffer *table,
const uint16_t num_glyphs,
const OpenTypeMetricsHeader *header,
@ -169,7 +169,7 @@ bool ParseMetricsTable(const ots::OpenTypeFile *file,
return true;
}
bool SerialiseMetricsTable(const ots::OpenTypeFile *file,
bool SerialiseMetricsTable(const ots::Font *font,
OTSStream *out,
const OpenTypeMetricsTable *metrics) {
for (unsigned i = 0; i < metrics->entries.size(); ++i) {

View File

@ -33,18 +33,18 @@ struct OpenTypeMetricsTable {
std::vector<int16_t> sbs;
};
bool ParseMetricsHeader(OpenTypeFile *file, Buffer *table,
bool ParseMetricsHeader(Font *font, Buffer *table,
OpenTypeMetricsHeader *header);
bool SerialiseMetricsHeader(const ots::OpenTypeFile *file,
bool SerialiseMetricsHeader(const ots::Font *font,
OTSStream *out,
const OpenTypeMetricsHeader *header);
bool ParseMetricsTable(const ots::OpenTypeFile *file,
bool ParseMetricsTable(const ots::Font *font,
Buffer *table,
const uint16_t num_glyphs,
const OpenTypeMetricsHeader *header,
OpenTypeMetricsTable *metrics);
bool SerialiseMetricsTable(const ots::OpenTypeFile *file,
bool SerialiseMetricsTable(const ots::Font *font,
OTSStream *out,
const OpenTypeMetricsTable *metrics);

View File

@ -7,8 +7,6 @@
#include <algorithm>
#include <cstring>
#include "cff.h"
// name - Naming Table
// http://www.microsoft.com/typography/otspec/name.htm
@ -58,11 +56,11 @@ void AssignToUtf16BeFromAscii(std::string* target,
namespace ots {
bool ots_name_parse(OpenTypeFile* file, const uint8_t* data, size_t length) {
bool ots_name_parse(Font *font, const uint8_t* data, size_t length) {
Buffer table(data, length);
OpenTypeNAME* name = new OpenTypeNAME;
file->name = name;
font->name = name;
uint16_t format = 0;
if (!table.ReadU16(&format) || format > 1) {
@ -81,7 +79,6 @@ bool ots_name_parse(OpenTypeFile* file, const uint8_t* data, size_t length) {
const char* string_base = reinterpret_cast<const char*>(data) +
string_offset;
NameRecord prev_record;
bool sort_required = false;
// Read all the names, discarding any with invalid IDs,
@ -141,27 +138,22 @@ bool ots_name_parse(OpenTypeFile* file, const uint8_t* data, size_t length) {
if (rec.name_id == 6) {
// PostScript name: check that it is valid, if not then discard it
if (rec.platform_id == 1) {
if (file->cff && !file->cff->name.empty()) {
rec.text = file->cff->name;
} else if (!CheckPsNameAscii(rec.text)) {
if (!CheckPsNameAscii(rec.text)) {
continue;
}
} else if (rec.platform_id == 0 || rec.platform_id == 3) {
if (file->cff && !file->cff->name.empty()) {
AssignToUtf16BeFromAscii(&rec.text, file->cff->name);
} else if (!CheckPsNameUtf16Be(rec.text)) {
if (!CheckPsNameUtf16Be(rec.text)) {
continue;
}
}
}
if ((i > 0) && !(prev_record < rec)) {
if (!name->names.empty() && !(name->names.back() < rec)) {
OTS_WARNING("name records are not sorted.");
sort_required = true;
}
name->names.push_back(rec);
prev_record = rec;
}
if (format == 1) {
@ -210,19 +202,13 @@ bool ots_name_parse(OpenTypeFile* file, const uint8_t* data, size_t length) {
"1.000",
"OTS-derived-font"
};
// The spec says that "In CFF OpenType fonts, these two name strings, when
// translated to ASCII, must also be identical to the font name as stored in
// the CFF's Name INDEX." And actually, Mac OS X's font parser requires that.
if (file->cff && !file->cff->name.empty()) {
kStdNames[6] = file->cff->name.c_str();
}
// scan the names to check whether the required "standard" ones are present;
// if not, we'll add our fixed versions here
bool mac_name[kStdNameCount] = { 0 };
bool win_name[kStdNameCount] = { 0 };
for (std::vector<NameRecord>::iterator name_iter = name->names.begin();
name_iter != name->names.end(); name_iter++) {
name_iter != name->names.end(); ++name_iter) {
const uint16_t id = name_iter->name_id;
if (id >= kStdNameCount || kStdNames[id] == NULL) {
continue;
@ -241,18 +227,17 @@ bool ots_name_parse(OpenTypeFile* file, const uint8_t* data, size_t length) {
if (kStdNames[i] == NULL) {
continue;
}
if (!mac_name[i]) {
NameRecord rec(1 /* platform_id */, 0 /* encoding_id */,
0 /* language_id */ , i /* name_id */);
rec.text.assign(kStdNames[i]);
name->names.push_back(rec);
sort_required = true;
}
if (!win_name[i]) {
NameRecord rec(3 /* platform_id */, 1 /* encoding_id */,
1033 /* language_id */ , i /* name_id */);
AssignToUtf16BeFromAscii(&rec.text, std::string(kStdNames[i]));
name->names.push_back(rec);
if (!mac_name[i] && !win_name[i]) {
NameRecord mac_rec(1 /* platform_id */, 0 /* encoding_id */,
0 /* language_id */ , i /* name_id */);
mac_rec.text.assign(kStdNames[i]);
NameRecord win_rec(3 /* platform_id */, 1 /* encoding_id */,
1033 /* language_id */ , i /* name_id */);
AssignToUtf16BeFromAscii(&win_rec.text, std::string(kStdNames[i]));
name->names.push_back(mac_rec);
name->names.push_back(win_rec);
sort_required = true;
}
}
@ -264,12 +249,12 @@ bool ots_name_parse(OpenTypeFile* file, const uint8_t* data, size_t length) {
return true;
}
bool ots_name_should_serialise(OpenTypeFile* file) {
return file->name != NULL;
bool ots_name_should_serialise(Font *font) {
return font->name != NULL;
}
bool ots_name_serialise(OTSStream* out, OpenTypeFile* file) {
const OpenTypeNAME* name = file->name;
bool ots_name_serialise(OTSStream* out, Font *font) {
const OpenTypeNAME* name = font->name;
uint16_t name_count = static_cast<uint16_t>(name->names.size());
uint16_t lang_tag_count = static_cast<uint16_t>(name->lang_tags.size());
@ -292,7 +277,7 @@ bool ots_name_serialise(OTSStream* out, OpenTypeFile* file) {
std::string string_data;
for (std::vector<NameRecord>::const_iterator name_iter = name->names.begin();
name_iter != name->names.end(); name_iter++) {
name_iter != name->names.end(); ++name_iter) {
const NameRecord& rec = *name_iter;
if (string_data.size() + rec.text.size() >
std::numeric_limits<uint16_t>::max() ||
@ -313,7 +298,7 @@ bool ots_name_serialise(OTSStream* out, OpenTypeFile* file) {
}
for (std::vector<std::string>::const_iterator tag_iter =
name->lang_tags.begin();
tag_iter != name->lang_tags.end(); tag_iter++) {
tag_iter != name->lang_tags.end(); ++tag_iter) {
if (string_data.size() + tag_iter->size() >
std::numeric_limits<uint16_t>::max() ||
!out->WriteU16(static_cast<uint16_t>(tag_iter->size())) ||
@ -331,8 +316,13 @@ bool ots_name_serialise(OTSStream* out, OpenTypeFile* file) {
return true;
}
void ots_name_free(OpenTypeFile* file) {
delete file->name;
void ots_name_reuse(Font *font, Font *other) {
font->name = other->name;
font->name_reused = true;
}
void ots_name_free(Font *font) {
delete font->name;
}
} // namespace

View File

@ -14,11 +14,11 @@
namespace ots {
bool ots_os2_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
bool ots_os2_parse(Font *font, const uint8_t *data, size_t length) {
Buffer table(data, length);
OpenTypeOS2 *os2 = new OpenTypeOS2;
file->os2 = os2;
font->os2 = os2;
if (!table.ReadU16(&os2->version) ||
!table.ReadS16(&os2->avg_char_width) ||
@ -39,7 +39,7 @@ bool ots_os2_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return OTS_FAILURE_MSG("Error reading basic table elements");
}
if (os2->version > 4) {
if (os2->version > 5) {
return OTS_FAILURE_MSG("Unsupported table version: %u", os2->version);
}
@ -131,32 +131,32 @@ bool ots_os2_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
// the settings of bits 0 and 1 must be reflected in the macStyle bits
// in the 'head' table.
if (!file->head) {
if (!font->head) {
return OTS_FAILURE_MSG("Needed head table is missing from the font");
}
if ((os2->selection & 0x1) &&
!(file->head->mac_style & 0x2)) {
!(font->head->mac_style & 0x2)) {
OTS_WARNING("adjusting Mac style (italic)");
file->head->mac_style |= 0x2;
font->head->mac_style |= 0x2;
}
if ((os2->selection & 0x2) &&
!(file->head->mac_style & 0x4)) {
!(font->head->mac_style & 0x4)) {
OTS_WARNING("adjusting Mac style (underscore)");
file->head->mac_style |= 0x4;
font->head->mac_style |= 0x4;
}
// While bit 6 on implies that bits 0 and 1 of macStyle are clear,
// the reverse is not true.
if ((os2->selection & 0x40) &&
(file->head->mac_style & 0x3)) {
(font->head->mac_style & 0x3)) {
OTS_WARNING("adjusting Mac style (regular)");
file->head->mac_style &= 0xfffcu;
font->head->mac_style &= 0xfffcu;
}
if ((os2->version < 4) &&
(os2->selection & 0x300)) {
// bit 8 and 9 must be unset in OS/2 table versions less than 4.
return OTS_FAILURE_MSG("OS2 version %d incompatible with selection %d", os2->version, os2->selection);
return OTS_FAILURE_MSG("Version %d incompatible with selection %d", os2->version, os2->selection);
}
// mask reserved bits. use only 0..9 bits.
@ -206,7 +206,7 @@ bool ots_os2_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
!table.ReadU16(&os2->default_char) ||
!table.ReadU16(&os2->break_char) ||
!table.ReadU16(&os2->max_context)) {
return OTS_FAILURE_MSG("Failed to read os2 version 2 information");
return OTS_FAILURE_MSG("Failed to read version 2-specific fields");
}
if (os2->x_height < 0) {
@ -218,15 +218,35 @@ bool ots_os2_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
os2->cap_height = 0;
}
if (os2->version < 5) {
// http://www.microsoft.com/typography/otspec/os2ver4.htm
return true;
}
if (!table.ReadU16(&os2->lower_optical_pointsize) ||
!table.ReadU16(&os2->upper_optical_pointsize)) {
return OTS_FAILURE_MSG("Failed to read version 5-specific fields");
}
if (os2->lower_optical_pointsize > 0xFFFE) {
OTS_WARNING("'usLowerOpticalPointSize' is bigger than 0xFFFE: %d", os2->lower_optical_pointsize);
os2->lower_optical_pointsize = 0xFFFE;
}
if (os2->upper_optical_pointsize < 2) {
OTS_WARNING("'usUpperOpticalPointSize' is lower than 2: %d", os2->upper_optical_pointsize);
os2->upper_optical_pointsize = 2;
}
return true;
}
bool ots_os2_should_serialise(OpenTypeFile *file) {
return file->os2 != NULL;
bool ots_os2_should_serialise(Font *font) {
return font->os2 != NULL;
}
bool ots_os2_serialise(OTSStream *out, OpenTypeFile *file) {
const OpenTypeOS2 *os2 = file->os2;
bool ots_os2_serialise(OTSStream *out, Font *font) {
const OpenTypeOS2 *os2 = font->os2;
if (!out->WriteU16(os2->version) ||
!out->WriteS16(os2->avg_char_width) ||
@ -266,7 +286,7 @@ bool ots_os2_serialise(OTSStream *out, OpenTypeFile *file) {
!out->WriteS16(os2->typo_linegap) ||
!out->WriteU16(os2->win_ascent) ||
!out->WriteU16(os2->win_descent)) {
return OTS_FAILURE_MSG("Failed to write os2 version 1 information");
return OTS_FAILURE_MSG("Failed to write version 1-specific fields");
}
if (os2->version < 1) {
@ -287,14 +307,28 @@ bool ots_os2_serialise(OTSStream *out, OpenTypeFile *file) {
!out->WriteU16(os2->default_char) ||
!out->WriteU16(os2->break_char) ||
!out->WriteU16(os2->max_context)) {
return OTS_FAILURE_MSG("Failed to write os2 version 2 information");
return OTS_FAILURE_MSG("Failed to write version 2-specific fields");
}
if (os2->version < 5) {
return true;
}
if (!out->WriteU16(os2->lower_optical_pointsize) ||
!out->WriteU16(os2->upper_optical_pointsize)) {
return OTS_FAILURE_MSG("Failed to write version 5-specific fields");
}
return true;
}
void ots_os2_free(OpenTypeFile *file) {
delete file->os2;
void ots_os2_reuse(Font *font, Font *other) {
font->os2 = other->os2;
font->os2_reused = true;
}
void ots_os2_free(Font *font) {
delete font->os2;
}
} // namespace ots

View File

@ -47,6 +47,8 @@ struct OpenTypeOS2 {
uint16_t default_char;
uint16_t break_char;
uint16_t max_context;
uint16_t lower_optical_pointsize;
uint16_t upper_optical_pointsize;
};
} // namespace ots

View File

@ -46,25 +46,6 @@ bool CheckTag(uint32_t tag_value) {
return true;
}
uint32_t Tag(const char *tag_str) {
uint32_t ret;
std::memcpy(&ret, tag_str, 4);
return ret;
}
struct OutputTable {
uint32_t tag;
size_t offset;
size_t length;
uint32_t chksum;
static bool SortByTag(const OutputTable& a, const OutputTable& b) {
const uint32_t atag = ntohl(a.tag);
const uint32_t btag = ntohl(b.tag);
return atag < btag;
}
};
struct Arena {
public:
~Arena() {
@ -85,72 +66,72 @@ struct Arena {
};
const struct {
const char* tag;
bool (*parse)(ots::OpenTypeFile *otf, const uint8_t *data, size_t length);
bool (*serialise)(ots::OTSStream *out, ots::OpenTypeFile *file);
bool (*should_serialise)(ots::OpenTypeFile *file);
void (*free)(ots::OpenTypeFile *file);
uint32_t tag;
bool (*parse)(ots::Font *font, const uint8_t *data, size_t length);
bool (*serialise)(ots::OTSStream *out, ots::Font *font);
bool (*should_serialise)(ots::Font *font);
void (*reuse)(ots::Font *font, ots::Font *other);
bool required;
} table_parsers[] = {
{ "maxp", ots::ots_maxp_parse, ots::ots_maxp_serialise,
ots::ots_maxp_should_serialise, ots::ots_maxp_free, true },
{ "head", ots::ots_head_parse, ots::ots_head_serialise,
ots::ots_head_should_serialise, ots::ots_head_free, true },
{ "OS/2", ots::ots_os2_parse, ots::ots_os2_serialise,
ots::ots_os2_should_serialise, ots::ots_os2_free, true },
{ "cmap", ots::ots_cmap_parse, ots::ots_cmap_serialise,
ots::ots_cmap_should_serialise, ots::ots_cmap_free, true },
{ "hhea", ots::ots_hhea_parse, ots::ots_hhea_serialise,
ots::ots_hhea_should_serialise, ots::ots_hhea_free, true },
{ "hmtx", ots::ots_hmtx_parse, ots::ots_hmtx_serialise,
ots::ots_hmtx_should_serialise, ots::ots_hmtx_free, true },
{ "name", ots::ots_name_parse, ots::ots_name_serialise,
ots::ots_name_should_serialise, ots::ots_name_free, true },
{ "post", ots::ots_post_parse, ots::ots_post_serialise,
ots::ots_post_should_serialise, ots::ots_post_free, true },
{ "loca", ots::ots_loca_parse, ots::ots_loca_serialise,
ots::ots_loca_should_serialise, ots::ots_loca_free, false },
{ "glyf", ots::ots_glyf_parse, ots::ots_glyf_serialise,
ots::ots_glyf_should_serialise, ots::ots_glyf_free, false },
{ "CFF ", ots::ots_cff_parse, ots::ots_cff_serialise,
ots::ots_cff_should_serialise, ots::ots_cff_free, false },
{ "VDMX", ots::ots_vdmx_parse, ots::ots_vdmx_serialise,
ots::ots_vdmx_should_serialise, ots::ots_vdmx_free, false },
{ "hdmx", ots::ots_hdmx_parse, ots::ots_hdmx_serialise,
ots::ots_hdmx_should_serialise, ots::ots_hdmx_free, false },
{ "gasp", ots::ots_gasp_parse, ots::ots_gasp_serialise,
ots::ots_gasp_should_serialise, ots::ots_gasp_free, false },
{ "cvt ", ots::ots_cvt_parse, ots::ots_cvt_serialise,
ots::ots_cvt_should_serialise, ots::ots_cvt_free, false },
{ "fpgm", ots::ots_fpgm_parse, ots::ots_fpgm_serialise,
ots::ots_fpgm_should_serialise, ots::ots_fpgm_free, false },
{ "prep", ots::ots_prep_parse, ots::ots_prep_serialise,
ots::ots_prep_should_serialise, ots::ots_prep_free, false },
{ "LTSH", ots::ots_ltsh_parse, ots::ots_ltsh_serialise,
ots::ots_ltsh_should_serialise, ots::ots_ltsh_free, false },
{ "VORG", ots::ots_vorg_parse, ots::ots_vorg_serialise,
ots::ots_vorg_should_serialise, ots::ots_vorg_free, false },
{ "kern", ots::ots_kern_parse, ots::ots_kern_serialise,
ots::ots_kern_should_serialise, ots::ots_kern_free, false },
{ OTS_TAG('m','a','x','p'), ots::ots_maxp_parse, ots::ots_maxp_serialise,
ots::ots_maxp_should_serialise, ots::ots_maxp_reuse, true },
{ OTS_TAG('h','e','a','d'), ots::ots_head_parse, ots::ots_head_serialise,
ots::ots_head_should_serialise, ots::ots_head_reuse, true },
{ OTS_TAG('O','S','/','2'), ots::ots_os2_parse, ots::ots_os2_serialise,
ots::ots_os2_should_serialise, ots::ots_os2_reuse, true },
{ OTS_TAG('c','m','a','p'), ots::ots_cmap_parse, ots::ots_cmap_serialise,
ots::ots_cmap_should_serialise, ots::ots_cmap_reuse, true },
{ OTS_TAG('h','h','e','a'), ots::ots_hhea_parse, ots::ots_hhea_serialise,
ots::ots_hhea_should_serialise, ots::ots_hhea_reuse, true },
{ OTS_TAG('h','m','t','x'), ots::ots_hmtx_parse, ots::ots_hmtx_serialise,
ots::ots_hmtx_should_serialise, ots::ots_hmtx_reuse, true },
{ OTS_TAG('n','a','m','e'), ots::ots_name_parse, ots::ots_name_serialise,
ots::ots_name_should_serialise, ots::ots_name_reuse, true },
{ OTS_TAG('p','o','s','t'), ots::ots_post_parse, ots::ots_post_serialise,
ots::ots_post_should_serialise, ots::ots_post_reuse, true },
{ OTS_TAG('l','o','c','a'), ots::ots_loca_parse, ots::ots_loca_serialise,
ots::ots_loca_should_serialise, ots::ots_loca_reuse, false },
{ OTS_TAG('g','l','y','f'), ots::ots_glyf_parse, ots::ots_glyf_serialise,
ots::ots_glyf_should_serialise, ots::ots_glyf_reuse, false },
{ OTS_TAG('C','F','F',' '), ots::ots_cff_parse, ots::ots_cff_serialise,
ots::ots_cff_should_serialise, ots::ots_cff_reuse, false },
{ OTS_TAG('V','D','M','X'), ots::ots_vdmx_parse, ots::ots_vdmx_serialise,
ots::ots_vdmx_should_serialise, ots::ots_vdmx_reuse, false },
{ OTS_TAG('h','d','m','x'), ots::ots_hdmx_parse, ots::ots_hdmx_serialise,
ots::ots_hdmx_should_serialise, ots::ots_hdmx_reuse, false },
{ OTS_TAG('g','a','s','p'), ots::ots_gasp_parse, ots::ots_gasp_serialise,
ots::ots_gasp_should_serialise, ots::ots_gasp_reuse, false },
{ OTS_TAG('c','v','t',' '), ots::ots_cvt_parse, ots::ots_cvt_serialise,
ots::ots_cvt_should_serialise, ots::ots_cvt_reuse, false },
{ OTS_TAG('f','p','g','m'), ots::ots_fpgm_parse, ots::ots_fpgm_serialise,
ots::ots_fpgm_should_serialise, ots::ots_fpgm_reuse, false },
{ OTS_TAG('p','r','e','p'), ots::ots_prep_parse, ots::ots_prep_serialise,
ots::ots_prep_should_serialise, ots::ots_prep_reuse, false },
{ OTS_TAG('L','T','S','H'), ots::ots_ltsh_parse, ots::ots_ltsh_serialise,
ots::ots_ltsh_should_serialise, ots::ots_ltsh_reuse, false },
{ OTS_TAG('V','O','R','G'), ots::ots_vorg_parse, ots::ots_vorg_serialise,
ots::ots_vorg_should_serialise, ots::ots_vorg_reuse, false },
{ OTS_TAG('k','e','r','n'), ots::ots_kern_parse, ots::ots_kern_serialise,
ots::ots_kern_should_serialise, ots::ots_kern_reuse, false },
// We need to parse GDEF table in advance of parsing GSUB/GPOS tables
// because they could refer GDEF table.
{ "GDEF", ots::ots_gdef_parse, ots::ots_gdef_serialise,
ots::ots_gdef_should_serialise, ots::ots_gdef_free, false },
{ "GPOS", ots::ots_gpos_parse, ots::ots_gpos_serialise,
ots::ots_gpos_should_serialise, ots::ots_gpos_free, false },
{ "GSUB", ots::ots_gsub_parse, ots::ots_gsub_serialise,
ots::ots_gsub_should_serialise, ots::ots_gsub_free, false },
{ "vhea", ots::ots_vhea_parse, ots::ots_vhea_serialise,
ots::ots_vhea_should_serialise, ots::ots_vhea_free, false },
{ "vmtx", ots::ots_vmtx_parse, ots::ots_vmtx_serialise,
ots::ots_vmtx_should_serialise, ots::ots_vmtx_free, false },
{ "MATH", ots::ots_math_parse, ots::ots_math_serialise,
ots::ots_math_should_serialise, ots::ots_math_free, false },
// TODO(bashi): Support mort, base, and jstf tables.
{ OTS_TAG('G','D','E','F'), ots::ots_gdef_parse, ots::ots_gdef_serialise,
ots::ots_gdef_should_serialise, ots::ots_gdef_reuse, false },
{ OTS_TAG('G','P','O','S'), ots::ots_gpos_parse, ots::ots_gpos_serialise,
ots::ots_gpos_should_serialise, ots::ots_gpos_reuse, false },
{ OTS_TAG('G','S','U','B'), ots::ots_gsub_parse, ots::ots_gsub_serialise,
ots::ots_gsub_should_serialise, ots::ots_gsub_reuse, false },
{ OTS_TAG('v','h','e','a'), ots::ots_vhea_parse, ots::ots_vhea_serialise,
ots::ots_vhea_should_serialise, ots::ots_vhea_reuse, false },
{ OTS_TAG('v','m','t','x'), ots::ots_vmtx_parse, ots::ots_vmtx_serialise,
ots::ots_vmtx_should_serialise, ots::ots_vmtx_reuse, false },
{ OTS_TAG('M','A','T','H'), ots::ots_math_parse, ots::ots_math_serialise,
ots::ots_math_should_serialise, ots::ots_math_reuse, false },
{ 0, NULL, NULL, NULL, NULL, false },
};
bool ProcessGeneric(ots::OpenTypeFile *header,
ots::Font *font,
uint32_t signature,
ots::OTSStream *output,
const uint8_t *data, size_t length,
@ -158,68 +139,74 @@ bool ProcessGeneric(ots::OpenTypeFile *header,
ots::Buffer& file);
bool ProcessTTF(ots::OpenTypeFile *header,
ots::OTSStream *output, const uint8_t *data, size_t length) {
ots::Buffer file(data, length);
ots::Font *font,
ots::OTSStream *output, const uint8_t *data, size_t length,
uint32_t offset = 0) {
ots::Buffer file(data + offset, length - offset);
if (offset > length) {
return OTS_FAILURE_MSG_HDR("offset beyond end of file");
}
// we disallow all files > 1GB in size for sanity.
if (length > 1024 * 1024 * 1024) {
return OTS_FAILURE_MSG_HDR("file exceeds 1GB");
}
if (!file.ReadTag(&header->version)) {
if (!file.ReadU32(&font->version)) {
return OTS_FAILURE_MSG_HDR("error reading version tag");
}
if (!ots::IsValidVersionTag(header->version)) {
if (!ots::IsValidVersionTag(font->version)) {
return OTS_FAILURE_MSG_HDR("invalid version tag");
}
if (!file.ReadU16(&header->num_tables) ||
!file.ReadU16(&header->search_range) ||
!file.ReadU16(&header->entry_selector) ||
!file.ReadU16(&header->range_shift)) {
if (!file.ReadU16(&font->num_tables) ||
!file.ReadU16(&font->search_range) ||
!file.ReadU16(&font->entry_selector) ||
!file.ReadU16(&font->range_shift)) {
return OTS_FAILURE_MSG_HDR("error reading table directory search header");
}
// search_range is (Maximum power of 2 <= numTables) x 16. Thus, to avoid
// overflow num_tables is, at most, 2^16 / 16 = 2^12
if (header->num_tables >= 4096 || header->num_tables < 1) {
if (font->num_tables >= 4096 || font->num_tables < 1) {
return OTS_FAILURE_MSG_HDR("excessive (or zero) number of tables");
}
unsigned max_pow2 = 0;
while (1u << (max_pow2 + 1) <= header->num_tables) {
while (1u << (max_pow2 + 1) <= font->num_tables) {
max_pow2++;
}
const uint16_t expected_search_range = (1u << max_pow2) << 4;
// Don't call ots_failure() here since ~25% of fonts (250+ fonts) in
// http://www.princexml.com/fonts/ have unexpected search_range value.
if (header->search_range != expected_search_range) {
OTS_FAILURE_MSG_HDR("bad search range");
header->search_range = expected_search_range; // Fix the value.
if (font->search_range != expected_search_range) {
OTS_WARNING_MSG_HDR("bad search range");
font->search_range = expected_search_range; // Fix the value.
}
// entry_selector is Log2(maximum power of 2 <= numTables)
if (header->entry_selector != max_pow2) {
if (font->entry_selector != max_pow2) {
return OTS_FAILURE_MSG_HDR("incorrect entrySelector for table directory");
}
// range_shift is NumTables x 16-searchRange. We know that 16*num_tables
// doesn't over flow because we range checked it above. Also, we know that
// it's > header->search_range by construction of search_range.
// it's > font->search_range by construction of search_range.
const uint16_t expected_range_shift =
16 * header->num_tables - header->search_range;
if (header->range_shift != expected_range_shift) {
OTS_FAILURE_MSG_HDR("bad range shift");
header->range_shift = expected_range_shift; // the same as above.
16 * font->num_tables - font->search_range;
if (font->range_shift != expected_range_shift) {
OTS_WARNING_MSG_HDR("bad range shift");
font->range_shift = expected_range_shift; // the same as above.
}
// Next up is the list of tables.
std::vector<OpenTypeTable> tables;
for (unsigned i = 0; i < header->num_tables; ++i) {
for (unsigned i = 0; i < font->num_tables; ++i) {
OpenTypeTable table;
if (!file.ReadTag(&table.tag) ||
if (!file.ReadU32(&table.tag) ||
!file.ReadU32(&table.chksum) ||
!file.ReadU32(&table.offset) ||
!file.ReadU32(&table.length)) {
@ -230,11 +217,99 @@ bool ProcessTTF(ots::OpenTypeFile *header,
tables.push_back(table);
}
return ProcessGeneric(header, header->version, output, data, length,
return ProcessGeneric(header, font, font->version, output, data, length,
tables, file);
}
bool ProcessTTC(ots::OpenTypeFile *header,
ots::OTSStream *output,
const uint8_t *data,
size_t length,
uint32_t index) {
ots::Buffer file(data, length);
// we disallow all files > 1GB in size for sanity.
if (length > 1024 * 1024 * 1024) {
return OTS_FAILURE_MSG_HDR("file exceeds 1GB");
}
uint32_t ttc_tag;
if (!file.ReadU32(&ttc_tag)) {
return OTS_FAILURE_MSG_HDR("Error reading TTC tag");
}
if (ttc_tag != OTS_TAG('t','t','c','f')) {
return OTS_FAILURE_MSG_HDR("Invalid TTC tag");
}
uint32_t ttc_version;
if (!file.ReadU32(&ttc_version)) {
return OTS_FAILURE_MSG_HDR("Error reading TTC version");
}
if (ttc_version != 0x00010000 && ttc_version != 0x00020000) {
return OTS_FAILURE_MSG_HDR("Invalid TTC version");
}
uint32_t num_fonts;
if (!file.ReadU32(&num_fonts)) {
return OTS_FAILURE_MSG_HDR("Error reading number of TTC fonts");
}
// Limit the allowed number of subfonts to have same memory allocation.
if (num_fonts > 0x10000) {
return OTS_FAILURE_MSG_HDR("Too many fonts in TTC");
}
std::vector<uint32_t> offsets(num_fonts);
for (unsigned i = 0; i < num_fonts; i++) {
if (!file.ReadU32(&offsets[i])) {
return OTS_FAILURE_MSG_HDR("Error reading offset to OffsetTable");
}
}
if (ttc_version == 0x00020000) {
// We don't care about these fields of the header:
// uint32_t dsig_tag, dsig_length, dsig_offset
if (!file.Skip(3 * 4)) {
return OTS_FAILURE_MSG_HDR("Error reading DSIG offset and length in TTC font");
}
}
if (index == static_cast<uint32_t>(-1)) {
if (!output->WriteU32(ttc_tag) ||
!output->WriteU32(0x00010000) ||
!output->WriteU32(num_fonts) ||
!output->Seek((3 + num_fonts) * 4)) {
return OTS_FAILURE_MSG_HDR("Error writing output");
}
// Keep references to the fonts processed in the loop below, as we need
// them for reused tables.
std::vector<ots::Font> fonts(num_fonts, ots::Font(header));
for (unsigned i = 0; i < num_fonts; i++) {
uint32_t out_offset = output->Tell();
if (!output->Seek((3 + i) * 4) ||
!output->WriteU32(out_offset) ||
!output->Seek(out_offset)) {
return OTS_FAILURE_MSG_HDR("Error writing output");
}
if (!ProcessTTF(header, &fonts[i], output, data, length, offsets[i])) {
return false;
}
}
return true;
} else {
if (index >= num_fonts) {
return OTS_FAILURE_MSG_HDR("Requested font index is bigger than the number of fonts in the TTC file");
}
ots::Font font(header);
return ProcessTTF(header, &font, output, data, length, offsets[index]);
}
}
bool ProcessWOFF(ots::OpenTypeFile *header,
ots::Font *font,
ots::OTSStream *output, const uint8_t *data, size_t length) {
ots::Buffer file(data, length);
@ -244,31 +319,27 @@ bool ProcessWOFF(ots::OpenTypeFile *header,
}
uint32_t woff_tag;
if (!file.ReadTag(&woff_tag)) {
if (!file.ReadU32(&woff_tag)) {
return OTS_FAILURE_MSG_HDR("error reading WOFF marker");
}
if (woff_tag != Tag("wOFF")) {
if (woff_tag != OTS_TAG('w','O','F','F')) {
return OTS_FAILURE_MSG_HDR("invalid WOFF marker");
}
if (!file.ReadTag(&header->version)) {
if (!file.ReadU32(&font->version)) {
return OTS_FAILURE_MSG_HDR("error reading version tag");
}
if (!ots::IsValidVersionTag(header->version)) {
if (!ots::IsValidVersionTag(font->version)) {
return OTS_FAILURE_MSG_HDR("invalid version tag");
}
header->search_range = 0;
header->entry_selector = 0;
header->range_shift = 0;
uint32_t reported_length;
if (!file.ReadU32(&reported_length) || length != reported_length) {
return OTS_FAILURE_MSG_HDR("incorrect file size in WOFF header");
}
if (!file.ReadU16(&header->num_tables) || !header->num_tables) {
if (!file.ReadU16(&font->num_tables) || !font->num_tables) {
return OTS_FAILURE_MSG_HDR("error reading number of tables");
}
@ -322,10 +393,10 @@ bool ProcessWOFF(ots::OpenTypeFile *header,
uint32_t first_index = 0;
uint32_t last_index = 0;
// Size of sfnt header plus size of table records.
uint64_t total_sfnt_size = 12 + 16 * header->num_tables;
for (unsigned i = 0; i < header->num_tables; ++i) {
uint64_t total_sfnt_size = 12 + 16 * font->num_tables;
for (unsigned i = 0; i < font->num_tables; ++i) {
OpenTypeTable table;
if (!file.ReadTag(&table.tag) ||
if (!file.ReadU32(&table.tag) ||
!file.ReadU32(&table.offset) ||
!file.ReadU32(&table.length) ||
!file.ReadU32(&table.uncompressed_length) ||
@ -389,12 +460,14 @@ bool ProcessWOFF(ots::OpenTypeFile *header,
return OTS_FAILURE_MSG_HDR("File length mismatch (trailing junk?)");
}
return ProcessGeneric(header, woff_tag, output, data, length, tables, file);
return ProcessGeneric(header, font, woff_tag, output, data, length, tables, file);
}
bool ProcessWOFF2(ots::OpenTypeFile *header,
ots::Font *font,
ots::OTSStream *output, const uint8_t *data, size_t length) {
size_t decompressed_size = ots::ComputeWOFF2FinalSize(data, length);
if (decompressed_size == 0) {
return OTS_FAILURE_MSG_HDR("Size of decompressed WOFF 2.0 is set to 0");
}
@ -404,17 +477,15 @@ bool ProcessWOFF2(ots::OpenTypeFile *header,
}
std::vector<uint8_t> decompressed_buffer(decompressed_size);
if (!ots::ConvertWOFF2ToSFNT(header, &decompressed_buffer[0], decompressed_size,
if (!ots::ConvertWOFF2ToSFNT(font, &decompressed_buffer[0], decompressed_size,
data, length)) {
return OTS_FAILURE_MSG_HDR("Failed to convert WOFF 2.0 font to SFNT");
}
return ProcessTTF(header, output, &decompressed_buffer[0], decompressed_size);
return ProcessTTF(header, font, output, &decompressed_buffer[0], decompressed_size);
}
ots::TableAction GetTableAction(ots::OpenTypeFile *header, uint32_t tag) {
ots::TableAction action = ots::TABLE_ACTION_DEFAULT;
action = header->context->GetTableAction(htonl(tag));
ots::TableAction action = header->context->GetTableAction(tag);
if (action == ots::TABLE_ACTION_DEFAULT) {
action = ots::TABLE_ACTION_DROP;
@ -422,7 +493,7 @@ ots::TableAction GetTableAction(ots::OpenTypeFile *header, uint32_t tag) {
for (unsigned i = 0; ; ++i) {
if (table_parsers[i].parse == NULL) break;
if (Tag(table_parsers[i].tag) == tag) {
if (table_parsers[i].tag == tag) {
action = ots::TABLE_ACTION_SANITIZE;
break;
}
@ -434,7 +505,7 @@ ots::TableAction GetTableAction(ots::OpenTypeFile *header, uint32_t tag) {
}
bool GetTableData(const uint8_t *data,
const OpenTypeTable table,
const OpenTypeTable& table,
Arena *arena,
size_t *table_length,
const uint8_t **table_data) {
@ -457,7 +528,9 @@ bool GetTableData(const uint8_t *data,
return true;
}
bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
bool ProcessGeneric(ots::OpenTypeFile *header,
ots::Font *font,
uint32_t signature,
ots::OTSStream *output,
const uint8_t *data, size_t length,
const std::vector<OpenTypeTable>& tables,
@ -466,12 +539,12 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
uint32_t uncompressed_sum = 0;
for (unsigned i = 0; i < header->num_tables; ++i) {
for (unsigned i = 0; i < font->num_tables; ++i) {
// the tables must be sorted by tag (when taken as big-endian numbers).
// This also remove the possibility of duplicate tables.
if (i) {
const uint32_t this_tag = ntohl(tables[i].tag);
const uint32_t prev_tag = ntohl(tables[i - 1].tag);
const uint32_t this_tag = tables[i].tag;
const uint32_t prev_tag = tables[i - 1].tag;
if (this_tag <= prev_tag) {
OTS_WARNING_MSG_HDR("Table directory is not correctly ordered");
}
@ -479,40 +552,40 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
// all tag names must be built from printable ASCII characters
if (!CheckTag(tables[i].tag)) {
return OTS_FAILURE_MSG_TAG("invalid table tag", &tables[i].tag);
return OTS_FAILURE_MSG_TAG("invalid table tag", tables[i].tag);
}
// tables must be 4-byte aligned
if (tables[i].offset & 3) {
return OTS_FAILURE_MSG_TAG("misaligned table", &tables[i].tag);
return OTS_FAILURE_MSG_TAG("misaligned table", tables[i].tag);
}
// and must be within the file
if (tables[i].offset < data_offset || tables[i].offset >= length) {
return OTS_FAILURE_MSG_TAG("invalid table offset", &tables[i].tag);
return OTS_FAILURE_MSG_TAG("invalid table offset", tables[i].tag);
}
// disallow all tables with a zero length
if (tables[i].length < 1) {
// Note: malayalam.ttf has zero length CVT table...
return OTS_FAILURE_MSG_TAG("zero-length table", &tables[i].tag);
return OTS_FAILURE_MSG_TAG("zero-length table", tables[i].tag);
}
// disallow all tables with a length > 1GB
if (tables[i].length > 1024 * 1024 * 1024) {
return OTS_FAILURE_MSG_TAG("table length exceeds 1GB", &tables[i].tag);
return OTS_FAILURE_MSG_TAG("table length exceeds 1GB", tables[i].tag);
}
// disallow tables where the uncompressed size is < the compressed size.
if (tables[i].uncompressed_length < tables[i].length) {
return OTS_FAILURE_MSG_TAG("invalid compressed table", &tables[i].tag);
return OTS_FAILURE_MSG_TAG("invalid compressed table", tables[i].tag);
}
if (tables[i].uncompressed_length > tables[i].length) {
// We'll probably be decompressing this table.
// disallow all tables which uncompress to > 30 MB
if (tables[i].uncompressed_length > 30 * 1024 * 1024) {
return OTS_FAILURE_MSG_TAG("uncompressed length exceeds 30MB", &tables[i].tag);
return OTS_FAILURE_MSG_TAG("uncompressed length exceeds 30MB", tables[i].tag);
}
if (uncompressed_sum + tables[i].uncompressed_length < uncompressed_sum) {
return OTS_FAILURE_MSG_TAG("overflow of uncompressed sum", &tables[i].tag);
return OTS_FAILURE_MSG_TAG("overflow of uncompressed sum", tables[i].tag);
}
uncompressed_sum += tables[i].uncompressed_length;
@ -521,11 +594,11 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
// length is < 1GB, the following addtion doesn't overflow
uint32_t end_byte = tables[i].offset + tables[i].length;
// Tables in the WOFF file must be aligned 4-byte boundary.
if (signature == Tag("wOFF")) {
if (signature == OTS_TAG('w','O','F','F')) {
end_byte = ots::Round4(end_byte);
}
if (!end_byte || end_byte > length) {
return OTS_FAILURE_MSG_TAG("table overruns end of file", &tables[i].tag);
return OTS_FAILURE_MSG_TAG("table overruns end of file", tables[i].tag);
}
}
@ -535,13 +608,13 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
}
std::map<uint32_t, OpenTypeTable> table_map;
for (unsigned i = 0; i < header->num_tables; ++i) {
for (unsigned i = 0; i < font->num_tables; ++i) {
table_map[tables[i].tag] = tables[i];
}
// check that the tables are not overlapping.
std::vector<std::pair<uint32_t, uint8_t> > overlap_checker;
for (unsigned i = 0; i < header->num_tables; ++i) {
for (unsigned i = 0; i < font->num_tables; ++i) {
overlap_checker.push_back(
std::make_pair(tables[i].offset, static_cast<uint8_t>(1) /* start */));
overlap_checker.push_back(
@ -562,7 +635,7 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
for (unsigned i = 0; ; ++i) {
if (table_parsers[i].parse == NULL) break;
uint32_t tag = Tag(table_parsers[i].tag);
uint32_t tag = table_parsers[i].tag;
const std::map<uint32_t, OpenTypeTable>::const_iterator it = table_map.find(tag);
ots::TableAction action = GetTableAction(header, tag);
@ -573,38 +646,43 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
continue;
}
const uint8_t* table_data;
size_t table_length;
uint32_t input_offset = it->second.offset;
const ots::TableMap::const_iterator ot = header->tables.find(input_offset);
if (ot == header->tables.end()) {
const uint8_t* table_data;
size_t table_length;
if (!GetTableData(data, it->second, &arena, &table_length, &table_data)) {
return OTS_FAILURE_MSG_TAG("uncompress failed", table_parsers[i].tag);
}
if (!GetTableData(data, it->second, &arena, &table_length, &table_data)) {
return OTS_FAILURE_MSG_TAG("uncompress failed", table_parsers[i].tag);
}
if (action == ots::TABLE_ACTION_SANITIZE &&
!table_parsers[i].parse(header, table_data, table_length)) {
// TODO: parsers should generate specific messages detailing the failure;
// once those are all added, we won't need a generic failure message here
return OTS_FAILURE_MSG_TAG("failed to parse table", table_parsers[i].tag);
if (action == ots::TABLE_ACTION_SANITIZE &&
!table_parsers[i].parse(font, table_data, table_length)) {
return OTS_FAILURE();
}
} else if (action == ots::TABLE_ACTION_SANITIZE) {
table_parsers[i].reuse(font, ot->second.first);
}
}
if (header->cff) {
if (font->cff) {
// font with PostScript glyph
if (header->version != Tag("OTTO")) {
if (font->version != OTS_TAG('O','T','T','O')) {
return OTS_FAILURE_MSG_HDR("wrong font version for PostScript glyph data");
}
if (header->glyf || header->loca) {
if (font->glyf || font->loca) {
// mixing outline formats is not recommended
return OTS_FAILURE_MSG_HDR("font contains both PS and TT glyphs");
}
} else {
if (!header->glyf || !header->loca) {
if (!font->glyf || !font->loca) {
// No TrueType glyph found.
#define PASSTHRU_TABLE(TAG) (table_map.find(Tag(TAG)) != table_map.end() && \
GetTableAction(header, Tag(TAG)) == ots::TABLE_ACTION_PASSTHRU)
#define PASSTHRU_TABLE(tag_) (table_map.find(tag_) != table_map.end() && \
GetTableAction(header, tag_) == ots::TABLE_ACTION_PASSTHRU)
// We don't sanitise bitmap table, but don't reject bitmap-only fonts if
// we keep the tables.
if (!PASSTHRU_TABLE("CBDT") || !PASSTHRU_TABLE("CBLC")) {
if (!PASSTHRU_TABLE(OTS_TAG('C','B','D','T')) ||
!PASSTHRU_TABLE(OTS_TAG('C','B','L','C'))) {
return OTS_FAILURE_MSG_HDR("no supported glyph shapes table(s) present");
}
#undef PASSTHRU_TABLE
@ -612,21 +690,19 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
}
uint16_t num_output_tables = 0;
for (unsigned i = 0; ; ++i) {
if (table_parsers[i].parse == NULL) {
break;
}
if (table_parsers[i].should_serialise(header)) {
num_output_tables++;
}
}
for (std::map<uint32_t, OpenTypeTable>::const_iterator it = table_map.begin();
it != table_map.end(); ++it) {
ots::TableAction action = GetTableAction(header, it->first);
if (action == ots::TABLE_ACTION_PASSTHRU) {
num_output_tables++;
} else {
for (unsigned i = 0; table_parsers[i].parse != NULL; ++i) {
if (table_parsers[i].tag == it->first &&
table_parsers[i].should_serialise(font)) {
num_output_tables++;
break;
}
}
}
}
@ -639,7 +715,7 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
// most of the errors here are highly unlikely - they'd only occur if the
// output stream returns a failure, e.g. lack of space to write
output->ResetChecksum();
if (!output->WriteTag(header->version) ||
if (!output->WriteU32(font->version) ||
!output->WriteU16(num_output_tables) ||
!output->WriteU16(output_search_range) ||
!output->WriteU16(max_pow2) ||
@ -653,92 +729,93 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
return OTS_FAILURE_MSG_HDR("error writing output");
}
std::vector<OutputTable> out_tables;
std::vector<ots::OutputTable> out_tables;
size_t head_table_offset = 0;
for (unsigned i = 0; ; ++i) {
if (table_parsers[i].parse == NULL) {
break;
}
if (!table_parsers[i].should_serialise(header)) {
continue;
}
OutputTable out;
uint32_t tag = Tag(table_parsers[i].tag);
out.tag = tag;
out.offset = output->Tell();
output->ResetChecksum();
if (tag == Tag("head")) {
head_table_offset = out.offset;
}
if (!table_parsers[i].serialise(output, header)) {
return OTS_FAILURE_MSG_TAG("failed to serialize table", table_parsers[i].tag);
}
const size_t end_offset = output->Tell();
if (end_offset <= out.offset) {
// paranoid check. |end_offset| is supposed to be greater than the offset,
// as long as the Tell() interface is implemented correctly.
return OTS_FAILURE_MSG_HDR("error writing output");
}
out.length = end_offset - out.offset;
// align tables to four bytes
if (!output->Pad((4 - (end_offset & 3)) % 4)) {
return OTS_FAILURE_MSG_HDR("error writing output");
}
out.chksum = output->chksum();
out_tables.push_back(out);
}
for (std::map<uint32_t, OpenTypeTable>::const_iterator it = table_map.begin();
it != table_map.end(); ++it) {
ots::TableAction action = GetTableAction(header, it->first);
if (action == ots::TABLE_ACTION_PASSTHRU) {
OutputTable out;
out.tag = it->second.tag;
uint32_t input_offset = it->second.offset;
const ots::TableMap::const_iterator ot = header->tables.find(input_offset);
if (ot != header->tables.end()) {
ots::OutputTable out = ot->second.second;
if (out.tag == OTS_TAG('h','e','a','d')) {
head_table_offset = out.offset;
}
out_tables.push_back(out);
} else {
ots::OutputTable out;
out.tag = it->first;
out.offset = output->Tell();
output->ResetChecksum();
if (it->second.tag == Tag("head")) {
if (out.tag == OTS_TAG('h','e','a','d')) {
head_table_offset = out.offset;
}
const uint8_t* table_data;
size_t table_length;
ots::TableAction action = GetTableAction(header, it->first);
if (action == ots::TABLE_ACTION_PASSTHRU) {
output->ResetChecksum();
const uint8_t* table_data;
size_t table_length;
if (!GetTableData(data, it->second, &arena, &table_length, &table_data)) {
return OTS_FAILURE_MSG_HDR("Failed to uncompress table");
}
if (!GetTableData(data, it->second, &arena, &table_length, &table_data)) {
return OTS_FAILURE_MSG_HDR("Failed to uncompress table");
}
if (!output->Write(table_data, table_length)) {
return OTS_FAILURE_MSG_HDR("Failed to serialize table");
}
if (!output->Write(table_data, table_length)) {
return OTS_FAILURE_MSG_HDR("Failed to serialize table");
}
const size_t end_offset = output->Tell();
if (end_offset <= out.offset) {
// paranoid check. |end_offset| is supposed to be greater than the offset,
// as long as the Tell() interface is implemented correctly.
return OTS_FAILURE_MSG_HDR("error writing output");
}
out.length = end_offset - out.offset;
const size_t end_offset = output->Tell();
if (end_offset <= out.offset) {
// paranoid check. |end_offset| is supposed to be greater than the offset,
// as long as the Tell() interface is implemented correctly.
return OTS_FAILURE_MSG_HDR("error writing output");
}
out.length = end_offset - out.offset;
// align tables to four bytes
if (!output->Pad((4 - (end_offset & 3)) % 4)) {
return OTS_FAILURE_MSG_HDR("error writing output");
// align tables to four bytes
if (!output->Pad((4 - (end_offset & 3)) % 4)) {
return OTS_FAILURE_MSG_HDR("error writing output");
}
out.chksum = output->chksum();
out_tables.push_back(out);
header->tables[input_offset] = std::make_pair(font, out);
} else {
for (unsigned i = 0; table_parsers[i].parse != NULL; ++i) {
if (table_parsers[i].tag == it->first &&
table_parsers[i].should_serialise(font)) {
output->ResetChecksum();
if (!table_parsers[i].serialise(output, font)) {
return OTS_FAILURE_MSG_TAG("failed to serialize table", table_parsers[i].tag);
}
const size_t end_offset = output->Tell();
if (end_offset <= out.offset) {
// paranoid check. |end_offset| is supposed to be greater than the offset,
// as long as the Tell() interface is implemented correctly.
return OTS_FAILURE_MSG_HDR("error writing output");
}
out.length = end_offset - out.offset;
// align tables to four bytes
if (!output->Pad((4 - (end_offset & 3)) % 4)) {
return OTS_FAILURE_MSG_HDR("error writing output");
}
out.chksum = output->chksum();
out_tables.push_back(out);
header->tables[input_offset] = std::make_pair(font, out);
break;
}
}
}
out.chksum = output->chksum();
out_tables.push_back(out);
}
}
const size_t end_of_file = output->Tell();
// Need to sort the output tables for inclusion in the file
std::sort(out_tables.begin(), out_tables.end(), OutputTable::SortByTag);
std::sort(out_tables.begin(), out_tables.end());
if (!output->Seek(table_record_offset)) {
return OTS_FAILURE_MSG_HDR("error writing output");
}
@ -746,7 +823,7 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
output->ResetChecksum();
uint32_t tables_chksum = 0;
for (unsigned i = 0; i < out_tables.size(); ++i) {
if (!output->WriteTag(out_tables[i].tag) ||
if (!output->WriteU32(out_tables[i].tag) ||
!output->WriteU32(out_tables[i].chksum) ||
!output->WriteU32(out_tables[i].offset) ||
!output->WriteU32(out_tables[i].length)) {
@ -784,19 +861,20 @@ bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
namespace ots {
bool IsValidVersionTag(uint32_t tag) {
return tag == Tag("\x00\x01\x00\x00") ||
return tag == 0x000010000 ||
// OpenType fonts with CFF data have 'OTTO' tag.
tag == Tag("OTTO") ||
tag == OTS_TAG('O','T','T','O') ||
// Older Mac fonts might have 'true' or 'typ1' tag.
tag == Tag("true") ||
tag == Tag("typ1");
tag == OTS_TAG('t','r','u','e') ||
tag == OTS_TAG('t','y','p','1');
}
bool OTSContext::Process(OTSStream *output,
const uint8_t *data,
size_t length) {
size_t length,
uint32_t index) {
OpenTypeFile header;
Font font(&header);
header.context = this;
if (length < 4) {
@ -805,17 +883,15 @@ bool OTSContext::Process(OTSStream *output,
bool result;
if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') {
result = ProcessWOFF(&header, output, data, length);
result = ProcessWOFF(&header, &font, output, data, length);
} else if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == '2') {
result = ProcessWOFF2(&header, output, data, length);
result = ProcessWOFF2(&header, &font, output, data, length);
} else if (data[0] == 't' && data[1] == 't' && data[2] == 'c' && data[3] == 'f') {
result = ProcessTTC(&header, output, data, length, index);
} else {
result = ProcessTTF(&header, output, data, length);
result = ProcessTTF(&header, &font, output, data, length);
}
for (unsigned i = 0; ; ++i) {
if (table_parsers[i].parse == NULL) break;
table_parsers[i].free(&header);
}
return result;
}

View File

@ -12,6 +12,7 @@
#include <cstdlib>
#include <cstring>
#include <limits>
#include <map>
#include "opentype-sanitiser.h"
@ -55,14 +56,14 @@ namespace ots {
// Generate a message with an associated table tag
#define OTS_FAILURE_MSG_TAG_(otf_,msg_,tag_) \
(OTS_MESSAGE_(0,otf_,"%4.4s: %s", tag_, msg_), false)
(OTS_MESSAGE_(0,otf_,"%c%c%c%c: %s", OTS_UNTAG(tag_), msg_), false)
// Convenience macros for use in files that only handle a single table tag,
// defined as TABLE_NAME at the top of the file; the 'file' variable is
// expected to be the current OpenTypeFile pointer.
#define OTS_FAILURE_MSG(...) OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__)
#define OTS_FAILURE_MSG(...) OTS_FAILURE_MSG_(font->file, TABLE_NAME ": " __VA_ARGS__)
#define OTS_WARNING(...) OTS_WARNING_MSG_(file, TABLE_NAME ": " __VA_ARGS__)
#define OTS_WARNING(...) OTS_WARNING_MSG_(font->file, TABLE_NAME ": " __VA_ARGS__)
// -----------------------------------------------------------------------------
// Buffer helper class
@ -145,15 +146,6 @@ class Buffer {
return ReadU32(reinterpret_cast<uint32_t*>(value));
}
bool ReadTag(uint32_t *value) {
if (offset_ + 4 > length_) {
return OTS_FAILURE();
}
std::memcpy(value, buffer_ + offset_, sizeof(uint32_t));
offset_ += 4;
return true;
}
bool ReadR64(uint64_t *value) {
if (offset_ + 8 > length_) {
return OTS_FAILURE();
@ -225,35 +217,77 @@ bool IsValidVersionTag(uint32_t tag);
FOR_EACH_TABLE_TYPE
#undef F
struct OpenTypeFile {
OpenTypeFile() {
#define F(name, capname) name = NULL;
struct Font;
struct OpenTypeFile;
#define F(name, capname) \
bool ots_##name##_parse(Font *f, const uint8_t *d, size_t l); \
bool ots_##name##_should_serialise(Font *f); \
bool ots_##name##_serialise(OTSStream *s, Font *f); \
void ots_##name##_reuse(Font *f, Font *o);\
void ots_##name##_free(Font *f);
FOR_EACH_TABLE_TYPE
#undef F
struct Font {
explicit Font(const OpenTypeFile *f)
: file(f),
version(0),
num_tables(0),
search_range(0),
entry_selector(0),
range_shift(0) {
#define F(name, capname) \
name = NULL; \
name##_reused = false;
FOR_EACH_TABLE_TYPE
#undef F
}
~Font() {
#define F(name, capname) \
if (!name##_reused) {\
ots_##name##_free(this); \
}
FOR_EACH_TABLE_TYPE
#undef F
}
const OpenTypeFile *file;
uint32_t version;
uint16_t num_tables;
uint16_t search_range;
uint16_t entry_selector;
uint16_t range_shift;
OTSContext *context;
#define F(name, capname) OpenType##capname *name;
#define F(name, capname) \
OpenType##capname *name; \
bool name##_reused;
FOR_EACH_TABLE_TYPE
#undef F
};
#define F(name, capname) \
bool ots_##name##_parse(OpenTypeFile *f, const uint8_t *d, size_t l); \
bool ots_##name##_should_serialise(OpenTypeFile *f); \
bool ots_##name##_serialise(OTSStream *s, OpenTypeFile *f); \
void ots_##name##_free(OpenTypeFile *f);
// TODO(yusukes): change these function names to follow Chromium coding rule.
FOR_EACH_TABLE_TYPE
#undef F
struct OutputTable {
uint32_t tag;
size_t offset;
size_t length;
uint32_t chksum;
bool operator<(const OutputTable& other) const {
return tag < other.tag;
}
};
typedef std::map<uint32_t, std::pair<Font*, OutputTable> > TableMap;
struct OpenTypeFile {
OTSContext *context;
TableMap tables;
};
} // namespace ots
#undef FOR_EACH_TABLE_TYPE
#endif // OTS_H_

View File

@ -13,11 +13,11 @@
namespace ots {
bool ots_post_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
bool ots_post_parse(Font *font, const uint8_t *data, size_t length) {
Buffer table(data, length);
OpenTypePOST *post = new OpenTypePOST;
file->post = post;
font->post = post;
if (!table.ReadU32(&post->version) ||
!table.ReadU32(&post->italic_angle) ||
@ -53,12 +53,12 @@ bool ots_post_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return OTS_FAILURE_MSG("Failed to read number of glyphs");
}
if (!file->maxp) {
if (!font->maxp) {
return OTS_FAILURE_MSG("No maxp table required by post table");
}
if (num_glyphs == 0) {
if (file->maxp->num_glyphs > 258) {
if (font->maxp->num_glyphs > 258) {
return OTS_FAILURE_MSG("Can't have no glyphs in the post table if there are more than 256 glyphs in the font");
}
OTS_WARNING("table version is 1, but no glyf names are found");
@ -68,7 +68,7 @@ bool ots_post_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return true;
}
if (num_glyphs != file->maxp->num_glyphs) {
if (num_glyphs != font->maxp->num_glyphs) {
// Note: Fixedsys500c.ttf seems to have inconsistent num_glyphs values.
return OTS_FAILURE_MSG("Bad number of glyphs in post table %d", num_glyphs);
}
@ -120,15 +120,15 @@ bool ots_post_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return true;
}
bool ots_post_should_serialise(OpenTypeFile *file) {
return file->post != NULL;
bool ots_post_should_serialise(Font *font) {
return font->post != NULL;
}
bool ots_post_serialise(OTSStream *out, OpenTypeFile *file) {
const OpenTypePOST *post = file->post;
bool ots_post_serialise(OTSStream *out, Font *font) {
const OpenTypePOST *post = font->post;
// OpenType with CFF glyphs must have v3 post table.
if (file->post && file->cff && file->post->version != 0x00030000) {
if (font->post && font->cff && font->post->version != 0x00030000) {
return OTS_FAILURE_MSG("Bad post version %x", post->version);
}
@ -179,8 +179,13 @@ bool ots_post_serialise(OTSStream *out, OpenTypeFile *file) {
return true;
}
void ots_post_free(OpenTypeFile *file) {
delete file->post;
void ots_post_reuse(Font *font, Font *other) {
font->post = other->post;
font->post_reused = true;
}
void ots_post_free(Font *font) {
delete font->post;
}
} // namespace ots

View File

@ -11,11 +11,11 @@
namespace ots {
bool ots_prep_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
bool ots_prep_parse(Font *font, const uint8_t *data, size_t length) {
Buffer table(data, length);
OpenTypePREP *prep = new OpenTypePREP;
file->prep = prep;
font->prep = prep;
if (length >= 128 * 1024u) {
return OTS_FAILURE_MSG("table length %ld > 120K", length); // almost all prep tables are less than 9k bytes.
@ -30,13 +30,13 @@ bool ots_prep_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return true;
}
bool ots_prep_should_serialise(OpenTypeFile *file) {
if (!file->glyf) return false; // this table is not for CFF fonts.
return file->prep != NULL;
bool ots_prep_should_serialise(Font *font) {
if (!font->glyf) return false; // this table is not for CFF fonts.
return font->prep != NULL;
}
bool ots_prep_serialise(OTSStream *out, OpenTypeFile *file) {
const OpenTypePREP *prep = file->prep;
bool ots_prep_serialise(OTSStream *out, Font *font) {
const OpenTypePREP *prep = font->prep;
if (!out->Write(prep->data, prep->length)) {
return OTS_FAILURE_MSG("Failed to write table length");
@ -45,8 +45,13 @@ bool ots_prep_serialise(OTSStream *out, OpenTypeFile *file) {
return true;
}
void ots_prep_free(OpenTypeFile *file) {
delete file->prep;
void ots_prep_reuse(Font *font, Font *other) {
font->prep = other->prep;
font->prep_reused = true;
}
void ots_prep_free(Font *font) {
delete font->prep;
}
} // namespace ots

View File

@ -11,18 +11,18 @@
#define DROP_THIS_TABLE(...) \
do { \
OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
OTS_FAILURE_MSG_(font->file, TABLE_NAME ": " __VA_ARGS__); \
OTS_FAILURE_MSG("Table discarded"); \
delete file->vdmx; \
file->vdmx = 0; \
delete font->vdmx; \
font->vdmx = 0; \
} while (0)
namespace ots {
bool ots_vdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
bool ots_vdmx_parse(Font *font, const uint8_t *data, size_t length) {
Buffer table(data, length);
file->vdmx = new OpenTypeVDMX;
OpenTypeVDMX * const vdmx = file->vdmx;
font->vdmx = new OpenTypeVDMX;
OpenTypeVDMX * const vdmx = font->vdmx;
if (!table.ReadU16(&vdmx->version) ||
!table.ReadU16(&vdmx->num_recs) ||
@ -121,13 +121,13 @@ bool ots_vdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return true;
}
bool ots_vdmx_should_serialise(OpenTypeFile *file) {
if (!file->glyf) return false; // this table is not for CFF fonts.
return file->vdmx != NULL;
bool ots_vdmx_should_serialise(Font *font) {
if (!font->glyf) return false; // this table is not for CFF fonts.
return font->vdmx != NULL;
}
bool ots_vdmx_serialise(OTSStream *out, OpenTypeFile *file) {
OpenTypeVDMX * const vdmx = file->vdmx;
bool ots_vdmx_serialise(OTSStream *out, Font *font) {
OpenTypeVDMX * const vdmx = font->vdmx;
if (!out->WriteU16(vdmx->version) ||
!out->WriteU16(vdmx->num_recs) ||
@ -171,8 +171,13 @@ bool ots_vdmx_serialise(OTSStream *out, OpenTypeFile *file) {
return true;
}
void ots_vdmx_free(OpenTypeFile *file) {
delete file->vdmx;
void ots_vdmx_reuse(Font *font, Font *other) {
font->vdmx = other->vdmx;
font->vdmx_reused = true;
}
void ots_vdmx_free(Font *font) {
delete font->vdmx;
}
} // namespace ots

View File

@ -15,10 +15,10 @@
namespace ots {
bool ots_vhea_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
bool ots_vhea_parse(Font *font, const uint8_t *data, size_t length) {
Buffer table(data, length);
OpenTypeVHEA *vhea = new OpenTypeVHEA;
file->vhea = vhea;
font->vhea = vhea;
if (!table.ReadU32(&vhea->header.version)) {
return OTS_FAILURE_MSG("Failed to read version");
@ -28,30 +28,35 @@ bool ots_vhea_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return OTS_FAILURE_MSG("Bad vhea version %x", vhea->header.version);
}
if (!ParseMetricsHeader(file, &table, &vhea->header)) {
if (!ParseMetricsHeader(font, &table, &vhea->header)) {
return OTS_FAILURE_MSG("Failed to parse metrics in vhea");
}
return true;
}
bool ots_vhea_should_serialise(OpenTypeFile *file) {
bool ots_vhea_should_serialise(Font *font) {
// vhea should'nt serialise when vmtx doesn't exist.
// Firefox developer pointed out that vhea/vmtx should serialise iff GSUB is
// preserved. See http://crbug.com/77386
return file->vhea != NULL && file->vmtx != NULL &&
ots_gsub_should_serialise(file);
return font->vhea != NULL && font->vmtx != NULL &&
ots_gsub_should_serialise(font);
}
bool ots_vhea_serialise(OTSStream *out, OpenTypeFile *file) {
if (!SerialiseMetricsHeader(file, out, &file->vhea->header)) {
bool ots_vhea_serialise(OTSStream *out, Font *font) {
if (!SerialiseMetricsHeader(font, out, &font->vhea->header)) {
return OTS_FAILURE_MSG("Failed to write vhea metrics");
}
return true;
}
void ots_vhea_free(OpenTypeFile *file) {
delete file->vhea;
void ots_vhea_reuse(Font *font, Font *other) {
font->vhea = other->vhea;
font->vhea_reused = true;
}
void ots_vhea_free(Font *font) {
delete font->vhea;
}
} // namespace ots

View File

@ -15,39 +15,44 @@
namespace ots {
bool ots_vmtx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
bool ots_vmtx_parse(Font *font, const uint8_t *data, size_t length) {
Buffer table(data, length);
OpenTypeVMTX *vmtx = new OpenTypeVMTX;
file->vmtx = vmtx;
font->vmtx = vmtx;
if (!file->vhea || !file->maxp) {
if (!font->vhea || !font->maxp) {
return OTS_FAILURE_MSG("vhea or maxp table missing as needed by vmtx");
}
if (!ParseMetricsTable(file, &table, file->maxp->num_glyphs,
&file->vhea->header, &vmtx->metrics)) {
if (!ParseMetricsTable(font, &table, font->maxp->num_glyphs,
&font->vhea->header, &vmtx->metrics)) {
return OTS_FAILURE_MSG("Failed to parse vmtx metrics");
}
return true;
}
bool ots_vmtx_should_serialise(OpenTypeFile *file) {
bool ots_vmtx_should_serialise(Font *font) {
// vmtx should serialise when vhea and GSUB are preserved.
// See the comment in ots_vhea_should_serialise().
return file->vmtx != NULL && file->vhea != NULL &&
ots_gsub_should_serialise(file);
return font->vmtx != NULL && font->vhea != NULL &&
ots_gsub_should_serialise(font);
}
bool ots_vmtx_serialise(OTSStream *out, OpenTypeFile *file) {
if (!SerialiseMetricsTable(file, out, &file->vmtx->metrics)) {
bool ots_vmtx_serialise(OTSStream *out, Font *font) {
if (!SerialiseMetricsTable(font, out, &font->vmtx->metrics)) {
return OTS_FAILURE_MSG("Failed to write vmtx metrics");
}
return true;
}
void ots_vmtx_free(OpenTypeFile *file) {
delete file->vmtx;
void ots_vmtx_reuse(Font *font, Font *other) {
font->vmtx = other->vmtx;
font->vmtx_reused = true;
}
void ots_vmtx_free(Font *font) {
delete font->vmtx;
}
} // namespace ots

View File

@ -13,18 +13,18 @@
#define DROP_THIS_TABLE(...) \
do { \
OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
OTS_FAILURE_MSG_(font->file, TABLE_NAME ": " __VA_ARGS__); \
OTS_FAILURE_MSG("Table discarded"); \
delete file->vorg; \
file->vorg = 0; \
delete font->vorg; \
font->vorg = 0; \
} while (0)
namespace ots {
bool ots_vorg_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
bool ots_vorg_parse(Font *font, const uint8_t *data, size_t length) {
Buffer table(data, length);
file->vorg = new OpenTypeVORG;
OpenTypeVORG * const vorg = file->vorg;
font->vorg = new OpenTypeVORG;
OpenTypeVORG * const vorg = font->vorg;
uint16_t num_recs;
if (!table.ReadU16(&vorg->major_version) ||
@ -68,13 +68,13 @@ bool ots_vorg_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
return true;
}
bool ots_vorg_should_serialise(OpenTypeFile *file) {
if (!file->cff) return false; // this table is not for fonts with TT glyphs.
return file->vorg != NULL;
bool ots_vorg_should_serialise(Font *font) {
if (!font->cff) return false; // this table is not for fonts with TT glyphs.
return font->vorg != NULL;
}
bool ots_vorg_serialise(OTSStream *out, OpenTypeFile *file) {
OpenTypeVORG * const vorg = file->vorg;
bool ots_vorg_serialise(OTSStream *out, Font *font) {
OpenTypeVORG * const vorg = font->vorg;
const uint16_t num_metrics = static_cast<uint16_t>(vorg->metrics.size());
if (num_metrics != vorg->metrics.size() ||
@ -96,8 +96,13 @@ bool ots_vorg_serialise(OTSStream *out, OpenTypeFile *file) {
return true;
}
void ots_vorg_free(OpenTypeFile *file) {
delete file->vorg;
void ots_vorg_reuse(Font *font, Font *other) {
font->vorg = other->vorg;
font->vorg_reused = true;
}
void ots_vorg_free(Font *font) {
delete font->vorg;
}
} // namespace ots

View File

@ -43,76 +43,72 @@ const size_t kCheckSumAdjustmentOffset = 8;
const size_t kEndPtsOfContoursOffset = 10;
const size_t kCompositeGlyphBegin = 10;
// Note that the byte order is big-endian, not the same as ots.cc
#define TAG(a, b, c, d) ((a << 24) | (b << 16) | (c << 8) | d)
#define CHR(t) (t >> 24), (t >> 16), (t >> 8), (t >> 0)
const unsigned int kWoff2FlagsTransform = 1 << 5;
const uint32_t kKnownTags[] = {
TAG('c', 'm', 'a', 'p'), // 0
TAG('h', 'e', 'a', 'd'), // 1
TAG('h', 'h', 'e', 'a'), // 2
TAG('h', 'm', 't', 'x'), // 3
TAG('m', 'a', 'x', 'p'), // 4
TAG('n', 'a', 'm', 'e'), // 5
TAG('O', 'S', '/', '2'), // 6
TAG('p', 'o', 's', 't'), // 7
TAG('c', 'v', 't', ' '), // 8
TAG('f', 'p', 'g', 'm'), // 9
TAG('g', 'l', 'y', 'f'), // 10
TAG('l', 'o', 'c', 'a'), // 11
TAG('p', 'r', 'e', 'p'), // 12
TAG('C', 'F', 'F', ' '), // 13
TAG('V', 'O', 'R', 'G'), // 14
TAG('E', 'B', 'D', 'T'), // 15
TAG('E', 'B', 'L', 'C'), // 16
TAG('g', 'a', 's', 'p'), // 17
TAG('h', 'd', 'm', 'x'), // 18
TAG('k', 'e', 'r', 'n'), // 19
TAG('L', 'T', 'S', 'H'), // 20
TAG('P', 'C', 'L', 'T'), // 21
TAG('V', 'D', 'M', 'X'), // 22
TAG('v', 'h', 'e', 'a'), // 23
TAG('v', 'm', 't', 'x'), // 24
TAG('B', 'A', 'S', 'E'), // 25
TAG('G', 'D', 'E', 'F'), // 26
TAG('G', 'P', 'O', 'S'), // 27
TAG('G', 'S', 'U', 'B'), // 28
TAG('E', 'B', 'S', 'C'), // 29
TAG('J', 'S', 'T', 'F'), // 30
TAG('M', 'A', 'T', 'H'), // 31
TAG('C', 'B', 'D', 'T'), // 32
TAG('C', 'B', 'L', 'C'), // 33
TAG('C', 'O', 'L', 'R'), // 34
TAG('C', 'P', 'A', 'L'), // 35
TAG('S', 'V', 'G', ' '), // 36
TAG('s', 'b', 'i', 'x'), // 37
TAG('a', 'c', 'n', 't'), // 38
TAG('a', 'v', 'a', 'r'), // 39
TAG('b', 'd', 'a', 't'), // 40
TAG('b', 'l', 'o', 'c'), // 41
TAG('b', 's', 'l', 'n'), // 42
TAG('c', 'v', 'a', 'r'), // 43
TAG('f', 'd', 's', 'c'), // 44
TAG('f', 'e', 'a', 't'), // 45
TAG('f', 'm', 't', 'x'), // 46
TAG('f', 'v', 'a', 'r'), // 47
TAG('g', 'v', 'a', 'r'), // 48
TAG('h', 's', 't', 'y'), // 49
TAG('j', 'u', 's', 't'), // 50
TAG('l', 'c', 'a', 'r'), // 51
TAG('m', 'o', 'r', 't'), // 52
TAG('m', 'o', 'r', 'x'), // 53
TAG('o', 'p', 'b', 'd'), // 54
TAG('p', 'r', 'o', 'p'), // 55
TAG('t', 'r', 'a', 'k'), // 56
TAG('Z', 'a', 'p', 'f'), // 57
TAG('S', 'i', 'l', 'f'), // 58
TAG('G', 'l', 'a', 't'), // 59
TAG('G', 'l', 'o', 'c'), // 60
TAG('F', 'e', 'a', 't'), // 61
TAG('S', 'i', 'l', 'l'), // 62
OTS_TAG('c','m','a','p'), // 0
OTS_TAG('h','e','a','d'), // 1
OTS_TAG('h','h','e','a'), // 2
OTS_TAG('h','m','t','x'), // 3
OTS_TAG('m','a','x','p'), // 4
OTS_TAG('n','a','m','e'), // 5
OTS_TAG('O','S','/','2'), // 6
OTS_TAG('p','o','s','t'), // 7
OTS_TAG('c','v','t',' '), // 8
OTS_TAG('f','p','g','m'), // 9
OTS_TAG('g','l','y','f'), // 10
OTS_TAG('l','o','c','a'), // 11
OTS_TAG('p','r','e','p'), // 12
OTS_TAG('C','F','F',' '), // 13
OTS_TAG('V','O','R','G'), // 14
OTS_TAG('E','B','D','T'), // 15
OTS_TAG('E','B','L','C'), // 16
OTS_TAG('g','a','s','p'), // 17
OTS_TAG('h','d','m','x'), // 18
OTS_TAG('k','e','r','n'), // 19
OTS_TAG('L','T','S','H'), // 20
OTS_TAG('P','C','L','T'), // 21
OTS_TAG('V','D','M','X'), // 22
OTS_TAG('v','h','e','a'), // 23
OTS_TAG('v','m','t','x'), // 24
OTS_TAG('B','A','S','E'), // 25
OTS_TAG('G','D','E','F'), // 26
OTS_TAG('G','P','O','S'), // 27
OTS_TAG('G','S','U','B'), // 28
OTS_TAG('E','B','S','C'), // 29
OTS_TAG('J','S','T','F'), // 30
OTS_TAG('M','A','T','H'), // 31
OTS_TAG('C','B','D','T'), // 32
OTS_TAG('C','B','L','C'), // 33
OTS_TAG('C','O','L','R'), // 34
OTS_TAG('C','P','A','L'), // 35
OTS_TAG('S','V','G',' '), // 36
OTS_TAG('s','b','i','x'), // 37
OTS_TAG('a','c','n','t'), // 38
OTS_TAG('a','v','a','r'), // 39
OTS_TAG('b','d','a','t'), // 40
OTS_TAG('b','l','o','c'), // 41
OTS_TAG('b','s','l','n'), // 42
OTS_TAG('c','v','a','r'), // 43
OTS_TAG('f','d','s','c'), // 44
OTS_TAG('f','e','a','t'), // 45
OTS_TAG('f','m','t','x'), // 46
OTS_TAG('f','v','a','r'), // 47
OTS_TAG('g','v','a','r'), // 48
OTS_TAG('h','s','t','y'), // 49
OTS_TAG('j','u','s','t'), // 50
OTS_TAG('l','c','a','r'), // 51
OTS_TAG('m','o','r','t'), // 52
OTS_TAG('m','o','r','x'), // 53
OTS_TAG('o','p','b','d'), // 54
OTS_TAG('p','r','o','p'), // 55
OTS_TAG('t','r','a','k'), // 56
OTS_TAG('Z','a','p','f'), // 57
OTS_TAG('S','i','l','f'), // 58
OTS_TAG('G','l','a','t'), // 59
OTS_TAG('G','l','o','c'), // 60
OTS_TAG('F','e','a','t'), // 61
OTS_TAG('S','i','l','l'), // 62
};
struct Point {
@ -186,6 +182,9 @@ bool ReadBase128(ots::Buffer* buf, uint32_t* value) {
if (!buf->ReadU8(&code)) {
return OTS_FAILURE();
}
if (i == 0 && code == 0x80) {
return OTS_FAILURE();
}
// If any of the top seven bits are set then we're about to overflow.
if (result & 0xfe000000U) {
return OTS_FAILURE();
@ -514,7 +513,7 @@ bool StoreLoca(const std::vector<uint32_t>& loca_values, int index_format,
}
// Reconstruct entire glyf table based on transformed original
bool ReconstructGlyf(ots::OpenTypeFile* file,
bool ReconstructGlyf(ots::Font *font,
const uint8_t* data, size_t data_size,
uint8_t* dst, size_t dst_size,
uint8_t* loca_buf, size_t loca_size) {
@ -564,6 +563,7 @@ bool ReconstructGlyf(ots::OpenTypeFile* file,
std::vector<uint16_t> n_points_vec;
std::vector<Point> points;
uint32_t loca_offset = 0;
const uint8_t* bbox_bitmap = bbox_stream.buffer();
for (unsigned int i = 0; i < num_glyphs; ++i) {
size_t glyph_size = 0;
uint16_t n_contours = 0;
@ -574,6 +574,9 @@ bool ReconstructGlyf(ots::OpenTypeFile* file,
size_t glyf_dst_size = dst_size - loca_offset;
if (n_contours == 0xffff) {
// composite glyph
if (!(bbox_bitmap[i >> 3] & (0x80 >> (i & 7)))) {
return OTS_FAILURE_MSG("Composite glyph %d without bbox", i);
}
bool have_instructions = false;
uint16_t instruction_size = 0;
if (!ProcessComposite(&composite_stream, glyf_dst, glyf_dst_size,
@ -701,13 +704,13 @@ const Table* FindTable(const std::vector<Table>& tables, uint32_t tag) {
return NULL;
}
bool ReconstructTransformed(ots::OpenTypeFile* file,
bool ReconstructTransformed(ots::Font *font,
const std::vector<Table>& tables, uint32_t tag,
const uint8_t* transformed_buf, size_t transformed_size,
uint8_t* dst, size_t dst_length) {
if (tag == TAG('g', 'l', 'y', 'f')) {
if (tag == OTS_TAG('g','l','y','f')) {
const Table* glyf_table = FindTable(tables, tag);
const Table* loca_table = FindTable(tables, TAG('l', 'o', 'c', 'a'));
const Table* loca_table = FindTable(tables, OTS_TAG('l','o','c','a'));
if (glyf_table == NULL || loca_table == NULL) {
return OTS_FAILURE();
}
@ -719,12 +722,12 @@ bool ReconstructTransformed(ots::OpenTypeFile* file,
dst_length) {
return OTS_FAILURE();
}
return ReconstructGlyf(file, transformed_buf, transformed_size,
return ReconstructGlyf(font, transformed_buf, transformed_size,
dst + glyf_table->dst_offset, glyf_table->dst_length,
dst + loca_table->dst_offset, loca_table->dst_length);
} else if (tag == TAG('l', 'o', 'c', 'a')) {
} else if (tag == OTS_TAG('l','o','c','a')) {
// processing was already done by glyf table, but validate
if (!FindTable(tables, TAG('g', 'l', 'y', 'f'))) {
if (!FindTable(tables, OTS_TAG('g','l','y','f'))) {
return OTS_FAILURE();
}
} else {
@ -745,7 +748,7 @@ uint32_t ComputeChecksum(const uint8_t* buf, size_t size) {
}
bool FixChecksums(const std::vector<Table>& tables, uint8_t* dst) {
const Table* head_table = FindTable(tables, TAG('h', 'e', 'a', 'd'));
const Table* head_table = FindTable(tables, OTS_TAG('h','e','a','d'));
if (head_table == NULL ||
head_table->dst_length < kCheckSumAdjustmentOffset + 4) {
return OTS_FAILURE();
@ -772,18 +775,7 @@ bool FixChecksums(const std::vector<Table>& tables, uint8_t* dst) {
return true;
}
bool Woff2Uncompress(uint8_t* dst_buf, size_t dst_size,
const uint8_t* src_buf, size_t src_size) {
size_t uncompressed_size = dst_size;
int ok = BrotliDecompressBuffer(src_size, src_buf,
&uncompressed_size, dst_buf);
if (!ok || uncompressed_size != dst_size) {
return OTS_FAILURE();
}
return true;
}
bool ReadTableDirectory(ots::OpenTypeFile* file,
bool ReadTableDirectory(ots::Font *font,
ots::Buffer* buffer, std::vector<Table>* tables,
size_t num_tables) {
for (size_t i = 0; i < num_tables; ++i) {
@ -806,18 +798,22 @@ bool ReadTableDirectory(ots::OpenTypeFile* file,
}
uint32_t flags = 0;
// Always transform the glyf and loca tables
if (tag == TAG('g', 'l', 'y', 'f') ||
tag == TAG('l', 'o', 'c', 'a')) {
if (tag == OTS_TAG('g','l','y','f') ||
tag == OTS_TAG('l','o','c','a')) {
flags |= kWoff2FlagsTransform;
}
uint32_t dst_length;
if (!ReadBase128(buffer, &dst_length)) {
return OTS_FAILURE_MSG("Failed to read 'origLength' for table '%c%c%c%c'", CHR(tag));
return OTS_FAILURE_MSG("Failed to read 'origLength' for table '%c%c%c%c'", OTS_UNTAG(tag));
}
uint32_t transform_length = dst_length;
if ((flags & kWoff2FlagsTransform) != 0) {
if (!ReadBase128(buffer, &transform_length)) {
return OTS_FAILURE_MSG("Failed to read 'transformLength' for table '%c%c%c%c'", CHR(tag));
return OTS_FAILURE_MSG("Failed to read 'transformLength' for table '%c%c%c%c'", OTS_UNTAG(tag));
}
if (tag == OTS_TAG('l','o','c','a') && transform_length != 0) {
return OTS_FAILURE_MSG("The 'transformLength' of 'loca' table must be zero: %d", transform_length);
}
}
// Disallow huge numbers (> 1GB) for sanity.
@ -848,7 +844,7 @@ size_t ComputeWOFF2FinalSize(const uint8_t* data, size_t length) {
return total_length;
}
bool ConvertWOFF2ToSFNT(ots::OpenTypeFile* file,
bool ConvertWOFF2ToSFNT(ots::Font *font,
uint8_t* result, size_t result_length,
const uint8_t* data, size_t length) {
static const uint32_t kWoff2Signature = 0x774f4632; // "wOF2"
@ -861,7 +857,7 @@ bool ConvertWOFF2ToSFNT(ots::OpenTypeFile* file,
return OTS_FAILURE_MSG("Failed to read 'signature' or 'flavor', or not WOFF2 signature");
}
if (!IsValidVersionTag(ntohl(flavor))) {
if (!IsValidVersionTag(flavor)) {
return OTS_FAILURE_MSG("Invalid 'flavor'");
}
@ -927,7 +923,7 @@ bool ConvertWOFF2ToSFNT(ots::OpenTypeFile* file,
}
std::vector<Table> tables(num_tables);
if (!ReadTableDirectory(file, &buffer, &tables, num_tables)) {
if (!ReadTableDirectory(font, &buffer, &tables, num_tables)) {
return OTS_FAILURE_MSG("Failed to read table directory");
}
uint64_t compressed_offset = buffer.offset();
@ -1020,13 +1016,16 @@ bool ConvertWOFF2ToSFNT(ots::OpenTypeFile* file,
if (total_size > 30 * 1024 * 1024) {
return OTS_FAILURE();
}
const size_t total_size_size_t = static_cast<size_t>(total_size);
uncompressed_buf.resize(total_size_size_t);
const uint8_t* src_buf = data + compressed_offset;
if (!Woff2Uncompress(&uncompressed_buf[0], total_size_size_t,
src_buf, compressed_length)) {
size_t uncompressed_size = static_cast<size_t>(total_size);
uncompressed_buf.resize(uncompressed_size);
const uint8_t* compressed_buf = data + compressed_offset;
if (!BrotliDecompressBuffer(compressed_length, compressed_buf,
&uncompressed_size, &uncompressed_buf[0])) {
return OTS_FAILURE_MSG("Failed to uncompress font data");
}
if (uncompressed_size != static_cast<size_t>(total_size)) {
return OTS_FAILURE_MSG("Decompressed font data size does not match the sum of 'origLength' and 'transformLength'");
}
transform_buf = &uncompressed_buf[0];
for (uint16_t i = 0; i < num_tables; ++i) {
@ -1045,9 +1044,9 @@ bool ConvertWOFF2ToSFNT(ots::OpenTypeFile* file,
std::memcpy(result + table->dst_offset, transform_buf,
transform_length);
} else {
if (!ReconstructTransformed(file, tables, table->tag,
if (!ReconstructTransformed(font, tables, table->tag,
transform_buf, transform_length, result, result_length)) {
return OTS_FAILURE_MSG("Failed to reconstruct '%c%c%c%c' table", CHR(table->tag));
return OTS_FAILURE_MSG("Failed to reconstruct '%c%c%c%c' table", OTS_UNTAG(table->tag));
}
}

View File

@ -13,7 +13,7 @@ size_t ComputeWOFF2FinalSize(const uint8_t *data, size_t length);
// Decompresses the font into the target buffer. The result_length should
// be the same as determined by ComputeFinalSize(). Returns true on successful
// decompression.
bool ConvertWOFF2ToSFNT(OpenTypeFile *file, uint8_t *result, size_t result_length,
bool ConvertWOFF2ToSFNT(Font *font, uint8_t *result, size_t result_length,
const uint8_t *data, size_t length);
}

View File

@ -22,7 +22,8 @@ cp -r $1/include .
echo "Updating README.mozilla..."
REVISION=`cd $1; git log | head -1 | sed "s/commit //"`
sed -e "s/\(Current revision: \).*/\1$REVISION/" -i "" README.mozilla
sed -e "s/\(Current revision: \).*/\1$REVISION/" README.mozilla > README.tmp
mv README.tmp README.mozilla
echo "Applying ots-visibility.patch..."
patch -p3 < ots-visibility.patch