golang-image/font/sfnt/truetype.go

573 lines
15 KiB
Go
Raw Permalink Normal View History

// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package sfnt
import (
"git.fireandbrimst.one/aw/golang-image/math/fixed"
)
// Flags for simple (non-compound) glyphs.
//
// See https://www.microsoft.com/typography/OTSPEC/glyf.htm
const (
flagOnCurve = 1 << 0 // 0x0001
flagXShortVector = 1 << 1 // 0x0002
flagYShortVector = 1 << 2 // 0x0004
flagRepeat = 1 << 3 // 0x0008
// The same flag bits are overloaded to have two meanings, dependent on the
// value of the flag{X,Y}ShortVector bits.
flagPositiveXShortVector = 1 << 4 // 0x0010
flagThisXIsSame = 1 << 4 // 0x0010
flagPositiveYShortVector = 1 << 5 // 0x0020
flagThisYIsSame = 1 << 5 // 0x0020
)
// Flags for compound glyphs.
//
// See https://www.microsoft.com/typography/OTSPEC/glyf.htm
const (
flagArg1And2AreWords = 1 << 0 // 0x0001
flagArgsAreXYValues = 1 << 1 // 0x0002
flagRoundXYToGrid = 1 << 2 // 0x0004
flagWeHaveAScale = 1 << 3 // 0x0008
flagReserved4 = 1 << 4 // 0x0010
flagMoreComponents = 1 << 5 // 0x0020
flagWeHaveAnXAndYScale = 1 << 6 // 0x0040
flagWeHaveATwoByTwo = 1 << 7 // 0x0080
flagWeHaveInstructions = 1 << 8 // 0x0100
flagUseMyMetrics = 1 << 9 // 0x0200
flagOverlapCompound = 1 << 10 // 0x0400
flagScaledComponentOffset = 1 << 11 // 0x0800
flagUnscaledComponentOffset = 1 << 12 // 0x1000
)
func midPoint(p, q fixed.Point26_6) fixed.Point26_6 {
return fixed.Point26_6{
X: (p.X + q.X) / 2,
Y: (p.Y + q.Y) / 2,
}
}
func parseLoca(src *source, loca table, glyfOffset uint32, indexToLocFormat bool, numGlyphs int32) (locations []uint32, err error) {
if indexToLocFormat {
if loca.length != 4*uint32(numGlyphs+1) {
return nil, errInvalidLocaTable
}
} else {
if loca.length != 2*uint32(numGlyphs+1) {
return nil, errInvalidLocaTable
}
}
locations = make([]uint32, numGlyphs+1)
buf, err := src.view(nil, int(loca.offset), int(loca.length))
if err != nil {
return nil, err
}
if indexToLocFormat {
for i := range locations {
locations[i] = 1*uint32(u32(buf[4*i:])) + glyfOffset
}
} else {
for i := range locations {
locations[i] = 2*uint32(u16(buf[2*i:])) + glyfOffset
}
}
return locations, err
}
// https://www.microsoft.com/typography/OTSPEC/glyf.htm says that "Each
// glyph begins with the following [10 byte] header".
const glyfHeaderLen = 10
func loadGlyf(f *Font, b *Buffer, x GlyphIndex, stackBottom, recursionDepth uint32) error {
data, _, _, err := f.viewGlyphData(b, x)
if err != nil {
return err
}
if len(data) == 0 {
return nil
}
if len(data) < glyfHeaderLen {
return errInvalidGlyphData
}
index := glyfHeaderLen
numContours, numPoints := int16(u16(data)), 0
switch {
case numContours == -1:
// We have a compound glyph. No-op.
case numContours == 0:
return nil
case numContours > 0:
// We have a simple (non-compound) glyph.
index += 2 * int(numContours)
if index > len(data) {
return errInvalidGlyphData
}
// The +1 for numPoints is because the value in the file format is
// inclusive, but Go's slice[:index] semantics are exclusive.
numPoints = 1 + int(u16(data[index-2:]))
default:
return errInvalidGlyphData
}
if numContours < 0 {
return loadCompoundGlyf(f, b, data[glyfHeaderLen:], stackBottom, recursionDepth)
}
// Skip the hinting instructions.
index += 2
if index > len(data) {
return errInvalidGlyphData
}
hintsLength := int(u16(data[index-2:]))
index += hintsLength
if index > len(data) {
return errInvalidGlyphData
}
// For simple (non-compound) glyphs, the remainder of the glyf data
// consists of (flags, x, y) points: the Bézier curve segments. These are
// stored in columns (all the flags first, then all the x coordinates, then
// all the y coordinates), not rows, as it compresses better.
//
// Decoding those points in row order involves two passes. The first pass
// determines the indexes (relative to the data slice) of where the flags,
// the x coordinates and the y coordinates each start.
flagIndex := int32(index)
xIndex, yIndex, ok := findXYIndexes(data, index, numPoints)
if !ok {
return errInvalidGlyphData
}
// The second pass decodes each (flags, x, y) tuple in row order.
g := glyfIter{
data: data,
flagIndex: flagIndex,
xIndex: xIndex,
yIndex: yIndex,
endIndex: glyfHeaderLen,
// The -1 is because the contour-end index in the file format is
// inclusive, but Go's slice[:index] semantics are exclusive.
prevEnd: -1,
numContours: int32(numContours),
}
for g.nextContour() {
for g.nextSegment() {
b.segments = append(b.segments, g.seg)
}
}
return g.err
}
func findXYIndexes(data []byte, index, numPoints int) (xIndex, yIndex int32, ok bool) {
xDataLen := 0
yDataLen := 0
for i := 0; ; {
if i > numPoints {
return 0, 0, false
}
if i == numPoints {
break
}
repeatCount := 1
if index >= len(data) {
return 0, 0, false
}
flag := data[index]
index++
if flag&flagRepeat != 0 {
if index >= len(data) {
return 0, 0, false
}
repeatCount += int(data[index])
index++
}
xSize := 0
if flag&flagXShortVector != 0 {
xSize = 1
} else if flag&flagThisXIsSame == 0 {
xSize = 2
}
xDataLen += xSize * repeatCount
ySize := 0
if flag&flagYShortVector != 0 {
ySize = 1
} else if flag&flagThisYIsSame == 0 {
ySize = 2
}
yDataLen += ySize * repeatCount
i += repeatCount
}
if index+xDataLen+yDataLen > len(data) {
return 0, 0, false
}
return int32(index), int32(index + xDataLen), true
}
func loadCompoundGlyf(f *Font, b *Buffer, data []byte, stackBottom, recursionDepth uint32) error {
if recursionDepth++; recursionDepth == maxCompoundRecursionDepth {
return errUnsupportedCompoundGlyph
}
// Read and process the compound glyph's components. They are two separate
// for loops, since reading parses the elements of the data slice, and
// processing can overwrite the backing array.
stackTop := stackBottom
for {
if stackTop >= maxCompoundStackSize {
return errUnsupportedCompoundGlyph
}
elem := &b.compoundStack[stackTop]
stackTop++
if len(data) < 4 {
return errInvalidGlyphData
}
flags := u16(data)
elem.glyphIndex = GlyphIndex(u16(data[2:]))
if flags&flagArg1And2AreWords == 0 {
if len(data) < 6 {
return errInvalidGlyphData
}
elem.dx = int16(int8(data[4]))
elem.dy = int16(int8(data[5]))
data = data[6:]
} else {
if len(data) < 8 {
return errInvalidGlyphData
}
elem.dx = int16(u16(data[4:]))
elem.dy = int16(u16(data[6:]))
data = data[8:]
}
if flags&flagArgsAreXYValues == 0 {
return errUnsupportedCompoundGlyph
}
elem.hasTransform = flags&(flagWeHaveAScale|flagWeHaveAnXAndYScale|flagWeHaveATwoByTwo) != 0
if elem.hasTransform {
switch {
case flags&flagWeHaveAScale != 0:
if len(data) < 2 {
return errInvalidGlyphData
}
elem.transformXX = int16(u16(data))
elem.transformXY = 0
elem.transformYX = 0
elem.transformYY = elem.transformXX
data = data[2:]
case flags&flagWeHaveAnXAndYScale != 0:
if len(data) < 4 {
return errInvalidGlyphData
}
elem.transformXX = int16(u16(data[0:]))
elem.transformXY = 0
elem.transformYX = 0
elem.transformYY = int16(u16(data[2:]))
data = data[4:]
case flags&flagWeHaveATwoByTwo != 0:
if len(data) < 8 {
return errInvalidGlyphData
}
elem.transformXX = int16(u16(data[0:]))
elem.transformXY = int16(u16(data[2:]))
elem.transformYX = int16(u16(data[4:]))
elem.transformYY = int16(u16(data[6:]))
data = data[8:]
}
}
if flags&flagMoreComponents == 0 {
break
}
}
// To support hinting, we'd have to save the remaining bytes in data here
// and interpret them after the for loop below, since that for loop's
// loadGlyf calls can overwrite the backing array.
for i := stackBottom; i < stackTop; i++ {
elem := &b.compoundStack[i]
base := len(b.segments)
if err := loadGlyf(f, b, elem.glyphIndex, stackTop, recursionDepth); err != nil {
return err
}
dx, dy := fixed.Int26_6(elem.dx), fixed.Int26_6(elem.dy)
segs := b.segments[base:]
if elem.hasTransform {
txx := elem.transformXX
txy := elem.transformXY
tyx := elem.transformYX
tyy := elem.transformYY
for j := range segs {
transformArgs(&segs[j].Args, txx, txy, tyx, tyy, dx, dy)
}
} else {
for j := range segs {
translateArgs(&segs[j].Args, dx, dy)
}
}
}
return nil
}
type glyfIter struct {
data []byte
err error
// Various indices into the data slice. See the "Decoding those points in
// row order" comment above.
flagIndex int32
xIndex int32
yIndex int32
// endIndex points to the uint16 that is the inclusive point index of the
// current contour's end. prevEnd is the previous contour's end.
endIndex int32
prevEnd int32
// c and p count the current contour and point, up to numContours and
// numPoints.
c, numContours int32
p, nPoints int32
// The next two groups of fields track points and segments. Points are what
// the underlying file format provides. Bézier curve segments are what the
// rasterizer consumes.
//
// Points are either on-curve or off-curve. Two consecutive on-curve points
// define a linear curve segment between them. N off-curve points between
// on-curve points define N quadratic curve segments. The TrueType glyf
// format does not use cubic curves. If N is greater than 1, some of these
// segment end points are implicit, the midpoint of two off-curve points.
// Given the points A, B1, B2, ..., BN, C, where A and C are on-curve and
// all the Bs are off-curve, the segments are:
//
// - A, B1, midpoint(B1, B2)
// - midpoint(B1, B2), B2, midpoint(B2, B3)
// - midpoint(B2, B3), B3, midpoint(B3, B4)
// - ...
// - midpoint(BN-1, BN), BN, C
//
// Note that the sequence of Bs may wrap around from the last point in the
// glyf data to the first. A and C may also be the same point (the only
// explicit on-curve point), or there may be no explicit on-curve points at
// all (but still implicit ones between explicit off-curve points).
// Points.
x, y int16
on bool
flag uint8
repeats uint8
// Segments.
closing bool
closed bool
firstOnCurveValid bool
firstOffCurveValid bool
lastOffCurveValid bool
firstOnCurve fixed.Point26_6
firstOffCurve fixed.Point26_6
lastOffCurve fixed.Point26_6
seg Segment
}
func (g *glyfIter) nextContour() (ok bool) {
if g.c == g.numContours {
return false
}
g.c++
end := int32(u16(g.data[g.endIndex:]))
g.endIndex += 2
if end <= g.prevEnd {
g.err = errInvalidGlyphData
return false
}
g.nPoints = end - g.prevEnd
g.p = 0
g.prevEnd = end
g.closing = false
g.closed = false
g.firstOnCurveValid = false
g.firstOffCurveValid = false
g.lastOffCurveValid = false
return true
}
func (g *glyfIter) close() {
switch {
case !g.firstOffCurveValid && !g.lastOffCurveValid:
g.closed = true
g.seg = Segment{
Op: SegmentOpLineTo,
Args: [3]fixed.Point26_6{g.firstOnCurve},
}
case !g.firstOffCurveValid && g.lastOffCurveValid:
g.closed = true
g.seg = Segment{
Op: SegmentOpQuadTo,
Args: [3]fixed.Point26_6{g.lastOffCurve, g.firstOnCurve},
}
case g.firstOffCurveValid && !g.lastOffCurveValid:
g.closed = true
g.seg = Segment{
Op: SegmentOpQuadTo,
Args: [3]fixed.Point26_6{g.firstOffCurve, g.firstOnCurve},
}
case g.firstOffCurveValid && g.lastOffCurveValid:
g.lastOffCurveValid = false
g.seg = Segment{
Op: SegmentOpQuadTo,
Args: [3]fixed.Point26_6{
g.lastOffCurve,
midPoint(g.lastOffCurve, g.firstOffCurve),
},
}
}
}
func (g *glyfIter) nextSegment() (ok bool) {
for !g.closed {
if g.closing || !g.nextPoint() {
g.closing = true
g.close()
return true
}
// Convert the tuple (g.x, g.y) to a fixed.Point26_6, since the latter
// is what's held in a Segment. The input (g.x, g.y) is a pair of int16
// values, measured in font units, since that is what the underlying
// format provides. The output is a pair of fixed.Int26_6 values. A
// fixed.Int26_6 usually represents a 26.6 fixed number of pixels, but
// this here is just a straight numerical conversion, with no scaling
// factor. A later step scales the Segment.Args values by such a factor
// to convert e.g. 1792 font units to 10.5 pixels at 2048 font units
// per em and 12 ppem (pixels per em).
p := fixed.Point26_6{
X: fixed.Int26_6(g.x),
Y: fixed.Int26_6(g.y),
}
if !g.firstOnCurveValid {
if g.on {
g.firstOnCurve = p
g.firstOnCurveValid = true
g.seg = Segment{
Op: SegmentOpMoveTo,
Args: [3]fixed.Point26_6{p},
}
return true
} else if !g.firstOffCurveValid {
g.firstOffCurve = p
g.firstOffCurveValid = true
continue
} else {
g.firstOnCurve = midPoint(g.firstOffCurve, p)
g.firstOnCurveValid = true
g.lastOffCurve = p
g.lastOffCurveValid = true
g.seg = Segment{
Op: SegmentOpMoveTo,
Args: [3]fixed.Point26_6{g.firstOnCurve},
}
return true
}
} else if !g.lastOffCurveValid {
if !g.on {
g.lastOffCurve = p
g.lastOffCurveValid = true
continue
} else {
g.seg = Segment{
Op: SegmentOpLineTo,
Args: [3]fixed.Point26_6{p},
}
return true
}
} else {
if !g.on {
g.seg = Segment{
Op: SegmentOpQuadTo,
Args: [3]fixed.Point26_6{
g.lastOffCurve,
midPoint(g.lastOffCurve, p),
},
}
g.lastOffCurve = p
g.lastOffCurveValid = true
return true
} else {
g.seg = Segment{
Op: SegmentOpQuadTo,
Args: [3]fixed.Point26_6{g.lastOffCurve, p},
}
g.lastOffCurveValid = false
return true
}
}
}
return false
}
func (g *glyfIter) nextPoint() (ok bool) {
if g.p == g.nPoints {
return false
}
g.p++
if g.repeats > 0 {
g.repeats--
} else {
g.flag = g.data[g.flagIndex]
g.flagIndex++
if g.flag&flagRepeat != 0 {
g.repeats = g.data[g.flagIndex]
g.flagIndex++
}
}
if g.flag&flagXShortVector != 0 {
if g.flag&flagPositiveXShortVector != 0 {
g.x += int16(g.data[g.xIndex])
} else {
g.x -= int16(g.data[g.xIndex])
}
g.xIndex += 1
} else if g.flag&flagThisXIsSame == 0 {
g.x += int16(u16(g.data[g.xIndex:]))
g.xIndex += 2
}
if g.flag&flagYShortVector != 0 {
if g.flag&flagPositiveYShortVector != 0 {
g.y += int16(g.data[g.yIndex])
} else {
g.y -= int16(g.data[g.yIndex])
}
g.yIndex += 1
} else if g.flag&flagThisYIsSame == 0 {
g.y += int16(u16(g.data[g.yIndex:]))
g.yIndex += 2
}
g.on = g.flag&flagOnCurve != 0
return true
}