diff --git a/draw2dbase/text.go b/draw2dbase/text.go index 4283bad..4e5e339 100644 --- a/draw2dbase/text.go +++ b/draw2dbase/text.go @@ -2,21 +2,29 @@ package draw2dbase import "github.com/llgcode/draw2d" -var glyphCache map[string]map[rune]*Glyph +// GlyphCache manage a map of glyphs +type GlyphCache struct { + glyphs map[string]map[rune]*Glyph +} -func init() { - glyphCache = make(map[string]map[rune]*Glyph) + +// NewGlyphCache initializes a GlyphCache +func NewGlyphCache() *GlyphCache { + glyphs := make(map[string]map[rune]*Glyph) + return &GlyphCache { + glyphs: glyphs, + } } // FetchGlyph fetches a glyph from the cache, calling renderGlyph first if it doesn't already exist -func FetchGlyph(gc draw2d.GraphicContext, fontName string, chr rune) *Glyph { - if glyphCache[fontName] == nil { - glyphCache[fontName] = make(map[rune]*Glyph, 60) +func (glyphCache *GlyphCache) FetchGlyph(gc draw2d.GraphicContext, fontName string, chr rune) *Glyph { + if glyphCache.glyphs[fontName] == nil { + glyphCache.glyphs[fontName] = make(map[rune]*Glyph, 60) } - if glyphCache[fontName][chr] == nil { - glyphCache[fontName][chr] = renderGlyph(gc, fontName, chr) + if glyphCache.glyphs[fontName][chr] == nil { + glyphCache.glyphs[fontName][chr] = renderGlyph(gc, fontName, chr) } - return glyphCache[fontName][chr].Copy() + return glyphCache.glyphs[fontName][chr].Copy() } // renderGlyph renders a glyph then caches and returns it @@ -40,6 +48,7 @@ type Glyph struct { Width float64 } +// Returns a copy of a Glyph func (g *Glyph) Copy() *Glyph { return &Glyph{ path: g.path.Copy(), diff --git a/draw2dimg/ftgc.go b/draw2dimg/ftgc.go index abaf7e5..8195c64 100644 --- a/draw2dimg/ftgc.go +++ b/draw2dimg/ftgc.go @@ -4,7 +4,6 @@ package draw2dimg import ( - "errors" "image" "image/color" "log" @@ -35,6 +34,8 @@ type GraphicContext struct { painter Painter fillRasterizer *raster.Rasterizer strokeRasterizer *raster.Rasterizer + FontCache draw2d.FontCache + glyphCache *draw2dbase.GlyphCache glyphBuf *truetype.GlyphBuf DPI int } @@ -74,6 +75,8 @@ func NewGraphicContextWithPainter(img draw.Image, painter Painter) *GraphicConte painter, raster.NewRasterizer(width, height), raster.NewRasterizer(width, height), + draw2d.GetGlobalFontCache(), + draw2dbase.NewGlyphCache(), &truetype.GlyphBuf{}, dpi, } @@ -136,7 +139,7 @@ func (gc *GraphicContext) FillStringAt(text string, x, y float64) (width float64 if hasPrev { x += fUnitsToFloat64(f.Kern(fixed.Int26_6(gc.Current.Scale), prev, index)) } - glyph := draw2dbase.FetchGlyph(gc, fontName, r) + glyph := gc.glyphCache.FetchGlyph(gc, fontName, r) x += glyph.Fill(gc, x, y) prev, hasPrev = index, true } @@ -163,7 +166,7 @@ func (gc *GraphicContext) StrokeStringAt(text string, x, y float64) (width float if hasPrev { x += fUnitsToFloat64(f.Kern(fixed.Int26_6(gc.Current.Scale), prev, index)) } - glyph := draw2dbase.FetchGlyph(gc, fontName, r) + glyph := gc.glyphCache.FetchGlyph(gc, fontName, r) x += glyph.Stroke(gc, x, y) prev, hasPrev = index, true } @@ -171,16 +174,15 @@ func (gc *GraphicContext) StrokeStringAt(text string, x, y float64) (width float } func (gc *GraphicContext) loadCurrentFont() (*truetype.Font, error) { - font := draw2d.GetFont(gc.Current.FontData) - if font == nil { - font = draw2d.GetFont(draw2dbase.DefaultFontData) + font, err := gc.FontCache.Load(gc.Current.FontData) + if err != nil { + font, err = gc.FontCache.Load(draw2dbase.DefaultFontData) } - if font == nil { - return nil, errors.New("No font set, and no default font available.") + if font != nil { + gc.SetFont(font) + gc.SetFontSize(gc.Current.FontSize) } - gc.SetFont(font) - gc.SetFontSize(gc.Current.FontSize) - return font, nil + return font, err } // p is a truetype.Point measured in FUnits and positive Y going upwards. diff --git a/font.go b/font.go index cd0ec1b..61c0171 100644 --- a/font.go +++ b/font.go @@ -79,6 +79,10 @@ func GetFontFolder() string { return defaultFonts.folder } +func GetGlobalFontCache() FontCache { + return defaultFonts +} + func SetFontFolder(folder string) { defaultFonts.folder = filepath.Clean(folder) } @@ -113,13 +117,24 @@ func SetFontCache(cache FontCache) { } } -type defaultFontCache struct { +// FolderFontCache can Load font from folder +type FolderFontCache struct { fonts map[string]*truetype.Font folder string namer FontFileNamer } -func (cache *defaultFontCache) Load(fontData FontData) (font *truetype.Font, err error) { +// NewFolderFontCache creates FolderFontCache +func NewFolderFontCache(folder string) *FolderFontCache { + return &FolderFontCache{ + fonts: make(map[string]*truetype.Font), + folder: folder, + namer: FontFileName, + } +} + +// Load a font from cache if exists otherwise it will load the font from file +func (cache *FolderFontCache) Load(fontData FontData) (font *truetype.Font, err error) { if font = cache.fonts[cache.namer(fontData)]; font != nil { return font, nil } @@ -139,16 +154,13 @@ func (cache *defaultFontCache) Load(fontData FontData) (font *truetype.Font, err return } -func (cache *defaultFontCache) Store(fontData FontData, font *truetype.Font) { +// Store a font to this cache +func (cache *FolderFontCache) Store(fontData FontData, font *truetype.Font) { cache.fonts[cache.namer(fontData)] = font } var ( - defaultFonts = &defaultFontCache{ - fonts: make(map[string]*truetype.Font), - folder: "../resource/font", - namer: FontFileName, - } + defaultFonts = NewFolderFontCache("../resource/font") fontCache FontCache = defaultFonts ) diff --git a/sync_test.go b/sync_test.go index 8580a81..41eef62 100644 --- a/sync_test.go +++ b/sync_test.go @@ -2,6 +2,7 @@ package draw2d_test + import ( "fmt" "github.com/llgcode/draw2d" @@ -25,10 +26,10 @@ func TestSync(t *testing.T) { } func Draw(i int, ch chan<- int) { - draw2d.SetFontFolder("./resource/font") // Draw a rounded rectangle using default colors dest := image.NewRGBA(image.Rect(0, 0, 297, 210.0)) gc := draw2dimg.NewGraphicContext(dest) + gc.FontCache = draw2d.NewFolderFontCache("./resource/font") draw2dkit.RoundedRectangle(gc, 5, 5, 135, 95, 10, 10) gc.FillStroke()