1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
commit 362a59be47f9e187eec43df0938def661be6c972
Author: Jonathan Kew <jkew@mozilla.com>
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<OpenTypeNAME*>(
+ 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<NameRecord> names;
|