text: deprecate BoundString

After we found a correct definition of the term 'dot', BoundString seems
less useful than expected. In order to adjust the position of a text, we
should use a face's Metrics and a string's advance (font.MeasureString).
This commit is contained in:
Hajime Hoshi 2023-06-10 19:21:01 +09:00
parent 585e929f9f
commit 911cf0c48c
2 changed files with 36 additions and 16 deletions

View File

@ -19,10 +19,12 @@ import (
"log" "log"
"math" "math"
"math/rand" "math/rand"
"strings"
"time" "time"
"golang.org/x/image/font" "golang.org/x/image/font"
"golang.org/x/image/font/opentype" "golang.org/x/image/font/opentype"
"golang.org/x/image/math/fixed"
"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"
@ -87,19 +89,45 @@ func (g *Game) Update() error {
return nil return nil
} }
func boundString(face font.Face, str string) fixed.Rectangle26_6 {
str = strings.TrimRight(str, "\n")
lines := strings.Split(str, "\n")
if len(lines) == 0 {
return fixed.Rectangle26_6{}
}
minX := fixed.I(0)
maxX := fixed.I(0)
for _, line := range lines {
a := font.MeasureString(face, line)
if maxX < a {
maxX = a
}
}
m := face.Metrics()
minY := -m.Ascent
maxY := fixed.Int26_6(len(lines)-1)*m.Height + m.Descent
return fixed.Rectangle26_6{fixed.Point26_6{X: minX, Y: minY}, fixed.Point26_6{X: maxX, Y: maxY}}
}
func fixed26_6ToFloat32(x fixed.Int26_6) float32 {
return float32(x>>6) + float32(x&((1<<6)-1))/(1<<6)
}
func (g *Game) Draw(screen *ebiten.Image) { func (g *Game) Draw(screen *ebiten.Image) {
gray := color.RGBA{0x80, 0x80, 0x80, 0xff} gray := color.RGBA{0x80, 0x80, 0x80, 0xff}
{ {
const x, y = 20, 40 const x, y = 20, 40
b := text.BoundString(mplusNormalFont, sampleText) b := boundString(mplusNormalFont, sampleText)
vector.DrawFilledRect(screen, float32(b.Min.X+x), float32(b.Min.Y+y), float32(b.Dx()), float32(b.Dy()), gray, false) vector.DrawFilledRect(screen, fixed26_6ToFloat32(b.Min.X)+x, fixed26_6ToFloat32(b.Min.Y)+y, fixed26_6ToFloat32(b.Max.X-b.Min.X), fixed26_6ToFloat32(b.Max.Y-b.Min.Y), gray, false)
text.Draw(screen, sampleText, mplusNormalFont, x, y, color.White) text.Draw(screen, sampleText, mplusNormalFont, x, y, color.White)
} }
{ {
const x, y = 20, 140 const x, y = 20, 140
b := text.BoundString(mplusBigFont, sampleText) b := boundString(mplusBigFont, sampleText)
vector.DrawFilledRect(screen, float32(b.Min.X+x), float32(b.Min.Y+y), float32(b.Dx()), float32(b.Dy()), gray, false) vector.DrawFilledRect(screen, fixed26_6ToFloat32(b.Min.X)+x, fixed26_6ToFloat32(b.Min.Y)+y, fixed26_6ToFloat32(b.Max.X-b.Min.X), fixed26_6ToFloat32(b.Max.Y-b.Min.Y), gray, false)
text.Draw(screen, sampleText, mplusBigFont, x, y, color.White) text.Draw(screen, sampleText, mplusBigFont, x, y, color.White)
} }
{ {
@ -113,8 +141,8 @@ func (g *Game) Draw(screen *ebiten.Image) {
{ {
const x, y = 160, 240 const x, y = 160, 240
const lineHeight = 80 const lineHeight = 80
b := text.BoundString(text.FaceWithLineHeight(mplusBigFont, lineHeight), sampleText) b := boundString(text.FaceWithLineHeight(mplusBigFont, lineHeight), sampleText)
vector.DrawFilledRect(screen, float32(b.Min.X+x), float32(b.Min.Y+y), float32(b.Dx()), float32(b.Dy()), gray, false) vector.DrawFilledRect(screen, fixed26_6ToFloat32(b.Min.X)+x, fixed26_6ToFloat32(b.Min.Y)+y, fixed26_6ToFloat32(b.Max.X-b.Min.X), fixed26_6ToFloat32(b.Max.Y-b.Min.Y), gray, false)
text.Draw(screen, sampleText, text.FaceWithLineHeight(mplusBigFont, lineHeight), x, y, color.White) text.Draw(screen, sampleText, text.FaceWithLineHeight(mplusBigFont, lineHeight), x, y, color.White)
} }
{ {

View File

@ -149,11 +149,6 @@ var textM sync.Mutex
// //
// clr is the color for text rendering. // clr is the color for text rendering.
// //
// If you want to adjust the position of the text, these functions are useful:
//
// - text.BoundString: the rendered bounds of the given text.
// - golang.org/x/image/font.Face.Metrics: the metrics of the face.
//
// The '\n' newline character puts the following text on the next line. // The '\n' newline character puts the following text on the next line.
// Line height is based on Metrics().Height of the font. // Line height is based on Metrics().Height of the font.
// //
@ -190,11 +185,6 @@ func Draw(dst *ebiten.Image, text string, face font.Face, x, y int, clr color.Co
// Be careful that the origin point is not upper-left corner position of dst. // Be careful that the origin point is not upper-left corner position of dst.
// The default glyph color is white. op's ColorM adjusts the color. // The default glyph color is white. op's ColorM adjusts the color.
// //
// If you want to adjust the position of the text, these functions are useful:
//
// - text.BoundString: the rendered bounds of the given text.
// - golang.org/x/image/font.Face.Metrics: the metrics of the face.
//
// The '\n' newline character puts the following text on the next line. // The '\n' newline character puts the following text on the next line.
// Line height is based on Metrics().Height of the font. // Line height is based on Metrics().Height of the font.
// //
@ -286,6 +276,8 @@ func DrawWithOptions(dst *ebiten.Image, text string, face font.Face, options *eb
// This is a known issue (#498). // This is a known issue (#498).
// //
// BoundString is concurrent-safe. // BoundString is concurrent-safe.
//
// Deprecated: as of v2.6. Use golang.org/x/image/font.BoundString instead, or use a face's Metrics (Ascent and Descent) and font.MeasureString instead.
func BoundString(face font.Face, text string) image.Rectangle { func BoundString(face font.Face, text string) image.Rectangle {
textM.Lock() textM.Lock()
defer textM.Unlock() defer textM.Unlock()