-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathtable_feat.go
146 lines (126 loc) · 3.13 KB
/
table_feat.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
138
139
140
141
142
143
144
145
146
package graphite
import (
"errors"
"fmt"
"sort"
"github.com/benoitkugler/textlayout/fonts/binaryreader"
"github.com/benoitkugler/textlayout/fonts/truetype"
)
// FeatureValue specifies a value for a given feature.
type FeatureValue struct {
ID Tag // ID of the feature
Value int16 // Value to use
}
// FeaturesValue are sorted by Id
type FeaturesValue []FeatureValue
// FindFeature return the feature for the given tag, or nil.
func (feats FeaturesValue) FindFeature(id Tag) *FeatureValue {
// binary search
for i, j := 0, len(feats); i < j; {
h := i + (j-i)/2
entry := &feats[h]
if id < entry.ID {
j = h
} else if entry.ID < id {
i = h + 1
} else {
return entry
}
}
return nil
}
// features are NOT sorted; they are accessed by (slice) index
// from the opcodes
type tableFeat []feature
type feature struct {
settings []featureSetting
id Tag
flags uint16
label truetype.NameID
}
type featureSetting struct {
Value int16
Label truetype.NameID
}
// return the feature with their first setting selected (or 0)
func (tf tableFeat) defaultFeatures() FeaturesValue {
out := make(FeaturesValue, len(tf))
for i, f := range tf {
out[i].ID = zeroToSpace(f.id)
if len(f.settings) != 0 {
out[i].Value = f.settings[0].Value
}
}
// sort by id
sort.Slice(out, func(i, j int) bool { return out[i].ID < out[j].ID })
return out
}
func (tf tableFeat) findFeature(id Tag) (feature, bool) {
for _, feat := range tf {
if feat.id == id {
return feat, true
}
}
return feature{}, false
}
func parseTableFeat(data []byte) (tableFeat, error) {
const headerSize = 12
if len(data) < headerSize {
return nil, errors.New("invalid Feat table (EOF)")
}
r := binaryreader.NewReader(data)
version_, _ := r.Uint32()
version := version_ >> 16
numFeat, _ := r.Uint16()
r.Skip(6)
recordSize := 12
if version >= 2 {
recordSize = 16
}
featSlice, err := r.FixedSizes(int(numFeat), recordSize)
if err != nil {
return nil, fmt.Errorf("invalid Feat table: %s", err)
}
rFeat := binaryreader.NewReader(featSlice)
out := make(tableFeat, numFeat)
tmpIndexes := make([][2]int, numFeat)
var maxSettingsLength int
for i := range out {
if version >= 2 {
id_, _ := rFeat.Uint32()
out[i].id = Tag(id_)
} else {
id_, _ := rFeat.Uint16()
out[i].id = Tag(id_)
}
numSettings, _ := rFeat.Uint16()
if version >= 2 {
rFeat.Skip(2)
}
offset, _ := rFeat.Uint32()
out[i].flags, _ = rFeat.Uint16()
label_, _ := rFeat.Uint16()
out[i].label = truetype.NameID(label_)
// convert from offset to index
index := (int(offset) - headerSize - len(featSlice)) / 4
end := index + int(numSettings)
if numSettings != 0 && end > maxSettingsLength {
maxSettingsLength = end
}
tmpIndexes[i] = [2]int{index, int(numSettings)}
}
// parse the settings array
allSettings := make([]featureSetting, maxSettingsLength)
err = r.ReadStruct(allSettings)
if err != nil {
return nil, fmt.Errorf("invalid Feat table: %s", err)
}
for i, indexes := range tmpIndexes {
index, length := indexes[0], indexes[1]
if length == 0 {
continue
}
out[i].settings = allSettings[index : index+length]
}
return out, nil
}