Skip to content

Commit fad8121

Browse files
author
Randall C. O'Reilly
committed
apply PRs from golang/freetype: golang#70, golang#86; set UseNonZeroWinding = true in rasterizer; return !ok in GlyphAdvance if rune index == 0, consistent with opentype.
1 parent 7a161fd commit fad8121

File tree

5 files changed

+63
-20
lines changed

5 files changed

+63
-20
lines changed

CONTRIBUTORS

+2
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@
2727
# Please keep the list sorted.
2828

2929
Andrew Gerrand <[email protected]>
30+
Dmitri Shuralyov <[email protected]>
3031
3132
Maksim Kochkin <[email protected]>
3233
Michael Fogleman <[email protected]>
3334
Nigel Tao <[email protected]>
35+
Randall O'Reilly <[email protected]>
3436
3537
3638
Roger Peppe <[email protected]>

freetype.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ type Context struct {
7878
// PointToFixed converts the given number of points (as in "a 12 point font")
7979
// into a 26.6 fixed point number of pixels.
8080
func (c *Context) PointToFixed(x float64) fixed.Int26_6 {
81-
return fixed.Int26_6(x * float64(c.dpi) * (64.0 / 72.0))
81+
return fixed.Int26_6(0.5 + (x * c.dpi * 64 / 72))
8282
}
8383

8484
// drawContour draws the given closed contour with the given offset.
@@ -260,7 +260,7 @@ func (c *Context) DrawString(s string, p fixed.Point26_6) (fixed.Point26_6, erro
260260
// recalc recalculates scale and bounds values from the font size, screen
261261
// resolution and font metrics, and invalidates the glyph cache.
262262
func (c *Context) recalc() {
263-
c.scale = fixed.Int26_6(c.fontSize * c.dpi * (64.0 / 72.0))
263+
c.scale = fixed.Int26_6(0.5 + (c.fontSize * c.dpi * 64 / 72))
264264
if c.f == nil {
265265
c.r.SetBounds(0, 0)
266266
} else {
@@ -332,10 +332,12 @@ func (c *Context) SetClip(clip image.Rectangle) {
332332

333333
// NewContext creates a new Context.
334334
func NewContext() *Context {
335-
return &Context{
335+
c := &Context{
336336
r: raster.NewRasterizer(0, 0),
337337
fontSize: 12,
338338
dpi: 72,
339339
scale: 12 << 6,
340340
}
341+
c.r.UseNonZeroWinding = true // needed for font rendering
342+
return c
341343
}

freetype_test.go

+25
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import (
1212
"runtime"
1313
"strings"
1414
"testing"
15+
16+
"golang.org/x/image/math/fixed"
1517
)
1618

1719
func BenchmarkDrawString(b *testing.B) {
@@ -57,3 +59,26 @@ func BenchmarkDrawString(b *testing.B) {
5759
mallocs = ms.Mallocs - mallocs
5860
b.Logf("%d iterations, %d mallocs per iteration\n", b.N, int(mallocs)/b.N)
5961
}
62+
63+
func TestScaling(t *testing.T) {
64+
c := NewContext()
65+
for _, tc := range [...]struct {
66+
in float64
67+
want fixed.Int26_6
68+
}{
69+
{in: 12, want: fixed.I(12)},
70+
{in: 11.992, want: fixed.I(12) - 1},
71+
{in: 11.993, want: fixed.I(12)},
72+
{in: 12.007, want: fixed.I(12)},
73+
{in: 12.008, want: fixed.I(12) + 1},
74+
{in: 86.4, want: fixed.Int26_6(86<<6 + 26)}, // Issue https://github.com/golang/freetype/issues/85.
75+
} {
76+
c.SetFontSize(tc.in)
77+
if got, want := c.scale, tc.want; got != want {
78+
t.Errorf("scale after SetFontSize(%v) = %v, want %v", tc.in, got, want)
79+
}
80+
if got, want := c.PointToFixed(tc.in), tc.want; got != want {
81+
t.Errorf("PointToFixed(%v) = %v, want %v", tc.in, got, want)
82+
}
83+
}
84+
}

truetype/face.go

+12-8
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,12 @@ func (o *Options) subPixelsY() (value uint32, halfQuantum, mask fixed.Int26_6) {
139139
//
140140
// For example, q == 4 leads to a bias of 8 and a mask of 0xfffffff0, or -16,
141141
// because we want to round fractions of fixed.Int26_6 as:
142-
// - 0 to 7 rounds to 0.
143-
// - 8 to 23 rounds to 16.
144-
// - 24 to 39 rounds to 32.
145-
// - 40 to 55 rounds to 48.
146-
// - 56 to 63 rounds to 64.
142+
// - 0 to 7 rounds to 0.
143+
// - 8 to 23 rounds to 16.
144+
// - 24 to 39 rounds to 32.
145+
// - 40 to 55 rounds to 48.
146+
// - 56 to 63 rounds to 64.
147+
//
147148
// which means to add 8 and then bitwise-and with -16, in two's complement
148149
// representation.
149150
//
@@ -205,6 +206,7 @@ func NewFace(f *Font, opts *Options) IndexableFace {
205206
glyphCache: make([]glyphCacheEntry, opts.glyphCacheEntries()),
206207
stroke: fixed.I(opts.Stroke * 2),
207208
}
209+
a.r.UseNonZeroWinding = true // key for fonts
208210
a.subPixelX, a.subPixelBiasX, a.subPixelMaskX = opts.subPixelsX()
209211
a.subPixelY, a.subPixelBiasY, a.subPixelMaskY = opts.subPixelsY()
210212

@@ -388,13 +390,15 @@ func (a *face) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) {
388390
}
389391
advance, ok = a.advanceCache[r]
390392
if ok {
391-
return
393+
idx := a.index(r)
394+
return advance, (idx != 0)
392395
}
393-
if err := a.glyphBuf.Load(a.f, a.scale, a.index(r), a.hinting); err != nil {
396+
idx := a.index(r)
397+
if err := a.glyphBuf.Load(a.f, a.scale, idx, a.hinting); err != nil {
394398
return 0, false
395399
}
396400
a.advanceCache[r] = a.glyphBuf.AdvanceWidth
397-
return a.glyphBuf.AdvanceWidth, true
401+
return a.glyphBuf.AdvanceWidth, (idx != 0)
398402
}
399403

400404
// rasterize returns the advance width, integer-pixel offset to render at, and

truetype/truetype.go

+19-9
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@
1919
package truetype
2020

2121
import (
22+
"bytes"
2223
"fmt"
24+
"unicode/utf16"
25+
"unicode/utf8"
2326

2427
"golang.org/x/image/math/fixed"
2528
)
@@ -429,20 +432,27 @@ func (f *Font) Name(id NameID) string {
429432
// Return the ASCII value of the encoded string.
430433
// The string is encoded as UTF-16 on non-Apple platformIDs; Apple is platformID 1.
431434
src := f.name[offset : offset+length]
432-
var dst []byte
433435
if platformID != 1 { // UTF-16.
434436
if len(src)&1 != 0 {
435437
return ""
436438
}
437-
dst = make([]byte, len(src)/2)
438-
for i := range dst {
439-
dst[i] = printable(u16(src, 2*i))
440-
}
441-
} else { // ASCII.
442-
dst = make([]byte, len(src))
443-
for i, c := range src {
444-
dst[i] = printable(uint16(c))
439+
lb := len(src) / 2
440+
b8buf := make([]byte, 4)
441+
u16s := make([]uint16, 1)
442+
var buf bytes.Buffer
443+
for i := 0; i < lb; i++ {
444+
u16s[0] = u16(src, i)
445+
r := utf16.Decode(u16s)
446+
n := utf8.EncodeRune(b8buf, r[0])
447+
buf.Write([]byte(string(b8buf[:n])))
445448
}
449+
return buf.String()
450+
}
451+
// ASCII.
452+
var dst []byte
453+
dst = make([]byte, len(src))
454+
for i, c := range src {
455+
dst[i] = printable(uint16(c))
446456
}
447457
return string(dst)
448458
}

0 commit comments

Comments
 (0)