From f5437632f486b7d0a0a181c58f113c86d032b02c Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Mon, 24 Apr 2017 20:11:36 -0400 Subject: Upgrading server dependancies (#6215) --- vendor/golang.org/x/image/font/sfnt/postscript.go | 507 +++++++++++++++------- 1 file changed, 348 insertions(+), 159 deletions(-) (limited to 'vendor/golang.org/x/image/font/sfnt/postscript.go') diff --git a/vendor/golang.org/x/image/font/sfnt/postscript.go b/vendor/golang.org/x/image/font/sfnt/postscript.go index 1a00b827f..7c5db789d 100644 --- a/vendor/golang.org/x/image/font/sfnt/postscript.go +++ b/vendor/golang.org/x/image/font/sfnt/postscript.go @@ -80,6 +80,44 @@ func bigEndian(b []byte) uint32 { panic("unreachable") } +// fdSelect holds a CFF font's Font Dict Select data. +type fdSelect struct { + format uint8 + numRanges uint16 + offset int32 +} + +func (t *fdSelect) lookup(f *Font, b *Buffer, x GlyphIndex) (int, error) { + switch t.format { + case 0: + buf, err := b.view(&f.src, int(t.offset)+int(x), 1) + if err != nil { + return 0, err + } + return int(buf[0]), nil + case 3: + lo, hi := 0, int(t.numRanges) + for lo < hi { + i := (lo + hi) / 2 + buf, err := b.view(&f.src, int(t.offset)+3*i, 3+2) + if err != nil { + return 0, err + } + // buf holds the range [xlo, xhi). + if xlo := GlyphIndex(u16(buf[0:])); x < xlo { + hi = i + continue + } + if xhi := GlyphIndex(u16(buf[3:])); xhi <= x { + lo = i + 1 + continue + } + return int(buf[2]), nil + } + } + return 0, ErrNotFound +} + // cffParser parses the CFF table from an SFNT font. type cffParser struct { src *source @@ -94,14 +132,14 @@ type cffParser struct { psi psInterpreter } -func (p *cffParser) parse() (locations, gsubrs, subrs []uint32, err error) { +func (p *cffParser) parse(numGlyphs int32) (ret glyphData, err error) { // Parse the header. { if !p.read(4) { - return nil, nil, nil, p.err + return glyphData{}, p.err } if p.buf[0] != 1 || p.buf[1] != 0 || p.buf[2] != 4 { - return nil, nil, nil, errUnsupportedCFFVersion + return glyphData{}, errUnsupportedCFFVersion } } @@ -109,15 +147,15 @@ func (p *cffParser) parse() (locations, gsubrs, subrs []uint32, err error) { { count, offSize, ok := p.parseIndexHeader() if !ok { - return nil, nil, nil, p.err + return glyphData{}, p.err } // https://www.microsoft.com/typography/OTSPEC/cff.htm says that "The // Name INDEX in the CFF must contain only one entry". if count != 1 { - return nil, nil, nil, errInvalidCFFTable + return glyphData{}, errInvalidCFFTable } if !p.parseIndexLocations(p.locBuf[:2], count, offSize) { - return nil, nil, nil, p.err + return glyphData{}, p.err } p.offset = int(p.locBuf[1]) } @@ -127,21 +165,21 @@ func (p *cffParser) parse() (locations, gsubrs, subrs []uint32, err error) { { count, offSize, ok := p.parseIndexHeader() if !ok { - return nil, nil, nil, p.err + return glyphData{}, p.err } // 5176.CFF.pdf section 8 "Top DICT INDEX" says that the count here // should match the count of the Name INDEX, which is 1. if count != 1 { - return nil, nil, nil, errInvalidCFFTable + return glyphData{}, errInvalidCFFTable } if !p.parseIndexLocations(p.locBuf[:2], count, offSize) { - return nil, nil, nil, p.err + return glyphData{}, p.err } if !p.read(int(p.locBuf[1] - p.locBuf[0])) { - return nil, nil, nil, p.err + return glyphData{}, p.err } if p.err = p.psi.run(psContextTopDict, p.buf, 0, 0); p.err != nil { - return nil, nil, nil, p.err + return glyphData{}, p.err } } @@ -149,25 +187,25 @@ func (p *cffParser) parse() (locations, gsubrs, subrs []uint32, err error) { { count, offSize, ok := p.parseIndexHeader() if !ok { - return nil, nil, nil, p.err + return glyphData{}, p.err } if count != 0 { // Read the last location. Locations are off by 1 byte. See the // comment in parseIndexLocations. if !p.skip(int(count * offSize)) { - return nil, nil, nil, p.err + return glyphData{}, p.err } if !p.read(int(offSize)) { - return nil, nil, nil, p.err + return glyphData{}, p.err } loc := bigEndian(p.buf) - 1 // Check that locations are in bounds. if uint32(p.end-p.offset) < loc { - return nil, nil, nil, errInvalidCFFTable + return glyphData{}, errInvalidCFFTable } // Skip the index data. if !p.skip(int(loc)) { - return nil, nil, nil, p.err + return glyphData{}, p.err } } } @@ -176,80 +214,171 @@ func (p *cffParser) parse() (locations, gsubrs, subrs []uint32, err error) { { count, offSize, ok := p.parseIndexHeader() if !ok { - return nil, nil, nil, p.err + return glyphData{}, p.err } if count != 0 { if count > maxNumSubroutines { - return nil, nil, nil, errUnsupportedNumberOfSubroutines + return glyphData{}, errUnsupportedNumberOfSubroutines } - gsubrs = make([]uint32, count+1) - if !p.parseIndexLocations(gsubrs, count, offSize) { - return nil, nil, nil, p.err + ret.gsubrs = make([]uint32, count+1) + if !p.parseIndexLocations(ret.gsubrs, count, offSize) { + return glyphData{}, p.err } } } // Parse the CharStrings INDEX, whose location was found in the Top DICT. { - if p.psi.topDict.charStrings <= 0 || int32(p.end-p.base) < p.psi.topDict.charStrings { - return nil, nil, nil, errInvalidCFFTable + if !p.seekFromBase(p.psi.topDict.charStringsOffset) { + return glyphData{}, errInvalidCFFTable } - p.offset = p.base + int(p.psi.topDict.charStrings) count, offSize, ok := p.parseIndexHeader() if !ok { - return nil, nil, nil, p.err + return glyphData{}, p.err + } + if count == 0 || int32(count) != numGlyphs { + return glyphData{}, errInvalidCFFTable + } + ret.locations = make([]uint32, count+1) + if !p.parseIndexLocations(ret.locations, count, offSize) { + return glyphData{}, p.err + } + } + + if !p.psi.topDict.isCIDFont { + // Parse the Private DICT, whose location was found in the Top DICT. + ret.singleSubrs, err = p.parsePrivateDICT( + p.psi.topDict.privateDictOffset, + p.psi.topDict.privateDictLength, + ) + if err != nil { + return glyphData{}, err + } + + } else { + // Parse the Font Dict Select data, whose location was found in the Top + // DICT. + ret.fdSelect, err = p.parseFDSelect(p.psi.topDict.fdSelect, numGlyphs) + if err != nil { + return glyphData{}, err + } + + // Parse the Font Dicts. Each one contains its own Private DICT. + if !p.seekFromBase(p.psi.topDict.fdArray) { + return glyphData{}, errInvalidCFFTable + } + + count, offSize, ok := p.parseIndexHeader() + if !ok { + return glyphData{}, p.err + } + if count > maxNumFontDicts { + return glyphData{}, errUnsupportedNumberOfFontDicts } - if count == 0 { - return nil, nil, nil, errInvalidCFFTable + + fdLocations := make([]uint32, count+1) + if !p.parseIndexLocations(fdLocations, count, offSize) { + return glyphData{}, p.err + } + + privateDicts := make([]struct { + offset, length int32 + }, count) + + for i := range privateDicts { + length := fdLocations[i+1] - fdLocations[i] + if !p.read(int(length)) { + return glyphData{}, errInvalidCFFTable + } + p.psi.topDict.initialize() + if p.err = p.psi.run(psContextTopDict, p.buf, 0, 0); p.err != nil { + return glyphData{}, p.err + } + privateDicts[i].offset = p.psi.topDict.privateDictOffset + privateDicts[i].length = p.psi.topDict.privateDictLength + } + + ret.multiSubrs = make([][]uint32, count) + for i, pd := range privateDicts { + ret.multiSubrs[i], err = p.parsePrivateDICT(pd.offset, pd.length) + if err != nil { + return glyphData{}, err + } + } + } + + return ret, err +} + +// parseFDSelect parses the Font Dict Select data as per 5176.CFF.pdf section +// 19 "FDSelect". +func (p *cffParser) parseFDSelect(offset int32, numGlyphs int32) (ret fdSelect, err error) { + if !p.seekFromBase(p.psi.topDict.fdSelect) { + return fdSelect{}, errInvalidCFFTable + } + if !p.read(1) { + return fdSelect{}, p.err + } + ret.format = p.buf[0] + switch ret.format { + case 0: + if p.end-p.offset < int(numGlyphs) { + return fdSelect{}, errInvalidCFFTable } - locations = make([]uint32, count+1) - if !p.parseIndexLocations(locations, count, offSize) { - return nil, nil, nil, p.err + ret.offset = int32(p.offset) + return ret, nil + case 3: + if !p.read(2) { + return fdSelect{}, p.err + } + ret.numRanges = u16(p.buf) + if p.end-p.offset < 3*int(ret.numRanges)+2 { + return fdSelect{}, errInvalidCFFTable } + ret.offset = int32(p.offset) + return ret, nil } + return fdSelect{}, errUnsupportedCFFFDSelectTable +} - // Parse the Private DICT, whose location was found in the Top DICT. +func (p *cffParser) parsePrivateDICT(offset, length int32) (subrs []uint32, err error) { p.psi.privateDict.initialize() - if p.psi.topDict.privateDictLength != 0 { - offset := p.psi.topDict.privateDictOffset - length := p.psi.topDict.privateDictLength + if length != 0 { fullLength := int32(p.end - p.base) if offset <= 0 || fullLength < offset || fullLength-offset < length || length < 0 { - return nil, nil, nil, errInvalidCFFTable + return nil, errInvalidCFFTable } p.offset = p.base + int(offset) if !p.read(int(length)) { - return nil, nil, nil, p.err + return nil, p.err } if p.err = p.psi.run(psContextPrivateDict, p.buf, 0, 0); p.err != nil { - return nil, nil, nil, p.err + return nil, p.err } } // Parse the Local Subrs [Subroutines] INDEX, whose location was found in // the Private DICT. - if p.psi.privateDict.subrs != 0 { - offset := p.psi.topDict.privateDictOffset + p.psi.privateDict.subrs - if offset <= 0 || int32(p.end-p.base) < offset { - return nil, nil, nil, errInvalidCFFTable + if p.psi.privateDict.subrsOffset != 0 { + if !p.seekFromBase(offset + p.psi.privateDict.subrsOffset) { + return nil, errInvalidCFFTable } - p.offset = p.base + int(offset) count, offSize, ok := p.parseIndexHeader() if !ok { - return nil, nil, nil, p.err + return nil, p.err } if count != 0 { if count > maxNumSubroutines { - return nil, nil, nil, errUnsupportedNumberOfSubroutines + return nil, errUnsupportedNumberOfSubroutines } subrs = make([]uint32, count+1) if !p.parseIndexLocations(subrs, count, offSize) { - return nil, nil, nil, p.err + return nil, p.err } } } - return locations, gsubrs, subrs, nil + return subrs, err } // read sets p.buf to view the n bytes from p.offset to p.offset+n. It also @@ -263,11 +392,12 @@ func (p *cffParser) parse() (locations, gsubrs, subrs []uint32, err error) { // maximize the opportunity to re-use p.buf's allocated memory when viewing the // underlying source data for subsequent read calls. func (p *cffParser) read(n int) (ok bool) { - if p.end-p.offset < n { + if n < 0 || p.end-p.offset < n { p.err = errInvalidCFFTable return false } p.buf, p.err = p.src.view(p.buf, p.offset, n) + // TODO: if p.err == io.EOF, change that to a different error?? p.offset += n return p.err == nil } @@ -281,6 +411,14 @@ func (p *cffParser) skip(n int) (ok bool) { return true } +func (p *cffParser) seekFromBase(offset int32) (ok bool) { + if offset < 0 || int32(p.end-p.base) < offset { + return false + } + p.offset = p.base + int(offset) + return true +} + func (p *cffParser) parseIndexHeader() (count, offSize int32, ok bool) { if !p.read(2) { return 0, 0, false @@ -367,7 +505,10 @@ const ( // psTopDictData contains fields specific to the Top DICT context. type psTopDictData struct { - charStrings int32 + charStringsOffset int32 + fdArray int32 + fdSelect int32 + isCIDFont bool privateDictOffset int32 privateDictLength int32 } @@ -378,7 +519,7 @@ func (d *psTopDictData) initialize() { // psPrivateDictData contains fields specific to the Private DICT context. type psPrivateDictData struct { - subrs int32 + subrsOffset int32 } func (d *psPrivateDictData) initialize() { @@ -388,21 +529,88 @@ func (d *psPrivateDictData) initialize() { // psType2CharstringsData contains fields specific to the Type 2 Charstrings // context. type psType2CharstringsData struct { - f *Font - b *Buffer - x, y int32 - hintBits int32 - seenWidth bool - ended bool + f *Font + b *Buffer + x int32 + y int32 + firstX int32 + firstY int32 + hintBits int32 + seenWidth bool + ended bool + glyphIndex GlyphIndex + // fdSelectIndexPlusOne is the result of the Font Dict Select lookup, plus + // one. That plus one lets us use the zero value to denote either unused + // (for CFF fonts with a single Font Dict) or lazily evaluated. + fdSelectIndexPlusOne int32 } -func (d *psType2CharstringsData) initialize(f *Font, b *Buffer) { +func (d *psType2CharstringsData) initialize(f *Font, b *Buffer, glyphIndex GlyphIndex) { *d = psType2CharstringsData{ - f: f, - b: b, + f: f, + b: b, + glyphIndex: glyphIndex, + } +} + +func (d *psType2CharstringsData) closePath() { + if d.x != d.firstX || d.y != d.firstY { + d.b.segments = append(d.b.segments, Segment{ + Op: SegmentOpLineTo, + Args: [3]fixed.Point26_6{{ + X: fixed.Int26_6(d.firstX), + Y: fixed.Int26_6(d.firstY), + }}, + }) } } +func (d *psType2CharstringsData) moveTo(dx, dy int32) { + d.closePath() + d.x += dx + d.y += dy + d.b.segments = append(d.b.segments, Segment{ + Op: SegmentOpMoveTo, + Args: [3]fixed.Point26_6{{ + X: fixed.Int26_6(d.x), + Y: fixed.Int26_6(d.y), + }}, + }) + d.firstX = d.x + d.firstY = d.y +} + +func (d *psType2CharstringsData) lineTo(dx, dy int32) { + d.x += dx + d.y += dy + d.b.segments = append(d.b.segments, Segment{ + Op: SegmentOpLineTo, + Args: [3]fixed.Point26_6{{ + X: fixed.Int26_6(d.x), + Y: fixed.Int26_6(d.y), + }}, + }) +} + +func (d *psType2CharstringsData) cubeTo(dxa, dya, dxb, dyb, dxc, dyc int32) { + d.x += dxa + d.y += dya + xa := fixed.Int26_6(d.x) + ya := fixed.Int26_6(d.y) + d.x += dxb + d.y += dyb + xb := fixed.Int26_6(d.x) + yb := fixed.Int26_6(d.y) + d.x += dxc + d.y += dyc + xc := fixed.Int26_6(d.x) + yc := fixed.Int26_6(d.y) + d.b.segments = append(d.b.segments, Segment{ + Op: SegmentOpCubeTo, + Args: [3]fixed.Point26_6{{X: xa, Y: ya}, {X: xb, Y: yb}, {X: xc, Y: yc}}, + }) +} + // psInterpreter is a PostScript interpreter. type psInterpreter struct { ctx psContext @@ -513,7 +721,7 @@ func (p *psInterpreter) parseNumber() (hasResult bool, err error) { number, hasResult = int32(int16(u16(p.instructions[1:]))), true p.instructions = p.instructions[3:] - case b == 29 && p.ctx == psContextTopDict: + case b == 29 && p.ctx != psContextType2Charstring: if len(p.instructions) < 5 { return true, errInvalidCFFTable } @@ -651,7 +859,7 @@ var psOperators = [...][2][]psOperator{ 15: {+1, "charset", nil}, 16: {+1, "Encoding", nil}, 17: {+1, "CharStrings", func(p *psInterpreter) error { - p.topDict.charStrings = p.argStack.a[p.argStack.top-1] + p.topDict.charStringsOffset = p.argStack.a[p.argStack.top-1] return nil }}, 18: {+2, "Private", func(p *psInterpreter) error { @@ -674,14 +882,23 @@ var psOperators = [...][2][]psOperator{ 21: {+1, "PostScript", nil}, 22: {+1, "BaseFontName", nil}, 23: {-2, "BaseFontBlend", nil}, - 30: {+3, "ROS", nil}, + 30: {+3, "ROS", func(p *psInterpreter) error { + p.topDict.isCIDFont = true + return nil + }}, 31: {+1, "CIDFontVersion", nil}, 32: {+1, "CIDFontRevision", nil}, 33: {+1, "CIDFontType", nil}, 34: {+1, "CIDCount", nil}, 35: {+1, "UIDBase", nil}, - 36: {+1, "FDArray", nil}, - 37: {+1, "FDSelect", nil}, + 36: {+1, "FDArray", func(p *psInterpreter) error { + p.topDict.fdArray = p.argStack.a[p.argStack.top-1] + return nil + }}, + 37: {+1, "FDSelect", func(p *psInterpreter) error { + p.topDict.fdSelect = p.argStack.a[p.argStack.top-1] + return nil + }}, 38: {+1, "FontName", nil}, }}, @@ -696,7 +913,7 @@ var psOperators = [...][2][]psOperator{ 10: {+1, "StdHW", nil}, 11: {+1, "StdVW", nil}, 19: {+1, "Subrs", func(p *psInterpreter) error { - p.privateDict.subrs = p.argStack.a[p.argStack.top-1] + p.privateDict.subrsOffset = p.argStack.a[p.argStack.top-1] return nil }}, 20: {+1, "defaultWidthX", nil}, @@ -762,7 +979,8 @@ var psOperators = [...][2][]psOperator{ const escapeByte = 12 // t2CReadWidth reads the optional width adjustment. If present, it is on the -// bottom of the stack. +// bottom of the arg stack. nArgs is the expected number of arguments on the +// stack. A negative nArgs means a multiple of 2. // // 5177.Type2.pdf page 16 Note 4 says: "The first stack-clearing operator, // which must be one of hstem, hstemhm, vstem, vstemhm, cntrmask, hintmask, @@ -773,19 +991,12 @@ func t2CReadWidth(p *psInterpreter, nArgs int32) { return } p.type2Charstrings.seenWidth = true - switch nArgs { - case 0: - if p.argStack.top != 1 { - return - } - case 1: - if p.argStack.top <= 1 { - return - } - default: - if p.argStack.top%nArgs != 1 { + if nArgs >= 0 { + if p.argStack.top != nArgs+1 { return } + } else if p.argStack.top&1 == 0 { + return } // When parsing a standalone CFF, we'd save the value of p.argStack.a[0] // here as it defines the glyph's width (horizontal advance). Specifically, @@ -803,7 +1014,7 @@ func t2CReadWidth(p *psInterpreter, nArgs int32) { } func t2CStem(p *psInterpreter) error { - t2CReadWidth(p, 2) + t2CReadWidth(p, -1) if p.argStack.top%2 != 0 { return errInvalidCFFTable } @@ -818,8 +1029,27 @@ func t2CStem(p *psInterpreter) error { } func t2CMask(p *psInterpreter) error { + // 5176.CFF.pdf section 4.3 "Hint Operators" says that "If hstem and vstem + // hints are both declared at the beginning of a charstring, and this + // sequence is followed directly by the hintmask or cntrmask operators, the + // vstem hint operator need not be included." + // + // What we implement here is more permissive (but the same as what the + // FreeType implementation does, and simpler than tracking the previous + // operator and other hinting state): if a hintmask is given any arguments + // (i.e. the argStack is non-empty), we run an implicit vstem operator. + // + // Note that the vstem operator consumes from p.argStack, but the hintmask + // or cntrmask operators consume from p.instructions. + if p.argStack.top != 0 { + if err := t2CStem(p); err != nil { + return err + } + } else if !p.type2Charstrings.seenWidth { + p.type2Charstrings.seenWidth = true + } + hintBytes := (p.type2Charstrings.hintBits + 7) / 8 - t2CReadWidth(p, hintBytes) if len(p.instructions) < int(hintBytes) { return errInvalidCFFTable } @@ -827,86 +1057,30 @@ func t2CMask(p *psInterpreter) error { return nil } -func t2CAppendMoveto(p *psInterpreter) { - p.type2Charstrings.b.segments = append(p.type2Charstrings.b.segments, Segment{ - Op: SegmentOpMoveTo, - Args: [6]fixed.Int26_6{ - 0: fixed.Int26_6(p.type2Charstrings.x), - 1: fixed.Int26_6(p.type2Charstrings.y), - }, - }) -} - -func t2CAppendLineto(p *psInterpreter) { - p.type2Charstrings.b.segments = append(p.type2Charstrings.b.segments, Segment{ - Op: SegmentOpLineTo, - Args: [6]fixed.Int26_6{ - 0: fixed.Int26_6(p.type2Charstrings.x), - 1: fixed.Int26_6(p.type2Charstrings.y), - }, - }) -} - -func t2CAppendCubeto(p *psInterpreter, dxa, dya, dxb, dyb, dxc, dyc int32) { - p.type2Charstrings.x += dxa - p.type2Charstrings.y += dya - xa := p.type2Charstrings.x - ya := p.type2Charstrings.y - p.type2Charstrings.x += dxb - p.type2Charstrings.y += dyb - xb := p.type2Charstrings.x - yb := p.type2Charstrings.y - p.type2Charstrings.x += dxc - p.type2Charstrings.y += dyc - xc := p.type2Charstrings.x - yc := p.type2Charstrings.y - p.type2Charstrings.b.segments = append(p.type2Charstrings.b.segments, Segment{ - Op: SegmentOpCubeTo, - Args: [6]fixed.Int26_6{ - 0: fixed.Int26_6(xa), - 1: fixed.Int26_6(ya), - 2: fixed.Int26_6(xb), - 3: fixed.Int26_6(yb), - 4: fixed.Int26_6(xc), - 5: fixed.Int26_6(yc), - }, - }) -} - func t2CHmoveto(p *psInterpreter) error { t2CReadWidth(p, 1) - if p.argStack.top < 1 { + if p.argStack.top != 1 { return errInvalidCFFTable } - for i := int32(0); i < p.argStack.top; i++ { - p.type2Charstrings.x += p.argStack.a[i] - } - t2CAppendMoveto(p) + p.type2Charstrings.moveTo(p.argStack.a[0], 0) return nil } func t2CVmoveto(p *psInterpreter) error { t2CReadWidth(p, 1) - if p.argStack.top < 1 { + if p.argStack.top != 1 { return errInvalidCFFTable } - for i := int32(0); i < p.argStack.top; i++ { - p.type2Charstrings.y += p.argStack.a[i] - } - t2CAppendMoveto(p) + p.type2Charstrings.moveTo(0, p.argStack.a[0]) return nil } func t2CRmoveto(p *psInterpreter) error { t2CReadWidth(p, 2) - if p.argStack.top < 2 || p.argStack.top%2 != 0 { + if p.argStack.top != 2 { return errInvalidCFFTable } - for i := int32(0); i < p.argStack.top; i += 2 { - p.type2Charstrings.x += p.argStack.a[i+0] - p.type2Charstrings.y += p.argStack.a[i+1] - } - t2CAppendMoveto(p) + p.type2Charstrings.moveTo(p.argStack.a[0], p.argStack.a[1]) return nil } @@ -918,12 +1092,11 @@ func t2CLineto(p *psInterpreter, vertical bool) error { return errInvalidCFFTable } for i := int32(0); i < p.argStack.top; i, vertical = i+1, !vertical { + dx, dy := p.argStack.a[i], int32(0) if vertical { - p.type2Charstrings.y += p.argStack.a[i] - } else { - p.type2Charstrings.x += p.argStack.a[i] + dx, dy = dy, dx } - t2CAppendLineto(p) + p.type2Charstrings.lineTo(dx, dy) } return nil } @@ -933,9 +1106,7 @@ func t2CRlineto(p *psInterpreter) error { return errInvalidCFFTable } for i := int32(0); i < p.argStack.top; i += 2 { - p.type2Charstrings.x += p.argStack.a[i+0] - p.type2Charstrings.y += p.argStack.a[i+1] - t2CAppendLineto(p) + p.type2Charstrings.lineTo(p.argStack.a[i], p.argStack.a[i+1]) } return nil } @@ -954,7 +1125,7 @@ func t2CRcurveline(p *psInterpreter) error { } i := int32(0) for iMax := p.argStack.top - 2; i < iMax; i += 6 { - t2CAppendCubeto(p, + p.type2Charstrings.cubeTo( p.argStack.a[i+0], p.argStack.a[i+1], p.argStack.a[i+2], @@ -963,9 +1134,7 @@ func t2CRcurveline(p *psInterpreter) error { p.argStack.a[i+5], ) } - p.type2Charstrings.x += p.argStack.a[i+0] - p.type2Charstrings.y += p.argStack.a[i+1] - t2CAppendLineto(p) + p.type2Charstrings.lineTo(p.argStack.a[i], p.argStack.a[i+1]) return nil } @@ -975,11 +1144,9 @@ func t2CRlinecurve(p *psInterpreter) error { } i := int32(0) for iMax := p.argStack.top - 6; i < iMax; i += 2 { - p.type2Charstrings.x += p.argStack.a[i+0] - p.type2Charstrings.y += p.argStack.a[i+1] - t2CAppendLineto(p) + p.type2Charstrings.lineTo(p.argStack.a[i], p.argStack.a[i+1]) } - t2CAppendCubeto(p, + p.type2Charstrings.cubeTo( p.argStack.a[i+0], p.argStack.a[i+1], p.argStack.a[i+2], @@ -1083,7 +1250,7 @@ func t2CCurveto4(p *psInterpreter, swap bool, vertical bool, i int32) (j int32) dxc, dyc = dyc, dxc } - t2CAppendCubeto(p, dxa, dya, dxb, dyb, dxc, dyc) + p.type2Charstrings.cubeTo(dxa, dya, dxb, dyb, dxc, dyc) return i } @@ -1092,7 +1259,7 @@ func t2CRrcurveto(p *psInterpreter) error { return errInvalidCFFTable } for i := int32(0); i != p.argStack.top; i += 6 { - t2CAppendCubeto(p, + p.type2Charstrings.cubeTo( p.argStack.a[i+0], p.argStack.a[i+1], p.argStack.a[i+2], @@ -1116,8 +1283,29 @@ func subrBias(numSubroutines int) int32 { return 32768 } -func t2CCallgsubr(p *psInterpreter) error { return t2CCall(p, p.type2Charstrings.f.cached.gsubrs) } -func t2CCallsubr(p *psInterpreter) error { return t2CCall(p, p.type2Charstrings.f.cached.subrs) } +func t2CCallgsubr(p *psInterpreter) error { + return t2CCall(p, p.type2Charstrings.f.cached.glyphData.gsubrs) +} + +func t2CCallsubr(p *psInterpreter) error { + t := &p.type2Charstrings + d := &t.f.cached.glyphData + subrs := d.singleSubrs + if d.multiSubrs != nil { + if t.fdSelectIndexPlusOne == 0 { + index, err := d.fdSelect.lookup(t.f, t.b, t.glyphIndex) + if err != nil { + return err + } + if index < 0 || len(d.multiSubrs) <= index { + return errInvalidCFFTable + } + t.fdSelectIndexPlusOne = int32(index + 1) + } + subrs = d.multiSubrs[t.fdSelectIndexPlusOne-1] + } + return t2CCall(p, subrs) +} func t2CCall(p *psInterpreter, subrs []uint32) error { if p.callStack.top == psCallStackSize || len(subrs) == 0 { @@ -1181,6 +1369,7 @@ func t2CEndchar(p *psInterpreter) error { } return errInvalidCFFTable } + p.type2Charstrings.closePath() p.type2Charstrings.ended = true return nil } -- cgit v1.2.3-1-g7c22