~eliasnaur/gio

bfb47538aa0db22d965be5f07fbf81c102b0050d — Chris Waldon 5 months ago 2db1a7b
text: ensure runereader behaves same as string

This commit fixes a subtle discrepancy in the handling of text input
within the shaper. Text provided as an io.RuneReader with a trailing
newline would generate an extra (empty) line of text, whereas the
same input provided as a string would not.

Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
2 files changed, 34 insertions(+), 5 deletions(-)

M text/shaper.go
M text/shaper_test.go
M text/shaper.go => text/shaper.go +7 -5
@@ 223,11 223,13 @@ func (l *Shaper) layoutText(params Parameters, minWidth, maxWidth int, lc system
			}
			done = endByte == len(str)
		}
		l.txt.append(l.layoutParagraph(params, minWidth, maxWidth, lc, str[startByte:endByte], l.paragraph))
		if truncating {
			params.MaxLines = maxLines - len(l.txt.lines)
			if params.MaxLines == 0 {
				done = true
		if startByte != endByte || len(l.paragraph) > 0 {
			l.txt.append(l.layoutParagraph(params, minWidth, maxWidth, lc, str[startByte:endByte], l.paragraph))
			if truncating {
				params.MaxLines = maxLines - len(l.txt.lines)
				if params.MaxLines == 0 {
					done = true
				}
			}
		}
		if done {

M text/shaper_test.go => text/shaper_test.go +27 -0
@@ 1,6 1,7 @@
package text

import (
	"strings"
	"testing"

	nsareg "eliasnaur.com/font/noto/sans/arabic/regular"


@@ 40,6 41,32 @@ func TestWrappingTruncation(t *testing.T) {
	}
}

// TestShapingNewlineHandling checks that the shaper's newline splitting behaves
// consistently and does not create spurious lines of text.
func TestShapingNewlineHandling(t *testing.T) {
	// Use a test string containing multiple newlines to ensure that they are shaped
	// as separate paragraphs.
	textInput := "\n"
	ltrFace, _ := opentype.Parse(goregular.TTF)
	collection := []FontFace{{Face: ltrFace}}
	cache := NewShaper(collection)
	cache.LayoutString(Parameters{
		Alignment: Middle,
		PxPerEm:   fixed.I(10),
	}, 200, 200, english, textInput)
	if lineCount := len(cache.txt.lines); lineCount > 1 {
		t.Errorf("shaping string %q created %d lines", textInput, lineCount)
	}

	cache.Layout(Parameters{
		Alignment: Middle,
		PxPerEm:   fixed.I(10),
	}, 200, 200, english, strings.NewReader(textInput))
	if lineCount := len(cache.txt.lines); lineCount > 1 {
		t.Errorf("shaping reader %q created %d lines", textInput, lineCount)
	}
}

// TestCacheEmptyString ensures that shaping the empty string returns a
// single synthetic glyph with ascent/descent info.
func TestCacheEmptyString(t *testing.T) {