[text, font] Bump go-text version to 0.2.1

Signed-off-by: Benoit KUGLER <benoit.kugler@gmail.com>
This commit is contained in:
Benoit KUGLER
2024-12-16 16:43:41 +01:00
committed by Chris Waldon
parent 1d95c7c6b3
commit 0cbbacc45a
5 changed files with 68 additions and 71 deletions
+1 -1
View File
@@ -34,7 +34,7 @@ type Font struct {
// Face is an opaque handle to a typeface. The concrete implementation depends // Face is an opaque handle to a typeface. The concrete implementation depends
// upon the kind of font and shaper in use. // upon the kind of font and shaper in use.
type Face interface { type Face interface {
Face() font.Face Face() *font.Face
} }
// Typeface identifies a list of font families to attempt to use for displaying // Typeface identifies a list of font families to attempt to use for displaying
+41 -43
View File
@@ -16,23 +16,21 @@ import (
_ "image/png" _ "image/png"
giofont "gioui.org/font" giofont "gioui.org/font"
"github.com/go-text/typesetting/font" fontapi "github.com/go-text/typesetting/font"
fontapi "github.com/go-text/typesetting/opentype/api/font" "github.com/go-text/typesetting/font/opentype"
"github.com/go-text/typesetting/opentype/api/metadata"
"github.com/go-text/typesetting/opentype/loader"
) )
// Face is a thread-safe representation of a loaded font. For efficiency, applications // Face is a thread-safe representation of a loaded font. For efficiency, applications
// should construct a face for any given font file once, reusing it across different // should construct a face for any given font file once, reusing it across different
// text shapers. // text shapers.
type Face struct { type Face struct {
face font.Font face *fontapi.Font
font giofont.Font font giofont.Font
} }
// Parse constructs a Face from source bytes. // Parse constructs a Face from source bytes.
func Parse(src []byte) (Face, error) { func Parse(src []byte) (Face, error) {
ld, err := loader.NewLoader(bytes.NewReader(src)) ld, err := opentype.NewLoader(bytes.NewReader(src))
if err != nil { if err != nil {
return Face{}, err return Face{}, err
} }
@@ -49,11 +47,11 @@ func Parse(src []byte) (Face, error) {
// ParseCollection parse an Opentype font file, with support for collections. // ParseCollection parse an Opentype font file, with support for collections.
// Single font files are supported, returning a slice with length 1. // Single font files are supported, returning a slice with length 1.
// The returned fonts are automatically wrapped in a text.FontFace with // The returned fonts are automatically wrapped in a text.FontFace with
// inferred font metadata. // inferred font font.
// BUG(whereswaldon): the only Variant that can be detected automatically is // BUG(whereswaldon): the only Variant that can be detected automatically is
// "Mono". // "Mono".
func ParseCollection(src []byte) ([]giofont.FontFace, error) { func ParseCollection(src []byte) ([]giofont.FontFace, error) {
lds, err := loader.NewLoaders(bytes.NewReader(src)) lds, err := opentype.NewLoaders(bytes.NewReader(src))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -76,7 +74,7 @@ func ParseCollection(src []byte) ([]giofont.FontFace, error) {
return out, nil return out, nil
} }
func DescriptionToFont(md metadata.Description) giofont.Font { func DescriptionToFont(md fontapi.Description) giofont.Font {
return giofont.Font{ return giofont.Font{
Typeface: giofont.Typeface(md.Family), Typeface: giofont.Typeface(md.Family),
Style: gioStyle(md.Aspect.Style), Style: gioStyle(md.Aspect.Style),
@@ -84,30 +82,30 @@ func DescriptionToFont(md metadata.Description) giofont.Font {
} }
} }
func FontToDescription(font giofont.Font) metadata.Description { func FontToDescription(font giofont.Font) fontapi.Description {
return metadata.Description{ return fontapi.Description{
Family: string(font.Typeface), Family: string(font.Typeface),
Aspect: metadata.Aspect{ Aspect: fontapi.Aspect{
Style: mdStyle(font.Style), Style: mdStyle(font.Style),
Weight: mdWeight(font.Weight), Weight: mdWeight(font.Weight),
}, },
} }
} }
// parseLoader parses the contents of the loader into a face and its metadata. // parseLoader parses the contents of the loader into a face and its font.
func parseLoader(ld *loader.Loader) (font.Font, giofont.Font, error) { func parseLoader(ld *opentype.Loader) (*fontapi.Font, giofont.Font, error) {
ft, err := fontapi.NewFont(ld) ft, err := fontapi.NewFont(ld)
if err != nil { if err != nil {
return nil, giofont.Font{}, err return nil, giofont.Font{}, err
} }
data := DescriptionToFont(metadata.Metadata(ld)) data := DescriptionToFont(ft.Describe())
return ft, data, nil return ft, data, nil
} }
// Face returns a thread-unsafe wrapper for this Face suitable for use by a single shaper. // Face returns a thread-unsafe wrapper for this Face suitable for use by a single shaper.
// Face many be invoked any number of times and is safe so long as each return value is // Face many be invoked any number of times and is safe so long as each return value is
// only used by one goroutine. // only used by one goroutine.
func (f Face) Face() font.Face { func (f Face) Face() *fontapi.Face {
return &fontapi.Face{Font: f.face} return &fontapi.Face{Font: f.face}
} }
@@ -119,74 +117,74 @@ func (f Face) Font() giofont.Font {
return f.font return f.font
} }
func gioStyle(s metadata.Style) giofont.Style { func gioStyle(s fontapi.Style) giofont.Style {
switch s { switch s {
case metadata.StyleItalic: case fontapi.StyleItalic:
return giofont.Italic return giofont.Italic
case metadata.StyleNormal: case fontapi.StyleNormal:
fallthrough fallthrough
default: default:
return giofont.Regular return giofont.Regular
} }
} }
func mdStyle(g giofont.Style) metadata.Style { func mdStyle(g giofont.Style) fontapi.Style {
switch g { switch g {
case giofont.Italic: case giofont.Italic:
return metadata.StyleItalic return fontapi.StyleItalic
case giofont.Regular: case giofont.Regular:
fallthrough fallthrough
default: default:
return metadata.StyleNormal return fontapi.StyleNormal
} }
} }
func gioWeight(w metadata.Weight) giofont.Weight { func gioWeight(w fontapi.Weight) giofont.Weight {
switch w { switch w {
case metadata.WeightThin: case fontapi.WeightThin:
return giofont.Thin return giofont.Thin
case metadata.WeightExtraLight: case fontapi.WeightExtraLight:
return giofont.ExtraLight return giofont.ExtraLight
case metadata.WeightLight: case fontapi.WeightLight:
return giofont.Light return giofont.Light
case metadata.WeightNormal: case fontapi.WeightNormal:
return giofont.Normal return giofont.Normal
case metadata.WeightMedium: case fontapi.WeightMedium:
return giofont.Medium return giofont.Medium
case metadata.WeightSemibold: case fontapi.WeightSemibold:
return giofont.SemiBold return giofont.SemiBold
case metadata.WeightBold: case fontapi.WeightBold:
return giofont.Bold return giofont.Bold
case metadata.WeightExtraBold: case fontapi.WeightExtraBold:
return giofont.ExtraBold return giofont.ExtraBold
case metadata.WeightBlack: case fontapi.WeightBlack:
return giofont.Black return giofont.Black
default: default:
return giofont.Normal return giofont.Normal
} }
} }
func mdWeight(g giofont.Weight) metadata.Weight { func mdWeight(g giofont.Weight) fontapi.Weight {
switch g { switch g {
case giofont.Thin: case giofont.Thin:
return metadata.WeightThin return fontapi.WeightThin
case giofont.ExtraLight: case giofont.ExtraLight:
return metadata.WeightExtraLight return fontapi.WeightExtraLight
case giofont.Light: case giofont.Light:
return metadata.WeightLight return fontapi.WeightLight
case giofont.Normal: case giofont.Normal:
return metadata.WeightNormal return fontapi.WeightNormal
case giofont.Medium: case giofont.Medium:
return metadata.WeightMedium return fontapi.WeightMedium
case giofont.SemiBold: case giofont.SemiBold:
return metadata.WeightSemibold return fontapi.WeightSemibold
case giofont.Bold: case giofont.Bold:
return metadata.WeightBold return fontapi.WeightBold
case giofont.ExtraBold: case giofont.ExtraBold:
return metadata.WeightExtraBold return fontapi.WeightExtraBold
case giofont.Black: case giofont.Black:
return metadata.WeightBlack return fontapi.WeightBlack
default: default:
return metadata.WeightNormal return fontapi.WeightNormal
} }
} }
+1 -1
View File
@@ -5,7 +5,7 @@ go 1.21
require ( require (
eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d
gioui.org/shader v1.0.8 gioui.org/shader v1.0.8
github.com/go-text/typesetting v0.1.2 github.com/go-text/typesetting v0.2.1
golang.org/x/exp v0.0.0-20240707233637-46b078467d37 golang.org/x/exp v0.0.0-20240707233637-46b078467d37
golang.org/x/exp/shiny v0.0.0-20240707233637-46b078467d37 golang.org/x/exp/shiny v0.0.0-20240707233637-46b078467d37
golang.org/x/image v0.18.0 golang.org/x/image v0.18.0
+4 -4
View File
@@ -3,10 +3,10 @@ eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d/go.mod h1:OYVuxibdk9OSLX8v
gioui.org/cpu v0.0.0-20210808092351-bfe733dd3334/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ= gioui.org/cpu v0.0.0-20210808092351-bfe733dd3334/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
gioui.org/shader v1.0.8 h1:6ks0o/A+b0ne7RzEqRZK5f4Gboz2CfG+mVliciy6+qA= gioui.org/shader v1.0.8 h1:6ks0o/A+b0ne7RzEqRZK5f4Gboz2CfG+mVliciy6+qA=
gioui.org/shader v1.0.8/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM= gioui.org/shader v1.0.8/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM=
github.com/go-text/typesetting v0.1.2 h1:KmZOfoxrrYgghohzXgNY7aQPgQ4W+QeKPeRI8yqpDDE= github.com/go-text/typesetting v0.2.1 h1:x0jMOGyO3d1qFAPI0j4GSsh7M0Q3Ypjzr4+CEVg82V8=
github.com/go-text/typesetting v0.1.2/go.mod h1:2+owI/sxa73XA581LAzVuEBZ3WEEV2pXeDswCH/3i1I= github.com/go-text/typesetting v0.2.1/go.mod h1:mTOxEwasOFpAMBjEQDhdWRckoLLeI/+qrQeBCTGEt6M=
github.com/go-text/typesetting-utils v0.0.0-20240317173224-1986cbe96c66 h1:GUrm65PQPlhFSKjLPGOZNPNxLCybjzjYBzjfoBGaDUY= github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066 h1:qCuYC+94v2xrb1PoS4NIDe7DGYtLnU2wWiQe9a1B1c0=
github.com/go-text/typesetting-utils v0.0.0-20240317173224-1986cbe96c66/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o= github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o=
golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w= golang.org/x/exp v0.0.0-20240707233637-46b078467d37 h1:uLDX+AfeFCct3a2C7uIWBKMJIR3CJMhcgfrUAqjRK6w=
golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/exp v0.0.0-20240707233637-46b078467d37/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/exp/shiny v0.0.0-20240707233637-46b078467d37 h1:SOSg7+sueresE4IbmmGM60GmlIys+zNX63d6/J4CMtU= golang.org/x/exp/shiny v0.0.0-20240707233637-46b078467d37 h1:SOSg7+sueresE4IbmmGM60GmlIys+zNX63d6/J4CMtU=
+21 -22
View File
@@ -12,10 +12,9 @@ import (
"github.com/go-text/typesetting/di" "github.com/go-text/typesetting/di"
"github.com/go-text/typesetting/font" "github.com/go-text/typesetting/font"
gotextot "github.com/go-text/typesetting/font/opentype"
"github.com/go-text/typesetting/fontscan" "github.com/go-text/typesetting/fontscan"
"github.com/go-text/typesetting/language" "github.com/go-text/typesetting/language"
"github.com/go-text/typesetting/opentype/api"
"github.com/go-text/typesetting/opentype/api/metadata"
"github.com/go-text/typesetting/shaping" "github.com/go-text/typesetting/shaping"
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
"golang.org/x/image/math/fixed" "golang.org/x/image/math/fixed"
@@ -201,7 +200,7 @@ type runLayout struct {
// Direction is the layout direction of the glyphs. // Direction is the layout direction of the glyphs.
Direction system.TextDirection Direction system.TextDirection
// face is the font face that the ID of each Glyph in the Layout refers to. // face is the font face that the ID of each Glyph in the Layout refers to.
face font.Face face *font.Face
// truncator indicates that this run is a text truncator standing in for remaining // truncator indicates that this run is a text truncator standing in for remaining
// text. // text.
truncator bool truncator bool
@@ -211,8 +210,8 @@ type runLayout struct {
type shaperImpl struct { type shaperImpl struct {
// Fields for tracking fonts/faces. // Fields for tracking fonts/faces.
fontMap *fontscan.FontMap fontMap *fontscan.FontMap
faces []font.Face faces []*font.Face
faceToIndex map[font.Font]int faceToIndex map[*font.Font]int
faceMeta []giofont.Font faceMeta []giofont.Font
defaultFaces []string defaultFaces []string
logger interface { logger interface {
@@ -254,7 +253,7 @@ func newShaperImpl(systemFonts bool, collection []FontFace) *shaperImpl {
var shaper shaperImpl var shaper shaperImpl
shaper.logger = newDebugLogger() shaper.logger = newDebugLogger()
shaper.fontMap = fontscan.NewFontMap(shaper.logger) shaper.fontMap = fontscan.NewFontMap(shaper.logger)
shaper.faceToIndex = make(map[font.Font]int) shaper.faceToIndex = make(map[*font.Font]int)
if systemFonts { if systemFonts {
str, err := os.UserCacheDir() str, err := os.UserCacheDir()
if err != nil { if err != nil {
@@ -282,7 +281,7 @@ func (s *shaperImpl) Load(f FontFace) {
s.addFace(f.Face.Face(), f.Font) s.addFace(f.Face.Face(), f.Font)
} }
func (s *shaperImpl) addFace(f font.Face, md giofont.Font) { func (s *shaperImpl) addFace(f *font.Face, md giofont.Font) {
if _, ok := s.faceToIndex[f.Font]; ok { if _, ok := s.faceToIndex[f.Font]; ok {
return return
} }
@@ -377,11 +376,11 @@ func (s *shaperImpl) splitBidi(input shaping.Input) []shaping.Input {
// ResolveFace allows shaperImpl to implement shaping.FontMap, wrapping its fontMap // ResolveFace allows shaperImpl to implement shaping.FontMap, wrapping its fontMap
// field and ensuring that any faces loaded as part of the search are registered with // field and ensuring that any faces loaded as part of the search are registered with
// ids so that they can be referred to by a GlyphID. // ids so that they can be referred to by a GlyphID.
func (s *shaperImpl) ResolveFace(r rune) font.Face { func (s *shaperImpl) ResolveFace(r rune) *font.Face {
face := s.fontMap.ResolveFace(r) face := s.fontMap.ResolveFace(r)
if face != nil { if face != nil {
family, aspect := s.fontMap.FontMetadata(face.Font) family, aspect := s.fontMap.FontMetadata(face.Font)
md := opentype.DescriptionToFont(metadata.Description{ md := opentype.DescriptionToFont(font.Description{
Family: family, Family: family,
Aspect: aspect, Aspect: aspect,
}) })
@@ -663,7 +662,7 @@ func (s *shaperImpl) Shape(pathOps *op.Ops, gs []Glyph) clip.PathSpec {
scaleFactor := fixedToFloat(ppem) / float32(face.Upem()) scaleFactor := fixedToFloat(ppem) / float32(face.Upem())
glyphData := face.GlyphData(gid) glyphData := face.GlyphData(gid)
switch glyphData := glyphData.(type) { switch glyphData := glyphData.(type) {
case api.GlyphOutline: case font.GlyphOutline:
outline := glyphData outline := glyphData
// Move to glyph position. // Move to glyph position.
pos := f32.Point{ pos := f32.Point{
@@ -678,9 +677,9 @@ func (s *shaperImpl) Shape(pathOps *op.Ops, gs []Glyph) clip.PathSpec {
for _, fseg := range outline.Segments { for _, fseg := range outline.Segments {
nargs := 1 nargs := 1
switch fseg.Op { switch fseg.Op {
case api.SegmentOpQuadTo: case gotextot.SegmentOpQuadTo:
nargs = 2 nargs = 2
case api.SegmentOpCubeTo: case gotextot.SegmentOpCubeTo:
nargs = 3 nargs = 3
} }
var args [3]f32.Point var args [3]f32.Point
@@ -695,13 +694,13 @@ func (s *shaperImpl) Shape(pathOps *op.Ops, gs []Glyph) clip.PathSpec {
} }
} }
switch fseg.Op { switch fseg.Op {
case api.SegmentOpMoveTo: case gotextot.SegmentOpMoveTo:
builder.Move(args[0]) builder.Move(args[0])
case api.SegmentOpLineTo: case gotextot.SegmentOpLineTo:
builder.Line(args[0]) builder.Line(args[0])
case api.SegmentOpQuadTo: case gotextot.SegmentOpQuadTo:
builder.Quad(args[0], args[1]) builder.Quad(args[0], args[1])
case api.SegmentOpCubeTo: case gotextot.SegmentOpCubeTo:
builder.Cube(args[0], args[1], args[2]) builder.Cube(args[0], args[1], args[2])
default: default:
panic("unsupported segment op") panic("unsupported segment op")
@@ -742,16 +741,16 @@ func (s *shaperImpl) Bitmaps(ops *op.Ops, gs []Glyph) op.CallOp {
} }
glyphData := face.GlyphData(gid) glyphData := face.GlyphData(gid)
switch glyphData := glyphData.(type) { switch glyphData := glyphData.(type) {
case api.GlyphBitmap: case font.GlyphBitmap:
var imgOp paint.ImageOp var imgOp paint.ImageOp
var imgSize image.Point var imgSize image.Point
bitmapData, ok := s.bitmapGlyphCache.Get(g.ID) bitmapData, ok := s.bitmapGlyphCache.Get(g.ID)
if !ok { if !ok {
var img image.Image var img image.Image
switch glyphData.Format { switch glyphData.Format {
case api.PNG, api.JPG, api.TIFF: case font.PNG, font.JPG, font.TIFF:
img, _, _ = image.Decode(bytes.NewReader(glyphData.Data)) img, _, _ = image.Decode(bytes.NewReader(glyphData.Data))
case api.BlackAndWhite: case font.BlackAndWhite:
// This is a complex family of uncompressed bitmaps that don't seem to be // This is a complex family of uncompressed bitmaps that don't seem to be
// very common in practice. We can try adding support later if needed. // very common in practice. We can try adding support later if needed.
fallthrough fallthrough
@@ -807,7 +806,7 @@ type langConfig struct {
} }
// toInput converts its parameters into a shaping.Input. // toInput converts its parameters into a shaping.Input.
func toInput(face font.Face, ppem fixed.Int26_6, lc langConfig, runes []rune) shaping.Input { func toInput(face *font.Face, ppem fixed.Int26_6, lc langConfig, runes []rune) shaping.Input {
var input shaping.Input var input shaping.Input
input.Direction = lc.Direction input.Direction = lc.Direction
input.Text = runes input.Text = runes
@@ -867,7 +866,7 @@ func toGioGlyphs(in []shaping.Glyph, ppem fixed.Int26_6, faceIdx int) []glyph {
} }
// toLine converts the output into a Line with the provided dominant text direction. // toLine converts the output into a Line with the provided dominant text direction.
func toLine(faceToIndex map[font.Font]int, o shaping.Line, dir system.TextDirection) line { func toLine(faceToIndex map[*font.Font]int, o shaping.Line, dir system.TextDirection) line {
if len(o) < 1 { if len(o) < 1 {
return line{} return line{}
} }
@@ -881,7 +880,7 @@ func toLine(faceToIndex map[font.Font]int, o shaping.Line, dir system.TextDirect
if run.Size > maxSize { if run.Size > maxSize {
maxSize = run.Size maxSize = run.Size
} }
var font font.Font var font *font.Font
if run.Face != nil { if run.Face != nil {
font = run.Face.Font font = run.Face.Font
} }