commit 362a59be47f9e187eec43df0938def661be6c972 Author: Jonathan Kew Date: Wed Aug 30 12:55:02 2023 +0000 Bug 1850314 - Don't do glyph bounding-box fixup for "tricky" fonts, because it may disrupt glyph rendering on macOS. r=gfx-reviewers,lsalzman Differential Revision: https://phabricator.services.mozilla.com/D187096 diff --git a/src/glyf.cc b/src/glyf.cc index 0ed9515ef16d6..31487957bf99b 100644 --- a/src/glyf.cc +++ b/src/glyf.cc @@ -10,6 +10,7 @@ #include "head.h" #include "loca.h" #include "maxp.h" +#include "name.h" // glyf - Glyph Data // http://www.microsoft.com/typography/otspec/glyf.htm @@ -97,7 +98,8 @@ bool OpenTypeGLYF::ParseSimpleGlyph(Buffer &glyph, int16_t& xmin, int16_t& ymin, int16_t& xmax, - int16_t& ymax) { + int16_t& ymax, + bool is_tricky_font) { // read the end-points array uint16_t num_flags = 0; for (int i = 0; i < num_contours; ++i) { @@ -219,27 +221,32 @@ bool OpenTypeGLYF::ParseSimpleGlyph(Buffer &glyph, } if (adjusted_bbox) { - Warning("Glyph bbox was incorrect; adjusting (glyph %u)", gid); - // copy the numberOfContours field - this->iov.push_back(std::make_pair(glyph.buffer(), 2)); - // output a fixed-up version of the bounding box - uint8_t* fixed_bbox = new uint8_t[8]; - fixed_bboxes.push_back(fixed_bbox); - xmin = ots_htons(xmin); - std::memcpy(fixed_bbox, &xmin, 2); - ymin = ots_htons(ymin); - std::memcpy(fixed_bbox + 2, &ymin, 2); - xmax = ots_htons(xmax); - std::memcpy(fixed_bbox + 4, &xmax, 2); - ymax = ots_htons(ymax); - std::memcpy(fixed_bbox + 6, &ymax, 2); - this->iov.push_back(std::make_pair(fixed_bbox, 8)); - // copy the remainder of the glyph data - this->iov.push_back(std::make_pair(glyph.buffer() + 10, glyph.offset() - 10)); - } else { - this->iov.push_back(std::make_pair(glyph.buffer(), glyph.offset())); + if (is_tricky_font) { + Warning("Glyph bbox was incorrect; NOT adjusting tricky font (glyph %u)", gid); + } else { + Warning("Glyph bbox was incorrect; adjusting (glyph %u)", gid); + // copy the numberOfContours field + this->iov.push_back(std::make_pair(glyph.buffer(), 2)); + // output a fixed-up version of the bounding box + uint8_t* fixed_bbox = new uint8_t[8]; + fixed_bboxes.push_back(fixed_bbox); + xmin = ots_htons(xmin); + std::memcpy(fixed_bbox, &xmin, 2); + ymin = ots_htons(ymin); + std::memcpy(fixed_bbox + 2, &ymin, 2); + xmax = ots_htons(xmax); + std::memcpy(fixed_bbox + 4, &xmax, 2); + ymax = ots_htons(ymax); + std::memcpy(fixed_bbox + 6, &ymax, 2); + this->iov.push_back(std::make_pair(fixed_bbox, 8)); + // copy the remainder of the glyph data + this->iov.push_back(std::make_pair(glyph.buffer() + 10, glyph.offset() - 10)); + return true; + } } + this->iov.push_back(std::make_pair(glyph.buffer(), glyph.offset())); + return true; } @@ -342,6 +349,10 @@ bool OpenTypeGLYF::Parse(const uint8_t *data, size_t length) { return Error("Missing maxp or loca or head table needed by glyf table"); } + OpenTypeNAME *name = static_cast( + GetFont()->GetTypedTable(OTS_TAG_NAME)); + bool is_tricky = name->IsTrickyFont(); + this->maxp = maxp; const unsigned num_glyphs = maxp->num_glyphs; @@ -397,7 +408,7 @@ bool OpenTypeGLYF::Parse(const uint8_t *data, size_t length) { // does we will simply ignore it. glyph.set_offset(0); } else if (num_contours > 0) { - if (!ParseSimpleGlyph(glyph, i, num_contours, xmin, ymin, xmax, ymax)) { + if (!ParseSimpleGlyph(glyph, i, num_contours, xmin, ymin, xmax, ymax, is_tricky)) { return Error("Failed to parse glyph %d", i); } } else { diff --git a/src/glyf.h b/src/glyf.h index 05e846f1cb6e8..f85fdc4652fcf 100644 --- a/src/glyf.h +++ b/src/glyf.h @@ -51,7 +51,8 @@ class OpenTypeGLYF : public Table { int16_t& xmin, int16_t& ymin, int16_t& xmax, - int16_t& ymax); + int16_t& ymax, + bool is_tricky_font); bool ParseCompositeGlyph( Buffer &glyph, ComponentPointCount* component_point_count); diff --git a/src/name.cc b/src/name.cc index fc5074b0587a3..7526e1f72b9ea 100644 --- a/src/name.cc +++ b/src/name.cc @@ -366,4 +366,44 @@ bool OpenTypeNAME::IsValidNameId(uint16_t nameID, bool addIfMissing) { return this->name_ids.count(nameID); } +// List of font names considered "tricky" (dependent on applying original TrueType instructions) by FreeType, see +// https://gitlab.freedesktop.org/freetype/freetype/-/blob/2d9fce53d4ce89f36075168282fcdd7289e082f9/src/truetype/ttobjs.c#L170-241 +static const char* tricky_font_names[] = { + "cpop", + "DFGirl-W6-WIN-BF", + "DFGothic-EB", + "DFGyoSho-Lt", + "DFHei", + "DFHSGothic-W5", + "DFHSMincho-W3", + "DFHSMincho-W7", + "DFKaiSho-SB", + "DFKaiShu", + "DFKai-SB", + "DFMing", + "DLC", + "HuaTianKaiTi?", + "HuaTianSongTi?", + "Ming(for ISO10646)", + "MingLiU", + "MingMedium", + "PMingLiU", + "MingLi43" +}; + +bool OpenTypeNAME::IsTrickyFont() const { + for (const auto& name : this->names) { + const uint16_t id = name.name_id; + if (id != 1) { + continue; + } + for (const auto* p : tricky_font_names) { + if (name.text.find(p) != std::string::npos) { + return true; + } + } + } + return false; +} + } // namespace diff --git a/src/name.h b/src/name.h index 68c7ac096d3f8..a241e77ee26bb 100644 --- a/src/name.h +++ b/src/name.h @@ -52,6 +52,7 @@ class OpenTypeNAME : public Table { bool Parse(const uint8_t *data, size_t length); bool Serialize(OTSStream *out); bool IsValidNameId(uint16_t nameID, bool addIfMissing = false); + bool IsTrickyFont() const; private: std::vector names;