Use the fixed.Int26_6 type in package truetype.
This commit is contained in:
parent
a9554eda48
commit
2a5cbfd47e
8 changed files with 117 additions and 103 deletions
|
@ -116,14 +116,14 @@ func main() {
|
|||
}
|
||||
|
||||
// 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 {
|
||||
_, err = c.DrawString(s, pt)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
pt.Y += c.PointToFix32(*size * *spacing)
|
||||
pt.Y += c.PointToFixed(*size * *spacing)
|
||||
}
|
||||
|
||||
// Save that RGBA image to disk.
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"log"
|
||||
|
||||
"github.com/golang/freetype/truetype"
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
var fontfile = flag.String("fontfile", "../../testdata/luxisr.ttf", "filename of the ttf font")
|
||||
|
@ -56,7 +57,7 @@ func main() {
|
|||
log.Println(err)
|
||||
return
|
||||
}
|
||||
fupe := font.FUnitsPerEm()
|
||||
fupe := fixed.Int26_6(font.FUnitsPerEm())
|
||||
printBounds(font.Bounds(fupe))
|
||||
fmt.Printf("FUnitsPerEm:%d\n\n", fupe)
|
||||
|
||||
|
|
10
freetype.go
10
freetype.go
|
@ -78,15 +78,15 @@ type Context struct {
|
|||
// 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.
|
||||
fontSize, dpi float64
|
||||
scale int32
|
||||
scale fixed.Int26_6
|
||||
hinting Hinting
|
||||
// cache is the glyph cache.
|
||||
cache [nGlyphs * nXFractions * nYFractions]cacheEntry
|
||||
}
|
||||
|
||||
// PointToFix32 converts the given number of points (as in ``a 12 point font'')
|
||||
// into fixed point units.
|
||||
func (c *Context) PointToFix32(x float64) fixed.Int26_6 {
|
||||
// PointToFixed converts the given number of points (as in ``a 12 point font'')
|
||||
// into a 26.6 fixed point number of pixels.
|
||||
func (c *Context) PointToFixed(x float64) fixed.Int26_6 {
|
||||
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
|
|||
// recalc recalculates scale and bounds values from the font size, screen
|
||||
// resolution and font metrics, and invalidates the glyph cache.
|
||||
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 {
|
||||
c.r.SetBounds(0, 0)
|
||||
} else {
|
||||
|
|
|
@ -5,8 +5,12 @@
|
|||
|
||||
package truetype
|
||||
|
||||
import (
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
// Hinting is the policy for snapping a glyph's contours to pixel boundaries.
|
||||
type Hinting int32
|
||||
type Hinting uint32
|
||||
|
||||
const (
|
||||
// NoHinting means to not perform any hinting.
|
||||
|
@ -20,7 +24,7 @@ const (
|
|||
// A Point is a co-ordinate pair plus whether it is ``on'' a contour or an
|
||||
// ``off'' control point.
|
||||
type Point struct {
|
||||
X, Y int32
|
||||
X, Y fixed.Int26_6
|
||||
// The Flags' LSB means whether or not this Point is ``on'' the contour.
|
||||
// Other bits are reserved for internal use.
|
||||
Flags uint32
|
||||
|
@ -30,7 +34,7 @@ type Point struct {
|
|||
// series of glyphs from a Font.
|
||||
type GlyphBuf struct {
|
||||
// AdvanceWidth is the glyph's advance width.
|
||||
AdvanceWidth int32
|
||||
AdvanceWidth fixed.Int26_6
|
||||
// B is the glyph's bounding box.
|
||||
B Bounds
|
||||
// Point contains all Points from all contours of the glyph. If
|
||||
|
@ -45,7 +49,7 @@ type GlyphBuf struct {
|
|||
End []int
|
||||
|
||||
font *Font
|
||||
scale int32
|
||||
scale fixed.Int26_6
|
||||
hinting Hinting
|
||||
hinter hinter
|
||||
// phantomPoints are the co-ordinates of the synthetic phantom points
|
||||
|
@ -54,7 +58,7 @@ type GlyphBuf struct {
|
|||
// 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.
|
||||
// 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
|
||||
// compound glyph, a sub-glyph may override the outer glyph's metrics.
|
||||
metricsSet bool
|
||||
|
@ -84,10 +88,10 @@ const (
|
|||
flagThisYIsSame = flagPositiveYShortVector
|
||||
)
|
||||
|
||||
// Load loads a glyph's contours from a Font, overwriting any previously
|
||||
// loaded contours for this GlyphBuf. scale is the number of 26.6 fixed point
|
||||
// units in 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 {
|
||||
// Load loads a glyph's contours from a Font, overwriting any previously loaded
|
||||
// contours for this GlyphBuf. scale is the number of 26.6 fixed point units in
|
||||
// 1 em, i is the glyph index, and h is the hinting policy.
|
||||
func (g *GlyphBuf) Load(f *Font, scale fixed.Int26_6, i Index, h Hinting) error {
|
||||
g.Point = g.Point[:0]
|
||||
g.Unhinted = g.Unhinted[:0]
|
||||
g.InFontUnits = g.InFontUnits[:0]
|
||||
|
@ -125,8 +129,8 @@ func (g *GlyphBuf) Load(f *Font, scale int32, i Index, h Hinting) error {
|
|||
if len(f.hdmx) >= 8 {
|
||||
if n := u32(f.hdmx, 4); n > 3+uint32(i) {
|
||||
for hdmx := f.hdmx[8:]; uint32(len(hdmx)) >= n; hdmx = hdmx[n:] {
|
||||
if int32(hdmx[0]) == scale>>6 {
|
||||
advanceWidth = int32(hdmx[2+i]) << 6
|
||||
if fixed.Int26_6(hdmx[0]) == scale>>6 {
|
||||
advanceWidth = fixed.Int26_6(hdmx[2+i]) << 6
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -175,7 +179,7 @@ func (g *GlyphBuf) Load(f *Font, scale int32, i Index, h Hinting) error {
|
|||
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.
|
||||
if recursion >= 32 {
|
||||
return UnsupportedError("excessive compound glyph recursion")
|
||||
|
@ -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
|
||||
// 10 bytes of the glyf data. boundsYMin and boundsXMax, at offsets 4
|
||||
// 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 {
|
||||
glyf = g.font.glyf[g0:g1]
|
||||
ne = int(int16(u16(glyf, 0)))
|
||||
boundsXMin = int32(int16(u16(glyf, 2)))
|
||||
boundsYMax = int32(int16(u16(glyf, 8)))
|
||||
boundsXMin = fixed.Int26_6(int16(u16(glyf, 2)))
|
||||
boundsYMax = fixed.Int26_6(int16(u16(glyf, 8)))
|
||||
}
|
||||
|
||||
// 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)
|
||||
g.phantomPoints = [4]Point{
|
||||
{X: boundsXMin - uhm.LeftSideBearing},
|
||||
|
@ -322,7 +326,7 @@ func (g *GlyphBuf) loadSimple(glyf []byte, ne int) (program []byte) {
|
|||
x += int16(u16(glyf, offset))
|
||||
offset += 2
|
||||
}
|
||||
g.Point[i].X = int32(x)
|
||||
g.Point[i].X = fixed.Int26_6(x)
|
||||
}
|
||||
var y int16
|
||||
for i := np0; i < np1; i++ {
|
||||
|
@ -339,13 +343,13 @@ func (g *GlyphBuf) loadSimple(glyf []byte, ne int) (program []byte) {
|
|||
y += int16(u16(glyf, offset))
|
||||
offset += 2
|
||||
}
|
||||
g.Point[i].Y = int32(y)
|
||||
g.Point[i].Y = fixed.Int26_6(y)
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
// 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,
|
|||
for {
|
||||
flags := u16(glyf, offset)
|
||||
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 {
|
||||
dx = int32(int16(u16(glyf, offset+4)))
|
||||
dy = int32(int16(u16(glyf, offset+6)))
|
||||
dx = fixed.Int26_6(int16(u16(glyf, offset+4)))
|
||||
dy = fixed.Int26_6(int16(u16(glyf, offset+6)))
|
||||
offset += 8
|
||||
} else {
|
||||
dx = int32(int16(int8(glyf[offset+4])))
|
||||
dy = int32(int16(int8(glyf[offset+5])))
|
||||
dx = fixed.Int26_6(int16(int8(glyf[offset+4])))
|
||||
dy = fixed.Int26_6(int16(int8(glyf[offset+5])))
|
||||
offset += 6
|
||||
}
|
||||
if flags&flagArgsAreXYValues == 0 {
|
||||
|
@ -385,18 +389,18 @@ func (g *GlyphBuf) loadCompound(recursion int32, uhm HMetric, i Index,
|
|||
hasTransform = true
|
||||
switch {
|
||||
case flags&flagWeHaveAScale != 0:
|
||||
transform[0] = int32(int16(u16(glyf, offset+0)))
|
||||
transform[0] = int16(u16(glyf, offset+0))
|
||||
transform[3] = transform[0]
|
||||
offset += 2
|
||||
case flags&flagWeHaveAnXAndYScale != 0:
|
||||
transform[0] = int32(int16(u16(glyf, offset+0)))
|
||||
transform[3] = int32(int16(u16(glyf, offset+2)))
|
||||
transform[0] = int16(u16(glyf, offset+0))
|
||||
transform[3] = int16(u16(glyf, offset+2))
|
||||
offset += 4
|
||||
case flags&flagWeHaveATwoByTwo != 0:
|
||||
transform[0] = int32(int16(u16(glyf, offset+0)))
|
||||
transform[1] = int32(int16(u16(glyf, offset+2)))
|
||||
transform[2] = int32(int16(u16(glyf, offset+4)))
|
||||
transform[3] = int32(int16(u16(glyf, offset+6)))
|
||||
transform[0] = int16(u16(glyf, offset+0))
|
||||
transform[1] = int16(u16(glyf, offset+2))
|
||||
transform[2] = int16(u16(glyf, offset+4))
|
||||
transform[3] = int16(u16(glyf, offset+6))
|
||||
offset += 8
|
||||
}
|
||||
}
|
||||
|
@ -412,10 +416,12 @@ func (g *GlyphBuf) loadCompound(recursion int32, uhm HMetric, i Index,
|
|||
if hasTransform {
|
||||
for j := np0; j < len(g.Point); j++ {
|
||||
p := &g.Point[j]
|
||||
newX := int32((int64(p.X)*int64(transform[0])+1<<13)>>14) +
|
||||
int32((int64(p.Y)*int64(transform[2])+1<<13)>>14)
|
||||
newY := int32((int64(p.X)*int64(transform[1])+1<<13)>>14) +
|
||||
int32((int64(p.Y)*int64(transform[3])+1<<13)>>14)
|
||||
newX := 0 +
|
||||
fixed.Int26_6((int64(p.X)*int64(transform[0])+1<<13)>>14) +
|
||||
fixed.Int26_6((int64(p.Y)*int64(transform[2])+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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ package truetype
|
|||
import (
|
||||
"errors"
|
||||
"math"
|
||||
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -47,7 +49,7 @@ type hinter struct {
|
|||
// Changing the font will require running the new font's fpgm bytecode.
|
||||
// Changing either will require running the font's prep bytecode.
|
||||
font *Font
|
||||
scale int32
|
||||
scale fixed.Int26_6
|
||||
|
||||
// gs and defaultGS are the current and default graphics state. The
|
||||
// default graphics state is the global default graphics state after
|
||||
|
@ -113,7 +115,7 @@ func resetTwilightPoints(f *Font, p []Point) []Point {
|
|||
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][1] = resetTwilightPoints(f, h.points[twilightZone][1])
|
||||
h.points[twilightZone][2] = resetTwilightPoints(f, h.points[twilightZone][2])
|
||||
|
@ -315,8 +317,8 @@ func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point,
|
|||
mulDiv(int64(dy), int64(dbx), 0x40)
|
||||
rx := mulDiv(val, int64(dax), discriminant)
|
||||
ry := mulDiv(val, int64(day), discriminant)
|
||||
p.X = a0.X + int32(rx)
|
||||
p.Y = a0.Y + int32(ry)
|
||||
p.X = a0.X + fixed.Int26_6(rx)
|
||||
p.Y = a0.Y + fixed.Int26_6(ry)
|
||||
} else {
|
||||
p.X = (a0.X + a1.X + b0.X + b1.X) / 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,
|
|||
|
||||
case opSSW:
|
||||
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:
|
||||
if top >= len(h.stack) {
|
||||
|
@ -711,8 +713,8 @@ func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point,
|
|||
if h.gs.zp[0] == 0 {
|
||||
p := h.point(0, unhinted, i)
|
||||
q := h.point(0, current, i)
|
||||
p.X = int32((int64(distance) * int64(h.gs.fv[0])) >> 14)
|
||||
p.Y = int32((int64(distance) * int64(h.gs.fv[1])) >> 14)
|
||||
p.X = fixed.Int26_6((int64(distance) * int64(h.gs.fv[0])) >> 14)
|
||||
p.Y = fixed.Int26_6((int64(distance) * int64(h.gs.fv[1])) >> 14)
|
||||
*q = *p
|
||||
}
|
||||
p := h.point(0, current, i)
|
||||
|
@ -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))
|
||||
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
|
||||
|
||||
|
@ -818,7 +820,7 @@ func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point,
|
|||
return errors.New("truetype: hinting: stack overflow")
|
||||
}
|
||||
// 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++
|
||||
|
||||
case opFLIPON, opFLIPOFF:
|
||||
|
@ -935,7 +937,7 @@ func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point,
|
|||
|
||||
case opWCVTF:
|
||||
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:
|
||||
goto delta
|
||||
|
@ -1144,7 +1146,7 @@ func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point,
|
|||
p0 := h.point(1, inFontUnits, i)
|
||||
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 = f26dot6(h.font.scale(h.scale * int32(oldDist)))
|
||||
oldDist = f26dot6(h.font.scale(h.scale * fixed.Int26_6(oldDist)))
|
||||
}
|
||||
|
||||
// Single-width cut-in test.
|
||||
|
@ -1358,7 +1360,7 @@ func (h *hinter) run(program []byte, pCurrent, pUnhinted, pInFontUnits []Point,
|
|||
c += 32
|
||||
}
|
||||
c += h.gs.deltaBase
|
||||
if ppem := (h.scale + 1<<5) >> 6; ppem != c {
|
||||
if ppem := (int32(h.scale) + 1<<5) >> 6; ppem != c {
|
||||
continue
|
||||
}
|
||||
b = (b & 0x0f) - 8
|
||||
|
@ -1399,7 +1401,7 @@ func (h *hinter) initializeScaledCVT() {
|
|||
}
|
||||
for i := range h.scaledCVT {
|
||||
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) {
|
|||
fvx := int64(h.gs.fv[0])
|
||||
pvx := int64(h.gs.pv[0])
|
||||
if fvx == 0x4000 && pvx == 0x4000 {
|
||||
p.X += int32(distance)
|
||||
p.X += fixed.Int26_6(distance)
|
||||
if touch {
|
||||
p.Flags |= flagTouchedX
|
||||
}
|
||||
|
@ -1447,7 +1449,7 @@ func (h *hinter) move(p *Point, distance f26dot6, touch bool) {
|
|||
fvy := int64(h.gs.fv[1])
|
||||
pvy := int64(h.gs.pv[1])
|
||||
if fvy == 0x4000 && pvy == 0x4000 {
|
||||
p.Y += int32(distance)
|
||||
p.Y += fixed.Int26_6(distance)
|
||||
if touch {
|
||||
p.Flags |= flagTouchedY
|
||||
}
|
||||
|
@ -1457,14 +1459,14 @@ func (h *hinter) move(p *Point, distance f26dot6, touch bool) {
|
|||
fvDotPv := (fvx*pvx + fvy*pvy) >> 14
|
||||
|
||||
if fvx != 0 {
|
||||
p.X += int32(mulDiv(fvx, int64(distance), fvDotPv))
|
||||
p.X += fixed.Int26_6(mulDiv(fvx, int64(distance), fvDotPv))
|
||||
if touch {
|
||||
p.Flags |= flagTouchedX
|
||||
}
|
||||
}
|
||||
|
||||
if fvy != 0 {
|
||||
p.Y += int32(mulDiv(fvy, int64(distance), fvDotPv))
|
||||
p.Y += fixed.Int26_6(mulDiv(fvy, int64(distance), fvDotPv))
|
||||
if touch {
|
||||
p.Flags |= flagTouchedY
|
||||
}
|
||||
|
@ -1480,7 +1482,7 @@ func (h *hinter) iupInterp(interpY bool, p1, p2, ref1, ref2 int) {
|
|||
return
|
||||
}
|
||||
|
||||
var ifu1, ifu2 int32
|
||||
var ifu1, ifu2 fixed.Int26_6
|
||||
if interpY {
|
||||
ifu1 = h.points[glyphZone][inFontUnits][ref1].Y
|
||||
ifu2 = h.points[glyphZone][inFontUnits][ref2].Y
|
||||
|
@ -1493,7 +1495,7 @@ func (h *hinter) iupInterp(interpY bool, p1, p2, ref1, ref2 int) {
|
|||
ref1, ref2 = ref2, ref1
|
||||
}
|
||||
|
||||
var unh1, unh2, delta1, delta2 int32
|
||||
var unh1, unh2, delta1, delta2 fixed.Int26_6
|
||||
if interpY {
|
||||
unh1 = h.points[glyphZone][unhinted][ref1].Y
|
||||
unh2 = h.points[glyphZone][unhinted][ref2].Y
|
||||
|
@ -1506,7 +1508,7 @@ func (h *hinter) iupInterp(interpY bool, p1, p2, ref1, ref2 int) {
|
|||
delta2 = h.points[glyphZone][current][ref2].X - unh2
|
||||
}
|
||||
|
||||
var xy, ifuXY int32
|
||||
var xy, ifuXY fixed.Int26_6
|
||||
if ifu1 == ifu2 {
|
||||
for i := p1; i <= p2; i++ {
|
||||
if interpY {
|
||||
|
@ -1555,7 +1557,7 @@ func (h *hinter) iupInterp(interpY bool, p1, p2, ref1, ref2 int) {
|
|||
} else {
|
||||
numer -= 0x8000
|
||||
}
|
||||
xy = unh1 + delta1 + int32(numer/0x10000)
|
||||
xy = unh1 + delta1 + fixed.Int26_6(numer/0x10000)
|
||||
}
|
||||
|
||||
if interpY {
|
||||
|
@ -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) {
|
||||
var delta int32
|
||||
var delta fixed.Int26_6
|
||||
if interpY {
|
||||
delta = h.points[glyphZone][current][p].Y - h.points[glyphZone][unhinted][p].Y
|
||||
} else {
|
||||
|
|
|
@ -9,6 +9,8 @@ import (
|
|||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
func TestBytecode(t *testing.T) {
|
||||
|
@ -589,7 +591,7 @@ func TestMove(t *testing.T) {
|
|||
h, p := hinter{}, Point{}
|
||||
testCases := []struct {
|
||||
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},
|
||||
|
|
|
@ -9,10 +9,9 @@
|
|||
//
|
||||
// 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
|
||||
// is the number of device units in 1 em. For example, if 1 em is 10 pixels and
|
||||
// 1 pixel is 64 units, then scale is 640. If the device space involves pixels,
|
||||
// 64 units per pixel is recommended, since that is what the bytecode hinter
|
||||
// uses when snapping point co-ordinates to the pixel grid.
|
||||
// is the number of pixels in 1 em, expressed as a 26.6 fixed point value. For
|
||||
// example, if 1 em is 10 pixels then scale is fixed.I(10), which is equal to
|
||||
// fixed.Int26_6(10 << 6).
|
||||
//
|
||||
// To measure a TrueType font in ideal FUnit space, use scale equal to
|
||||
// font.FUnitsPerEm().
|
||||
|
@ -20,6 +19,8 @@ package truetype // import "github.com/golang/freetype/truetype"
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
// An Index is a Font's index of a rune.
|
||||
|
@ -28,17 +29,17 @@ type Index uint16
|
|||
// A Bounds holds the co-ordinate range of one or more glyphs.
|
||||
// The endpoints are inclusive.
|
||||
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.
|
||||
type HMetric struct {
|
||||
AdvanceWidth, LeftSideBearing int32
|
||||
AdvanceWidth, LeftSideBearing fixed.Int26_6
|
||||
}
|
||||
|
||||
// A VMetric holds the vertical metrics of a single glyph.
|
||||
type VMetric struct {
|
||||
AdvanceHeight, TopSideBearing int32
|
||||
AdvanceHeight, TopSideBearing fixed.Int26_6
|
||||
}
|
||||
|
||||
// A FormatError reports that the input is not a valid TrueType font.
|
||||
|
@ -226,10 +227,10 @@ func (f *Font) parseHead() error {
|
|||
return FormatError(fmt.Sprintf("bad head length: %d", len(f.head)))
|
||||
}
|
||||
f.fUnitsPerEm = int32(u16(f.head, 18))
|
||||
f.bounds.XMin = int32(int16(u16(f.head, 36)))
|
||||
f.bounds.YMin = int32(int16(u16(f.head, 38)))
|
||||
f.bounds.XMax = int32(int16(u16(f.head, 40)))
|
||||
f.bounds.YMax = int32(int16(u16(f.head, 42)))
|
||||
f.bounds.XMin = fixed.Int26_6(int16(u16(f.head, 36)))
|
||||
f.bounds.YMin = fixed.Int26_6(int16(u16(f.head, 38)))
|
||||
f.bounds.XMax = fixed.Int26_6(int16(u16(f.head, 40)))
|
||||
f.bounds.YMax = fixed.Int26_6(int16(u16(f.head, 42)))
|
||||
switch i := u16(f.head, 50); i {
|
||||
case 0:
|
||||
f.locaOffsetFormat = locaOffsetFormatShort
|
||||
|
@ -306,17 +307,17 @@ func (f *Font) parseMaxp() error {
|
|||
}
|
||||
|
||||
// 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 {
|
||||
x += f.fUnitsPerEm / 2
|
||||
x += fixed.Int26_6(f.fUnitsPerEm) / 2
|
||||
} 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.
|
||||
func (f *Font) Bounds(scale int32) Bounds {
|
||||
func (f *Font) Bounds(scale fixed.Int26_6) Bounds {
|
||||
b := f.bounds
|
||||
b.XMin = f.scale(scale * b.XMin)
|
||||
b.YMin = f.scale(scale * b.YMin)
|
||||
|
@ -360,18 +361,18 @@ func (f *Font) unscaledHMetric(i Index) (h HMetric) {
|
|||
if j >= f.nHMetric {
|
||||
p := 4 * (f.nHMetric - 1)
|
||||
return HMetric{
|
||||
AdvanceWidth: int32(u16(f.hmtx, p)),
|
||||
LeftSideBearing: int32(int16(u16(f.hmtx, p+2*(j-f.nHMetric)+4))),
|
||||
AdvanceWidth: fixed.Int26_6(u16(f.hmtx, p)),
|
||||
LeftSideBearing: fixed.Int26_6(int16(u16(f.hmtx, p+2*(j-f.nHMetric)+4))),
|
||||
}
|
||||
}
|
||||
return HMetric{
|
||||
AdvanceWidth: int32(u16(f.hmtx, 4*j)),
|
||||
LeftSideBearing: int32(int16(u16(f.hmtx, 4*j+2))),
|
||||
AdvanceWidth: fixed.Int26_6(u16(f.hmtx, 4*j)),
|
||||
LeftSideBearing: fixed.Int26_6(int16(u16(f.hmtx, 4*j+2))),
|
||||
}
|
||||
}
|
||||
|
||||
// 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.AdvanceWidth = f.scale(scale * h.AdvanceWidth)
|
||||
h.LeftSideBearing = f.scale(scale * h.LeftSideBearing)
|
||||
|
@ -380,15 +381,15 @@ func (f *Font) HMetric(scale int32, i Index) HMetric {
|
|||
|
||||
// unscaledVMetric returns the unscaled vertical metrics for the glyph with
|
||||
// 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)
|
||||
if j < 0 || f.nGlyph <= j {
|
||||
return VMetric{}
|
||||
}
|
||||
if 4*j+4 <= len(f.vmtx) {
|
||||
return VMetric{
|
||||
AdvanceHeight: int32(u16(f.vmtx, 4*j)),
|
||||
TopSideBearing: int32(int16(u16(f.vmtx, 4*j+2))),
|
||||
AdvanceHeight: fixed.Int26_6(u16(f.vmtx, 4*j)),
|
||||
TopSideBearing: fixed.Int26_6(int16(u16(f.vmtx, 4*j+2))),
|
||||
}
|
||||
}
|
||||
// The OS/2 table has grown over time.
|
||||
|
@ -397,21 +398,21 @@ func (f *Font) unscaledVMetric(i Index, yMax int32) (v VMetric) {
|
|||
// the ascender and descender, are described at
|
||||
// http://www.microsoft.com/typography/otspec/os2.htm
|
||||
if len(f.os2) >= 72 {
|
||||
sTypoAscender := int32(int16(u16(f.os2, 68)))
|
||||
sTypoDescender := int32(int16(u16(f.os2, 70)))
|
||||
sTypoAscender := fixed.Int26_6(int16(u16(f.os2, 68)))
|
||||
sTypoDescender := fixed.Int26_6(int16(u16(f.os2, 70)))
|
||||
return VMetric{
|
||||
AdvanceHeight: sTypoAscender - sTypoDescender,
|
||||
TopSideBearing: sTypoAscender - yMax,
|
||||
}
|
||||
}
|
||||
return VMetric{
|
||||
AdvanceHeight: f.fUnitsPerEm,
|
||||
AdvanceHeight: fixed.Int26_6(f.fUnitsPerEm),
|
||||
TopSideBearing: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// 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?
|
||||
v := f.unscaledVMetric(i, 0)
|
||||
v.AdvanceHeight = f.scale(scale * v.AdvanceHeight)
|
||||
|
@ -420,7 +421,7 @@ func (f *Font) VMetric(scale int32, i Index) VMetric {
|
|||
}
|
||||
|
||||
// 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 {
|
||||
return 0
|
||||
}
|
||||
|
@ -434,7 +435,7 @@ func (f *Font) Kerning(scale int32, i0, i1 Index) int32 {
|
|||
} else if ig > g {
|
||||
hi = i
|
||||
} 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
|
||||
|
|
|
@ -14,6 +14,8 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
func parseTestdataFont(name string) (font *Font, testdataIsOptional bool, err error) {
|
||||
|
@ -40,7 +42,7 @@ func TestParse(t *testing.T) {
|
|||
if got, want := font.FUnitsPerEm(), int32(2048); 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 {
|
||||
t.Errorf("Bounds: got %v, want %v", got, want)
|
||||
}
|
||||
|
@ -56,7 +58,7 @@ func TestParse(t *testing.T) {
|
|||
if got, want := font.VMetric(fupe, i0), (VMetric{2465, 553}); 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)
|
||||
}
|
||||
|
||||
|
@ -196,7 +198,7 @@ func TestIndex(t *testing.T) {
|
|||
}
|
||||
|
||||
type scalingTestData struct {
|
||||
advanceWidth int32
|
||||
advanceWidth fixed.Int26_6
|
||||
bounds Bounds
|
||||
points []Point
|
||||
}
|
||||
|
@ -205,13 +207,13 @@ type scalingTestData struct {
|
|||
// 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".
|
||||
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, " ")
|
||||
if i != -1 {
|
||||
s, t = s[:i], s[i+1:]
|
||||
}
|
||||
x, _ := strconv.Atoi(s)
|
||||
return t, int32(x)
|
||||
return t, fixed.Int26_6(x)
|
||||
}
|
||||
|
||||
i := strings.Index(line, ";")
|
||||
|
@ -257,7 +259,7 @@ func scalingTestEquals(a, b []Point) (index int, equals bool) {
|
|||
|
||||
var scalingTestCases = []struct {
|
||||
name string
|
||||
size int32
|
||||
size int
|
||||
}{
|
||||
{"luxisr", 12},
|
||||
{"x-arial-bold", 11},
|
||||
|
@ -318,7 +320,7 @@ func testScaling(t *testing.T, h Hinting) {
|
|||
|
||||
glyphBuf := NewGlyphBuf()
|
||||
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)
|
||||
continue
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue