text: make Shaper an interface

And rename out the caching implementation to FontRegistry.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2020-01-13 14:48:31 +01:00
parent 3f6a1c34d3
commit e25b1639b9
9 changed files with 27 additions and 20 deletions
+2 -2
View File
@@ -12,12 +12,12 @@ import (
var ( var (
mu sync.Mutex mu sync.Mutex
initialized bool initialized bool
shaper = new(text.Shaper) shaper = new(text.FontRegistry)
) )
// Default returns a singleton *text.Shaper that contains // Default returns a singleton *text.Shaper that contains
// the registered fonts. // the registered fonts.
func Default() *text.Shaper { func Default() *text.FontRegistry {
mu.Lock() mu.Lock()
defer mu.Unlock() defer mu.Unlock()
initialized = true initialized = true
+16 -9
View File
@@ -12,12 +12,19 @@ import (
"golang.org/x/image/math/fixed" "golang.org/x/image/math/fixed"
) )
// Shaper implements layout and shaping of text and a cache of // Shaper implements layout and shaping of text.
type Shaper interface {
Layout(c unit.Converter, font Font, str string, opts LayoutOptions) *Layout
Shape(c unit.Converter, font Font, str String) op.CallOp
Metrics(c unit.Converter, font Font) font.Metrics
}
// FontRegistry implements layout and shaping of text and a cache of
// computed results. // computed results.
// //
// If a font matches no registered shape, Shaper falls back to the // If a font matches no registered shape, FontRegistry falls back to the
// first registered face. // first registered face.
type Shaper struct { type FontRegistry struct {
def Typeface def Typeface
faces map[Font]*face faces map[Font]*face
} }
@@ -28,7 +35,7 @@ type face struct {
pathCache pathCache pathCache pathCache
} }
func (s *Shaper) Register(font Font, tf Face) { func (s *FontRegistry) Register(font Font, tf Face) {
if s.faces == nil { if s.faces == nil {
s.def = font.Typeface s.def = font.Typeface
s.faces = make(map[Font]*face) s.faces = make(map[Font]*face)
@@ -43,22 +50,22 @@ func (s *Shaper) Register(font Font, tf Face) {
} }
} }
func (s *Shaper) Layout(c unit.Converter, font Font, str string, opts LayoutOptions) *Layout { func (s *FontRegistry) Layout(c unit.Converter, font Font, str string, opts LayoutOptions) *Layout {
tf := s.faceForFont(font) tf := s.faceForFont(font)
return tf.layout(fixed.I(c.Px(font.Size)), str, opts) return tf.layout(fixed.I(c.Px(font.Size)), str, opts)
} }
func (s *Shaper) Shape(c unit.Converter, font Font, str String) op.CallOp { func (s *FontRegistry) Shape(c unit.Converter, font Font, str String) op.CallOp {
tf := s.faceForFont(font) tf := s.faceForFont(font)
return tf.shape(fixed.I(c.Px(font.Size)), str) return tf.shape(fixed.I(c.Px(font.Size)), str)
} }
func (s *Shaper) Metrics(c unit.Converter, font Font) font.Metrics { func (s *FontRegistry) Metrics(c unit.Converter, font Font) font.Metrics {
tf := s.faceForFont(font) tf := s.faceForFont(font)
return tf.metrics(fixed.I(c.Px(font.Size))) return tf.metrics(fixed.I(c.Px(font.Size)))
} }
func (s *Shaper) faceForStyle(font Font) *face { func (s *FontRegistry) faceForStyle(font Font) *face {
tf := s.faces[font] tf := s.faces[font]
if tf == nil { if tf == nil {
font := font font := font
@@ -79,7 +86,7 @@ func (s *Shaper) faceForStyle(font Font) *face {
return tf return tf
} }
func (s *Shaper) faceForFont(font Font) *face { func (s *FontRegistry) faceForFont(font Font) *face {
font.Size = unit.Value{} font.Size = unit.Value{}
tf := s.faceForStyle(font) tf := s.faceForStyle(font)
if tf == nil { if tf == nil {
+3 -3
View File
@@ -213,7 +213,7 @@ func (e *Editor) Focus() {
} }
// Layout lays out the editor. // Layout lays out the editor.
func (e *Editor) Layout(gtx *layout.Context, sh *text.Shaper, font text.Font) { func (e *Editor) Layout(gtx *layout.Context, sh text.Shaper, font text.Font) {
// Flush events from before the previous frame. // Flush events from before the previous frame.
copy(e.events, e.events[e.prevEvents:]) copy(e.events, e.events[e.prevEvents:])
e.events = e.events[:len(e.events)-e.prevEvents] e.events = e.events[:len(e.events)-e.prevEvents]
@@ -226,7 +226,7 @@ func (e *Editor) Layout(gtx *layout.Context, sh *text.Shaper, font text.Font) {
e.layout(gtx, sh) e.layout(gtx, sh)
} }
func (e *Editor) layout(gtx *layout.Context, sh *text.Shaper) { func (e *Editor) layout(gtx *layout.Context, sh text.Shaper) {
// Crude configuration change detection. // Crude configuration change detection.
if scale := gtx.Px(unit.Sp(100)); scale != e.scale { if scale := gtx.Px(unit.Sp(100)); scale != e.scale {
e.invalidate() e.invalidate()
@@ -430,7 +430,7 @@ func (e *Editor) moveCoord(c unit.Converter, pos image.Point) {
e.moveToLine(x, carLine) e.moveToLine(x, carLine)
} }
func (e *Editor) layoutText(c unit.Converter, s *text.Shaper, font text.Font) ([]text.Line, layout.Dimensions) { func (e *Editor) layoutText(c unit.Converter, s text.Shaper, font text.Font) ([]text.Line, layout.Dimensions) {
txt := e.rr.String() txt := e.rr.String()
opts := text.LayoutOptions{MaxWidth: e.maxWidth} opts := text.LayoutOptions{MaxWidth: e.maxWidth}
textLayout := s.Layout(c, font, txt, opts) textLayout := s.Layout(c, font, txt, opts)
+1 -1
View File
@@ -82,7 +82,7 @@ func (l *lineIterator) Next() (text.String, f32.Point, bool) {
return text.String{}, f32.Point{}, false return text.String{}, f32.Point{}, false
} }
func (l Label) Layout(gtx *layout.Context, s *text.Shaper, font text.Font, txt string) { func (l Label) Layout(gtx *layout.Context, s text.Shaper, font text.Font, txt string) {
cs := gtx.Constraints cs := gtx.Constraints
textLayout := s.Layout(gtx, font, txt, text.LayoutOptions{MaxWidth: cs.Width.Max}) textLayout := s.Layout(gtx, font, txt, text.LayoutOptions{MaxWidth: cs.Width.Max})
lines := textLayout.Lines lines := textLayout.Lines
+1 -1
View File
@@ -24,7 +24,7 @@ type Button struct {
Font text.Font Font text.Font
Background color.RGBA Background color.RGBA
CornerRadius unit.Value CornerRadius unit.Value
shaper *text.Shaper shaper text.Shaper
} }
type IconButton struct { type IconButton struct {
+1 -1
View File
@@ -20,7 +20,7 @@ type checkable struct {
Font text.Font Font text.Font
IconColor color.RGBA IconColor color.RGBA
Size unit.Value Size unit.Value
shaper *text.Shaper shaper text.Shaper
checkedStateIcon *Icon checkedStateIcon *Icon
uncheckedStateIcon *Icon uncheckedStateIcon *Icon
} }
+1 -1
View File
@@ -21,7 +21,7 @@ type Editor struct {
// HintColor is the color of hint text. // HintColor is the color of hint text.
HintColor color.RGBA HintColor color.RGBA
shaper *text.Shaper shaper text.Shaper
} }
func (t *Theme) Editor(hint string) Editor { func (t *Theme) Editor(hint string) Editor {
+1 -1
View File
@@ -23,7 +23,7 @@ type Label struct {
MaxLines int MaxLines int
Text string Text string
shaper *text.Shaper shaper text.Shaper
} }
func (t *Theme) H1(txt string) Label { func (t *Theme) H1(txt string) Label {
+1 -1
View File
@@ -16,7 +16,7 @@ import (
) )
type Theme struct { type Theme struct {
Shaper *text.Shaper Shaper text.Shaper
Color struct { Color struct {
Primary color.RGBA Primary color.RGBA
Text color.RGBA Text color.RGBA