From 38dc470adc44675593e79e65c3ba7894f181d47c Mon Sep 17 00:00:00 2001 From: JessonChan Date: Sat, 6 Aug 2022 21:50:16 +0800 Subject: [PATCH] cache the font files --- internal/gdi/font/font.go | 47 ++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/internal/gdi/font/font.go b/internal/gdi/font/font.go index 6912970f..08cdde1c 100644 --- a/internal/gdi/font/font.go +++ b/internal/gdi/font/font.go @@ -6,7 +6,8 @@ package font import ( "fmt" "image" - "io/ioutil" + "io" + "os" "path" "sync" @@ -87,19 +88,43 @@ func (p *Default) findFontAtPath( return false } -func (p *Default) tryFontFile(name, tryFile string, options *truetype.Options) bool { - fp, err := fsutil.OpenFile(tryFile) - if err != nil { - return false - } - defer fp.Close() +// Each Default.(Font.Face) object holds all the content of the font file in memory, +// in fact the file content is read-only. +// Different Default-Objects with same file should share the content,not allocate new memory. +var fontFileCache = struct { + files map[string][]byte + sync.Mutex +}{ + files: map[string][]byte{}, +} - b, err := ioutil.ReadAll(fp) - if err != nil { - return false +func (p *Default) tryFontFile(name, tryFile string, options *truetype.Options) bool { + fontFileCache.Lock() + var bs []byte + var ok bool + if bs, ok = fontFileCache.files[tryFile]; !ok { + fp, err := fsutil.OpenFile(tryFile) + if err != nil { + fontFileCache.Unlock() + return false + } + defer fp.Close() + fi, err := os.Stat(tryFile) + if err != nil { + fontFileCache.Unlock() + return false + } + bs = make([]byte, fi.Size()) + n, err := io.ReadFull(fp, bs) + if err != nil || n != len(bs) { + fontFileCache.Unlock() + return false + } + fontFileCache.files[tryFile] = bs } + fontFileCache.Unlock() - tt, err := truetype.Parse(b) + tt, err := truetype.Parse(bs) if err != nil { return false }