fixed dependencies
This commit is contained in:
335
vendor/gonum.org/v1/plot/font/font.go
generated
vendored
Normal file
335
vendor/gonum.org/v1/plot/font/font.go
generated
vendored
Normal file
@@ -0,0 +1,335 @@
|
||||
// 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 (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/image/font"
|
||||
"golang.org/x/image/font/opentype"
|
||||
"golang.org/x/image/font/sfnt"
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
// DefaultCache is the global cache for fonts.
|
||||
var DefaultCache *Cache = NewCache(nil)
|
||||
|
||||
// Font represents a font face.
|
||||
type Font struct {
|
||||
// Typeface identifies the Font.
|
||||
Typeface Typeface
|
||||
|
||||
// TODO(sbinet): Gio@v0.2.0 has dropped font.Font.Variant
|
||||
// we should probably follow suit.
|
||||
|
||||
// Variant is the variant of a font, such as "Mono" or "Smallcaps".
|
||||
Variant Variant
|
||||
|
||||
// Style is the style of a font, such as Regular or Italic.
|
||||
Style font.Style
|
||||
|
||||
// Weight is the weight of a font, such as Normal or Bold.
|
||||
Weight font.Weight
|
||||
|
||||
// Size is the size of the font.
|
||||
Size Length
|
||||
}
|
||||
|
||||
// Name returns a fully qualified name for the given font.
|
||||
func (f *Font) Name() string {
|
||||
v := f.Variant
|
||||
w := weightName(f.Weight)
|
||||
s := styleName(f.Style)
|
||||
|
||||
switch f.Style {
|
||||
case font.StyleNormal:
|
||||
s = ""
|
||||
if f.Weight == font.WeightNormal {
|
||||
w = "Regular"
|
||||
}
|
||||
default:
|
||||
if f.Weight == font.WeightNormal {
|
||||
w = ""
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s%s-%s%s", f.Typeface, v, w, s)
|
||||
}
|
||||
|
||||
// From returns a copy of the provided font with its size set.
|
||||
func From(fnt Font, size Length) Font {
|
||||
o := fnt
|
||||
o.Size = size
|
||||
return o
|
||||
}
|
||||
|
||||
// Typeface identifies a particular typeface design.
|
||||
// The empty string denotes the default typeface.
|
||||
type Typeface string
|
||||
|
||||
// Variant denotes a typeface variant, such as "Mono", "Smallcaps" or "Math".
|
||||
type Variant string
|
||||
|
||||
// Extents contains font metric information.
|
||||
type Extents struct {
|
||||
// Ascent is the distance that the text
|
||||
// extends above the baseline.
|
||||
Ascent Length
|
||||
|
||||
// Descent is the distance that the text
|
||||
// extends below the baseline. The descent
|
||||
// is given as a positive value.
|
||||
Descent Length
|
||||
|
||||
// Height is the distance from the lowest
|
||||
// descending point to the highest ascending
|
||||
// point.
|
||||
Height Length
|
||||
}
|
||||
|
||||
// Face holds a font descriptor and the associated font face.
|
||||
type Face struct {
|
||||
Font Font
|
||||
Face *opentype.Font
|
||||
}
|
||||
|
||||
// Name returns a fully qualified name for the given font.
|
||||
func (f *Face) Name() string {
|
||||
return f.Font.Name()
|
||||
}
|
||||
|
||||
// FontFace returns the opentype font face for the requested
|
||||
// dots-per-inch resolution.
|
||||
func (f *Face) FontFace(dpi float64) font.Face {
|
||||
face, err := opentype.NewFace(f.Face, &opentype.FaceOptions{
|
||||
Size: f.Font.Size.Points(),
|
||||
DPI: dpi,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return face
|
||||
}
|
||||
|
||||
// default hinting for OpenType fonts
|
||||
const defaultHinting = font.HintingNone
|
||||
|
||||
// Extents returns the FontExtents for a font.
|
||||
func (f *Face) Extents() Extents {
|
||||
var (
|
||||
// TODO(sbinet): re-use a Font-level sfnt.Buffer instead?
|
||||
buf sfnt.Buffer
|
||||
ppem = fixed.Int26_6(f.Face.UnitsPerEm())
|
||||
)
|
||||
|
||||
met, err := f.Face.Metrics(&buf, ppem, defaultHinting)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("could not extract font extents: %v", err))
|
||||
}
|
||||
scale := f.Font.Size / Points(float64(ppem))
|
||||
return Extents{
|
||||
Ascent: Points(float64(met.Ascent)) * scale,
|
||||
Descent: Points(float64(met.Descent)) * scale,
|
||||
Height: Points(float64(met.Height)) * scale,
|
||||
}
|
||||
}
|
||||
|
||||
// Width returns width of a string when drawn using the font.
|
||||
func (f *Face) Width(s string) Length {
|
||||
var (
|
||||
pixelsPerEm = fixed.Int26_6(f.Face.UnitsPerEm())
|
||||
|
||||
// scale converts sfnt.Unit to float64
|
||||
scale = f.Font.Size / Points(float64(pixelsPerEm))
|
||||
|
||||
width = 0
|
||||
hasPrev = false
|
||||
buf sfnt.Buffer
|
||||
prev, idx sfnt.GlyphIndex
|
||||
hinting = defaultHinting
|
||||
)
|
||||
for _, rune := range s {
|
||||
var err error
|
||||
idx, err = f.Face.GlyphIndex(&buf, rune)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("could not get glyph index: %v", err))
|
||||
}
|
||||
if hasPrev {
|
||||
kern, err := f.Face.Kern(&buf, prev, idx, pixelsPerEm, hinting)
|
||||
switch {
|
||||
case err == nil:
|
||||
width += int(kern)
|
||||
case errors.Is(err, sfnt.ErrNotFound):
|
||||
// no-op
|
||||
default:
|
||||
panic(fmt.Errorf("could not get kerning: %v", err))
|
||||
}
|
||||
}
|
||||
adv, err := f.Face.GlyphAdvance(&buf, idx, pixelsPerEm, hinting)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("could not retrieve glyph's advance: %v", err))
|
||||
}
|
||||
width += int(adv)
|
||||
prev, hasPrev = idx, true
|
||||
}
|
||||
return Points(float64(width)) * scale
|
||||
}
|
||||
|
||||
// Collection is a collection of fonts, regrouped under a common typeface.
|
||||
type Collection []Face
|
||||
|
||||
// Cache collects font faces.
|
||||
type Cache struct {
|
||||
mu sync.RWMutex
|
||||
def Typeface
|
||||
faces map[Font]*opentype.Font
|
||||
}
|
||||
|
||||
// We make Cache implement dummy GobDecoder and GobEncoder interfaces
|
||||
// to allow plot.Plot (or any other type holding a Cache) to be (de)serialized
|
||||
// with encoding/gob.
|
||||
// As Cache holds opentype.Font, the reflect-based gob (de)serialization can not
|
||||
// work: gob isn't happy with opentype.Font having no exported field:
|
||||
//
|
||||
// error: gob: type font.Cache has no exported fields
|
||||
//
|
||||
// FIXME(sbinet): perhaps encode/decode Cache.def typeface?
|
||||
|
||||
func (c *Cache) GobEncode() ([]byte, error) { return nil, nil }
|
||||
func (c *Cache) GobDecode([]byte) error {
|
||||
if c.faces == nil {
|
||||
c.faces = make(map[Font]*opentype.Font)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewCache creates a new cache of fonts from the provided collection of
|
||||
// font Faces.
|
||||
// The first font Face in the collection is set to be the default one.
|
||||
func NewCache(coll Collection) *Cache {
|
||||
cache := &Cache{
|
||||
faces: make(map[Font]*opentype.Font, len(coll)),
|
||||
}
|
||||
cache.Add(coll)
|
||||
return cache
|
||||
}
|
||||
|
||||
// Add adds a whole collection of font Faces to the font cache.
|
||||
// If the cache is empty, the first font Face in the collection is set
|
||||
// to be the default one.
|
||||
func (c *Cache) Add(coll Collection) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
if c.faces == nil {
|
||||
c.faces = make(map[Font]*opentype.Font, len(coll))
|
||||
}
|
||||
for i, f := range coll {
|
||||
if i == 0 && c.def == "" {
|
||||
c.def = f.Font.Typeface
|
||||
}
|
||||
fnt := f.Font
|
||||
fnt.Size = 0 // store all font descriptors with the same size.
|
||||
c.faces[fnt] = f.Face
|
||||
}
|
||||
}
|
||||
|
||||
// Lookup returns the font Face corresponding to the provided Font descriptor,
|
||||
// with the provided font size set.
|
||||
//
|
||||
// If no matching font Face could be found, the one corresponding to
|
||||
// the default typeface is selected and returned.
|
||||
func (c *Cache) Lookup(fnt Font, size Length) Face {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
|
||||
if len(c.faces) == 0 {
|
||||
return Face{}
|
||||
}
|
||||
|
||||
face := c.lookup(fnt)
|
||||
if face == nil {
|
||||
fnt.Typeface = c.def
|
||||
face = c.lookup(fnt)
|
||||
}
|
||||
|
||||
ff := Face{
|
||||
Font: fnt,
|
||||
Face: face,
|
||||
}
|
||||
ff.Font.Size = size
|
||||
return ff
|
||||
}
|
||||
|
||||
// Has returns whether the cache contains the exact font descriptor.
|
||||
func (c *Cache) Has(fnt Font) bool {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
|
||||
face := c.lookup(fnt)
|
||||
return face != nil
|
||||
}
|
||||
|
||||
func (c *Cache) lookup(key Font) *opentype.Font {
|
||||
key.Size = 0
|
||||
|
||||
tf := c.faces[key]
|
||||
if tf == nil {
|
||||
key := key
|
||||
key.Weight = font.WeightNormal
|
||||
tf = c.faces[key]
|
||||
}
|
||||
if tf == nil {
|
||||
key := key
|
||||
key.Style = font.StyleNormal
|
||||
tf = c.faces[key]
|
||||
}
|
||||
if tf == nil {
|
||||
key := key
|
||||
key.Style = font.StyleNormal
|
||||
key.Weight = font.WeightNormal
|
||||
tf = c.faces[key]
|
||||
}
|
||||
|
||||
return tf
|
||||
}
|
||||
|
||||
func weightName(w font.Weight) string {
|
||||
switch w {
|
||||
case font.WeightThin:
|
||||
return "Thin"
|
||||
case font.WeightExtraLight:
|
||||
return "ExtraLight"
|
||||
case font.WeightLight:
|
||||
return "Light"
|
||||
case font.WeightNormal:
|
||||
return "Regular"
|
||||
case font.WeightMedium:
|
||||
return "Medium"
|
||||
case font.WeightSemiBold:
|
||||
return "SemiBold"
|
||||
case font.WeightBold:
|
||||
return "Bold"
|
||||
case font.WeightExtraBold:
|
||||
return "ExtraBold"
|
||||
case font.WeightBlack:
|
||||
return "Black"
|
||||
}
|
||||
return fmt.Sprintf("weight(%d)", w)
|
||||
}
|
||||
|
||||
func styleName(sty font.Style) string {
|
||||
switch sty {
|
||||
case font.StyleNormal:
|
||||
return "Normal"
|
||||
case font.StyleItalic:
|
||||
return "Italic"
|
||||
case font.StyleOblique:
|
||||
return "Oblique"
|
||||
}
|
||||
return fmt.Sprintf("style(%d)", sty)
|
||||
}
|
||||
Reference in New Issue
Block a user