~eliasnaur/gio

e25b1639b9efb65b8c25329dffdd2f4ec8883833 — Elias Naur 1 year, 9 months ago 3f6a1c3
text: make Shaper an interface

And rename out the caching implementation to FontRegistry.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
M font/font.go => font/font.go +2 -2
@@ 12,12 12,12 @@ import (
var (
	mu          sync.Mutex
	initialized bool
	shaper      = new(text.Shaper)
	shaper      = new(text.FontRegistry)
)

// Default returns a singleton *text.Shaper that contains
// the registered fonts.
func Default() *text.Shaper {
func Default() *text.FontRegistry {
	mu.Lock()
	defer mu.Unlock()
	initialized = true

M text/shaper.go => text/shaper.go +16 -9
@@ 12,12 12,19 @@ import (
	"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.
//
// 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.
type Shaper struct {
type FontRegistry struct {
	def   Typeface
	faces map[Font]*face
}


@@ 28,7 35,7 @@ type face struct {
	pathCache   pathCache
}

func (s *Shaper) Register(font Font, tf Face) {
func (s *FontRegistry) Register(font Font, tf Face) {
	if s.faces == nil {
		s.def = font.Typeface
		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)
	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)
	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)
	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]
	if tf == nil {
		font := font


@@ 79,7 86,7 @@ func (s *Shaper) faceForStyle(font Font) *face {
	return tf
}

func (s *Shaper) faceForFont(font Font) *face {
func (s *FontRegistry) faceForFont(font Font) *face {
	font.Size = unit.Value{}
	tf := s.faceForStyle(font)
	if tf == nil {

M widget/editor.go => widget/editor.go +3 -3
@@ 213,7 213,7 @@ func (e *Editor) Focus() {
}

// 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.
	copy(e.events, 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)
}

func (e *Editor) layout(gtx *layout.Context, sh *text.Shaper) {
func (e *Editor) layout(gtx *layout.Context, sh text.Shaper) {
	// Crude configuration change detection.
	if scale := gtx.Px(unit.Sp(100)); scale != e.scale {
		e.invalidate()


@@ 430,7 430,7 @@ func (e *Editor) moveCoord(c unit.Converter, pos image.Point) {
	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()
	opts := text.LayoutOptions{MaxWidth: e.maxWidth}
	textLayout := s.Layout(c, font, txt, opts)

M widget/label.go => widget/label.go +1 -1
@@ 82,7 82,7 @@ func (l *lineIterator) Next() (text.String, f32.Point, bool) {
	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
	textLayout := s.Layout(gtx, font, txt, text.LayoutOptions{MaxWidth: cs.Width.Max})
	lines := textLayout.Lines

M widget/material/button.go => widget/material/button.go +1 -1
@@ 24,7 24,7 @@ type Button struct {
	Font         text.Font
	Background   color.RGBA
	CornerRadius unit.Value
	shaper       *text.Shaper
	shaper       text.Shaper
}

type IconButton struct {

M widget/material/checkable.go => widget/material/checkable.go +1 -1
@@ 20,7 20,7 @@ type checkable struct {
	Font               text.Font
	IconColor          color.RGBA
	Size               unit.Value
	shaper             *text.Shaper
	shaper             text.Shaper
	checkedStateIcon   *Icon
	uncheckedStateIcon *Icon
}

M widget/material/editor.go => widget/material/editor.go +1 -1
@@ 21,7 21,7 @@ type Editor struct {
	// HintColor is the color of hint text.
	HintColor color.RGBA

	shaper *text.Shaper
	shaper text.Shaper
}

func (t *Theme) Editor(hint string) Editor {

M widget/material/label.go => widget/material/label.go +1 -1
@@ 23,7 23,7 @@ type Label struct {
	MaxLines int
	Text     string

	shaper *text.Shaper
	shaper text.Shaper
}

func (t *Theme) H1(txt string) Label {

M widget/material/theme.go => widget/material/theme.go +1 -1
@@ 16,7 16,7 @@ import (
)

type Theme struct {
	Shaper *text.Shaper
	Shaper text.Shaper
	Color  struct {
		Primary color.RGBA
		Text    color.RGBA