mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 07:35:40 +00:00
widget: fix label vertical glyph padding logic
We previously were not handling glyphs that extended vertically beyond the ascent/descent declared by their font. This is done rarely with text fonts, but is apparently common among symbol and emoji fonts. Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit is contained in:
@@ -150,11 +150,26 @@ func (it *textIterator) processGlyph(g text.Glyph, ok bool) (_ text.Glyph, visib
|
||||
// Compute the maximum extent to which glyphs overhang on the horizontal
|
||||
// axis.
|
||||
if d := g.Bounds.Min.X.Floor(); d < it.padding.Min.X {
|
||||
// If the distance between the dot and the left edge of this glyph is
|
||||
// less than the current padding, increase the left padding.
|
||||
it.padding.Min.X = d
|
||||
}
|
||||
if d := (g.Bounds.Max.X - g.Advance).Ceil(); d > it.padding.Max.X {
|
||||
// If the distance between the dot and the right edge of this glyph
|
||||
// minus the logical advance of this glyph is greater than the current
|
||||
// padding, increase the right padding.
|
||||
it.padding.Max.X = d
|
||||
}
|
||||
if d := (g.Bounds.Min.Y + g.Ascent).Floor(); d < it.padding.Min.Y {
|
||||
// If the distance between the dot and the top of this glyph is greater
|
||||
// than the ascent of the glyph, increase the top padding.
|
||||
it.padding.Min.Y = d
|
||||
}
|
||||
if d := (g.Bounds.Max.Y - g.Descent).Ceil(); d > it.padding.Max.Y {
|
||||
// If the distance between the dot and the bottom of this glyph is greater
|
||||
// than the descent of the glyph, increase the bottom padding.
|
||||
it.padding.Max.Y = d
|
||||
}
|
||||
logicalBounds := image.Rectangle{
|
||||
Min: image.Pt(g.X.Floor(), int(g.Y)-g.Ascent.Ceil()),
|
||||
Max: image.Pt((g.X + g.Advance).Ceil(), int(g.Y)+g.Descent.Ceil()),
|
||||
|
||||
@@ -166,3 +166,67 @@ func TestGlyphIterator(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestGlyphIteratorPadding ensures that the glyph iterator computes correct padding
|
||||
// around glyphs with unusual bounding boxes.
|
||||
func TestGlyphIteratorPadding(t *testing.T) {
|
||||
type testcase struct {
|
||||
name string
|
||||
glyph text.Glyph
|
||||
viewport image.Rectangle
|
||||
expectedDims image.Rectangle
|
||||
expectedPadding image.Rectangle
|
||||
expectedBaseline int
|
||||
}
|
||||
for _, tc := range []testcase{
|
||||
{
|
||||
name: "simple",
|
||||
glyph: text.Glyph{
|
||||
X: 0,
|
||||
Y: 50,
|
||||
Advance: fixed.I(50),
|
||||
Ascent: fixed.I(50),
|
||||
Descent: fixed.I(50),
|
||||
Bounds: fixed.Rectangle26_6{
|
||||
Min: fixed.Point26_6{
|
||||
X: fixed.I(-5),
|
||||
Y: fixed.I(-56),
|
||||
},
|
||||
Max: fixed.Point26_6{
|
||||
X: fixed.I(57),
|
||||
Y: fixed.I(58),
|
||||
},
|
||||
},
|
||||
},
|
||||
viewport: image.Rectangle{Max: image.Pt(math.MaxInt, math.MaxInt)},
|
||||
expectedDims: image.Rectangle{
|
||||
Max: image.Point{X: 50, Y: 100},
|
||||
},
|
||||
expectedBaseline: 50,
|
||||
expectedPadding: image.Rectangle{
|
||||
Min: image.Point{
|
||||
X: -5,
|
||||
Y: -6,
|
||||
},
|
||||
Max: image.Point{
|
||||
X: 7,
|
||||
Y: 8,
|
||||
},
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
it := textIterator{viewport: tc.viewport}
|
||||
it.processGlyph(tc.glyph, true)
|
||||
if it.bounds != tc.expectedDims {
|
||||
t.Errorf("expected bounds %#+v, got %#+v", tc.expectedDims, it.bounds)
|
||||
}
|
||||
if it.baseline != tc.expectedBaseline {
|
||||
t.Errorf("expected baseline %d, got %d", tc.expectedBaseline, it.baseline)
|
||||
}
|
||||
if it.padding != tc.expectedPadding {
|
||||
t.Errorf("expected padding %d, got %d", tc.expectedPadding, it.padding)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user