From 341978dbcd57e99a5ee92966ad666459beb12666 Mon Sep 17 00:00:00 2001 From: Chris Waldon Date: Wed, 2 Aug 2023 10:32:14 -0400 Subject: [PATCH] text: fix zero-width truncated newline rune accounting This commit fixes another rune accounting issue that only existed when shaping a solitary newline with zero width while truncating the line. Signed-off-by: Chris Waldon --- text/gotext.go | 31 ++++++++++++++++++------------- text/shaper_test.go | 13 +++++++++++++ 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/text/gotext.go b/text/gotext.go index 8a6ecfdb..f9ff8c6d 100644 --- a/text/gotext.go +++ b/text/gotext.go @@ -523,22 +523,27 @@ func calculateYOffsets(lines []line) { // LayoutRunes shapes and wraps the text, and returns the result in Gio's shaped text format. func (s *shaperImpl) LayoutRunes(params Parameters, txt []rune) document { hasNewline := len(txt) > 0 && txt[len(txt)-1] == '\n' - justNewline := false + var ls []shaping.Line + var truncated int if hasNewline { txt = txt[:len(txt)-1] - if len(txt) == 0 { - // If we only have a newline, shape a space to get line metrics. - txt = []rune{' '} - justNewline = true - } } - ls, truncated := s.shapeAndWrapText(params, replaceControlCharacters(txt)) - if justNewline { - // We shaped a space to get proper line metrics, but we need to drop - // the rune/glyph info since it isn't actually part of the text. - ls[0][0].Glyphs = ls[0][0].Glyphs[:0] - ls[0][0].Runes.Count = 0 - ls[0][0].Advance = 0 + if hasNewline && len(txt) == 0 { + // If we only have a newline, shape a space to get line metrics. + ls, truncated = s.shapeAndWrapText(params, []rune{' '}) + if truncated > 0 { + // Our space was truncated. Since our space didn't exist in any meaningful + // capacity, ensure the truncated count is zeroed out. + truncated = 0 + } else { + // We shaped a space to get proper line metrics, but we need to drop + // the rune/glyph info since it isn't actually part of the text. + ls[0][0].Glyphs = ls[0][0].Glyphs[:0] + ls[0][0].Advance = 0 + ls[0][0].Runes.Count = 0 + } + } else { + ls, truncated = s.shapeAndWrapText(params, replaceControlCharacters(txt)) } didTruncate := truncated > 0 || (params.forceTruncate && params.MaxLines == len(ls)) diff --git a/text/shaper_test.go b/text/shaper_test.go index 6d3d69a3..87f7dd71 100644 --- a/text/shaper_test.go +++ b/text/shaper_test.go @@ -484,6 +484,19 @@ func TestShapeStringRuneAccounting(t *testing.T) { MaxWidth: 999929, }, }, + { + name: "newline zero-width 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: 0, + }, + }, } { t.Run(tc.name, func(t *testing.T) { for _, setup := range []setup{