aboutsummaryrefslogtreecommitdiff
path: root/vendor/golang.org/x/image/font/sfnt/truetype.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/image/font/sfnt/truetype.go')
-rw-r--r--vendor/golang.org/x/image/font/sfnt/truetype.go572
1 files changed, 0 insertions, 572 deletions
diff --git a/vendor/golang.org/x/image/font/sfnt/truetype.go b/vendor/golang.org/x/image/font/sfnt/truetype.go
deleted file mode 100644
index ab27f5b..0000000
--- a/vendor/golang.org/x/image/font/sfnt/truetype.go
+++ /dev/null
@@ -1,572 +0,0 @@
-// 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 (
- "golang.org/x/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
-}