mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-07 02:15:34 +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
|
// Compute the maximum extent to which glyphs overhang on the horizontal
|
||||||
// axis.
|
// axis.
|
||||||
if d := g.Bounds.Min.X.Floor(); d < it.padding.Min.X {
|
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
|
it.padding.Min.X = d
|
||||||
}
|
}
|
||||||
if d := (g.Bounds.Max.X - g.Advance).Ceil(); d > it.padding.Max.X {
|
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
|
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{
|
logicalBounds := image.Rectangle{
|
||||||
Min: image.Pt(g.X.Floor(), int(g.Y)-g.Ascent.Ceil()),
|
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()),
|
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