Files
gio/text/shaper.go
T
Elias Naur bef7c39e4c text: replace Family with Shaper, add Font, Face
There is now a single shaping implementation, Shaper, for all fonts, replacing
Family that only covered a single typeface.

A typeface is identified by a name, where the empty string denotes the
default typeface.

Font is introduced to specify a particular font from the typeface, style,
weight and size.

Face is changed to an interface for a particular layout and shaping method.
The text/shape package is renamed to text/opentype and contains a Face
implementation based on golang.org/x/image/font/sfnt.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
2019-10-12 14:04:34 +02:00

110 lines
2.1 KiB
Go

// SPDX-License-Identifier: Unlicense OR MIT
package text
import (
"gioui.org/op/paint"
"gioui.org/unit"
"golang.org/x/image/math/fixed"
)
// Shaper implements layout and shaping of text and a cache of
// computed results.
//
// Specify the default and fallback font by calling Register with the
// empty Font.
type Shaper struct {
faces map[Font]*face
}
type face struct {
face Face
layoutCache layoutCache
pathCache pathCache
}
func (s *Shaper) Register(font Font, tf Face) {
if s.faces == nil {
s.faces = make(map[Font]*face)
}
// Treat all font sizes equally.
font.Size = unit.Value{}
if font.Weight == 0 {
font.Weight = Normal
}
s.faces[font] = &face{
face: tf,
}
}
func (s *Shaper) 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) paint.ClipOp {
tf := s.faceForFont(font)
return tf.shape(fixed.I(c.Px(font.Size)), str)
}
func (s *Shaper) faceForStyle(font Font) *face {
tf := s.faces[font]
if tf == nil {
font := font
font.Weight = Normal
tf = s.faces[font]
}
if tf == nil {
font := font
font.Style = Regular
tf = s.faces[font]
}
if tf == nil {
font := font
font.Style = Regular
font.Weight = Normal
tf = s.faces[font]
}
return tf
}
func (s *Shaper) faceForFont(font Font) *face {
font.Size = unit.Value{}
tf := s.faceForStyle(font)
if tf == nil {
font.Typeface = ""
tf = s.faceForStyle(font)
}
if tf == nil {
panic("no default typeface defined")
}
return tf
}
func (t *face) layout(ppem fixed.Int26_6, str string, opts LayoutOptions) *Layout {
lk := layoutKey{
ppem: ppem,
str: str,
opts: opts,
}
if l, ok := t.layoutCache.Get(lk); ok {
return l
}
l := t.face.Layout(ppem, str, opts)
t.layoutCache.Put(lk, l)
return l
}
func (t *face) shape(ppem fixed.Int26_6, str String) paint.ClipOp {
pk := pathKey{
ppem: ppem,
str: str.String,
}
if clip, ok := t.pathCache.Get(pk); ok {
return clip
}
clip := t.face.Shape(ppem, str)
t.pathCache.Put(pk, clip)
return clip
}