diff --git a/gfx/ots/README.mozilla b/gfx/ots/README.mozilla index 5a70099bec02..abed50018dd8 100644 --- a/gfx/ots/README.mozilla +++ b/gfx/ots/README.mozilla @@ -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/ diff --git a/gfx/ots/include/opentype-sanitiser.h b/gfx/ots/include/opentype-sanitiser.h index 9f77881050af..bd55df8c5044 100644 --- a/gfx/ots/include/opentype-sanitiser.h +++ b/gfx/ots/include/opentype-sanitiser.h @@ -49,6 +49,9 @@ typedef unsigned __int64 uint64_t; #include #include +#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(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(4) - chksum_offset); + uint32_t tmp = 0; + std::memcpy(reinterpret_cast(&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(data) + offset, length); - chksum_buffer_offset_ = length; + uint32_t tmp = 0; + std::memcpy(&tmp, + reinterpret_cast(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; } }; diff --git a/gfx/ots/src/cff.cc b/gfx/ots/src/cff.cc index 9c7204d999eb..23b6dadac273 100644 --- a/gfx/ots/src/cff.cc +++ b/gfx/ots/src/cff.cc @@ -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::const_iterator iter; - std::map::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::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; } } diff --git a/gfx/ots/src/cff_type2_charstring.cc b/gfx/ots/src/cff_type2_charstring.cc index 6dd47664d091..8c5544b2ec4b 100644 --- a/gfx/ots/src/cff_type2_charstring.cc +++ b/gfx/ots/src/cff_type2_charstring.cc @@ -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 &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 &fd_select, const std::vector &local_subrs_per_font, const CFFIndex *local_subrs, Buffer* cff_table) { - const uint16_t num_offsets = - static_cast(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, diff --git a/gfx/ots/src/cff_type2_charstring.h b/gfx/ots/src/cff_type2_charstring.h index 673234257bd5..be44bc72c318 100644 --- a/gfx/ots/src/cff_type2_charstring.h +++ b/gfx/ots/src/cff_type2_charstring.h @@ -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 &fd_select, diff --git a/gfx/ots/src/cmap.cc b/gfx/ots/src/cmap.cc index b1bf5fd159f6..6729c665c684 100644 --- a/gfx/ots/src/cmap.cc +++ b/gfx/ots/src/cmap.cc @@ -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 &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 &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& 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(have_034) + static_cast(have_0514) + static_cast(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 &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 &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 &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 diff --git a/gfx/ots/src/cvt.cc b/gfx/ots/src/cvt.cc index f83ad0ee2078..1402e7c06a66 100644 --- a/gfx/ots/src/cvt.cc +++ b/gfx/ots/src/cvt.cc @@ -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 diff --git a/gfx/ots/src/fpgm.cc b/gfx/ots/src/fpgm.cc index eba03e73e6f5..faa9a2392ad5 100644 --- a/gfx/ots/src/fpgm.cc +++ b/gfx/ots/src/fpgm.cc @@ -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 diff --git a/gfx/ots/src/gasp.cc b/gfx/ots/src/gasp.cc index 1e2327f19bc4..5ebf5d84b4b2 100644 --- a/gfx/ots/src/gasp.cc +++ b/gfx/ots/src/gasp.cc @@ -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(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 diff --git a/gfx/ots/src/gdef.cc b/gfx/ots/src/gdef.cc index 4553d58fbc51..71c6fc59286c 100644 --- a/gfx/ots/src/gdef.cc +++ b/gfx/ots/src/gdef.cc @@ -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 diff --git a/gfx/ots/src/glyf.cc b/gfx/ots/src/glyf.cc index 357939782e69..311916dc0ca2 100644 --- a/gfx/ots/src/glyf.cc +++ b/gfx/ots/src/glyf.cc @@ -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 &offsets = file->loca->offsets; + const unsigned num_glyphs = font->maxp->num_glyphs; + std::vector &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::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 diff --git a/gfx/ots/src/gpos.cc b/gfx/ots/src/gpos.cc index a2b968726e27..83d9ab0536a4 100644 --- a/gfx/ots/src/gpos.cc +++ b/gfx/ots/src/gpos.cc @@ -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 diff --git a/gfx/ots/src/gsub.cc b/gfx/ots/src/gsub.cc index af31144635f6..9baf2e88bfd6 100644 --- a/gfx/ots/src/gsub.cc +++ b/gfx/ots/src/gsub.cc @@ -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(6) + sequence_count * 2; if (sequence_end > std::numeric_limits::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(6) + alternate_set_count * 2; if (alternate_set_end > std::numeric_limits::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(6) + lig_set_count * 2; if (ligature_set_end > std::numeric_limits::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 diff --git a/gfx/ots/src/hdmx.cc b/gfx/ots/src/hdmx.cc index 098802b7f261..f57b71f59df2 100644 --- a/gfx/ots/src/hdmx.cc +++ b/gfx/ots/src/hdmx.cc @@ -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(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 diff --git a/gfx/ots/src/head.cc b/gfx/ots/src/head.cc index dcd234d24c00..229ea71f9035 100644 --- a/gfx/ots/src/head.cc +++ b/gfx/ots/src/head.cc @@ -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 diff --git a/gfx/ots/src/hhea.cc b/gfx/ots/src/hhea.cc index 8430442d8ef6..6242872802ae 100644 --- a/gfx/ots/src/hhea.cc +++ b/gfx/ots/src/hhea.cc @@ -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 diff --git a/gfx/ots/src/hmtx.cc b/gfx/ots/src/hmtx.cc index ae86513196a8..667d1fe6f566 100644 --- a/gfx/ots/src/hmtx.cc +++ b/gfx/ots/src/hmtx.cc @@ -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 diff --git a/gfx/ots/src/kern.cc b/gfx/ots/src/kern.cc index 744c057db6c1..d4ae8fcc480f 100644 --- a/gfx/ots/src/kern.cc +++ b/gfx/ots/src/kern.cc @@ -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(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 diff --git a/gfx/ots/src/layout.cc b/gfx/ots/src/layout.cc index 856152c18ac1..7f467221a89b 100644 --- a/gfx/ots/src/layout.cc +++ b/gfx/ots/src/layout.cc @@ -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(lang_sys_count) + 4; if (lang_sys_record_end > std::numeric_limits::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 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"); } diff --git a/gfx/ots/src/layout.h b/gfx/ots/src/layout.h index 3b94589e16d0..d195646d4190 100644 --- a/gfx/ots/src/layout.h +++ b/gfx/ots/src/layout.h @@ -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); diff --git a/gfx/ots/src/loca.cc b/gfx/ots/src/loca.cc index 4b291f028c08..aae04c25ab78 100644 --- a/gfx/ots/src/loca.cc +++ b/gfx/ots/src/loca.cc @@ -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 diff --git a/gfx/ots/src/ltsh.cc b/gfx/ots/src/ltsh.cc index 418c1598e432..5b34cf4ad8b6 100644 --- a/gfx/ots/src/ltsh.cc +++ b/gfx/ots/src/ltsh.cc @@ -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(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 diff --git a/gfx/ots/src/math.cc b/gfx/ots/src/math.cc index 9124a88c512d..0688071d7c82 100644 --- a/gfx/ots/src/math.cc +++ b/gfx/ots/src/math.cc @@ -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(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 diff --git a/gfx/ots/src/maxp.cc b/gfx/ots/src/maxp.cc index aaf00760a90c..41e29a7452f7 100644 --- a/gfx/ots/src/maxp.cc +++ b/gfx/ots/src/maxp.cc @@ -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 diff --git a/gfx/ots/src/metrics.cc b/gfx/ots/src/metrics.cc index 8d59b953b18a..579d0bd1e75b 100644 --- a/gfx/ots/src/metrics.cc +++ b/gfx/ots/src/metrics.cc @@ -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) { diff --git a/gfx/ots/src/metrics.h b/gfx/ots/src/metrics.h index f0b4ee8c68ad..767be2fdb4d8 100644 --- a/gfx/ots/src/metrics.h +++ b/gfx/ots/src/metrics.h @@ -33,18 +33,18 @@ struct OpenTypeMetricsTable { std::vector 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); diff --git a/gfx/ots/src/name.cc b/gfx/ots/src/name.cc index 2ea10dc8e67d..e55be75371a6 100644 --- a/gfx/ots/src/name.cc +++ b/gfx/ots/src/name.cc @@ -7,8 +7,6 @@ #include #include -#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(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::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(name->names.size()); uint16_t lang_tag_count = static_cast(name->lang_tags.size()); @@ -292,7 +277,7 @@ bool ots_name_serialise(OTSStream* out, OpenTypeFile* file) { std::string string_data; for (std::vector::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::max() || @@ -313,7 +298,7 @@ bool ots_name_serialise(OTSStream* out, OpenTypeFile* file) { } for (std::vector::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::max() || !out->WriteU16(static_cast(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 diff --git a/gfx/ots/src/os2.cc b/gfx/ots/src/os2.cc index 8cdc5d037fe7..fd5cdd1d6860 100644 --- a/gfx/ots/src/os2.cc +++ b/gfx/ots/src/os2.cc @@ -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 diff --git a/gfx/ots/src/os2.h b/gfx/ots/src/os2.h index 9e0fc3475287..01511c5dc37c 100644 --- a/gfx/ots/src/os2.h +++ b/gfx/ots/src/os2.h @@ -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 diff --git a/gfx/ots/src/ots.cc b/gfx/ots/src/ots.cc index 28d0285de670..8fd17549efd5 100644 --- a/gfx/ots/src/ots.cc +++ b/gfx/ots/src/ots.cc @@ -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 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 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(-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 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 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& 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 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 > 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(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::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::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 out_tables; + std::vector 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::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; } diff --git a/gfx/ots/src/ots.h b/gfx/ots/src/ots.h index ba3ba77a286c..ffd24c7d59ab 100644 --- a/gfx/ots/src/ots.h +++ b/gfx/ots/src/ots.h @@ -12,6 +12,7 @@ #include #include #include +#include #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(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 > TableMap; + +struct OpenTypeFile { + OTSContext *context; + TableMap tables; +}; } // namespace ots +#undef FOR_EACH_TABLE_TYPE + #endif // OTS_H_ diff --git a/gfx/ots/src/post.cc b/gfx/ots/src/post.cc index 338d869b33fb..e7ed92b4a699 100644 --- a/gfx/ots/src/post.cc +++ b/gfx/ots/src/post.cc @@ -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 diff --git a/gfx/ots/src/prep.cc b/gfx/ots/src/prep.cc index ea3dec0b5361..1c9b45f91bf9 100644 --- a/gfx/ots/src/prep.cc +++ b/gfx/ots/src/prep.cc @@ -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 diff --git a/gfx/ots/src/vdmx.cc b/gfx/ots/src/vdmx.cc index 4853d631a439..cd80946aee50 100644 --- a/gfx/ots/src/vdmx.cc +++ b/gfx/ots/src/vdmx.cc @@ -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 diff --git a/gfx/ots/src/vhea.cc b/gfx/ots/src/vhea.cc index c689a834f0c1..fa898a8b5c52 100644 --- a/gfx/ots/src/vhea.cc +++ b/gfx/ots/src/vhea.cc @@ -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 diff --git a/gfx/ots/src/vmtx.cc b/gfx/ots/src/vmtx.cc index e29d32b29f9b..0944e598baca 100644 --- a/gfx/ots/src/vmtx.cc +++ b/gfx/ots/src/vmtx.cc @@ -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 diff --git a/gfx/ots/src/vorg.cc b/gfx/ots/src/vorg.cc index 2662067559d1..358923125647 100644 --- a/gfx/ots/src/vorg.cc +++ b/gfx/ots/src/vorg.cc @@ -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(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 diff --git a/gfx/ots/src/woff2.cc b/gfx/ots/src/woff2.cc index 0d7130076076..579dd33bfd4c 100644 --- a/gfx/ots/src/woff2.cc +++ b/gfx/ots/src/woff2.cc @@ -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& 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 n_points_vec; std::vector 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& tables, uint32_t tag) { return NULL; } -bool ReconstructTransformed(ots::OpenTypeFile* file, +bool ReconstructTransformed(ots::Font *font, const std::vector
& 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
& 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
& 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
* 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
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(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(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(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)); } } diff --git a/gfx/ots/src/woff2.h b/gfx/ots/src/woff2.h index f03f4f58e533..54de1ba3579c 100644 --- a/gfx/ots/src/woff2.h +++ b/gfx/ots/src/woff2.h @@ -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); } diff --git a/gfx/ots/sync.sh b/gfx/ots/sync.sh index 32e2c6711d2f..5a7e54b0a9d8 100755 --- a/gfx/ots/sync.sh +++ b/gfx/ots/sync.sh @@ -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