зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1193050 - Update OTS to latest upstream version. r=jfkthame
This commit is contained in:
Родитель
22c545a76c
Коммит
7324f7cce8
|
@ -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/
|
||||
|
||||
|
|
|
@ -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; }
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(<sh->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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче