@@ -6,10 +6,12 @@ package opentype
6
6
7
7
import (
8
8
"image"
9
+ "image/draw"
9
10
10
11
"golang.org/x/image/font"
11
12
"golang.org/x/image/font/sfnt"
12
13
"golang.org/x/image/math/fixed"
14
+ "golang.org/x/image/vector"
13
15
)
14
16
15
17
// FaceOptions describes the possible options given to NewFace when
@@ -34,7 +36,12 @@ type Face struct {
34
36
hinting font.Hinting
35
37
scale fixed.Int26_6
36
38
37
- buf sfnt.Buffer
39
+ metrics font.Metrics
40
+ metricsSet bool
41
+
42
+ buf sfnt.Buffer
43
+ rast vector.Rasterizer
44
+ mask image.Alpha
38
45
}
39
46
40
47
// NewFace returns a new font.Face for the given sfnt.Font.
@@ -58,11 +65,15 @@ func (f *Face) Close() error {
58
65
59
66
// Metrics satisfies the font.Face interface.
60
67
func (f * Face ) Metrics () font.Metrics {
61
- m , err := f .f .Metrics (& f .buf , f .scale , f .hinting )
62
- if err != nil {
63
- return font.Metrics {}
68
+ if ! f .metricsSet {
69
+ var err error
70
+ f .metrics , err = f .f .Metrics (& f .buf , f .scale , f .hinting )
71
+ if err != nil {
72
+ f .metrics = font.Metrics {}
73
+ }
74
+ f .metricsSet = true
64
75
}
65
- return m
76
+ return f . metrics
66
77
}
67
78
68
79
// Kern satisfies the font.Face interface.
@@ -78,22 +89,120 @@ func (f *Face) Kern(r0, r1 rune) fixed.Int26_6 {
78
89
79
90
// Glyph satisfies the font.Face interface.
80
91
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 ) {
81
- panic ("not implemented" )
92
+ x , err := f .f .GlyphIndex (& f .buf , r )
93
+ if err != nil {
94
+ return image.Rectangle {}, nil , image.Point {}, 0 , false
95
+ }
96
+
97
+ segments , err := f .f .LoadGlyph (& f .buf , x , f .scale , nil )
98
+ if err != nil {
99
+ return image.Rectangle {}, nil , image.Point {}, 0 , false
100
+ }
101
+
102
+ bounds , advance , err := f .f .GlyphBounds (& f .buf , x , f .scale , f .hinting )
103
+ if err != nil {
104
+ return image.Rectangle {}, nil , image.Point {}, 0 , false
105
+ }
106
+
107
+ // Numerical notation used below:
108
+ // - 2 is an integer, "two"
109
+ // - 2:16 is a 26.6 fixed point number, "two and a quarter"
110
+ // - 2.5 is a float32 number, "two and a half"
111
+ // Using 26.6 fixed point numbers means that there are 64 sub-pixel units
112
+ // in 1 integer pixel unit.
113
+ // Translate the sub-pixel bounding box from glyph space (where the glyph
114
+ // origin is at (0:00, 0:00)) to dst space (where the glyph origin is at
115
+ // the dot). dst space is the coordinate space that contains both the dot
116
+ // (a sub-pixel position) and dr (a pixel rectangle).
117
+ dBounds := bounds .Add (dot )
118
+
119
+ // Quantize the sub-pixel bounds (dBounds) to integer-pixel bounds (dr).
120
+ dr .Min .X = dBounds .Min .X .Floor ()
121
+ dr .Min .Y = dBounds .Min .Y .Floor ()
122
+ dr .Max .X = dBounds .Max .X .Ceil ()
123
+ dr .Max .Y = dBounds .Max .Y .Ceil ()
124
+ width := dr .Dx ()
125
+ height := dr .Dy ()
126
+ if width < 0 || height < 0 {
127
+ return image.Rectangle {}, nil , image.Point {}, 0 , false
128
+ }
129
+
130
+ // Calculate the sub-pixel bias to convert from glyph space to rasterizer
131
+ // space. In glyph space, the segments may be to the left or right and
132
+ // above or below the glyph origin. In rasterizer space, the segments
133
+ // should only be right and below (or equal to) the top-left corner (0.0,
134
+ // 0.0). They should also be left and above (or equal to) the bottom-right
135
+ // corner (width, height), as the rasterizer should enclose the glyph
136
+ // bounding box.
137
+ //
138
+ // For example, suppose that dot.X was at the sub-pixel position 25:48,
139
+ // three quarters of the way into the 26th pixel, and that bounds.Min.X was
140
+ // 1:20. We then have dBounds.Min.X = 1:20 + 25:48 = 27:04, dr.Min.X = 27
141
+ // and biasX = 25:48 - 27:00 = -1:16. A vertical stroke at 1:20 in glyph
142
+ // space becomes (1:20 + -1:16) = 0:04 in rasterizer space. 0:04 as a
143
+ // fixed.Int26_6 value is float32(4)/64.0 = 0.0625 as a float32 value.
144
+ biasX := dot .X - fixed .Int26_6 (dr .Min .X << 6 )
145
+ biasY := dot .Y - fixed .Int26_6 (dr .Min .Y << 6 )
146
+
147
+ // Configure the mask image, re-allocating its buffer if necessary.
148
+ nPixels := width * height
149
+ if cap (f .mask .Pix ) < nPixels {
150
+ f .mask .Pix = make ([]uint8 , 2 * nPixels )
151
+ }
152
+ f .mask .Pix = f .mask .Pix [:nPixels ]
153
+ f .mask .Stride = width
154
+ f .mask .Rect .Min .X = 0
155
+ f .mask .Rect .Min .Y = 0
156
+ f .mask .Rect .Max .X = width
157
+ f .mask .Rect .Max .Y = height
158
+
159
+ // Rasterize the biased segments, converting from fixed.Int26_6 to float32.
160
+ f .rast .Reset (width , height )
161
+ f .rast .DrawOp = draw .Src
162
+ for _ , seg := range segments {
163
+ switch seg .Op {
164
+ case sfnt .SegmentOpMoveTo :
165
+ f .rast .MoveTo (
166
+ float32 (seg .Args [0 ].X + biasX )/ 64 ,
167
+ float32 (seg .Args [0 ].Y + biasY )/ 64 ,
168
+ )
169
+ case sfnt .SegmentOpLineTo :
170
+ f .rast .LineTo (
171
+ float32 (seg .Args [0 ].X + biasX )/ 64 ,
172
+ float32 (seg .Args [0 ].Y + biasY )/ 64 ,
173
+ )
174
+ case sfnt .SegmentOpQuadTo :
175
+ f .rast .QuadTo (
176
+ float32 (seg .Args [0 ].X + biasX )/ 64 ,
177
+ float32 (seg .Args [0 ].Y + biasY )/ 64 ,
178
+ float32 (seg .Args [1 ].X + biasX )/ 64 ,
179
+ float32 (seg .Args [1 ].Y + biasY )/ 64 ,
180
+ )
181
+ case sfnt .SegmentOpCubeTo :
182
+ f .rast .CubeTo (
183
+ float32 (seg .Args [0 ].X + biasX )/ 64 ,
184
+ float32 (seg .Args [0 ].Y + biasY )/ 64 ,
185
+ float32 (seg .Args [1 ].X + biasX )/ 64 ,
186
+ float32 (seg .Args [1 ].Y + biasY )/ 64 ,
187
+ float32 (seg .Args [2 ].X + biasX )/ 64 ,
188
+ float32 (seg .Args [2 ].Y + biasY )/ 64 ,
189
+ )
190
+ }
191
+ }
192
+ f .rast .Draw (& f .mask , f .mask .Bounds (), image .Opaque , image.Point {})
193
+
194
+ return dr , & f .mask , f .mask .Rect .Min , advance , true
82
195
}
83
196
84
197
// GlyphBounds satisfies the font.Face interface.
85
198
func (f * Face ) GlyphBounds (r rune ) (bounds fixed.Rectangle26_6 , advance fixed.Int26_6 , ok bool ) {
86
- advance , ok = f .GlyphAdvance (r )
87
- if ! ok {
88
- return bounds , advance , ok
89
- }
90
- panic ("not implemented" )
199
+ bounds , advance , err := f .f .GlyphBounds (& f .buf , f .index (r ), f .scale , f .hinting )
200
+ return bounds , advance , err == nil
91
201
}
92
202
93
203
// GlyphAdvance satisfies the font.Face interface.
94
204
func (f * Face ) GlyphAdvance (r rune ) (advance fixed.Int26_6 , ok bool ) {
95
- idx := f .index (r )
96
- advance , err := f .f .GlyphAdvance (& f .buf , idx , f .scale , f .hinting )
205
+ advance , err := f .f .GlyphAdvance (& f .buf , f .index (r ), f .scale , f .hinting )
97
206
return advance , err == nil
98
207
}
99
208
0 commit comments