/
buildfont.go
137 lines (126 loc) · 2.77 KB
/
buildfont.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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package draw
import (
"fmt"
"strconv"
"unicode"
)
func skip(b []byte) []byte {
for len(b) > 0 && (b[0] == ' ' || b[0] == '\t' || b[0] == '\n') {
b = b[1:]
}
return b
}
func strtol(b []byte) (int, []byte) {
b = skip(b)
i := 0
if len(b) == 0 || b[0] < '0' || '9' < b[0] {
return 0, b
}
for i < len(b) && '0' <= b[i] && b[i] <= '9' || 'A' <= b[i] && b[i] <= 'Z' || 'a' <= b[i] && b[i] <= 'z' {
i++
}
n, _ := strconv.ParseInt(string(b[:i]), 0, 0)
return int(n), skip(b[i:])
}
// BuildFont builds a font of the given name using the description
// provided by the buffer, typically the contents of a font file.
func (d *Display) BuildFont(buf []byte, name string) (*Font, error) {
d.mu.Lock()
defer d.mu.Unlock()
return d.buildFont(buf, name)
}
func (d *Display) buildFont(buf []byte, name string) (*Font, error) {
fnt := &Font{
Display: d,
Scale: 1,
Name: name,
cache: make([]cacheinfo, _NFCACHE+_NFLOOK),
subf: make([]cachesubf, _NFSUBF),
age: 1,
}
s := buf
fnt.Height, s = strtol(s)
fnt.Ascent, s = strtol(s)
if fnt.Height <= 0 || fnt.Ascent <= 0 {
return nil, fmt.Errorf("bad height or ascent in font file")
}
for {
if len(s) == 0 || s[0] < '0' || '9' < s[0] {
goto Errbad
}
var min, max int
min, s = strtol(s)
if len(s) == 0 || s[0] < '0' || '9' < s[0] {
goto Errbad
}
max, s = strtol(s)
if len(s) == 0 || min > unicode.MaxRune || max > unicode.MaxRune || min > max {
return nil, fmt.Errorf("illegal subfont range")
}
offset, t := strtol(s)
if len(t) < len(s) {
s = t
}
c := &cachefont{
min: rune(min),
max: rune(max),
offset: offset,
}
t = s
for len(s) > 0 && s[0] != ' ' && s[0] != '\n' && s[0] != '\t' {
s = s[1:]
}
c.name = string(t[:len(t)-len(s)])
fnt.sub = append(fnt.sub, c)
s = skip(s)
if len(s) == 0 {
break
}
}
return fnt, nil
Errbad:
return nil, fmt.Errorf("bad font format: number expected (char position %d)", len(buf)-len(s))
}
// Free frees the server resources for the Font. Fonts have a finalizer that
// calls Free automatically, if necessary, for garbage collected Images, but it
// is more efficient to be explicit.
// TODO: Implement the Finalizer!
func (f *Font) Free() {
if f == nil {
return
}
f.lock()
defer f.unlock()
if f.ondisplaylist {
f.ondisplaylist = false
if f.next != nil {
f.next.prev = f.prev
} else {
f.Display.lastfont = f.prev
}
if f.prev != nil {
f.prev.next = f.next
} else {
f.Display.firstfont = f.next
}
}
if f.lodpi != f {
f.lodpi.Free()
}
if f.hidpi != f {
f.hidpi.Free()
}
f.free()
}
func (f *Font) free() {
if f == nil {
return
}
for _, subf := range f.subf {
s := subf.f
if s != nil && (f.Display == nil || s != f.Display.defaultSubfont) {
s.free()
}
}
f.cacheimage.free()
}