text: eliminate path cache memory leak

This commit alters the method we use to check for valid cache hits
in the text path cache. Previously we stored the entire text.Layout
that was provided when the cache entry was set so that we could ensure
only identical text.Layouts would produce hits (guarding against hash
collisions). This commit instead pulls the glyph IDs for every glyph
in the text.Layout and stores them in the cache. This uses far less
memory and seems to allow cache entries to be GCed after eviction.

Fixes: https://todo.sr.ht/~eliasnaur/gio/418
Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
This commit is contained in:
Chris Waldon
2022-06-01 16:40:16 -04:00
committed by Elias Naur
parent 9bf68963da
commit 11192a5142
+20 -3
View File
@@ -5,6 +5,7 @@ package text
import (
"gioui.org/io/system"
"gioui.org/op/clip"
"github.com/benoitkugler/textlayout/fonts"
"golang.org/x/image/math/fixed"
)
@@ -28,7 +29,7 @@ type path struct {
next, prev *path
key pathKey
val clip.PathSpec
layout Layout
gids []fonts.GID
}
type layoutKey struct {
@@ -84,8 +85,20 @@ func (l *layoutCache) insert(lt *layoutElem) {
lt.next.prev = lt
}
func gidsMatch(gids []fonts.GID, l Layout) bool {
if len(gids) != len(l.Glyphs) {
return false
}
for i := range gids {
if gids[i] != l.Glyphs[i].ID {
return false
}
}
return true
}
func (c *pathCache) Get(k pathKey, l Layout) (clip.PathSpec, bool) {
if v, ok := c.m[k]; ok && l.equals(v.layout) {
if v, ok := c.m[k]; ok && gidsMatch(v.gids, l) {
c.remove(v)
c.insert(v)
return v.val, true
@@ -101,7 +114,11 @@ func (c *pathCache) Put(k pathKey, l Layout, v clip.PathSpec) {
c.head.prev = c.tail
c.tail.next = c.head
}
val := &path{key: k, val: v, layout: l}
gids := make([]fonts.GID, len(l.Glyphs))
for i := range l.Glyphs {
gids[i] = l.Glyphs[i].ID
}
val := &path{key: k, val: v, gids: gids}
c.m[k] = val
c.insert(val)
if len(c.m) > maxSize {