Skip to content

Commit 08ca817

Browse files
committed
font: have Glyph return !ok for U+FFFD substitute
The other return values may still be non-zero, but this lets callers identify when substitution happens. "TODO: is falling back on the U+FFFD glyph the responsibility of the Drawer or the Face?" was resolved. The answer is "the Face". For kerning, the previous rune is unchanged (and not set to U+FFFD). This also fixes an inconsistency in the basicfont.Face implementation, where GlyphAdvance and GlyphBounds would unconditionally return a non-zero advance, but Glyph could return a zero advance when the Face doesn't have a U+FFFD entry. Fixes golang/go#58252 Change-Id: Ie97e68e1d5e2efd13c9e84ad12db4495d83a5ca3 Reviewed-on: https://go-review.googlesource.com/c/image/+/474376 TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]> Reviewed-by: Nigel Tao (INACTIVE; USE @golang.org INSTEAD) <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]> Run-TryBot: Nigel Tao <[email protected]>
1 parent b6ac75b commit 08ca817

File tree

3 files changed

+75
-88
lines changed

3 files changed

+75
-88
lines changed

font/basicfont/basicfont.go

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -89,41 +89,50 @@ func (f *Face) Metrics() font.Metrics {
8989
func (f *Face) Glyph(dot fixed.Point26_6, r rune) (
9090
dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) {
9191

92-
loop:
93-
for _, rr := range [2]rune{r, '\ufffd'} {
94-
for _, rng := range f.Ranges {
95-
if rr < rng.Low || rng.High <= rr {
96-
continue
97-
}
98-
maskp.Y = (int(rr-rng.Low) + rng.Offset) * (f.Ascent + f.Descent)
99-
ok = true
100-
break loop
92+
if found, rng := f.find(r); rng != nil {
93+
maskp.Y = (int(found-rng.Low) + rng.Offset) * (f.Ascent + f.Descent)
94+
x := int(dot.X+32)>>6 + f.Left
95+
y := int(dot.Y+32) >> 6
96+
dr = image.Rectangle{
97+
Min: image.Point{
98+
X: x,
99+
Y: y - f.Ascent,
100+
},
101+
Max: image.Point{
102+
X: x + f.Width,
103+
Y: y + f.Descent,
104+
},
101105
}
102-
}
103-
if !ok {
104-
return image.Rectangle{}, nil, image.Point{}, 0, false
105-
}
106106

107-
x := int(dot.X+32)>>6 + f.Left
108-
y := int(dot.Y+32) >> 6
109-
dr = image.Rectangle{
110-
Min: image.Point{
111-
X: x,
112-
Y: y - f.Ascent,
113-
},
114-
Max: image.Point{
115-
X: x + f.Width,
116-
Y: y + f.Descent,
117-
},
107+
return dr, f.Mask, maskp, fixed.I(f.Advance), r == found
118108
}
119-
120-
return dr, f.Mask, maskp, fixed.I(f.Advance), true
109+
return image.Rectangle{}, nil, image.Point{}, 0, false
121110
}
122111

123112
func (f *Face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) {
124-
return fixed.R(0, -f.Ascent, f.Width, +f.Descent), fixed.I(f.Advance), true
113+
if found, rng := f.find(r); rng != nil {
114+
return fixed.R(0, -f.Ascent, f.Width, +f.Descent), fixed.I(f.Advance), r == found
115+
}
116+
return fixed.Rectangle26_6{}, 0, false
125117
}
126118

127119
func (f *Face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) {
128-
return fixed.I(f.Advance), true
120+
if found, rng := f.find(r); rng != nil {
121+
return fixed.I(f.Advance), r == found
122+
}
123+
return 0, false
124+
}
125+
126+
func (f *Face) find(r rune) (rune, *Range) {
127+
for {
128+
for i, rng := range f.Ranges {
129+
if (rng.Low <= r) && (r < rng.High) {
130+
return r, &f.Ranges[i]
131+
}
132+
}
133+
if r == '\ufffd' {
134+
return 0, nil
135+
}
136+
r = '\ufffd'
137+
}
129138
}

font/font.go

Lines changed: 30 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,10 @@ type Face interface {
3838
// glyph at the sub-pixel destination location dot, and that glyph's
3939
// advance width.
4040
//
41-
// It returns !ok if the face does not contain a glyph for r.
41+
// It returns !ok if the face does not contain a glyph for r. This includes
42+
// returning !ok for a fallback glyph (such as substituting a U+FFFD glyph
43+
// or OpenType's .notdef glyph), in which case the other return values may
44+
// still be non-zero.
4245
//
4346
// The contents of the mask image returned by one Glyph call may change
4447
// after the next Glyph call. Callers that want to cache the mask must make
@@ -49,7 +52,10 @@ type Face interface {
4952
// GlyphBounds returns the bounding box of r's glyph, drawn at a dot equal
5053
// to the origin, and that glyph's advance width.
5154
//
52-
// It returns !ok if the face does not contain a glyph for r.
55+
// It returns !ok if the face does not contain a glyph for r. This includes
56+
// returning !ok for a fallback glyph (such as substituting a U+FFFD glyph
57+
// or OpenType's .notdef glyph), in which case the other return values may
58+
// still be non-zero.
5359
//
5460
// The glyph's ascent and descent are equal to -bounds.Min.Y and
5561
// +bounds.Max.Y. The glyph's left-side and right-side bearings are equal
@@ -60,7 +66,10 @@ type Face interface {
6066

6167
// GlyphAdvance returns the advance width of r's glyph.
6268
//
63-
// It returns !ok if the face does not contain a glyph for r.
69+
// It returns !ok if the face does not contain a glyph for r. This includes
70+
// returning !ok for a fallback glyph (such as substituting a U+FFFD glyph
71+
// or OpenType's .notdef glyph), in which case the other return values may
72+
// still be non-zero.
6473
GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool)
6574

6675
// Kern returns the horizontal adjustment for the kerning pair (r0, r1). A
@@ -150,14 +159,10 @@ func (d *Drawer) DrawBytes(s []byte) {
150159
if prevC >= 0 {
151160
d.Dot.X += d.Face.Kern(prevC, c)
152161
}
153-
dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c)
154-
if !ok {
155-
// TODO: is falling back on the U+FFFD glyph the responsibility of
156-
// the Drawer or the Face?
157-
// TODO: set prevC = '\ufffd'?
158-
continue
162+
dr, mask, maskp, advance, _ := d.Face.Glyph(d.Dot, c)
163+
if !dr.Empty() {
164+
draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over)
159165
}
160-
draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over)
161166
d.Dot.X += advance
162167
prevC = c
163168
}
@@ -170,14 +175,10 @@ func (d *Drawer) DrawString(s string) {
170175
if prevC >= 0 {
171176
d.Dot.X += d.Face.Kern(prevC, c)
172177
}
173-
dr, mask, maskp, advance, ok := d.Face.Glyph(d.Dot, c)
174-
if !ok {
175-
// TODO: is falling back on the U+FFFD glyph the responsibility of
176-
// the Drawer or the Face?
177-
// TODO: set prevC = '\ufffd'?
178-
continue
178+
dr, mask, maskp, advance, _ := d.Face.Glyph(d.Dot, c)
179+
if !dr.Empty() {
180+
draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over)
179181
}
180-
draw.DrawMask(d.Dst, dr, d.Src, image.Point{}, mask, maskp, draw.Over)
181182
d.Dot.X += advance
182183
prevC = c
183184
}
@@ -227,16 +228,12 @@ func BoundBytes(f Face, s []byte) (bounds fixed.Rectangle26_6, advance fixed.Int
227228
if prevC >= 0 {
228229
advance += f.Kern(prevC, c)
229230
}
230-
b, a, ok := f.GlyphBounds(c)
231-
if !ok {
232-
// TODO: is falling back on the U+FFFD glyph the responsibility of
233-
// the Drawer or the Face?
234-
// TODO: set prevC = '\ufffd'?
235-
continue
231+
b, a, _ := f.GlyphBounds(c)
232+
if !b.Empty() {
233+
b.Min.X += advance
234+
b.Max.X += advance
235+
bounds = bounds.Union(b)
236236
}
237-
b.Min.X += advance
238-
b.Max.X += advance
239-
bounds = bounds.Union(b)
240237
advance += a
241238
prevC = c
242239
}
@@ -251,16 +248,12 @@ func BoundString(f Face, s string) (bounds fixed.Rectangle26_6, advance fixed.In
251248
if prevC >= 0 {
252249
advance += f.Kern(prevC, c)
253250
}
254-
b, a, ok := f.GlyphBounds(c)
255-
if !ok {
256-
// TODO: is falling back on the U+FFFD glyph the responsibility of
257-
// the Drawer or the Face?
258-
// TODO: set prevC = '\ufffd'?
259-
continue
251+
b, a, _ := f.GlyphBounds(c)
252+
if !b.Empty() {
253+
b.Min.X += advance
254+
b.Max.X += advance
255+
bounds = bounds.Union(b)
260256
}
261-
b.Min.X += advance
262-
b.Max.X += advance
263-
bounds = bounds.Union(b)
264257
advance += a
265258
prevC = c
266259
}
@@ -278,13 +271,7 @@ func MeasureBytes(f Face, s []byte) (advance fixed.Int26_6) {
278271
if prevC >= 0 {
279272
advance += f.Kern(prevC, c)
280273
}
281-
a, ok := f.GlyphAdvance(c)
282-
if !ok {
283-
// TODO: is falling back on the U+FFFD glyph the responsibility of
284-
// the Drawer or the Face?
285-
// TODO: set prevC = '\ufffd'?
286-
continue
287-
}
274+
a, _ := f.GlyphAdvance(c)
288275
advance += a
289276
prevC = c
290277
}
@@ -298,13 +285,7 @@ func MeasureString(f Face, s string) (advance fixed.Int26_6) {
298285
if prevC >= 0 {
299286
advance += f.Kern(prevC, c)
300287
}
301-
a, ok := f.GlyphAdvance(c)
302-
if !ok {
303-
// TODO: is falling back on the U+FFFD glyph the responsibility of
304-
// the Drawer or the Face?
305-
// TODO: set prevC = '\ufffd'?
306-
continue
307-
}
288+
a, _ := f.GlyphAdvance(c)
308289
advance += a
309290
prevC = c
310291
}

font/opentype/opentype.go

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ func (f *Face) Metrics() font.Metrics {
133133

134134
// Kern satisfies the font.Face interface.
135135
func (f *Face) Kern(r0, r1 rune) fixed.Int26_6 {
136-
x0 := f.index(r0)
137-
x1 := f.index(r1)
136+
x0, _ := f.f.GlyphIndex(&f.buf, r0)
137+
x1, _ := f.f.GlyphIndex(&f.buf, r1)
138138
k, err := f.f.Kern(&f.buf, x0, x1, fixed.Int26_6(f.f.UnitsPerEm()), f.hinting)
139139
if err != nil {
140140
return 0
@@ -251,22 +251,19 @@ func (f *Face) Glyph(dot fixed.Point26_6, r rune) (dr image.Rectangle, mask imag
251251
}
252252
f.rast.Draw(&f.mask, f.mask.Bounds(), image.Opaque, image.Point{})
253253

254-
return dr, &f.mask, f.mask.Rect.Min, advance, true
254+
return dr, &f.mask, f.mask.Rect.Min, advance, x != 0
255255
}
256256

257257
// GlyphBounds satisfies the font.Face interface.
258258
func (f *Face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) {
259-
bounds, advance, err := f.f.GlyphBounds(&f.buf, f.index(r), f.scale, f.hinting)
260-
return bounds, advance, err == nil
259+
x, _ := f.f.GlyphIndex(&f.buf, r)
260+
bounds, advance, err := f.f.GlyphBounds(&f.buf, x, f.scale, f.hinting)
261+
return bounds, advance, (err == nil) && (x != 0)
261262
}
262263

263264
// GlyphAdvance satisfies the font.Face interface.
264265
func (f *Face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) {
265-
advance, err := f.f.GlyphAdvance(&f.buf, f.index(r), f.scale, f.hinting)
266-
return advance, err == nil
267-
}
268-
269-
func (f *Face) index(r rune) sfnt.GlyphIndex {
270266
x, _ := f.f.GlyphIndex(&f.buf, r)
271-
return x
267+
advance, err := f.f.GlyphAdvance(&f.buf, x, f.scale, f.hinting)
268+
return advance, (err == nil) && (x != 0)
272269
}

0 commit comments

Comments
 (0)