text/v2: bug fix: Measure didn't work correctly with vertical faces

This also updates examples/texti18n to use text.Measure.

Updates #2143
Updates #2454
This commit is contained in:
Hajime Hoshi 2023-11-23 23:13:27 +09:00
parent c4b16bec9b
commit b9b365a576
2 changed files with 69 additions and 42 deletions

View File

@ -20,6 +20,7 @@ package main
import ( import (
"bytes" "bytes"
_ "embed" _ "embed"
"image/color"
"log" "log"
"golang.org/x/text/language" "golang.org/x/text/language"
@ -27,6 +28,7 @@ import (
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/examples/resources/fonts" "github.com/hajimehoshi/ebiten/v2/examples/resources/fonts"
"github.com/hajimehoshi/ebiten/v2/text/v2" "github.com/hajimehoshi/ebiten/v2/text/v2"
"github.com/hajimehoshi/ebiten/v2/vector"
) )
//go:embed NotoSansArabic-Regular.ttf //go:embed NotoSansArabic-Regular.ttf
@ -91,48 +93,70 @@ func (g *Game) Update() error {
} }
func (g *Game) Draw(screen *ebiten.Image) { func (g *Game) Draw(screen *ebiten.Image) {
const arabicText = "لمّا كان الاعتراف بالكرامة المتأصلة في جميع" gray := color.RGBA{0x80, 0x80, 0x80, 0xff}
op := &text.DrawOptions{} {
op.GeoM.Translate(screenWidth-20, 40) const arabicText = "لمّا كان الاعتراف بالكرامة المتأصلة في جميع"
text.Draw(screen, arabicText, &text.GoTextFace{ f := &text.GoTextFace{
Source: arabicFaceSource, Source: arabicFaceSource,
Direction: text.DirectionRightToLeft, Direction: text.DirectionRightToLeft,
Size: 24, Size: 24,
Language: language.Arabic, Language: language.Arabic,
}, op) }
x, y := screenWidth-20, 40
const hindiText = "चूंकि मानव परिवार के सभी सदस्यों के जन्मजात गौरव और समान" w, h := text.Measure(arabicText, f, 0)
// The left upper point is not x but x-w, since the text runs in the rigth-to-left direction.
op.GeoM.Reset() vector.DrawFilledRect(screen, float32(x)-float32(w), float32(y), float32(w), float32(h), gray, false)
op.GeoM.Translate(20, 110) op := &text.DrawOptions{}
text.Draw(screen, hindiText, &text.GoTextFace{ op.GeoM.Translate(float64(x), float64(y))
Source: devanagariFaceSource, text.Draw(screen, arabicText, f, op)
Size: 24, }
Language: language.Hindi, {
}, op) const hindiText = "चूंकि मानव परिवार के सभी सदस्यों के जन्मजात गौरव और समान"
f := &text.GoTextFace{
const thaiText = "โดยที่การไม่นำพาและการหมิ่นในคุณค่าของสิทธิมนุษยชน" Source: devanagariFaceSource,
Size: 24,
op.GeoM.Reset() Language: language.Hindi,
op.GeoM.Translate(20, 160) }
text.Draw(screen, thaiText, &text.GoTextFace{ x, y := 20, 100
Source: thaiFaceSource, w, h := text.Measure(hindiText, f, 0)
Size: 24, vector.DrawFilledRect(screen, float32(x), float32(y), float32(w), float32(h), gray, false)
Language: language.Thai, op := &text.DrawOptions{}
}, op) op.GeoM.Translate(float64(x), float64(y))
text.Draw(screen, hindiText, f, op)
const japaneseText = "あのイーハトーヴォの\nすきとおった風、\n夏でも底に冷たさを\nもつ青いそら…" }
{
op.GeoM.Reset() const thaiText = "โดยที่การไม่นำพาและการหมิ่นในคุณค่าของสิทธิมนุษยชน"
op.GeoM.Translate(screenWidth-20, 210) f := &text.GoTextFace{
op.LineSpacingInPixels = 48 Source: thaiFaceSource,
text.Draw(screen, japaneseText, &text.GoTextFace{ Size: 24,
Source: japaneseFaceSource, Language: language.Thai,
Direction: text.DirectionTopToBottomAndRightToLeft, }
Size: 24, x, y := 20, 160
Language: language.Japanese, w, h := text.Measure(thaiText, f, 0)
}, op) vector.DrawFilledRect(screen, float32(x), float32(y), float32(w), float32(h), gray, false)
op := &text.DrawOptions{}
op.GeoM.Translate(float64(x), float64(y))
text.Draw(screen, thaiText, f, op)
}
{
const japaneseText = "あのイーハトーヴォの\nすきとおった風、\n夏でも底に冷たさを\nもつ青いそら…"
f := &text.GoTextFace{
Source: japaneseFaceSource,
Direction: text.DirectionTopToBottomAndRightToLeft,
Size: 24,
Language: language.Japanese,
}
const lineSpacing = 48
x, y := screenWidth-20, 210
w, h := text.Measure(japaneseText, f, lineSpacing)
// The left upper point is not x but x-w, since the text runs in the rigth-to-left direction as the secondary direction.
vector.DrawFilledRect(screen, float32(x)-float32(w), float32(y), float32(w), float32(h), gray, false)
op := &text.DrawOptions{}
op.GeoM.Translate(float64(x), float64(y))
op.LineSpacingInPixels = lineSpacing
text.Draw(screen, japaneseText, f, op)
}
} }
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) { func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {

View File

@ -284,7 +284,10 @@ func (g *GoTextFace) gScript() glanguage.Script {
// advance implements Face. // advance implements Face.
func (g *GoTextFace) advance(text string) float64 { func (g *GoTextFace) advance(text string) float64 {
output, _ := g.Source.shape(text, g) output, _ := g.Source.shape(text, g)
return fixed26_6ToFloat64(output.Advance) if g.direction().isHorizontal() {
return fixed26_6ToFloat64(output.Advance)
}
return -fixed26_6ToFloat64(output.Advance)
} }
// appendGlyphsForLine implements Face. // appendGlyphsForLine implements Face.