~whereswaldon/gio-x

5f0f290b15c8b028a8a250a9a5e54ad57b008d01 — Chris Waldon 5 months ago 360dbef richtext-fixes
wip

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

M styledtext/iterator.go
M styledtext/styledtext_test.go
M styledtext/iterator.go => styledtext/iterator.go +8 -4
@@ 53,12 53,20 @@ type textIterator struct {
// processGlyph checks whether the glyph is visible within the iterator's configured
// viewport and (if so) updates the iterator's text dimensions to include the glyph.
func (it *textIterator) processGlyph(g text.Glyph, ok bool) (_ text.Glyph, visibleOrBefore bool) {
	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()),
	}
	if g.Flags&text.FlagTruncator != 0 {
		// If the truncator is the first glyph, force a newline.
		if it.runes == 0 {
			it.runes = 1
			it.hasNewline = true
		}
		// We always need to update the vertical bounds for the truncator glyph in case it's the only
		// glyph on its line. Otherwise the line will seem to have zero size.
		it.bounds.Min.Y = min(it.bounds.Min.Y, logicalBounds.Min.Y)
		it.bounds.Max.Y = max(it.bounds.Max.Y, logicalBounds.Max.Y)
		return g, false
	}
	it.runes += int(g.Runes)


@@ 79,10 87,6 @@ func (it *textIterator) processGlyph(g text.Glyph, ok bool) (_ text.Glyph, visib
	if d := (g.Bounds.Max.X - g.Advance).Ceil(); d > it.padding.Max.X {
		it.padding.Max.X = 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()),
	}
	if !it.first {
		it.first = true
		it.baseline = int(g.Y)

M styledtext/styledtext_test.go => styledtext/styledtext_test.go +37 -0
@@ 82,3 82,40 @@ func TestStyledtextRegressions(t *testing.T) {
		})
	}
}

// TestStyledtextNewlines ensures that newlines create appropriate gaps between text.
func TestStyledtextNewlines(t *testing.T) {
	gtx := layout.NewContext(new(op.Ops), system.FrameEvent{
		Metric: unit.Metric{PxPerDp: 1, PxPerSp: 1},
		Size:   image.Point{X: 1000, Y: 1000},
	})
	gtx.Constraints.Min = image.Point{}
	shaper := text.NewShaper(text.NoSystemFonts(), text.WithCollection(gofont.Collection()))

	singleLineTxt := Text(shaper, SpanStyle{Size: 12, Content: "a"})
	singleLineDims := singleLineTxt.Layout(gtx, func(gtx layout.Context, idx int, dims layout.Dimensions) {})

	txt := Text(shaper,
		SpanStyle{
			Font:    font.Font{Typeface: "Go", Style: font.Regular, Weight: font.Bold},
			Size:    12,
			Content: "a",
		},
		SpanStyle{
			Font:    font.Font{Typeface: "Go", Style: font.Regular, Weight: font.Normal},
			Size:    12,
			Content: "\n\n",
		},
		SpanStyle{
			Font:    font.Font{Typeface: "Go", Style: font.Regular, Weight: font.Normal},
			Size:    12,
			Content: "b",
		},
	)
	txtDims := txt.Layout(gtx, func(gtx layout.Context, idx int, dims layout.Dimensions) {})

	if expectedY := int(2.5 * float32(singleLineDims.Size.Y)); txtDims.Size.Y <= expectedY {
		t.Errorf("expected double newline to create 3 lines, dimensions too small")
		t.Logf("expected > %d, got %d (single line height is %d)", expectedY, txtDims.Size.Y, singleLineDims.Size.Y)
	}
}