mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 07:35:40 +00:00
text: fix EOF detection at newline boundaries
This commit tests and fixes some edge cases that threw off rune accounting when a newline character was the final rune in the input *and* the text was being truncated. I imagine they were never previously reported because it's rare to try to truncate such text. Thanks to Dominik Honnef for the report and reproducer. Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit is contained in:
+4
-1
@@ -316,7 +316,9 @@ func (l *Shaper) layoutText(params Parameters, txt io.Reader, str string) {
|
||||
if !done {
|
||||
_, re := l.reader.ReadByte()
|
||||
done = re != nil
|
||||
_ = l.reader.UnreadByte()
|
||||
if !done {
|
||||
_ = l.reader.UnreadByte()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
idx := strings.IndexByte(str, '\n')
|
||||
@@ -325,6 +327,7 @@ func (l *Shaper) layoutText(params Parameters, txt io.Reader, str string) {
|
||||
endByte = len(str)
|
||||
} else {
|
||||
endByte = idx + 1
|
||||
done = endByte == len(str)
|
||||
}
|
||||
}
|
||||
if len(str[:endByte]) > 0 || (len(l.paragraph) > 0 || len(l.txt.lines) == 0) {
|
||||
|
||||
+22
-2
@@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
nsareg "eliasnaur.com/font/noto/sans/arabic/regular"
|
||||
"gioui.org/font"
|
||||
"gioui.org/font/gofont"
|
||||
"gioui.org/font/opentype"
|
||||
"gioui.org/io/system"
|
||||
@@ -161,6 +162,7 @@ func TestShapingNewlineHandling(t *testing.T) {
|
||||
{textInput: "a\n", expectedLines: 1, expectedGlyphs: 3},
|
||||
{textInput: "a\nb", expectedLines: 2, expectedGlyphs: 3},
|
||||
{textInput: "", expectedLines: 1, expectedGlyphs: 1},
|
||||
{textInput: "\n", expectedLines: 1, expectedGlyphs: 2},
|
||||
} {
|
||||
t.Run(fmt.Sprintf("%q", tc.textInput), func(t *testing.T) {
|
||||
ltrFace, _ := opentype.Parse(goregular.TTF)
|
||||
@@ -168,8 +170,13 @@ func TestShapingNewlineHandling(t *testing.T) {
|
||||
cache := NewShaper(NoSystemFonts(), WithCollection(collection))
|
||||
checkGlyphs := func() {
|
||||
glyphs := []Glyph{}
|
||||
runes := 0
|
||||
for g, ok := cache.NextGlyph(); ok; g, ok = cache.NextGlyph() {
|
||||
glyphs = append(glyphs, g)
|
||||
runes += g.Runes
|
||||
}
|
||||
if expected := len([]rune(tc.textInput)); expected != runes {
|
||||
t.Errorf("expected %d runes, got %d", expected, runes)
|
||||
}
|
||||
if len(glyphs) != tc.expectedGlyphs {
|
||||
t.Errorf("expected %d glyphs, got %d", tc.expectedGlyphs, len(glyphs))
|
||||
@@ -191,8 +198,8 @@ func TestShapingNewlineHandling(t *testing.T) {
|
||||
}
|
||||
breakX, breakY := breakGlyph.X, breakGlyph.Y
|
||||
startX, startY := startGlyph.X, startGlyph.Y
|
||||
if breakX == startX {
|
||||
t.Errorf("expected paragraph start glyph to have cursor x")
|
||||
if breakX == startX && idx != 0 {
|
||||
t.Errorf("expected paragraph start glyph to have cursor x, got %v", startX)
|
||||
}
|
||||
if breakY == startY {
|
||||
t.Errorf("expected paragraph start glyph to have cursor y")
|
||||
@@ -464,6 +471,19 @@ func TestShapeStringRuneAccounting(t *testing.T) {
|
||||
MaxWidth: 100,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "newline regression",
|
||||
input: "\n",
|
||||
params: Parameters{
|
||||
Font: font.Font{Typeface: "Go", Style: font.Regular, Weight: font.Normal},
|
||||
Alignment: Start,
|
||||
PxPerEm: 768,
|
||||
MaxLines: 1,
|
||||
Truncator: "\u200b",
|
||||
WrapPolicy: WrapHeuristically,
|
||||
MaxWidth: 999929,
|
||||
},
|
||||
},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
for _, setup := range []setup{
|
||||
|
||||
Reference in New Issue
Block a user