diff --git a/text/gotext.go b/text/gotext.go index 066e18f54..06994c3f2 100644 --- a/text/gotext.go +++ b/text/gotext.go @@ -895,11 +895,18 @@ func toLine(faceToIndex map[font.Font]int, o shaping.Line, dir system.TextDirect } line.runeCount += run.Runes.Count line.width += run.Advance - if line.ascent < run.LineBounds.Ascent { - line.ascent = run.LineBounds.Ascent + + // fix ascent to make all glyphes (CJK or not) always in same baseline + // fixedDescent + fixedAscent should equal fontSize + scale := fixedToFloat(run.Size) / fixedToFloat(run.LineBounds.LineHeight()) + fixedAscent := floatToFixed(fixedToFloat(run.LineBounds.Ascent) * scale) + fixedDescent := floatToFixed(fixedToFloat(-run.LineBounds.Descent+run.LineBounds.Gap) * scale) + + if line.ascent < fixedAscent { + line.ascent = fixedAscent } - if line.descent < -run.LineBounds.Descent+run.LineBounds.Gap { - line.descent = -run.LineBounds.Descent + run.LineBounds.Gap + if line.descent < fixedDescent { + line.descent = fixedDescent } } line.lineHeight = maxSize diff --git a/text/gotext_test.go b/text/gotext_test.go index 2ed5f9b73..201ad2503 100644 --- a/text/gotext_test.go +++ b/text/gotext_test.go @@ -52,14 +52,44 @@ func TestEmptyString(t *testing.T) { t.Fatalf("Layout returned no lines for empty string; expected 1") } l := lines.lines[0] - if expected := fixed.Int26_6(12094); l.ascent != expected { + if expected := fixed.Int26_6(10463); l.ascent != expected { t.Errorf("unexpected ascent for empty string: %v, expected %v", l.ascent, expected) } - if expected := fixed.Int26_6(2700); l.descent != expected { + if expected := fixed.Int26_6(2336); l.descent != expected { t.Errorf("unexpected descent for empty string: %v, expected %v", l.descent, expected) } } +func TestCJKOrNotString(t *testing.T) { + ppem := fixed.I(200) + ltrFace, _ := opentype.Parse(goregular.TTF) + shaper := testShaper(ltrFace) + + for _, r := range [][]rune{ + []rune("Sa"), + []rune("SayHi"), + []rune("SayHi 您好"), + []rune("✨ⷽℎ↞⋇ⱜ⪫⢡⽛⣦␆Ⱨⳏ⳯⒛⭣╎⌞⟻⢇┃➡⬎⩱⸇ⷎ⟅▤⼶⇺⩳⎏⤬⬞ⴈ⋠⿶⢒₍☟⽂ⶦ⫰⭢⌹∼▀⾯⧂❽⩏ⓖ⟅⤔⍇␋⽓ₑ⢳⠑❂⊪⢘⽨⃯▴ⷿ"), + } { + t.Run("ascent/descent should fit font size", func(t *testing.T) { + lines := shaper.LayoutRunes(Parameters{ + PxPerEm: ppem, + MaxWidth: 2000, + Locale: english, + }, r) + + l := lines.lines[0] + + if expected := fixed.Int26_6(10463); l.ascent != expected { + t.Errorf("unexpected ascent for string: %v, expected %v", l.ascent, expected) + } + if expected := fixed.Int26_6(2336); l.descent != expected { + t.Errorf("unexpected descent for empty string: %v, expected %v", l.descent, expected) + } + }) + } +} + func TestNoFaces(t *testing.T) { ppem := fixed.I(200) shaper := testShaper()