-
Notifications
You must be signed in to change notification settings - Fork 0
/
face.go
116 lines (102 loc) · 3.09 KB
/
face.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package unifont
import (
"errors"
"image"
"slices"
"golang.org/x/image/font"
"golang.org/x/image/math/fixed"
)
type face struct {
u *Unifont
m int
}
// Helper function for finding the glyph structure for a supplied rune. If the glyph is not found,
// the function returns false and the placeholder glyph (codepoint U+FFDF) if available. This is to
// match the expected behavior of the Glyph/GlyphBounds/GlyphAdvance interface functions.
func (f *Unifont) findGlyph(r rune) (*glyph, bool) {
if r < 0 {
return f.placeholder, false
}
// in the continuous range, can do a direct slice offset lookup
if r <= f.lastContinuous {
return &f.glyphs[r], true
}
// outside the continuous range, do a binary search of the remaining glyphs
i, ok := slices.BinarySearchFunc(f.glyphs[f.lastContinuous:], r, func(g glyph, r rune) int { return int(g.r - r) })
if !ok {
return f.placeholder, false
}
return &f.glyphs[int(f.lastContinuous)+i], true
}
func (f *face) Close() error {
// Because we read the entire font into memory, this is a no-op.
return nil
}
func (f *face) Glyph(dot fixed.Point26_6, r rune) (dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) {
g, ok := f.u.findGlyph(r)
// because we generate the glyph images at runtime
if g != nil {
yOffset := -unifontHeight * f.m
x, y := dot.X.Round(), dot.Y.Round()
if g.combining <= 0 {
// combining character, offset the draw
x += int(g.combining) * f.m
} else {
// non-combining character, advance dot
advance = fixed.I(int(g.width) * f.m)
}
dr = image.Rect(x, y+yOffset, x+int(g.width)*f.m, y+unifontHeight*f.m+yOffset)
mask = f.u.glyphImage(g, f.m)
maskp = image.Point{}
}
return
}
func (f *face) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) {
g, ok := f.u.findGlyph(r)
if g != nil {
xOffset := 0
yOffset := -unifontHeight * f.m
if g.combining <= 0 {
// combining character, offset the bounding box
xOffset = int(g.combining) * f.m
} else {
// non-combining character, advance dot
advance = fixed.I(int(g.width) * f.m)
}
bounds = fixed.R(xOffset, yOffset, int(g.width)*f.m+xOffset, unifontHeight*f.m+yOffset)
}
return
}
func (f *face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) {
g, ok := f.u.findGlyph(r)
if g != nil {
if g.combining > 0 {
advance = fixed.I(int(g.width) * f.m)
}
}
return
}
func (f *face) Kern(r0, r1 rune) fixed.Int26_6 {
return 0
}
func (f *face) Metrics() font.Metrics {
return font.Metrics{
Height: fixed.I(unifontHeight * f.m),
Ascent: fixed.I(unifontHeight * f.m),
Descent: 0,
XHeight: fixed.I(unifontHeight * f.m),
CapHeight: fixed.I(unifontHeight * f.m),
CaretSlope: image.Pt(0, 1),
}
}
// NewFace returns a new font.Face for the given Unifont. The multiplier parameter defines the
// output size of the font face. 1 means the default 16px height, 2 means 32px height, and so on.
func NewFace(u *Unifont, multipler int) (font.Face, error) {
if multipler <= 0 {
return nil, errors.New("multipler must be positive")
}
return &face{
u: u,
m: multipler,
}, nil
}