提交 2a5cbfd4 编写于 作者: N Nigel Tao

Use the fixed.Int26_6 type in package truetype.

上级 a9554eda
...@@ -116,14 +116,14 @@ func main() { ...@@ -116,14 +116,14 @@ func main() {
} }
// Draw the text. // Draw the text.
pt := freetype.Pt(10, 10+int(c.PointToFix32(*size)>>6)) pt := freetype.Pt(10, 10+int(c.PointToFixed(*size)>>6))
for _, s := range text { for _, s := range text {
_, err = c.DrawString(s, pt) _, err = c.DrawString(s, pt)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
return return
} }
pt.Y += c.PointToFix32(*size * *spacing) pt.Y += c.PointToFixed(*size * *spacing)
} }
// Save that RGBA image to disk. // Save that RGBA image to disk.
......
...@@ -17,6 +17,7 @@ import ( ...@@ -17,6 +17,7 @@ import (
"log" "log"
"github.com/golang/freetype/truetype" "github.com/golang/freetype/truetype"
"golang.org/x/image/math/fixed"
) )
var fontfile = flag.String("fontfile", "../../testdata/luxisr.ttf", "filename of the ttf font") var fontfile = flag.String("fontfile", "../../testdata/luxisr.ttf", "filename of the ttf font")
...@@ -56,7 +57,7 @@ func main() { ...@@ -56,7 +57,7 @@ func main() {
log.Println(err) log.Println(err)
return return
} }
fupe := font.FUnitsPerEm() fupe := fixed.Int26_6(font.FUnitsPerEm())
printBounds(font.Bounds(fupe)) printBounds(font.Bounds(fupe))
fmt.Printf("FUnitsPerEm:%d\n\n", fupe) fmt.Printf("FUnitsPerEm:%d\n\n", fupe)
......
...@@ -78,15 +78,15 @@ type Context struct { ...@@ -78,15 +78,15 @@ type Context struct {
// fontSize and dpi are used to calculate scale. scale is the number of // fontSize and dpi are used to calculate scale. scale is the number of
// 26.6 fixed point units in 1 em. hinting is the hinting policy. // 26.6 fixed point units in 1 em. hinting is the hinting policy.
fontSize, dpi float64 fontSize, dpi float64
scale int32 scale fixed.Int26_6
hinting Hinting hinting Hinting
// cache is the glyph cache. // cache is the glyph cache.
cache [nGlyphs * nXFractions * nYFractions]cacheEntry cache [nGlyphs * nXFractions * nYFractions]cacheEntry
} }
// PointToFix32 converts the given number of points (as in ``a 12 point font'') // PointToFixed converts the given number of points (as in ``a 12 point font'')
// into fixed point units. // into a 26.6 fixed point number of pixels.
func (c *Context) PointToFix32(x float64) fixed.Int26_6 { func (c *Context) PointToFixed(x float64) fixed.Int26_6 {
return fixed.Int26_6(x * float64(c.dpi) * (64.0 / 72.0)) return fixed.Int26_6(x * float64(c.dpi) * (64.0 / 72.0))
} }
...@@ -269,7 +269,7 @@ func (c *Context) DrawString(s string, p fixed.Point26_6) (fixed.Point26_6, erro ...@@ -269,7 +269,7 @@ func (c *Context) DrawString(s string, p fixed.Point26_6) (fixed.Point26_6, erro
// recalc recalculates scale and bounds values from the font size, screen // recalc recalculates scale and bounds values from the font size, screen
// resolution and font metrics, and invalidates the glyph cache. // resolution and font metrics, and invalidates the glyph cache.
func (c *Context) recalc() { func (c *Context) recalc() {
c.scale = int32(c.fontSize * c.dpi * (64.0 / 72.0)) c.scale = fixed.Int26_6(c.fontSize * c.dpi * (64.0 / 72.0))
if c.font == nil { if c.font == nil {
c.r.SetBounds(0, 0) c.r.SetBounds(0, 0)
} else { } else {
......
...@@ -5,8 +5,12 @@ ...@@ -5,8 +5,12 @@
package truetype package truetype
import (
"golang.org/x/image/math/fixed"
)
// Hinting is the policy for snapping a glyph's contours to pixel boundaries. // Hinting is the policy for snapping a glyph's contours to pixel boundaries.
type Hinting int32 type Hinting uint32
const ( const (
// NoHinting means to not perform any hinting. // NoHinting means to not perform any hinting.
...@@ -20,7 +24,7 @@ const ( ...@@ -20,7 +24,7 @@ const (
// A Point is a co-ordinate pair plus whether it is ``on'' a contour or an // A Point is a co-ordinate pair plus whether it is ``on'' a contour or an
// ``off'' control point. // ``off'' control point.
type Point struct { type Point struct {
X, Y int32 X, Y fixed.Int26_6
// The Flags' LSB means whether or not this Point is ``on'' the contour. // The Flags' LSB means whether or not this Point is ``on'' the contour.
// Other bits are reserved for internal use. // Other bits are reserved for internal use.
Flags uint32 Flags uint32
...@@ -30,7 +34,7 @@ type Point struct { ...@@ -30,7 +34,7 @@ type Point struct {
// series of glyphs from a Font. // series of glyphs from a Font.
type GlyphBuf struct { type GlyphBuf struct {
// AdvanceWidth is the glyph's advance width. // AdvanceWidth is the glyph's advance width.
AdvanceWidth int32 AdvanceWidth fixed.Int26_6
// B is the glyph's bounding box. // B is the glyph's bounding box.
B Bounds B Bounds
// Point contains all Points from all contours of the glyph. If // Point contains all Points from all contours of the glyph. If
...@@ -45,7 +49,7 @@ type GlyphBuf struct { ...@@ -45,7 +49,7 @@ type GlyphBuf struct {
End []int End []int
font *Font font *Font
scale int32 scale fixed.Int26_6
hinting Hinting hinting Hinting
hinter hinter hinter hinter
// phantomPoints are the co-ordinates of the synthetic phantom points // phantomPoints are the co-ordinates of the synthetic phantom points
...@@ -54,7 +58,7 @@ type GlyphBuf struct { ...@@ -54,7 +58,7 @@ type GlyphBuf struct {
// pp1x is the X co-ordinate of the first phantom point. The '1' is // pp1x is the X co-ordinate of the first phantom point. The '1' is
// using 1-based indexing; pp1x is almost always phantomPoints[0].X. // using 1-based indexing; pp1x is almost always phantomPoints[0].X.
// TODO: eliminate this and consistently use phantomPoints[0].X. // TODO: eliminate this and consistently use phantomPoints[0].X.
pp1x int32 pp1x fixed.Int26_6
// metricsSet is whether the glyph's metrics have been set yet. For a // metricsSet is whether the glyph's metrics have been set yet. For a
// compound glyph, a sub-glyph may override the outer glyph's metrics. // compound glyph, a sub-glyph may override the outer glyph's metrics.
metricsSet bool metricsSet bool
...@@ -84,10 +88,10 @@ const ( ...@@ -84,10 +88,10 @@ const (
flagThisYIsSame = flagPositiveYShortVector flagThisYIsSame = flagPositiveYShortVector
) )
// Load loads a glyph's contours from a Font, overwriting any previously // Load loads a glyph's contours from a Font, overwriting any previously loaded
// loaded contours for this GlyphBuf. scale is the number of 26.6 fixed point // contours for this GlyphBuf. scale is the number of 26.6 fixed point units in
// units in 1 em, i is the glyph index, and h is the hinting policy. // 1 em, i is the glyph index, and h is the hinting policy.
func (g *GlyphBuf) Load(f *Font, scale int32, i Index, h Hinting) error { func (g *GlyphBuf) Load(f *Font, scale fixed.Int26_6, i Index, h Hinting) error {
g.Point = g.Point[:0] g.Point = g.Point[:0]
g.Unhinted = g.Unhinted[:0] g.Unhinted = g.Unhinted[:0]
g.InFontUnits = g.InFontUnits[:0] g.InFontUnits = g.InFontUnits[:0]
...@@ -125,8 +129,8 @@ func (g *GlyphBuf) Load(f *Font, scale int32, i Index, h Hinting) error { ...@@ -125,8 +129,8 @@ func (g *GlyphBuf) Load(f *Font, scale int32, i Index, h Hinting) error {
if len(f.hdmx) >= 8 { if len(f.hdmx) >= 8 {
if n := u32(f.hdmx, 4); n > 3+uint32(i) { if n := u32(f.hdmx, 4); n > 3+uint32(i) {
for hdmx := f.hdmx[8:]; uint32(len(hdmx)) >= n; hdmx = hdmx[n:] { for hdmx := f.hdmx[8:]; uint32(len(hdmx)) >= n; hdmx = hdmx[n:] {
if int32(hdmx[0]) == scale>>6 { if fixed.Int26_6(hdmx[0]) == scale>>6 {
advanceWidth = int32(hdmx[2+i]) << 6 advanceWidth = fixed.Int26_6(hdmx[2+i]) << 6
break break
} }
} }
...@@ -175,7 +179,7 @@ func (g *GlyphBuf) Load(f *Font, scale int32, i Index, h Hinting) error { ...@@ -175,7 +179,7 @@ func (g *GlyphBuf) Load(f *Font, scale int32, i Index, h Hinting) error {
return nil return nil
} }
func (g *GlyphBuf) load(recursion int32, i Index, useMyMetrics bool) (err error) { func (g *GlyphBuf) load(recursion uint32, i Index, useMyMetrics bool) (err error) {
// The recursion limit here is arbitrary, but defends against malformed glyphs. // The recursion limit here is arbitrary, but defends against malformed glyphs.
if recursion >= 32 { if recursion >= 32 {
return UnsupportedError("excessive compound glyph recursion") return UnsupportedError("excessive compound glyph recursion")
...@@ -193,16 +197,16 @@ func (g *GlyphBuf) load(recursion int32, i Index, useMyMetrics bool) (err error) ...@@ -193,16 +197,16 @@ func (g *GlyphBuf) load(recursion int32, i Index, useMyMetrics bool) (err error)
// Decode the contour count and nominal bounding box, from the first // Decode the contour count and nominal bounding box, from the first
// 10 bytes of the glyf data. boundsYMin and boundsXMax, at offsets 4 // 10 bytes of the glyf data. boundsYMin and boundsXMax, at offsets 4
// and 6, are unused. // and 6, are unused.
glyf, ne, boundsXMin, boundsYMax := []byte(nil), 0, int32(0), int32(0) glyf, ne, boundsXMin, boundsYMax := []byte(nil), 0, fixed.Int26_6(0), fixed.Int26_6(0)
if g0+10 <= g1 { if g0+10 <= g1 {
glyf = g.font.glyf[g0:g1] glyf = g.font.glyf[g0:g1]
ne = int(int16(u16(glyf, 0))) ne = int(int16(u16(glyf, 0)))
boundsXMin = int32(int16(u16(glyf, 2))) boundsXMin = fixed.Int26_6(int16(u16(glyf, 2)))
boundsYMax = int32(int16(u16(glyf, 8))) boundsYMax = fixed.Int26_6(int16(u16(glyf, 8)))
} }
// Create the phantom points. // Create the phantom points.
uhm, pp1x := g.font.unscaledHMetric(i), int32(0) uhm, pp1x := g.font.unscaledHMetric(i), fixed.Int26_6(0)
uvm := g.font.unscaledVMetric(i, boundsYMax) uvm := g.font.unscaledVMetric(i, boundsYMax)
g.phantomPoints = [4]Point{ g.phantomPoints = [4]Point{
{X: boundsXMin - uhm.LeftSideBearing}, {X: boundsXMin - uhm.LeftSideBearing},
...@@ -322,7 +326,7 @@ func (g *GlyphBuf) loadSimple(glyf []byte, ne int) (program []byte) { ...@@ -322,7 +326,7 @@ func (g *GlyphBuf) loadSimple(glyf []byte, ne int) (program []byte) {
x += int16(u16(glyf, offset)) x += int16(u16(glyf, offset))
offset += 2 offset += 2
} }
g.Point[i].X = int32(x) g.Point[i].X = fixed.Int26_6(x)
} }
var y int16 var y int16
for i := np0; i < np1; i++ { for i := np0; i < np1; i++ {
...@@ -339,13 +343,13 @@ func (g *GlyphBuf) loadSimple(glyf []byte, ne int) (program []byte) { ...@@ -339,13 +343,13 @@ func (g *GlyphBuf) loadSimple(glyf []byte, ne int) (program []byte) {
y += int16(u16(glyf, offset)) y += int16(u16(glyf, offset))
offset += 2 offset += 2
} }
g.Point[i].Y = int32(y) g.Point[i].Y = fixed.Int26_6(y)
} }
return program return program
} }
func (g *GlyphBuf) loadCompound(recursion int32, uhm HMetric, i Index, func (g *GlyphBuf) loadCompound(recursion uint32, uhm HMetric, i Index,
glyf []byte, useMyMetrics bool) error { glyf []byte, useMyMetrics bool) error {
// Flags for decoding a compound glyph. These flags are documented at // Flags for decoding a compound glyph. These flags are documented at
...@@ -368,14 +372,14 @@ func (g *GlyphBuf) loadCompound(recursion int32, uhm HMetric, i Index, ...@@ -368,14 +372,14 @@ func (g *GlyphBuf) loadCompound(recursion int32, uhm HMetric, i Index,
for { for {
flags := u16(glyf, offset) flags := u16(glyf, offset)
component := Index(u16(glyf, offset+2)) component := Index(u16(glyf, offset+2))
dx, dy, transform, hasTransform := int32(0), int32(0), [4]int32{}, false dx, dy, transform, hasTransform := fixed.Int26_6(0), fixed.Int26_6(0), [4]int16{}, false
if flags&flagArg1And2AreWords != 0 { if flags&flagArg1And2AreWords != 0 {
dx = int32(int16(u16(glyf, offset+4))) dx = fixed.Int26_6(int16(u16(glyf, offset+4)))
dy = int32(int16(u16(glyf, offset+6))) dy = fixed.Int26_6(int16(u16(glyf, offset+6)))
offset += 8 offset += 8
} else { } else {
dx = int32(int16(int8(glyf[offset+4]))) dx = fixed.Int26_6(int16(int8(glyf[offset+4])))
dy = int32(int16(int8(glyf[offset+5]))) dy = fixed.Int26_6(int16(int8(glyf[offset+5])))
offset += 6 offset += 6
} }
if flags&flagArgsAreXYValues == 0 { if flags&flagArgsAreXYValues == 0 {
...@@ -385,18 +389,18 @@ func (g *GlyphBuf) loadCompound(recursion int32, uhm HMetric, i Index, ...@@ -385,18 +389,18 @@ func (g *GlyphBuf) loadCompound(recursion int32, uhm HMetric, i Index,
hasTransform = true hasTransform = true
switch { switch {
case flags&flagWeHaveAScale != 0: case flags&flagWeHaveAScale != 0:
transform[0] = int32(int16(u16(glyf, offset+0))) transform[0] = int16(u16(glyf, offset+0))
transform[3] = transform[0] transform[3] = transform[0]
offset += 2 offset += 2
case flags&flagWeHaveAnXAndYScale != 0: case flags&flagWeHaveAnXAndYScale != 0:
transform[0] = int32(int16(u16(glyf, offset+0))) transform[0] = int16(u16(glyf, offset+0))
transform[3] = int32(int16(u16(glyf, offset+2))) transform[3] = int16(u16(glyf, offset+2))
offset += 4 offset += 4
case flags&flagWeHaveATwoByTwo != 0: case flags&flagWeHaveATwoByTwo != 0:
transform[0] = int32(int16(u16(glyf, offset+0))) transform[0] = int16(u16(glyf, offset+0))
transform[1] = int32(int16(u16(glyf, offset+2))) transform[1] = int16(u16(glyf, offset+2))
transform[2] = int32(int16(u16(glyf, offset+4))) transform[2] = int16(u16(glyf, offset+4))
transform[3] = int32(int16(u16(glyf, offset+6))) transform[3] = int16(u16(glyf, offset+6))
offset += 8 offset += 8
} }
} }
...@@ -412,10 +416,12 @@ func (g *GlyphBuf) loadCompound(recursion int32, uhm HMetric, i Index, ...@@ -412,10 +416,12 @@ func (g *GlyphBuf) loadCompound(recursion int32, uhm HMetric, i Index,
if hasTransform { if hasTransform {
for j := np0; j < len(g.Point); j++ { for j := np0; j < len(g.Point); j++ {
p := &g.Point[j] p := &g.Point[j]
newX := int32((int64(p.X)*int64(transform[0])+1<<13)>>14) + newX := 0 +
int32((int64(p.Y)*int64(transform[2])+1<<13)>>14) fixed.Int26_6((int64(p.X)*int64(transform[0])+1<<13)>>14) +
newY := int32((int64(p.X)*int64(transform[1])+1<<13)>>14) + fixed.Int26_6((int64(p.Y)*int64(transform[2])+1<<13)>>14)
int32((int64(p.Y)*int64(transform[3])+1<<13)>>14) newY := 0 +
fixed.Int26_6((int64(p.X)*int64(transform[1])+1<<13)>>14) +
fixed.Int26_6((int64(p.Y)*int64(transform[3])+1<<13)>>14)
p.X, p.Y = newX, newY p.X, p.Y = newX, newY
} }
} }
......
...@@ -11,6 +11,8 @@ package truetype ...@@ -11,6 +11,8 @@ package truetype
import ( import (
"errors" "errors"
"math" "math"
"golang.org/x/image/math/fixed"
) )
const ( const (
...@@ -47,7 +49,7 @@ type hinter struct { ...@@ -47,7 +49,7 @@ type hinter struct {
// Changing the font will require running the new font's fpgm bytecode. // Changing the font will require running the new font's fpgm bytecode.
// Changing either will require running the font's prep bytecode. // Changing either will require running the font's prep bytecode.
font *Font font *Font
scale int32 scale fixed.Int26_6
// gs and defaultGS are the current and default graphics state. The // gs and defaultGS are the current and default graphics state. The
// default graphics state is the global default graphics state after // default graphics state is the global default graphics state after
...@@ -113,7 +115,7 @@ func resetTwilightPoints(f *Font, p []Point) []Point { ...@@ -113,7 +115,7 @@ func resetTwilightPoints(f *Font, p []Point) []Point {
return p return p
} }
func (h *hinter) init(f *Font, scale int32) error { func (h *hinter) init(f *Font, scale fixed.Int26_6) error {
h.points[twilightZone][0] = resetTwilightPoints(f, h.points[twilightZone][0]) h.points[twilightZone][0] = resetTwilightPoints(f, h.points[twilightZone][0])
h.points[twilightZone][1] = resetTwilightPoints(f, h.points[twilightZone][1]) h.points[twilightZone][1] = resetTwilightPoints(f, h.points[twilightZone][1])
h.points[twilightZone][2] = resetTwilightPoints(f, h.points[twilightZone][2]) h.points[twilightZone][2] = resetTwilightPoints(f, h.points[twilightZone][2])
...@@ -315,8 +317,8 @@ func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point, ...@@ -315,8 +317,8 @@ func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point,
mulDiv(int64(dy), int64(dbx), 0x40) mulDiv(int64(dy), int64(dbx), 0x40)
rx := mulDiv(val, int64(dax), discriminant) rx := mulDiv(val, int64(dax), discriminant)
ry := mulDiv(val, int64(day), discriminant) ry := mulDiv(val, int64(day), discriminant)
p.X = a0.X + int32(rx) p.X = a0.X + fixed.Int26_6(rx)
p.Y = a0.Y + int32(ry) p.Y = a0.Y + fixed.Int26_6(ry)
} else { } else {
p.X = (a0.X + a1.X + b0.X + b1.X) / 4 p.X = (a0.X + a1.X + b0.X + b1.X) / 4
p.Y = (a0.Y + a1.Y + b0.Y + b1.Y) / 4 p.Y = (a0.Y + a1.Y + b0.Y + b1.Y) / 4
...@@ -379,7 +381,7 @@ func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point, ...@@ -379,7 +381,7 @@ func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point,
case opSSW: case opSSW:
top-- top--
h.gs.singleWidth = f26dot6(h.font.scale(h.scale * h.stack[top])) h.gs.singleWidth = f26dot6(h.font.scale(h.scale * fixed.Int26_6(h.stack[top])))
case opDUP: case opDUP:
if top >= len(h.stack) { if top >= len(h.stack) {
...@@ -711,8 +713,8 @@ func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point, ...@@ -711,8 +713,8 @@ func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point,
if h.gs.zp[0] == 0 { if h.gs.zp[0] == 0 {
p := h.point(0, unhinted, i) p := h.point(0, unhinted, i)
q := h.point(0, current, i) q := h.point(0, current, i)
p.X = int32((int64(distance) * int64(h.gs.fv[0])) >> 14) p.X = fixed.Int26_6((int64(distance) * int64(h.gs.fv[0])) >> 14)
p.Y = int32((int64(distance) * int64(h.gs.fv[1])) >> 14) p.Y = fixed.Int26_6((int64(distance) * int64(h.gs.fv[1])) >> 14)
*q = *p *q = *p
} }
p := h.point(0, current, i) p := h.point(0, current, i)
...@@ -809,7 +811,7 @@ func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point, ...@@ -809,7 +811,7 @@ func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point,
} }
d := int32(dotProduct(f26dot6(p.X-q.X), f26dot6(p.Y-q.Y), v)) d := int32(dotProduct(f26dot6(p.X-q.X), f26dot6(p.Y-q.Y), v))
if scale { if scale {
d = int32(int64(d*h.scale) / int64(h.font.fUnitsPerEm)) d = int32(int64(d*int32(h.scale)) / int64(h.font.fUnitsPerEm))
} }
h.stack[top-1] = d h.stack[top-1] = d
...@@ -818,7 +820,7 @@ func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point, ...@@ -818,7 +820,7 @@ func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point,
return errors.New("truetype: hinting: stack overflow") return errors.New("truetype: hinting: stack overflow")
} }
// For MPS, point size should be irrelevant; we return the PPEM. // For MPS, point size should be irrelevant; we return the PPEM.
h.stack[top] = h.scale >> 6 h.stack[top] = int32(h.scale) >> 6
top++ top++
case opFLIPON, opFLIPOFF: case opFLIPON, opFLIPOFF:
...@@ -935,7 +937,7 @@ func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point, ...@@ -935,7 +937,7 @@ func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point,
case opWCVTF: case opWCVTF:
top -= 2 top -= 2
h.setScaledCVT(h.stack[top], f26dot6(h.font.scale(h.scale*h.stack[top+1]))) h.setScaledCVT(h.stack[top], f26dot6(h.font.scale(h.scale*fixed.Int26_6(h.stack[top+1]))))
case opDELTAP2, opDELTAP3, opDELTAC1, opDELTAC2, opDELTAC3: case opDELTAP2, opDELTAP3, opDELTAC1, opDELTAC2, opDELTAC3:
goto delta goto delta
...@@ -1144,7 +1146,7 @@ func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point, ...@@ -1144,7 +1146,7 @@ func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point,
p0 := h.point(1, inFontUnits, i) p0 := h.point(1, inFontUnits, i)
p1 := h.point(0, inFontUnits, h.gs.rp[0]) p1 := h.point(0, inFontUnits, h.gs.rp[0])
oldDist = dotProduct(f26dot6(p0.X-p1.X), f26dot6(p0.Y-p1.Y), h.gs.dv) oldDist = dotProduct(f26dot6(p0.X-p1.X), f26dot6(p0.Y-p1.Y), h.gs.dv)
oldDist = f26dot6(h.font.scale(h.scale * int32(oldDist))) oldDist = f26dot6(h.font.scale(h.scale * fixed.Int26_6(oldDist)))
} }
// Single-width cut-in test. // Single-width cut-in test.
...@@ -1358,7 +1360,7 @@ func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point, ...@@ -1358,7 +1360,7 @@ func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point,
c += 32 c += 32
} }
c += h.gs.deltaBase c += h.gs.deltaBase
if ppem := (h.scale + 1<<5) >> 6; ppem != c { if ppem := (int32(h.scale) + 1<<5) >> 6; ppem != c {
continue continue
} }
b = (b & 0x0f) - 8 b = (b & 0x0f) - 8
...@@ -1399,7 +1401,7 @@ func (h *hinter) initializeScaledCVT() { ...@@ -1399,7 +1401,7 @@ func (h *hinter) initializeScaledCVT() {
} }
for i := range h.scaledCVT { for i := range h.scaledCVT {
unscaled := uint16(h.font.cvt[2*i])<<8 | uint16(h.font.cvt[2*i+1]) unscaled := uint16(h.font.cvt[2*i])<<8 | uint16(h.font.cvt[2*i+1])
h.scaledCVT[i] = f26dot6(h.font.scale(h.scale * int32(int16(unscaled)))) h.scaledCVT[i] = f26dot6(h.font.scale(h.scale * fixed.Int26_6(int16(unscaled))))
} }
} }
...@@ -1437,7 +1439,7 @@ func (h *hinter) move(p *Point, distance f26dot6, touch bool) { ...@@ -1437,7 +1439,7 @@ func (h *hinter) move(p *Point, distance f26dot6, touch bool) {
fvx := int64(h.gs.fv[0]) fvx := int64(h.gs.fv[0])
pvx := int64(h.gs.pv[0]) pvx := int64(h.gs.pv[0])
if fvx == 0x4000 && pvx == 0x4000 { if fvx == 0x4000 && pvx == 0x4000 {
p.X += int32(distance) p.X += fixed.Int26_6(distance)
if touch { if touch {
p.Flags |= flagTouchedX p.Flags |= flagTouchedX
} }
...@@ -1447,7 +1449,7 @@ func (h *hinter) move(p *Point, distance f26dot6, touch bool) { ...@@ -1447,7 +1449,7 @@ func (h *hinter) move(p *Point, distance f26dot6, touch bool) {
fvy := int64(h.gs.fv[1]) fvy := int64(h.gs.fv[1])
pvy := int64(h.gs.pv[1]) pvy := int64(h.gs.pv[1])
if fvy == 0x4000 && pvy == 0x4000 { if fvy == 0x4000 && pvy == 0x4000 {
p.Y += int32(distance) p.Y += fixed.Int26_6(distance)
if touch { if touch {
p.Flags |= flagTouchedY p.Flags |= flagTouchedY
} }
...@@ -1457,14 +1459,14 @@ func (h *hinter) move(p *Point, distance f26dot6, touch bool) { ...@@ -1457,14 +1459,14 @@ func (h *hinter) move(p *Point, distance f26dot6, touch bool) {
fvDotPv := (fvx*pvx + fvy*pvy) >> 14 fvDotPv := (fvx*pvx + fvy*pvy) >> 14
if fvx != 0 { if fvx != 0 {
p.X += int32(mulDiv(fvx, int64(distance), fvDotPv)) p.X += fixed.Int26_6(mulDiv(fvx, int64(distance), fvDotPv))
if touch { if touch {
p.Flags |= flagTouchedX p.Flags |= flagTouchedX
} }
} }
if fvy != 0 { if fvy != 0 {
p.Y += int32(mulDiv(fvy, int64(distance), fvDotPv)) p.Y += fixed.Int26_6(mulDiv(fvy, int64(distance), fvDotPv))
if touch { if touch {
p.Flags |= flagTouchedY p.Flags |= flagTouchedY
} }
...@@ -1480,7 +1482,7 @@ func (h *hinter) iupInterp(interpY bool, p1, p2, ref1, ref2 int) { ...@@ -1480,7 +1482,7 @@ func (h *hinter) iupInterp(interpY bool, p1, p2, ref1, ref2 int) {
return return
} }
var ifu1, ifu2 int32 var ifu1, ifu2 fixed.Int26_6
if interpY { if interpY {
ifu1 = h.points[glyphZone][inFontUnits][ref1].Y ifu1 = h.points[glyphZone][inFontUnits][ref1].Y
ifu2 = h.points[glyphZone][inFontUnits][ref2].Y ifu2 = h.points[glyphZone][inFontUnits][ref2].Y
...@@ -1493,7 +1495,7 @@ func (h *hinter) iupInterp(interpY bool, p1, p2, ref1, ref2 int) { ...@@ -1493,7 +1495,7 @@ func (h *hinter) iupInterp(interpY bool, p1, p2, ref1, ref2 int) {
ref1, ref2 = ref2, ref1 ref1, ref2 = ref2, ref1
} }
var unh1, unh2, delta1, delta2 int32 var unh1, unh2, delta1, delta2 fixed.Int26_6
if interpY { if interpY {
unh1 = h.points[glyphZone][unhinted][ref1].Y unh1 = h.points[glyphZone][unhinted][ref1].Y
unh2 = h.points[glyphZone][unhinted][ref2].Y unh2 = h.points[glyphZone][unhinted][ref2].Y
...@@ -1506,7 +1508,7 @@ func (h *hinter) iupInterp(interpY bool, p1, p2, ref1, ref2 int) { ...@@ -1506,7 +1508,7 @@ func (h *hinter) iupInterp(interpY bool, p1, p2, ref1, ref2 int) {
delta2 = h.points[glyphZone][current][ref2].X - unh2 delta2 = h.points[glyphZone][current][ref2].X - unh2
} }
var xy, ifuXY int32 var xy, ifuXY fixed.Int26_6
if ifu1 == ifu2 { if ifu1 == ifu2 {
for i := p1; i <= p2; i++ { for i := p1; i <= p2; i++ {
if interpY { if interpY {
...@@ -1555,7 +1557,7 @@ func (h *hinter) iupInterp(interpY bool, p1, p2, ref1, ref2 int) { ...@@ -1555,7 +1557,7 @@ func (h *hinter) iupInterp(interpY bool, p1, p2, ref1, ref2 int) {
} else { } else {
numer -= 0x8000 numer -= 0x8000
} }
xy = unh1 + delta1 + int32(numer/0x10000) xy = unh1 + delta1 + fixed.Int26_6(numer/0x10000)
} }
if interpY { if interpY {
...@@ -1567,7 +1569,7 @@ func (h *hinter) iupInterp(interpY bool, p1, p2, ref1, ref2 int) { ...@@ -1567,7 +1569,7 @@ func (h *hinter) iupInterp(interpY bool, p1, p2, ref1, ref2 int) {
} }
func (h *hinter) iupShift(interpY bool, p1, p2, p int) { func (h *hinter) iupShift(interpY bool, p1, p2, p int) {
var delta int32 var delta fixed.Int26_6
if interpY { if interpY {
delta = h.points[glyphZone][current][p].Y - h.points[glyphZone][unhinted][p].Y delta = h.points[glyphZone][current][p].Y - h.points[glyphZone][unhinted][p].Y
} else { } else {
......
...@@ -9,6 +9,8 @@ import ( ...@@ -9,6 +9,8 @@ import (
"reflect" "reflect"
"strings" "strings"
"testing" "testing"
"golang.org/x/image/math/fixed"
) )
func TestBytecode(t *testing.T) { func TestBytecode(t *testing.T) {
...@@ -589,7 +591,7 @@ func TestMove(t *testing.T) { ...@@ -589,7 +591,7 @@ func TestMove(t *testing.T) {
h, p := hinter{}, Point{} h, p := hinter{}, Point{}
testCases := []struct { testCases := []struct {
pvX, pvY, fvX, fvY f2dot14 pvX, pvY, fvX, fvY f2dot14
wantX, wantY int32 wantX, wantY fixed.Int26_6
}{ }{
{+0x4000, +0x0000, +0x4000, +0x0000, +1000, +0}, {+0x4000, +0x0000, +0x4000, +0x0000, +1000, +0},
{+0x4000, +0x0000, -0x4000, +0x0000, +1000, +0}, {+0x4000, +0x0000, -0x4000, +0x0000, +1000, +0},
......
...@@ -9,10 +9,9 @@ ...@@ -9,10 +9,9 @@
// //
// Some of a font's methods provide lengths or co-ordinates, e.g. bounds, font // Some of a font's methods provide lengths or co-ordinates, e.g. bounds, font
// metrics and control points. All these methods take a scale parameter, which // metrics and control points. All these methods take a scale parameter, which
// is the number of device units in 1 em. For example, if 1 em is 10 pixels and // is the number of pixels in 1 em, expressed as a 26.6 fixed point value. For
// 1 pixel is 64 units, then scale is 640. If the device space involves pixels, // example, if 1 em is 10 pixels then scale is fixed.I(10), which is equal to
// 64 units per pixel is recommended, since that is what the bytecode hinter // fixed.Int26_6(10 << 6).
// uses when snapping point co-ordinates to the pixel grid.
// //
// To measure a TrueType font in ideal FUnit space, use scale equal to // To measure a TrueType font in ideal FUnit space, use scale equal to
// font.FUnitsPerEm(). // font.FUnitsPerEm().
...@@ -20,6 +19,8 @@ package truetype // import "github.com/golang/freetype/truetype" ...@@ -20,6 +19,8 @@ package truetype // import "github.com/golang/freetype/truetype"
import ( import (
"fmt" "fmt"
"golang.org/x/image/math/fixed"
) )
// An Index is a Font's index of a rune. // An Index is a Font's index of a rune.
...@@ -28,17 +29,17 @@ type Index uint16 ...@@ -28,17 +29,17 @@ type Index uint16
// A Bounds holds the co-ordinate range of one or more glyphs. // A Bounds holds the co-ordinate range of one or more glyphs.
// The endpoints are inclusive. // The endpoints are inclusive.
type Bounds struct { type Bounds struct {
XMin, YMin, XMax, YMax int32 XMin, YMin, XMax, YMax fixed.Int26_6
} }
// An HMetric holds the horizontal metrics of a single glyph. // An HMetric holds the horizontal metrics of a single glyph.
type HMetric struct { type HMetric struct {
AdvanceWidth, LeftSideBearing int32 AdvanceWidth, LeftSideBearing fixed.Int26_6
} }
// A VMetric holds the vertical metrics of a single glyph. // A VMetric holds the vertical metrics of a single glyph.
type VMetric struct { type VMetric struct {
AdvanceHeight, TopSideBearing int32 AdvanceHeight, TopSideBearing fixed.Int26_6
} }
// A FormatError reports that the input is not a valid TrueType font. // A FormatError reports that the input is not a valid TrueType font.
...@@ -226,10 +227,10 @@ func (f *Font) parseHead() error { ...@@ -226,10 +227,10 @@ func (f *Font) parseHead() error {
return FormatError(fmt.Sprintf("bad head length: %d", len(f.head))) return FormatError(fmt.Sprintf("bad head length: %d", len(f.head)))
} }
f.fUnitsPerEm = int32(u16(f.head, 18)) f.fUnitsPerEm = int32(u16(f.head, 18))
f.bounds.XMin = int32(int16(u16(f.head, 36))) f.bounds.XMin = fixed.Int26_6(int16(u16(f.head, 36)))
f.bounds.YMin = int32(int16(u16(f.head, 38))) f.bounds.YMin = fixed.Int26_6(int16(u16(f.head, 38)))
f.bounds.XMax = int32(int16(u16(f.head, 40))) f.bounds.XMax = fixed.Int26_6(int16(u16(f.head, 40)))
f.bounds.YMax = int32(int16(u16(f.head, 42))) f.bounds.YMax = fixed.Int26_6(int16(u16(f.head, 42)))
switch i := u16(f.head, 50); i { switch i := u16(f.head, 50); i {
case 0: case 0:
f.locaOffsetFormat = locaOffsetFormatShort f.locaOffsetFormat = locaOffsetFormatShort
...@@ -306,17 +307,17 @@ func (f *Font) parseMaxp() error { ...@@ -306,17 +307,17 @@ func (f *Font) parseMaxp() error {
} }
// scale returns x divided by f.fUnitsPerEm, rounded to the nearest integer. // scale returns x divided by f.fUnitsPerEm, rounded to the nearest integer.
func (f *Font) scale(x int32) int32 { func (f *Font) scale(x fixed.Int26_6) fixed.Int26_6 {
if x >= 0 { if x >= 0 {
x += f.fUnitsPerEm / 2 x += fixed.Int26_6(f.fUnitsPerEm) / 2
} else { } else {
x -= f.fUnitsPerEm / 2 x -= fixed.Int26_6(f.fUnitsPerEm) / 2
} }
return x / f.fUnitsPerEm return x / fixed.Int26_6(f.fUnitsPerEm)
} }
// Bounds returns the union of a Font's glyphs' bounds. // Bounds returns the union of a Font's glyphs' bounds.
func (f *Font) Bounds(scale int32) Bounds { func (f *Font) Bounds(scale fixed.Int26_6) Bounds {
b := f.bounds b := f.bounds
b.XMin = f.scale(scale * b.XMin) b.XMin = f.scale(scale * b.XMin)
b.YMin = f.scale(scale * b.YMin) b.YMin = f.scale(scale * b.YMin)
...@@ -360,18 +361,18 @@ func (f *Font) unscaledHMetric(i Index) (h HMetric) { ...@@ -360,18 +361,18 @@ func (f *Font) unscaledHMetric(i Index) (h HMetric) {
if j >= f.nHMetric { if j >= f.nHMetric {
p := 4 * (f.nHMetric - 1) p := 4 * (f.nHMetric - 1)
return HMetric{ return HMetric{
AdvanceWidth: int32(u16(f.hmtx, p)), AdvanceWidth: fixed.Int26_6(u16(f.hmtx, p)),
LeftSideBearing: int32(int16(u16(f.hmtx, p+2*(j-f.nHMetric)+4))), LeftSideBearing: fixed.Int26_6(int16(u16(f.hmtx, p+2*(j-f.nHMetric)+4))),
} }
} }
return HMetric{ return HMetric{
AdvanceWidth: int32(u16(f.hmtx, 4*j)), AdvanceWidth: fixed.Int26_6(u16(f.hmtx, 4*j)),
LeftSideBearing: int32(int16(u16(f.hmtx, 4*j+2))), LeftSideBearing: fixed.Int26_6(int16(u16(f.hmtx, 4*j+2))),
} }
} }
// HMetric returns the horizontal metrics for the glyph with the given index. // HMetric returns the horizontal metrics for the glyph with the given index.
func (f *Font) HMetric(scale int32, i Index) HMetric { func (f *Font) HMetric(scale fixed.Int26_6, i Index) HMetric {
h := f.unscaledHMetric(i) h := f.unscaledHMetric(i)
h.AdvanceWidth = f.scale(scale * h.AdvanceWidth) h.AdvanceWidth = f.scale(scale * h.AdvanceWidth)
h.LeftSideBearing = f.scale(scale * h.LeftSideBearing) h.LeftSideBearing = f.scale(scale * h.LeftSideBearing)
...@@ -380,15 +381,15 @@ func (f *Font) HMetric(scale int32, i Index) HMetric { ...@@ -380,15 +381,15 @@ func (f *Font) HMetric(scale int32, i Index) HMetric {
// unscaledVMetric returns the unscaled vertical metrics for the glyph with // unscaledVMetric returns the unscaled vertical metrics for the glyph with
// the given index. yMax is the top of the glyph's bounding box. // the given index. yMax is the top of the glyph's bounding box.
func (f *Font) unscaledVMetric(i Index, yMax int32) (v VMetric) { func (f *Font) unscaledVMetric(i Index, yMax fixed.Int26_6) (v VMetric) {
j := int(i) j := int(i)
if j < 0 || f.nGlyph <= j { if j < 0 || f.nGlyph <= j {
return VMetric{} return VMetric{}
} }
if 4*j+4 <= len(f.vmtx) { if 4*j+4 <= len(f.vmtx) {
return VMetric{ return VMetric{
AdvanceHeight: int32(u16(f.vmtx, 4*j)), AdvanceHeight: fixed.Int26_6(u16(f.vmtx, 4*j)),
TopSideBearing: int32(int16(u16(f.vmtx, 4*j+2))), TopSideBearing: fixed.Int26_6(int16(u16(f.vmtx, 4*j+2))),
} }
} }
// The OS/2 table has grown over time. // The OS/2 table has grown over time.
...@@ -397,21 +398,21 @@ func (f *Font) unscaledVMetric(i Index, yMax int32) (v VMetric) { ...@@ -397,21 +398,21 @@ func (f *Font) unscaledVMetric(i Index, yMax int32) (v VMetric) {
// the ascender and descender, are described at // the ascender and descender, are described at
// http://www.microsoft.com/typography/otspec/os2.htm // http://www.microsoft.com/typography/otspec/os2.htm
if len(f.os2) >= 72 { if len(f.os2) >= 72 {
sTypoAscender := int32(int16(u16(f.os2, 68))) sTypoAscender := fixed.Int26_6(int16(u16(f.os2, 68)))
sTypoDescender := int32(int16(u16(f.os2, 70))) sTypoDescender := fixed.Int26_6(int16(u16(f.os2, 70)))
return VMetric{ return VMetric{
AdvanceHeight: sTypoAscender - sTypoDescender, AdvanceHeight: sTypoAscender - sTypoDescender,
TopSideBearing: sTypoAscender - yMax, TopSideBearing: sTypoAscender - yMax,
} }
} }
return VMetric{ return VMetric{
AdvanceHeight: f.fUnitsPerEm, AdvanceHeight: fixed.Int26_6(f.fUnitsPerEm),
TopSideBearing: 0, TopSideBearing: 0,
} }
} }
// VMetric returns the vertical metrics for the glyph with the given index. // VMetric returns the vertical metrics for the glyph with the given index.
func (f *Font) VMetric(scale int32, i Index) VMetric { func (f *Font) VMetric(scale fixed.Int26_6, i Index) VMetric {
// TODO: should 0 be bounds.YMax? // TODO: should 0 be bounds.YMax?
v := f.unscaledVMetric(i, 0) v := f.unscaledVMetric(i, 0)
v.AdvanceHeight = f.scale(scale * v.AdvanceHeight) v.AdvanceHeight = f.scale(scale * v.AdvanceHeight)
...@@ -420,7 +421,7 @@ func (f *Font) VMetric(scale int32, i Index) VMetric { ...@@ -420,7 +421,7 @@ func (f *Font) VMetric(scale int32, i Index) VMetric {
} }
// Kerning returns the kerning for the given glyph pair. // Kerning returns the kerning for the given glyph pair.
func (f *Font) Kerning(scale int32, i0, i1 Index) int32 { func (f *Font) Kerning(scale fixed.Int26_6, i0, i1 Index) fixed.Int26_6 {
if f.nKern == 0 { if f.nKern == 0 {
return 0 return 0
} }
...@@ -434,7 +435,7 @@ func (f *Font) Kerning(scale int32, i0, i1 Index) int32 { ...@@ -434,7 +435,7 @@ func (f *Font) Kerning(scale int32, i0, i1 Index) int32 {
} else if ig > g { } else if ig > g {
hi = i hi = i
} else { } else {
return f.scale(scale * int32(int16(u16(f.kern, 22+6*i)))) return f.scale(scale * fixed.Int26_6(int16(u16(f.kern, 22+6*i))))
} }
} }
return 0 return 0
......
...@@ -14,6 +14,8 @@ import ( ...@@ -14,6 +14,8 @@ import (
"strconv" "strconv"
"strings" "strings"
"testing" "testing"
"golang.org/x/image/math/fixed"
) )
func parseTestdataFont(name string) (font *Font, testdataIsOptional bool, err error) { func parseTestdataFont(name string) (font *Font, testdataIsOptional bool, err error) {
...@@ -40,7 +42,7 @@ func TestParse(t *testing.T) { ...@@ -40,7 +42,7 @@ func TestParse(t *testing.T) {
if got, want := font.FUnitsPerEm(), int32(2048); got != want { if got, want := font.FUnitsPerEm(), int32(2048); got != want {
t.Errorf("FUnitsPerEm: got %v, want %v", got, want) t.Errorf("FUnitsPerEm: got %v, want %v", got, want)
} }
fupe := font.FUnitsPerEm() fupe := fixed.Int26_6(font.FUnitsPerEm())
if got, want := font.Bounds(fupe), (Bounds{-441, -432, 2024, 2033}); got != want { if got, want := font.Bounds(fupe), (Bounds{-441, -432, 2024, 2033}); got != want {
t.Errorf("Bounds: got %v, want %v", got, want) t.Errorf("Bounds: got %v, want %v", got, want)
} }
...@@ -56,7 +58,7 @@ func TestParse(t *testing.T) { ...@@ -56,7 +58,7 @@ func TestParse(t *testing.T) {
if got, want := font.VMetric(fupe, i0), (VMetric{2465, 553}); got != want { if got, want := font.VMetric(fupe, i0), (VMetric{2465, 553}); got != want {
t.Errorf("VMetric: got %v, want %v", got, want) t.Errorf("VMetric: got %v, want %v", got, want)
} }
if got, want := font.Kerning(fupe, i0, i1), int32(-144); got != want { if got, want := font.Kerning(fupe, i0, i1), fixed.Int26_6(-144); got != want {
t.Errorf("Kerning: got %v, want %v", got, want) t.Errorf("Kerning: got %v, want %v", got, want)
} }
...@@ -196,7 +198,7 @@ func TestIndex(t *testing.T) { ...@@ -196,7 +198,7 @@ func TestIndex(t *testing.T) {
} }
type scalingTestData struct { type scalingTestData struct {
advanceWidth int32 advanceWidth fixed.Int26_6
bounds Bounds bounds Bounds
points []Point points []Point
} }
...@@ -205,13 +207,13 @@ type scalingTestData struct { ...@@ -205,13 +207,13 @@ type scalingTestData struct {
// 213 -22 -111 236 555;-22 -111 1, 178 555 1, 236 555 1, 36 -111 1 // 213 -22 -111 236 555;-22 -111 1, 178 555 1, 236 555 1, 36 -111 1
// The line will not have a trailing "\n". // The line will not have a trailing "\n".
func scalingTestParse(line string) (ret scalingTestData) { func scalingTestParse(line string) (ret scalingTestData) {
next := func(s string) (string, int32) { next := func(s string) (string, fixed.Int26_6) {
t, i := "", strings.Index(s, " ") t, i := "", strings.Index(s, " ")
if i != -1 { if i != -1 {
s, t = s[:i], s[i+1:] s, t = s[:i], s[i+1:]
} }
x, _ := strconv.Atoi(s) x, _ := strconv.Atoi(s)
return t, int32(x) return t, fixed.Int26_6(x)
} }
i := strings.Index(line, ";") i := strings.Index(line, ";")
...@@ -257,7 +259,7 @@ func scalingTestEquals(a, b []Point) (index int, equals bool) { ...@@ -257,7 +259,7 @@ func scalingTestEquals(a, b []Point) (index int, equals bool) {
var scalingTestCases = []struct { var scalingTestCases = []struct {
name string name string
size int32 size int
}{ }{
{"luxisr", 12}, {"luxisr", 12},
{"x-arial-bold", 11}, {"x-arial-bold", 11},
...@@ -318,7 +320,7 @@ func testScaling(t *testing.T, h Hinting) { ...@@ -318,7 +320,7 @@ func testScaling(t *testing.T, h Hinting) {
glyphBuf := NewGlyphBuf() glyphBuf := NewGlyphBuf()
for i, want := range wants { for i, want := range wants {
if err = glyphBuf.Load(font, tc.size*64, Index(i), h); err != nil { if err = glyphBuf.Load(font, fixed.I(tc.size), Index(i), h); err != nil {
t.Errorf("%s: glyph #%d: Load: %v", tc.name, i, err) t.Errorf("%s: glyph #%d: Load: %v", tc.name, i, err)
continue continue
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册