text/v2: define different key types for StdFace and GoTextFaceSource

This commit is contained in:
Hajime Hoshi 2023-11-19 23:40:47 +09:00
parent 57ae07eb36
commit 03a8aaee5c
4 changed files with 27 additions and 26 deletions

View File

@ -18,8 +18,6 @@ import (
"math" "math"
"sync" "sync"
"golang.org/x/image/math/fixed"
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/internal/hook" "github.com/hajimehoshi/ebiten/v2/internal/hook"
) )
@ -39,27 +37,17 @@ func init() {
}) })
} }
type glyphImageCacheKey struct {
// id is rune for StdFace, and GID for GoTextFace.
id uint32
xoffset fixed.Int26_6
yoffset fixed.Int26_6
variations string
}
type glyphImageCacheEntry struct { type glyphImageCacheEntry struct {
image *ebiten.Image image *ebiten.Image
atime int64 atime int64
} }
type glyphImageCache struct { type glyphImageCache[Key comparable] struct {
cache map[glyphImageCacheKey]*glyphImageCacheEntry cache map[Key]*glyphImageCacheEntry
m sync.Mutex m sync.Mutex
} }
func (g *glyphImageCache) getOrCreate(face Face, key glyphImageCacheKey, create func() *ebiten.Image) *ebiten.Image { func (g *glyphImageCache[Key]) getOrCreate(face Face, key Key, create func() *ebiten.Image) *ebiten.Image {
g.m.Lock() g.m.Lock()
defer g.m.Unlock() defer g.m.Unlock()
@ -70,7 +58,7 @@ func (g *glyphImageCache) getOrCreate(face Face, key glyphImageCacheKey, create
} }
if g.cache == nil { if g.cache == nil {
g.cache = map[glyphImageCacheKey]*glyphImageCacheEntry{} g.cache = map[Key]*glyphImageCacheEntry{}
} }
img := create() img := create()

View File

@ -329,8 +329,8 @@ func (g *GoTextFace) glyphImage(glyph glyph, origin fixed.Point26_6) (*ebiten.Im
X: (origin.X + b.Min.X) & ((1 << 6) - 1), X: (origin.X + b.Min.X) & ((1 << 6) - 1),
Y: (origin.Y + b.Min.Y) & ((1 << 6) - 1), Y: (origin.Y + b.Min.Y) & ((1 << 6) - 1),
} }
key := glyphImageCacheKey{ key := goTextGlyphImageCacheKey{
id: uint32(glyph.shapingGlyph.GlyphID), gid: glyph.shapingGlyph.GlyphID,
xoffset: subpixelOffset.X, xoffset: subpixelOffset.X,
yoffset: subpixelOffset.Y, yoffset: subpixelOffset.Y,
variations: g.ensureVariationsString(), variations: g.ensureVariationsString(),

View File

@ -52,12 +52,19 @@ type goTextOutputCacheValue struct {
atime int64 atime int64
} }
type goTextGlyphImageCacheKey struct {
gid api.GID
xoffset fixed.Int26_6
yoffset fixed.Int26_6
variations string
}
// GoTextFaceSource is a source of a GoTextFace. This can be shared by multiple GoTextFace objects. // GoTextFaceSource is a source of a GoTextFace. This can be shared by multiple GoTextFace objects.
type GoTextFaceSource struct { type GoTextFaceSource struct {
f font.Face f font.Face
outputCache map[goTextOutputCacheKey]*goTextOutputCacheValue outputCache map[goTextOutputCacheKey]*goTextOutputCacheValue
glyphImageCache map[float64]*glyphImageCache glyphImageCache map[float64]*glyphImageCache[goTextGlyphImageCacheKey]
addr *GoTextFaceSource addr *GoTextFaceSource
@ -224,12 +231,12 @@ func (g *GoTextFaceSource) scale(size float64) float64 {
return size / float64(g.f.Upem()) return size / float64(g.f.Upem())
} }
func (g *GoTextFaceSource) getOrCreateGlyphImage(goTextFace *GoTextFace, key glyphImageCacheKey, create func() *ebiten.Image) *ebiten.Image { func (g *GoTextFaceSource) getOrCreateGlyphImage(goTextFace *GoTextFace, key goTextGlyphImageCacheKey, create func() *ebiten.Image) *ebiten.Image {
if g.glyphImageCache == nil { if g.glyphImageCache == nil {
g.glyphImageCache = map[float64]*glyphImageCache{} g.glyphImageCache = map[float64]*glyphImageCache[goTextGlyphImageCacheKey]{}
} }
if _, ok := g.glyphImageCache[goTextFace.Size]; !ok { if _, ok := g.glyphImageCache[goTextFace.Size]; !ok {
g.glyphImageCache[goTextFace.Size] = &glyphImageCache{} g.glyphImageCache[goTextFace.Size] = &glyphImageCache[goTextGlyphImageCacheKey]{}
} }
return g.glyphImageCache[goTextFace.Size].getOrCreate(goTextFace, key, create) return g.glyphImageCache[goTextFace.Size].getOrCreate(goTextFace, key, create)
} }

View File

@ -26,13 +26,20 @@ import (
var _ Face = (*StdFace)(nil) var _ Face = (*StdFace)(nil)
type stdFaceGlyphImageCacheKey struct {
rune rune
xoffset fixed.Int26_6
// yoffset is always the same if the rune is the same, so this doesn't have to be a key.
}
// StdFace is a Face implementation for a semi-standard font.Face (golang.org/x/image/font). // StdFace is a Face implementation for a semi-standard font.Face (golang.org/x/image/font).
// StdFace is useful to transit from existing codebase with text v1, or to use some bitmap fonts defined as font.Face. // StdFace is useful to transit from existing codebase with text v1, or to use some bitmap fonts defined as font.Face.
// StdFace must not be copied by value. // StdFace must not be copied by value.
type StdFace struct { type StdFace struct {
f *faceWithCache f *faceWithCache
glyphImageCache glyphImageCache glyphImageCache glyphImageCache[stdFaceGlyphImageCacheKey]
addr *StdFace addr *StdFace
} }
@ -121,10 +128,9 @@ func (s *StdFace) glyphImage(r rune, origin fixed.Point26_6) (*ebiten.Image, int
X: (origin.X + b.Min.X) & ((1 << 6) - 1), X: (origin.X + b.Min.X) & ((1 << 6) - 1),
Y: (origin.Y + b.Min.Y) & ((1 << 6) - 1), Y: (origin.Y + b.Min.Y) & ((1 << 6) - 1),
} }
key := glyphImageCacheKey{ key := stdFaceGlyphImageCacheKey{
id: uint32(r), rune: r,
xoffset: subpixelOffset.X, xoffset: subpixelOffset.X,
// yoffset is always the same if the rune is the same, so this doesn't have to be a key.
} }
img := s.glyphImageCache.getOrCreate(s, key, func() *ebiten.Image { img := s.glyphImageCache.getOrCreate(s, key, func() *ebiten.Image {
return s.glyphImageImpl(r, subpixelOffset, b) return s.glyphImageImpl(r, subpixelOffset, b)