Skip to content

Commit

Permalink
Merge pull request #266 from jfkthame/glyf-bbox
Browse files Browse the repository at this point in the history
Don't apply bounding-box fixup to "tricky" CJK fonts
  • Loading branch information
khaledhosny authored Aug 30, 2023
2 parents 6ba665a + c9b38cf commit 328c479
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 28 deletions.
59 changes: 35 additions & 24 deletions src/glyf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -94,10 +95,11 @@ bool OpenTypeGLYF::ParseFlagsForSimpleGlyph(Buffer &glyph,
bool OpenTypeGLYF::ParseSimpleGlyph(Buffer &glyph,
unsigned gid,
int16_t num_contours,
int16_t& xmin,
int16_t& ymin,
int16_t& xmax,
int16_t& ymax) {
int16_t xmin,
int16_t ymin,
int16_t xmax,
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) {
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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<OpenTypeNAME*>(
GetFont()->GetTypedTable(OTS_TAG_NAME));
bool is_tricky = name->IsTrickyFont();

this->maxp = maxp;

const unsigned num_glyphs = maxp->num_glyphs;
Expand Down Expand Up @@ -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 {
Expand Down
9 changes: 5 additions & 4 deletions src/glyf.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,11 @@ class OpenTypeGLYF : public Table {
bool ParseSimpleGlyph(Buffer &glyph,
unsigned gid,
int16_t num_contours,
int16_t& xmin,
int16_t& ymin,
int16_t& xmax,
int16_t& ymax);
int16_t xmin,
int16_t ymin,
int16_t xmax,
int16_t ymax,
bool is_tricky_font);
bool ParseCompositeGlyph(
Buffer &glyph,
ComponentPointCount* component_point_count);
Expand Down
40 changes: 40 additions & 0 deletions src/name.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions src/name.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<NameRecord> names;
Expand Down

0 comments on commit 328c479

Please sign in to comment.