text: Refactoring

This commit is contained in:
Hajime Hoshi 2018-02-12 22:02:05 +09:00
parent cc423c276d
commit 31ae457a8c

View File

@ -40,28 +40,15 @@ func now() int64 {
return monotonicClock return monotonicClock
} }
var ( type cacheEntry struct {
faces = map[font.Face]struct{}{}
)
func fontFaceToFace(f font.Face) font.Face {
if _, ok := faces[f]; ok {
return f
}
// If the (DeepEqual-ly) same font exists,
// reuse this to avoid to consume a lot of cache (#498).
for key := range faces {
if reflect.DeepEqual(key, f) {
return key
}
}
faces[f] = struct{}{}
return f
}
var (
// Use pointers to avoid copying on browsers. // Use pointers to avoid copying on browsers.
charBounds = map[font.Face]map[rune]*fixed.Rectangle26_6{} bounds map[rune]*fixed.Rectangle26_6
atlases map[int]*atlas
}
var (
cache = map[font.Face]*cacheEntry{}
) )
type char struct { type char struct {
@ -71,15 +58,12 @@ type char struct {
} }
func (c *char) bounds() *fixed.Rectangle26_6 { func (c *char) bounds() *fixed.Rectangle26_6 {
if m, ok := charBounds[c.face]; ok { e := cache[c.face]
if b, ok := m[c.rune]; ok { if b, ok := e.bounds[c.rune]; ok {
return b return b
} }
} else {
charBounds[c.face] = map[rune]*fixed.Rectangle26_6{}
}
b, _, _ := c.face.GlyphBounds(c.rune) b, _, _ := c.face.GlyphBounds(c.rune)
charBounds[c.face][c.rune] = &b e.bounds[c.rune] = &b
return &b return &b
} }
@ -180,7 +164,7 @@ func (g *glyph) draw(dst *ebiten.Image, x, y fixed.Int26_6, clr color.Color) {
} }
op.ColorM = e.m op.ColorM = e.m
a := atlases[g.char.face][g.char.atlasGroup()] a := cache[g.char.face].atlases[g.char.atlasGroup()]
sx, sy := a.at(g) sx, sy := a.at(g)
r := image.Rect(sx, sy, sx+a.glyphSize, sy+a.glyphSize) r := image.Rect(sx, sy, sx+a.glyphSize, sy+a.glyphSize)
op.SourceRect = &r op.SourceRect = &r
@ -188,10 +172,6 @@ func (g *glyph) draw(dst *ebiten.Image, x, y fixed.Int26_6, clr color.Color) {
dst.DrawImage(a.image, op) dst.DrawImage(a.image, op)
} }
var (
atlases = map[font.Face]map[int]*atlas{}
)
type atlas struct { type atlas struct {
// image is the back-end image to hold glyph cache. // image is the back-end image to hold glyph cache.
image *ebiten.Image image *ebiten.Image
@ -282,20 +262,14 @@ func getGlyphFromCache(face font.Face, r rune, now int64) *glyph {
face: face, face: face,
rune: r, rune: r,
} }
var at *atlas at, ok := cache[face].atlases[ch.atlasGroup()]
if m, ok := atlases[face]; ok {
a, ok := m[ch.atlasGroup()]
if ok { if ok {
g, ok := a.runeToGlyph[r] g, ok := at.runeToGlyph[r]
if ok { if ok {
g.atime = now g.atime = now
return g return g
} }
} }
at = a
} else {
atlases[face] = map[int]*atlas{}
}
if ch.empty() { if ch.empty() {
// The glyph doesn't have its size but might have valid 'advance' parameter // The glyph doesn't have its size but might have valid 'advance' parameter
@ -324,12 +298,30 @@ func getGlyphFromCache(face font.Face, r rune, now int64) *glyph {
glyphSize: ch.atlasGroup(), glyphSize: ch.atlasGroup(),
runeToGlyph: map[rune]*glyph{}, runeToGlyph: map[rune]*glyph{},
} }
atlases[face][ch.atlasGroup()] = at cache[face].atlases[ch.atlasGroup()] = at
} }
return at.appendGlyph(ch, now) return at.appendGlyph(ch, now)
} }
func uniqFace(f font.Face) font.Face {
if _, ok := cache[f]; ok {
return f
}
// If the (DeepEqual-ly) same font exists,
// reuse this to avoid to consume a lot of cache (#498).
for key := range cache {
if reflect.DeepEqual(key, f) {
return key
}
}
cache[f] = &cacheEntry{
bounds: map[rune]*fixed.Rectangle26_6{},
atlases: map[int]*atlas{},
}
return f
}
var textM sync.Mutex var textM sync.Mutex
// Draw draws a given text on a given destination image dst. // Draw draws a given text on a given destination image dst.
@ -355,7 +347,7 @@ func Draw(dst *ebiten.Image, text string, face font.Face, x, y int, clr color.Co
if prevC >= 0 { if prevC >= 0 {
fx += face.Kern(prevC, c) fx += face.Kern(prevC, c)
} }
fa := fontFaceToFace(face) fa := uniqFace(face)
if g := getGlyphFromCache(fa, c, n); g != nil { if g := getGlyphFromCache(fa, c, n); g != nil {
if !g.char.empty() { if !g.char.empty() {
g.draw(dst, fx, fixed.I(y), clr) g.draw(dst, fx, fixed.I(y), clr)