Skip to content

Commit

Permalink
font: introduce Cache.AddFrom convenience method
Browse files Browse the repository at this point in the history
Update gonum#702.
  • Loading branch information
sbinet committed Sep 27, 2021
1 parent 08671db commit cf01b00
Show file tree
Hide file tree
Showing 2 changed files with 226 additions and 0 deletions.
147 changes: 147 additions & 0 deletions font/face_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// Copyright ©2021 The Gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package font

import (
"testing"

"github.com/go-fonts/latin-modern/lmmono10italic"
"github.com/go-fonts/liberation/liberationmonobold"
"github.com/go-fonts/liberation/liberationmonobolditalic"
"github.com/go-fonts/liberation/liberationmonoitalic"
"github.com/go-fonts/liberation/liberationmonoregular"
"github.com/go-fonts/liberation/liberationsansbold"
"github.com/go-fonts/liberation/liberationsansbolditalic"
"github.com/go-fonts/liberation/liberationsansitalic"
"github.com/go-fonts/liberation/liberationsansregular"
"github.com/go-fonts/liberation/liberationserifbold"
"github.com/go-fonts/liberation/liberationserifbolditalic"
"github.com/go-fonts/liberation/liberationserifitalic"
"github.com/go-fonts/liberation/liberationserifregular"
xfnt "golang.org/x/image/font"
)

func TestFaceFrom(t *testing.T) {
for _, tc := range []struct {
raw []byte
want Font
}{
{
raw: lmmono10italic.TTF,
want: Font{
Typeface: "Latin Modern Mono",
Style: xfnt.StyleItalic,
Weight: xfnt.WeightNormal,
},
},
{
raw: liberationmonobold.TTF,
want: Font{
Typeface: "Liberation Mono",
Style: xfnt.StyleNormal,
Weight: xfnt.WeightBold,
},
},
{
raw: liberationmonobolditalic.TTF,
want: Font{
Typeface: "Liberation Mono",
Style: xfnt.StyleItalic,
Weight: xfnt.WeightBold,
},
},
{
raw: liberationmonoitalic.TTF,
want: Font{
Typeface: "Liberation Mono",
Style: xfnt.StyleItalic,
Weight: xfnt.WeightNormal,
},
},
{
raw: liberationmonoregular.TTF,
want: Font{
Typeface: "Liberation Mono",
Style: xfnt.StyleNormal,
Weight: xfnt.WeightNormal,
},
},
{
raw: liberationsansbold.TTF,
want: Font{
Typeface: "Liberation Sans",
Style: xfnt.StyleNormal,
Weight: xfnt.WeightBold,
},
},
{
raw: liberationsansbolditalic.TTF,
want: Font{
Typeface: "Liberation Sans",
Style: xfnt.StyleItalic,
Weight: xfnt.WeightBold,
},
},
{
raw: liberationsansitalic.TTF,
want: Font{
Typeface: "Liberation Sans",
Style: xfnt.StyleItalic,
Weight: xfnt.WeightNormal,
},
},
{
raw: liberationsansregular.TTF,
want: Font{
Typeface: "Liberation Sans",
Style: xfnt.StyleNormal,
Weight: xfnt.WeightNormal,
},
},
{
raw: liberationserifbold.TTF,
want: Font{
Typeface: "Liberation Serif",
Style: xfnt.StyleNormal,
Weight: xfnt.WeightBold,
},
},
{
raw: liberationserifbolditalic.TTF,
want: Font{
Typeface: "Liberation Serif",
Style: xfnt.StyleItalic,
Weight: xfnt.WeightBold,
},
},
{
raw: liberationserifitalic.TTF,
want: Font{
Typeface: "Liberation Serif",
Style: xfnt.StyleItalic,
Weight: xfnt.WeightNormal,
},
},
{
raw: liberationserifregular.TTF,
want: Font{
Typeface: "Liberation Serif",
Style: xfnt.StyleNormal,
Weight: xfnt.WeightNormal,
},
},
} {
face, err := faceFrom(tc.raw)
if err != nil {
t.Errorf("could not create Face: %+v", err)
continue
}
got := face.Font
if got != tc.want {
t.Errorf("invalid font face:\ngot= %+v\nwant=%+v", got, tc.want)
continue
}
}
}
79 changes: 79 additions & 0 deletions font/font.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package font
import (
"errors"
"fmt"
"strings"
"sync"

"golang.org/x/image/font"
Expand Down Expand Up @@ -94,6 +95,34 @@ type Face struct {
Face *opentype.Font
}

func faceFrom(raw []byte) (Face, error) {
var face Face
otf, err := opentype.Parse(raw)
if err != nil {
return face, fmt.Errorf("font: could not parse font data: %w", err)
}

var buf sfnt.Buffer
name, err := otf.Name(&buf, sfnt.NameIDFamily)
if err != nil {
return face, fmt.Errorf("font: could not retrieve font name: %w", err)
}

full, err := otf.Name(&buf, sfnt.NameIDFull)
if err != nil {
return face, fmt.Errorf("font: could not retrieve font fullname: %w", err)
}

face.Font = Font{
Typeface: Typeface(name),
Style: styleFrom(full),
Weight: weightFrom(full),
}
face.Face = otf

return face, nil
}

// Name returns a fully qualified name for the given font.
func (f *Face) Name() string {
return f.Font.Name()
Expand Down Expand Up @@ -235,6 +264,17 @@ func (c *Cache) Add(coll Collection) {
}
}

// AddFrom adds a font to the font cache.
func (c *Cache) AddFrom(raw []byte) error {
face, err := faceFrom(raw)
if err != nil {
return fmt.Errorf("font: could not load font/face: %w", err)
}
c.Add(Collection([]Face{face}))

return nil
}

// Lookup returns the font Face corresponding to the provided Font descriptor,
// with the provided font size set.
//
Expand Down Expand Up @@ -319,6 +359,33 @@ func weightName(w font.Weight) string {
return fmt.Sprintf("weight(%d)", w)
}

func weightFrom(v string) font.Weight {
v = strings.ToLower(v)
switch {
case strings.Contains(v, "thin"):
return font.WeightThin
case strings.Contains(v, "extralight"):
return font.WeightExtraLight
case strings.Contains(v, "light"):
return font.WeightLight
case strings.Contains(v, "regular"):
return font.WeightNormal
case strings.Contains(v, "medium"):
return font.WeightMedium
case strings.Contains(v, "extrabold"):
return font.WeightExtraBold
case strings.Contains(v, "semibold"):
return font.WeightSemiBold
case strings.Contains(v, "bold"):
return font.WeightBold
case strings.Contains(v, "black"):
return font.WeightBlack

default:
return font.WeightNormal
}
}

func styleName(sty font.Style) string {
switch sty {
case font.StyleNormal:
Expand All @@ -330,3 +397,15 @@ func styleName(sty font.Style) string {
}
return fmt.Sprintf("style(%d)", sty)
}

func styleFrom(v string) font.Style {
v = strings.ToLower(v)
switch {
case strings.Contains(v, "italic"):
return font.StyleItalic
case strings.Contains(v, "oblique"):
return font.StyleOblique
default:
return font.StyleNormal
}
}

0 comments on commit cf01b00

Please sign in to comment.