freetype: move the scaling from FUnits to pixels from package freetype
to package truetype. R=bsiegert CC=golang-dev http://codereview.appspot.com/6427062
This commit is contained in:
parent
f2517f3940
commit
28cc5fbc5d
8 changed files with 126 additions and 116 deletions
|
@ -21,7 +21,7 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
dpi = flag.Int("dpi", 72, "screen resolution in Dots Per Inch")
|
||||
dpi = flag.Float64("dpi", 72, "screen resolution in Dots Per Inch")
|
||||
fontfile = flag.String("fontfile", "../../luxi-fonts/luxisr.ttf", "filename of the ttf font")
|
||||
size = flag.Float64("size", 12, "font size in points")
|
||||
spacing = flag.Float64("spacing", 1.5, "line spacing (e.g. 2 means double spaced)")
|
||||
|
@ -104,7 +104,7 @@ func main() {
|
|||
}
|
||||
|
||||
// Draw the text.
|
||||
pt := freetype.Pt(10, 10+c.FUnitToPixelRU(font.UnitsPerEm()))
|
||||
pt := freetype.Pt(10, 10+int(c.PointToFix32(*size)>>8))
|
||||
for _, s := range text {
|
||||
_, err = c.DrawString(s, pt)
|
||||
if err != nil {
|
||||
|
|
|
@ -51,15 +51,16 @@ func main() {
|
|||
log.Println(err)
|
||||
return
|
||||
}
|
||||
printBounds(font.Bounds())
|
||||
fmt.Printf("UnitsPerEm:%d\n\n", font.UnitsPerEm())
|
||||
fupe := font.FUnitsPerEm()
|
||||
printBounds(font.Bounds(fupe))
|
||||
fmt.Printf("FUnitsPerEm:%d\n\n", fupe)
|
||||
|
||||
c0, c1 := 'A', 'V'
|
||||
|
||||
i0 := font.Index(c0)
|
||||
hm := font.HMetric(i0)
|
||||
hm := font.HMetric(fupe, i0)
|
||||
g := truetype.NewGlyphBuf()
|
||||
err = g.Load(font, i0)
|
||||
err = g.Load(font, fupe, i0, nil)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
|
@ -68,5 +69,5 @@ func main() {
|
|||
fmt.Printf("AdvanceWidth:%d LeftSideBearing:%d\n", hm.AdvanceWidth, hm.LeftSideBearing)
|
||||
printGlyph(g)
|
||||
i1 := font.Index(c1)
|
||||
fmt.Printf("\n'%c', '%c' Kerning:%d\n", c0, c1, font.Kerning(i0, i1))
|
||||
fmt.Printf("\n'%c', '%c' Kerning:%d\n", c0, c1, font.Kerning(fupe, i0, i1))
|
||||
}
|
||||
|
|
|
@ -63,42 +63,14 @@ type Context struct {
|
|||
// dst and src are the destination and source images for drawing.
|
||||
dst draw.Image
|
||||
src image.Image
|
||||
// fontSize, dpi and upe are used to calculate scale.
|
||||
// scale is a multiplication factor to convert 256 FUnits (which is truetype's
|
||||
// native unit) to 24.8 fixed point units (which is the rasterizer's native unit).
|
||||
// At the default values of 72 DPI and 2048 units-per-em, one em of a 12 point
|
||||
// font is 12 pixels, which is 3072 fixed point units, and scale is
|
||||
// (pointSize * resolution * 256 * 256) / (unitsPerEm * 72), or
|
||||
// (12 * 72 * 256 * 256) / (2048 * 72),
|
||||
// which equals 384 fixed point units per 256 FUnits.
|
||||
// To check this, 1 em * 2048 FUnits per em * 384 fixed point units per 256 FUnits
|
||||
// equals 3072 fixed point units.
|
||||
fontSize float64
|
||||
dpi int
|
||||
upe int
|
||||
scale int
|
||||
// fontSize and dpi are used to calculate scale. scale is the number of
|
||||
// 26.6 fixed point units in 1 em.
|
||||
fontSize, dpi float64
|
||||
scale int32
|
||||
// cache is the glyph cache.
|
||||
cache [nGlyphs * nXFractions * nYFractions]cacheEntry
|
||||
}
|
||||
|
||||
// FUnitToFix32 converts the given number of FUnits into fixed point units,
|
||||
// rounding to nearest.
|
||||
func (c *Context) FUnitToFix32(x int) raster.Fix32 {
|
||||
return raster.Fix32((x*c.scale + 128) >> 8)
|
||||
}
|
||||
|
||||
// FUnitToPixelRD converts the given number of FUnits into pixel units,
|
||||
// rounding down.
|
||||
func (c *Context) FUnitToPixelRD(x int) int {
|
||||
return x * c.scale >> 16
|
||||
}
|
||||
|
||||
// FUnitToPixelRU converts the given number of FUnits into pixel units,
|
||||
// rounding up.
|
||||
func (c *Context) FUnitToPixelRU(x int) int {
|
||||
return (x*c.scale + 0xffff) >> 16
|
||||
}
|
||||
|
||||
// PointToFix32 converts the given number of points (as in ``a 12 point font'')
|
||||
// into fixed point units.
|
||||
func (c *Context) PointToFix32(x float64) raster.Fix32 {
|
||||
|
@ -114,15 +86,15 @@ func (c *Context) drawContour(ps []truetype.Point, dx, dy raster.Fix32) {
|
|||
// start is the same thing measured in fixed point units and positive Y
|
||||
// going downwards, and offset by (dx, dy)
|
||||
start := raster.Point{
|
||||
X: dx + c.FUnitToFix32(int(ps[0].X)),
|
||||
Y: dy + c.FUnitToFix32(-int(ps[0].Y)),
|
||||
X: dx + raster.Fix32(ps[0].X<<2),
|
||||
Y: dy - raster.Fix32(ps[0].Y<<2),
|
||||
}
|
||||
c.r.Start(start)
|
||||
q0, on0 := start, true
|
||||
for _, p := range ps[1:] {
|
||||
q := raster.Point{
|
||||
X: dx + c.FUnitToFix32(int(p.X)),
|
||||
Y: dy + c.FUnitToFix32(-int(p.Y)),
|
||||
X: dx + raster.Fix32(p.X<<2),
|
||||
Y: dy - raster.Fix32(p.Y<<2),
|
||||
}
|
||||
on := p.Flags&0x01 != 0
|
||||
if on {
|
||||
|
@ -156,14 +128,14 @@ func (c *Context) drawContour(ps []truetype.Point, dx, dy raster.Fix32) {
|
|||
// given glyph at the given sub-pixel offsets.
|
||||
// The 24.8 fixed point arguments fx and fy must be in the range [0, 1).
|
||||
func (c *Context) rasterize(glyph truetype.Index, fx, fy raster.Fix32) (*image.Alpha, image.Point, error) {
|
||||
if err := c.glyphBuf.Load(c.font, glyph); err != nil {
|
||||
if err := c.glyphBuf.Load(c.font, c.scale, glyph, nil); err != nil {
|
||||
return nil, image.ZP, err
|
||||
}
|
||||
// Calculate the integer-pixel bounds for the glyph.
|
||||
xmin := int(fx+c.FUnitToFix32(+int(c.glyphBuf.B.XMin))) >> 8
|
||||
ymin := int(fy+c.FUnitToFix32(-int(c.glyphBuf.B.YMax))) >> 8
|
||||
xmax := int(fx+c.FUnitToFix32(+int(c.glyphBuf.B.XMax))+0xff) >> 8
|
||||
ymax := int(fy+c.FUnitToFix32(-int(c.glyphBuf.B.YMin))+0xff) >> 8
|
||||
xmin := int(fx+raster.Fix32(c.glyphBuf.B.XMin<<2)) >> 8
|
||||
ymin := int(fy-raster.Fix32(c.glyphBuf.B.YMax<<2)) >> 8
|
||||
xmax := int(fx+raster.Fix32(c.glyphBuf.B.XMax<<2)+0xff) >> 8
|
||||
ymax := int(fy-raster.Fix32(c.glyphBuf.B.YMin<<2)+0xff) >> 8
|
||||
if xmin > xmax || ymin > ymax {
|
||||
return nil, image.ZP, errors.New("freetype: negative sized glyph")
|
||||
}
|
||||
|
@ -226,13 +198,13 @@ func (c *Context) DrawString(s string, p raster.Point) (raster.Point, error) {
|
|||
for _, rune := range s {
|
||||
index := c.font.Index(rune)
|
||||
if hasPrev {
|
||||
p.X += c.FUnitToFix32(int(c.font.Kerning(prev, index)))
|
||||
p.X += raster.Fix32(c.font.Kerning(c.scale, prev, index)) << 2
|
||||
}
|
||||
mask, offset, err := c.glyph(index, p)
|
||||
if err != nil {
|
||||
return raster.Point{}, err
|
||||
}
|
||||
p.X += c.FUnitToFix32(int(c.font.HMetric(index).AdvanceWidth))
|
||||
p.X += raster.Fix32(c.font.HMetric(c.scale, index).AdvanceWidth) << 2
|
||||
glyphRect := mask.Bounds().Add(offset)
|
||||
dr := c.clip.Intersect(glyphRect)
|
||||
if !dr.Empty() {
|
||||
|
@ -247,16 +219,16 @@ func (c *Context) DrawString(s string, p raster.Point) (raster.Point, error) {
|
|||
// 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 = int((c.fontSize * float64(c.dpi) * 256 * 256) / (float64(c.upe) * 72))
|
||||
c.scale = int32(c.fontSize * c.dpi * (64.0 / 72.0))
|
||||
if c.font == nil {
|
||||
c.r.SetBounds(0, 0)
|
||||
} else {
|
||||
// Set the rasterizer's bounds to be big enough to handle the largest glyph.
|
||||
b := c.font.Bounds()
|
||||
xmin := c.FUnitToPixelRD(+int(b.XMin))
|
||||
ymin := c.FUnitToPixelRD(-int(b.YMax))
|
||||
xmax := c.FUnitToPixelRU(+int(b.XMax))
|
||||
ymax := c.FUnitToPixelRU(-int(b.YMin))
|
||||
b := c.font.Bounds(c.scale)
|
||||
xmin := +int(b.XMin) >> 6
|
||||
ymin := -int(b.YMax) >> 6
|
||||
xmax := +int(b.XMax+63) >> 6
|
||||
ymax := -int(b.YMin-63) >> 6
|
||||
c.r.SetBounds(xmax-xmin, ymax-ymin)
|
||||
}
|
||||
for i := range c.cache {
|
||||
|
@ -265,7 +237,7 @@ func (c *Context) recalc() {
|
|||
}
|
||||
|
||||
// SetDPI sets the screen resolution in dots per inch.
|
||||
func (c *Context) SetDPI(dpi int) {
|
||||
func (c *Context) SetDPI(dpi float64) {
|
||||
if c.dpi == dpi {
|
||||
return
|
||||
}
|
||||
|
@ -279,10 +251,6 @@ func (c *Context) SetFont(font *truetype.Font) {
|
|||
return
|
||||
}
|
||||
c.font = font
|
||||
c.upe = font.UnitsPerEm()
|
||||
if c.upe <= 0 {
|
||||
c.upe = 1
|
||||
}
|
||||
c.recalc()
|
||||
}
|
||||
|
||||
|
@ -320,7 +288,6 @@ func NewContext() *Context {
|
|||
glyphBuf: truetype.NewGlyphBuf(),
|
||||
fontSize: 12,
|
||||
dpi: 72,
|
||||
upe: 2048,
|
||||
scale: (12 * 72 * 256 * 256) / (2048 * 72),
|
||||
scale: 12 << 6,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,10 +8,10 @@ package truetype
|
|||
// A Point is a co-ordinate pair plus whether it is ``on'' a contour or an
|
||||
// ``off'' control point.
|
||||
type Point struct {
|
||||
X, Y int16
|
||||
X, Y int32
|
||||
// The Flags' LSB means whether or not this Point is ``on'' the contour.
|
||||
// Other bits are reserved for internal use.
|
||||
Flags uint8
|
||||
Flags uint32
|
||||
}
|
||||
|
||||
// A GlyphBuf holds a glyph's contours. A GlyphBuf can be re-used to load a
|
||||
|
@ -49,7 +49,7 @@ const (
|
|||
// and returns the remaining data.
|
||||
func (g *GlyphBuf) decodeFlags(d []byte, offset int, np0 int) (offset1 int) {
|
||||
for i := np0; i < len(g.Point); {
|
||||
c := d[offset]
|
||||
c := uint32(d[offset])
|
||||
offset++
|
||||
g.Point[i].Flags = c
|
||||
i++
|
||||
|
@ -82,7 +82,7 @@ func (g *GlyphBuf) decodeCoords(d []byte, offset int, np0 int) int {
|
|||
x += int16(u16(d, offset))
|
||||
offset += 2
|
||||
}
|
||||
g.Point[i].X = x
|
||||
g.Point[i].X = int32(x)
|
||||
}
|
||||
var y int16
|
||||
for i := np0; i < len(g.Point); i++ {
|
||||
|
@ -99,19 +99,34 @@ func (g *GlyphBuf) decodeCoords(d []byte, offset int, np0 int) int {
|
|||
y += int16(u16(d, offset))
|
||||
offset += 2
|
||||
}
|
||||
g.Point[i].Y = y
|
||||
g.Point[i].Y = int32(y)
|
||||
}
|
||||
return offset
|
||||
}
|
||||
|
||||
// Load loads a glyph's contours from a Font, overwriting any previously
|
||||
// loaded contours for this GlyphBuf.
|
||||
func (g *GlyphBuf) Load(f *Font, i Index) error {
|
||||
// loaded contours for this GlyphBuf. The Hinter is optional; if non-nil, then
|
||||
// the resulting glyph will be hinted by the Font's bytecode instructions.
|
||||
func (g *GlyphBuf) Load(f *Font, scale int32, i Index, h *Hinter) error {
|
||||
// Reset the GlyphBuf.
|
||||
g.B = Bounds{}
|
||||
g.Point = g.Point[:0]
|
||||
g.End = g.End[:0]
|
||||
return g.load(f, i, 0)
|
||||
if err := g.load(f, i, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
g.B.XMin = f.scale(scale * g.B.XMin)
|
||||
g.B.YMin = f.scale(scale * g.B.YMin)
|
||||
g.B.XMax = f.scale(scale * g.B.XMax)
|
||||
g.B.YMax = f.scale(scale * g.B.YMax)
|
||||
for i := range g.Point {
|
||||
g.Point[i].X = f.scale(scale * g.Point[i].X)
|
||||
g.Point[i].Y = f.scale(scale * g.Point[i].Y)
|
||||
}
|
||||
if h != nil {
|
||||
// TODO: invoke h.
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadCompound loads a glyph that is composed of other glyphs.
|
||||
|
@ -153,8 +168,8 @@ func (g *GlyphBuf) loadCompound(f *Font, glyf []byte, offset, recursion int) err
|
|||
b0, i0 := g.B, len(g.Point)
|
||||
g.load(f, Index(component), recursion+1)
|
||||
for i := i0; i < len(g.Point); i++ {
|
||||
g.Point[i].X += dx
|
||||
g.Point[i].Y += dy
|
||||
g.Point[i].X += int32(dx)
|
||||
g.Point[i].Y += int32(dy)
|
||||
}
|
||||
if flags&flagUseMyMetrics == 0 {
|
||||
g.B = b0
|
||||
|
@ -186,10 +201,10 @@ func (g *GlyphBuf) load(f *Font, i Index, recursion int) error {
|
|||
glyf := f.glyf[g0:g1]
|
||||
// Decode the contour end indices.
|
||||
ne := int(int16(u16(glyf, 0)))
|
||||
g.B.XMin = int16(u16(glyf, 2))
|
||||
g.B.YMin = int16(u16(glyf, 4))
|
||||
g.B.XMax = int16(u16(glyf, 6))
|
||||
g.B.YMax = int16(u16(glyf, 8))
|
||||
g.B.XMin = int32(int16(u16(glyf, 2)))
|
||||
g.B.YMin = int32(int16(u16(glyf, 4)))
|
||||
g.B.XMax = int32(int16(u16(glyf, 6)))
|
||||
g.B.YMax = int32(int16(u16(glyf, 8)))
|
||||
offset := 10
|
||||
if ne == -1 {
|
||||
return g.loadCompound(f, glyf, offset, recursion)
|
||||
|
|
|
@ -12,7 +12,10 @@ import (
|
|||
"errors"
|
||||
)
|
||||
|
||||
type hinter struct {
|
||||
// Hinter implements bytecode hinting. Pass a Hinter to GlyphBuf.Load to hint
|
||||
// the resulting glyph. A Hinter can be re-used to hint a series of glyphs from
|
||||
// a Font.
|
||||
type Hinter struct {
|
||||
stack, store []int32
|
||||
|
||||
// The fields below constitue the graphics state, which is described at
|
||||
|
@ -28,7 +31,7 @@ type hinter struct {
|
|||
roundPeriod, roundPhase, roundThreshold f26dot6
|
||||
}
|
||||
|
||||
func (h *hinter) init(f *Font) {
|
||||
func (h *Hinter) init(f *Font) {
|
||||
if x := int(f.maxStackElements); x > len(h.stack) {
|
||||
x += 255
|
||||
x &^= 255
|
||||
|
@ -41,7 +44,7 @@ func (h *hinter) init(f *Font) {
|
|||
}
|
||||
}
|
||||
|
||||
func (h *hinter) run(program []byte) error {
|
||||
func (h *Hinter) run(program []byte) error {
|
||||
// The default vectors are along the X axis.
|
||||
h.pv = [2]f2dot14{0x4000, 0}
|
||||
h.fv = [2]f2dot14{0x4000, 0}
|
||||
|
@ -517,7 +520,7 @@ func (x f26dot6) mul(y f26dot6) f26dot6 {
|
|||
|
||||
// round rounds the given number. The rounding algorithm is described at
|
||||
// https://developer.apple.com/fonts/TTRefMan/RM02/Chap2.html#rounding
|
||||
func (h *hinter) round(x f26dot6) f26dot6 {
|
||||
func (h *Hinter) round(x f26dot6) f26dot6 {
|
||||
if h.roundPeriod == 0 {
|
||||
return x
|
||||
}
|
||||
|
|
|
@ -508,7 +508,7 @@ func TestBytecode(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
h := &hinter{}
|
||||
h := &Hinter{}
|
||||
h.init(&Font{
|
||||
maxStorage: 32,
|
||||
maxStackElements: 100,
|
||||
|
|
|
@ -7,10 +7,15 @@
|
|||
// Those formats are documented at http://developer.apple.com/fonts/TTRefMan/
|
||||
// and http://www.microsoft.com/typography/otspec/
|
||||
//
|
||||
// All numbers (e.g. bounds, point co-ordinates, font metrics) are measured in
|
||||
// FUnits. To convert from FUnits to pixels, scale by
|
||||
// (pointSize * resolution) / (font.UnitsPerEm() * 72dpi)
|
||||
// For example, 550 FUnits at 18pt, 72dpi and 2048upe is 4.83 pixels.
|
||||
// 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.
|
||||
//
|
||||
// To measure a TrueType font in ideal FUnit space, use scale equal to
|
||||
// font.FUnitsPerEm().
|
||||
package truetype
|
||||
|
||||
import (
|
||||
|
@ -23,13 +28,13 @@ 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 int16
|
||||
XMin, YMin, XMax, YMax int32
|
||||
}
|
||||
|
||||
// An HMetric holds the horizontal metrics of a single glyph.
|
||||
type HMetric struct {
|
||||
AdvanceWidth uint16
|
||||
LeftSideBearing int16
|
||||
AdvanceWidth int32
|
||||
LeftSideBearing int32
|
||||
}
|
||||
|
||||
// A FormatError reports that the input is not a valid TrueType font.
|
||||
|
@ -96,7 +101,7 @@ type Font struct {
|
|||
cm []cm
|
||||
locaOffsetFormat int
|
||||
nGlyph, nHMetric, nKern int
|
||||
unitsPerEm int
|
||||
fUnitsPerEm int32
|
||||
bounds Bounds
|
||||
// Values from the maxp section.
|
||||
maxTwilightPoints, maxStorage, maxFunctionDefs, maxStackElements uint16
|
||||
|
@ -183,11 +188,11 @@ func (f *Font) parseHead() error {
|
|||
if len(f.head) != 54 {
|
||||
return FormatError(fmt.Sprintf("bad head length: %d", len(f.head)))
|
||||
}
|
||||
f.unitsPerEm = int(u16(f.head, 18))
|
||||
f.bounds.XMin = int16(u16(f.head, 36))
|
||||
f.bounds.YMin = int16(u16(f.head, 38))
|
||||
f.bounds.XMax = int16(u16(f.head, 40))
|
||||
f.bounds.YMax = int16(u16(f.head, 42))
|
||||
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)))
|
||||
switch i := u16(f.head, 50); i {
|
||||
case 0:
|
||||
f.locaOffsetFormat = locaOffsetFormatShort
|
||||
|
@ -263,14 +268,29 @@ func (f *Font) parseMaxp() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Bounds returns the union of a Font's glyphs' bounds.
|
||||
func (f *Font) Bounds() Bounds {
|
||||
return f.bounds
|
||||
// scale returns x divided by f.fUnitsPerEm, rounded to the nearest integer.
|
||||
func (f *Font) scale(x int32) int32 {
|
||||
if x >= 0 {
|
||||
x += f.fUnitsPerEm / 2
|
||||
} else {
|
||||
x -= f.fUnitsPerEm / 2
|
||||
}
|
||||
return x / f.fUnitsPerEm
|
||||
}
|
||||
|
||||
// UnitsPerEm returns the number of FUnits in a Font's em-square.
|
||||
func (f *Font) UnitsPerEm() int {
|
||||
return f.unitsPerEm
|
||||
// Bounds returns the union of a Font's glyphs' bounds.
|
||||
func (f *Font) Bounds(scale int32) Bounds {
|
||||
b := f.bounds
|
||||
b.XMin = f.scale(scale * b.XMin)
|
||||
b.YMin = f.scale(scale * b.YMin)
|
||||
b.XMax = f.scale(scale * b.XMax)
|
||||
b.YMax = f.scale(scale * b.YMax)
|
||||
return b
|
||||
}
|
||||
|
||||
// FUnitsPerEm returns the number of FUnits in a Font's em-square's side.
|
||||
func (f *Font) FUnitsPerEm() int32 {
|
||||
return f.fUnitsPerEm
|
||||
}
|
||||
|
||||
// Index returns a Font's index for the given rune.
|
||||
|
@ -290,23 +310,26 @@ func (f *Font) Index(x rune) Index {
|
|||
}
|
||||
|
||||
// HMetric returns the horizontal metrics for the glyph with the given index.
|
||||
func (f *Font) HMetric(i Index) HMetric {
|
||||
func (f *Font) HMetric(scale int32, i Index) (h HMetric) {
|
||||
j := int(i)
|
||||
if j >= f.nGlyph {
|
||||
return HMetric{}
|
||||
}
|
||||
if j >= f.nHMetric {
|
||||
p := 4 * (f.nHMetric - 1)
|
||||
return HMetric{
|
||||
u16(f.hmtx, p),
|
||||
int16(u16(f.hmtx, p+2*(j-f.nHMetric)+4)),
|
||||
}
|
||||
h.AdvanceWidth = int32(u16(f.hmtx, p))
|
||||
h.LeftSideBearing = int32(int16(u16(f.hmtx, p+2*(j-f.nHMetric)+4)))
|
||||
} else {
|
||||
h.AdvanceWidth = int32(u16(f.hmtx, 4*j))
|
||||
h.LeftSideBearing = int32(int16(u16(f.hmtx, 4*j+2)))
|
||||
}
|
||||
return HMetric{u16(f.hmtx, 4*j), int16(u16(f.hmtx, 4*j+2))}
|
||||
h.AdvanceWidth = f.scale(scale * h.AdvanceWidth)
|
||||
h.LeftSideBearing = f.scale(scale * h.LeftSideBearing)
|
||||
return h
|
||||
}
|
||||
|
||||
// Kerning returns the kerning for the given glyph pair.
|
||||
func (f *Font) Kerning(i0, i1 Index) int16 {
|
||||
func (f *Font) Kerning(scale int32, i0, i1 Index) int32 {
|
||||
if f.nKern == 0 {
|
||||
return 0
|
||||
}
|
||||
|
@ -320,7 +343,7 @@ func (f *Font) Kerning(i0, i1 Index) int16 {
|
|||
} else if ig > g {
|
||||
hi = i
|
||||
} else {
|
||||
return int16(u16(f.kern, 22+6*i))
|
||||
return f.scale(scale * int32(int16(u16(f.kern, 22+6*i))))
|
||||
}
|
||||
}
|
||||
return 0
|
||||
|
|
|
@ -22,11 +22,12 @@ func TestParse(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got, want := font.Bounds(), (Bounds{-441, -432, 2024, 2033}); got != want {
|
||||
t.Errorf("Bounds: got %v, want %v", got, want)
|
||||
if got, want := font.FUnitsPerEm(), int32(2048); got != want {
|
||||
t.Errorf("FUnitsPerEm: got %v, want %v", got, want)
|
||||
}
|
||||
if got, want := font.UnitsPerEm(), 2048; got != want {
|
||||
t.Errorf("UnitsPerEm: got %v, want %v", got, want)
|
||||
fupe := font.FUnitsPerEm()
|
||||
if got, want := font.Bounds(fupe), (Bounds{-441, -432, 2024, 2033}); got != want {
|
||||
t.Errorf("Bounds: got %v, want %v", got, want)
|
||||
}
|
||||
|
||||
i0 := font.Index('A')
|
||||
|
@ -34,15 +35,15 @@ func TestParse(t *testing.T) {
|
|||
if i0 != 36 || i1 != 57 {
|
||||
t.Fatalf("Index: i0, i1 = %d, %d, want 36, 57", i0, i1)
|
||||
}
|
||||
if got, want := font.HMetric(i0), (HMetric{1366, 19}); got != want {
|
||||
if got, want := font.HMetric(fupe, i0), (HMetric{1366, 19}); got != want {
|
||||
t.Errorf("HMetric: got %v, want %v", got, want)
|
||||
}
|
||||
if got, want := font.Kerning(i0, i1), int16(-144); got != want {
|
||||
if got, want := font.Kerning(fupe, i0, i1), int32(-144); got != want {
|
||||
t.Errorf("Kerning: got %v, want %v", got, want)
|
||||
}
|
||||
|
||||
g0 := NewGlyphBuf()
|
||||
err = g0.Load(font, i0)
|
||||
err = g0.Load(font, fupe, i0, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("Load: %v", err)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue