-
Notifications
You must be signed in to change notification settings - Fork 7
/
rd_outlines.go
153 lines (140 loc) · 3.83 KB
/
rd_outlines.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
147
148
149
150
151
152
153
package truetype
import (
"errors"
"fmt"
"github.com/benoitkugler/textlayout/fonts"
)
// this file converts from font format for glyph outlines to
// segments that rasterizer will consume
//
// adapted from snft/truetype.go
func midPoint(p, q fonts.SegmentPoint) fonts.SegmentPoint {
return fonts.SegmentPoint{
X: (p.X + q.X) / 2,
Y: (p.Y + q.Y) / 2,
}
}
// build the segments from the resolved contour points
func buildSegments(points []contourPoint) []fonts.Segment {
var (
firstOnCurveValid, firstOffCurveValid, lastOffCurveValid bool
firstOnCurve, firstOffCurve, lastOffCurve fonts.SegmentPoint
out []fonts.Segment
)
for _, point := range points {
p := point.SegmentPoint
if !firstOnCurveValid {
if point.isOnCurve {
firstOnCurve = p
firstOnCurveValid = true
out = append(out, fonts.Segment{
Op: fonts.SegmentOpMoveTo,
Args: [3]fonts.SegmentPoint{p},
})
} else if !firstOffCurveValid {
firstOffCurve = p
firstOffCurveValid = true
if !point.isEndPoint {
continue
}
} else {
firstOnCurve = midPoint(firstOffCurve, p)
firstOnCurveValid = true
lastOffCurve = p
lastOffCurveValid = true
out = append(out, fonts.Segment{
Op: fonts.SegmentOpMoveTo,
Args: [3]fonts.SegmentPoint{firstOnCurve},
})
}
} else if !lastOffCurveValid {
if !point.isOnCurve {
lastOffCurve = p
lastOffCurveValid = true
if !point.isEndPoint {
continue
}
} else {
out = append(out, fonts.Segment{
Op: fonts.SegmentOpLineTo,
Args: [3]fonts.SegmentPoint{p},
})
}
} else {
if !point.isOnCurve {
out = append(out, fonts.Segment{
Op: fonts.SegmentOpQuadTo,
Args: [3]fonts.SegmentPoint{
lastOffCurve,
midPoint(lastOffCurve, p),
},
})
lastOffCurve = p
lastOffCurveValid = true
} else {
out = append(out, fonts.Segment{
Op: fonts.SegmentOpQuadTo,
Args: [3]fonts.SegmentPoint{lastOffCurve, p},
})
lastOffCurveValid = false
}
}
if point.isEndPoint {
// closing the contour
switch {
case !firstOffCurveValid && !lastOffCurveValid:
out = append(out, fonts.Segment{
Op: fonts.SegmentOpLineTo,
Args: [3]fonts.SegmentPoint{firstOnCurve},
})
case !firstOffCurveValid && lastOffCurveValid:
out = append(out, fonts.Segment{
Op: fonts.SegmentOpQuadTo,
Args: [3]fonts.SegmentPoint{lastOffCurve, firstOnCurve},
})
case firstOffCurveValid && !lastOffCurveValid:
out = append(out, fonts.Segment{
Op: fonts.SegmentOpQuadTo,
Args: [3]fonts.SegmentPoint{firstOffCurve, firstOnCurve},
})
case firstOffCurveValid && lastOffCurveValid:
out = append(out, fonts.Segment{
Op: fonts.SegmentOpQuadTo,
Args: [3]fonts.SegmentPoint{
lastOffCurve,
midPoint(lastOffCurve, firstOffCurve),
},
},
fonts.Segment{
Op: fonts.SegmentOpQuadTo,
Args: [3]fonts.SegmentPoint{firstOffCurve, firstOnCurve},
},
)
}
firstOnCurveValid = false
firstOffCurveValid = false
lastOffCurveValid = false
}
}
return out
}
// apply variation when needed
func (f *Font) glyphDataFromGlyf(glyph GID) (fonts.GlyphOutline, error) {
if int(glyph) >= len(f.Glyf) {
return fonts.GlyphOutline{}, fmt.Errorf("out of range glyph %d", glyph)
}
var points []contourPoint
f.getPointsForGlyph(glyph, 0, &points)
segments := buildSegments(points[:len(points)-phantomCount])
return fonts.GlyphOutline{Segments: segments}, nil
}
func (f *Font) glyphDataFromCFF1(glyph GID) (fonts.GlyphOutline, error) {
if f.cff == nil {
return fonts.GlyphOutline{}, errors.New("no CFF table")
}
segments, _, err := f.cff.LoadGlyph(glyph)
if err != nil {
return fonts.GlyphOutline{}, err
}
return fonts.GlyphOutline{Segments: segments}, nil
}