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/sfnt.go | 399 +++++++++++++++++++++++----- 1 file changed, 327 insertions(+), 72 deletions(-) (limited to 'vendor/golang.org/x/image/font/sfnt/sfnt.go') diff --git a/vendor/golang.org/x/image/font/sfnt/sfnt.go b/vendor/golang.org/x/image/font/sfnt/sfnt.go index 356841db1..5cb1225ef 100644 --- a/vendor/golang.org/x/image/font/sfnt/sfnt.go +++ b/vendor/golang.org/x/image/font/sfnt/sfnt.go @@ -53,6 +53,7 @@ const ( maxCompoundStackSize = 64 maxGlyphDataLength = 64 * 1024 maxHintBits = 256 + maxNumFontDicts = 256 maxNumFonts = 256 maxNumTables = 256 maxRealNumberStrLen = 64 // Maximum length in bytes of the "-123.456E-7" representation. @@ -69,11 +70,14 @@ var ( errInvalidBounds = errors.New("sfnt: invalid bounds") errInvalidCFFTable = errors.New("sfnt: invalid CFF table") errInvalidCmapTable = errors.New("sfnt: invalid cmap table") + errInvalidDfont = errors.New("sfnt: invalid dfont") errInvalidFont = errors.New("sfnt: invalid font") errInvalidFontCollection = errors.New("sfnt: invalid font collection") errInvalidGlyphData = errors.New("sfnt: invalid glyph data") errInvalidGlyphDataLength = errors.New("sfnt: invalid glyph data length") errInvalidHeadTable = errors.New("sfnt: invalid head table") + errInvalidHheaTable = errors.New("sfnt: invalid hhea table") + errInvalidHmtxTable = errors.New("sfnt: invalid hmtx table") errInvalidKernTable = errors.New("sfnt: invalid kern table") errInvalidLocaTable = errors.New("sfnt: invalid loca table") errInvalidLocationData = errors.New("sfnt: invalid location data") @@ -86,6 +90,7 @@ var ( errInvalidTableTagOrder = errors.New("sfnt: invalid table tag order") errInvalidUCS2String = errors.New("sfnt: invalid UCS-2 string") + errUnsupportedCFFFDSelectTable = errors.New("sfnt: unsupported CFF FDSelect table") errUnsupportedCFFVersion = errors.New("sfnt: unsupported CFF version") errUnsupportedCmapEncodings = errors.New("sfnt: unsupported cmap encodings") errUnsupportedCompoundGlyph = errors.New("sfnt: unsupported compound glyph") @@ -93,6 +98,7 @@ var ( errUnsupportedKernTable = errors.New("sfnt: unsupported kern table") errUnsupportedRealNumberEncoding = errors.New("sfnt: unsupported real number encoding") errUnsupportedNumberOfCmapSegments = errors.New("sfnt: unsupported number of cmap segments") + errUnsupportedNumberOfFontDicts = errors.New("sfnt: unsupported number of font dicts") errUnsupportedNumberOfFonts = errors.New("sfnt: unsupported number of fonts") errUnsupportedNumberOfHints = errors.New("sfnt: unsupported number of hints") errUnsupportedNumberOfSubroutines = errors.New("sfnt: unsupported number of subroutines") @@ -298,6 +304,7 @@ func ParseCollectionReaderAt(src io.ReaderAt) (*Collection, error) { type Collection struct { src source offsets []uint32 + isDfont bool } // NumFonts returns the number of fonts in the collection. @@ -305,8 +312,13 @@ func (c *Collection) NumFonts() int { return len(c.offsets) } func (c *Collection) initialize() error { // The https://www.microsoft.com/typography/otspec/otff.htm "Font - // Collections" section describes the TTC Header. - buf, err := c.src.view(nil, 0, 12) + // Collections" section describes the TTC header. + // + // https://github.com/kreativekorp/ksfl/wiki/Macintosh-Resource-File-Format + // describes the dfont header. + // + // 16 is the maximum of sizeof(TTCHeader) and sizeof(DfontHeader). + buf, err := c.src.view(nil, 0, 16) if err != nil { return err } @@ -314,6 +326,8 @@ func (c *Collection) initialize() error { switch u32(buf) { default: return errInvalidFontCollection + case dfontResourceDataOffset: + return c.parseDfont(buf, u32(buf[4:]), u32(buf[12:])) case 0x00010000, 0x4f54544f: // Try parsing it as a single font instead of a collection. c.offsets = []uint32{0} @@ -338,13 +352,116 @@ func (c *Collection) initialize() error { return nil } +// dfontResourceDataOffset is the assumed value of a dfont file's resource data +// offset. +// +// https://github.com/kreativekorp/ksfl/wiki/Macintosh-Resource-File-Format +// says that "A Mac OS resource file... [starts with an] offset from start of +// file to start of resource data section... [usually] 0x0100". In theory, +// 0x00000100 isn't always a magic number for identifying dfont files. In +// practice, it seems to work. +const dfontResourceDataOffset = 0x00000100 + +// parseDfont parses a dfont resource map, as per +// https://github.com/kreativekorp/ksfl/wiki/Macintosh-Resource-File-Format +// +// That unofficial wiki page lists all of its fields as *signed* integers, +// which looks unusual. The actual file format might use *unsigned* integers in +// various places, but until we have either an official specification or an +// actual dfont file where this matters, we'll use signed integers and treat +// negative values as invalid. +func (c *Collection) parseDfont(buf []byte, resourceMapOffset, resourceMapLength uint32) error { + if resourceMapOffset > maxTableOffset || resourceMapLength > maxTableLength { + return errUnsupportedTableOffsetLength + } + + const headerSize = 28 + if resourceMapLength < headerSize { + return errInvalidDfont + } + buf, err := c.src.view(buf, int(resourceMapOffset+24), 2) + if err != nil { + return err + } + typeListOffset := int(int16(u16(buf))) + + if typeListOffset < headerSize || resourceMapLength < uint32(typeListOffset)+2 { + return errInvalidDfont + } + buf, err = c.src.view(buf, int(resourceMapOffset)+typeListOffset, 2) + if err != nil { + return err + } + typeCount := int(int16(u16(buf))) + + const tSize = 8 + if typeCount < 0 || tSize*uint32(typeCount) > resourceMapLength-uint32(typeListOffset)-2 { + return errInvalidDfont + } + buf, err = c.src.view(buf, int(resourceMapOffset)+typeListOffset+2, tSize*typeCount) + if err != nil { + return err + } + resourceCount, resourceListOffset := 0, 0 + for i := 0; i < typeCount; i++ { + if u32(buf[tSize*i:]) != 0x73666e74 { // "sfnt". + continue + } + + resourceCount = int(int16(u16(buf[tSize*i+4:]))) + if resourceCount < 0 { + return errInvalidDfont + } + // https://github.com/kreativekorp/ksfl/wiki/Macintosh-Resource-File-Format + // says that the value in the wire format is "the number of + // resources of this type, minus one." + resourceCount++ + + resourceListOffset = int(int16(u16(buf[tSize*i+6:]))) + if resourceListOffset < 0 { + return errInvalidDfont + } + break + } + if resourceCount == 0 { + return errInvalidDfont + } + if resourceCount > maxNumFonts { + return errUnsupportedNumberOfFonts + } + + const rSize = 12 + if o, n := uint32(typeListOffset+resourceListOffset), rSize*uint32(resourceCount); o > resourceMapLength || n > resourceMapLength-o { + return errInvalidDfont + } else { + buf, err = c.src.view(buf, int(resourceMapOffset+o), int(n)) + if err != nil { + return err + } + } + c.offsets = make([]uint32, resourceCount) + for i := range c.offsets { + o := 0xffffff & u32(buf[rSize*i+4:]) + // Offsets are relative to the resource data start, not the file start. + // A particular resource's data also starts with a 4-byte length, which + // we skip. + o += dfontResourceDataOffset + 4 + if o > maxTableOffset { + return errUnsupportedTableOffsetLength + } + c.offsets[i] = o + } + c.isDfont = true + return nil +} + // Font returns the i'th font in the collection. func (c *Collection) Font(i int) (*Font, error) { if i < 0 || len(c.offsets) <= i { return nil, ErrNotFound } f := &Font{src: c.src} - if err := f.initialize(int(c.offsets[i])); err != nil { + if err := f.initialize(int(c.offsets[i]), c.isDfont); err != nil { return nil, err } return f, nil @@ -354,7 +471,7 @@ func (c *Collection) Font(i int) (*Font, error) { // source. func Parse(src []byte) (*Font, error) { f := &Font{src: source{b: src}} - if err := f.initialize(0); err != nil { + if err := f.initialize(0, false); err != nil { return nil, err } return f, nil @@ -364,7 +481,7 @@ func Parse(src []byte) (*Font, error) { // io.ReaderAt data source. func ParseReaderAt(src io.ReaderAt) (*Font, error) { f := &Font{src: source{r: src}} - if err := f.initialize(0); err != nil { + if err := f.initialize(0, false); err != nil { return nil, err } return f, nil @@ -438,39 +555,30 @@ type Font struct { kern table cached struct { + glyphData glyphData glyphIndex glyphIndexFunc + bounds [4]int16 indexToLocFormat bool // false means short, true means long. isPostScript bool kernNumPairs int32 kernOffset int32 + numHMetrics int32 postTableVersion uint32 unitsPerEm Units - - // The glyph data for the i'th glyph index is in - // src[locations[i+0]:locations[i+1]]. - // - // The slice length equals 1 plus the number of glyphs. - locations []uint32 - - // For PostScript fonts, the bytecode for the i'th global or local - // subroutine is in src[x[i+0]:x[i+1]]. - // - // The slice length equals 1 plus the number of subroutines - gsubrs, subrs []uint32 } } // NumGlyphs returns the number of glyphs in f. -func (f *Font) NumGlyphs() int { return len(f.cached.locations) - 1 } +func (f *Font) NumGlyphs() int { return len(f.cached.glyphData.locations) - 1 } // UnitsPerEm returns the number of units per em for f. func (f *Font) UnitsPerEm() Units { return f.cached.unitsPerEm } -func (f *Font) initialize(offset int) error { +func (f *Font) initialize(offset int, isDfont bool) error { if !f.src.valid() { return errInvalidSourceData } - buf, isPostScript, err := f.initializeTables(offset) + buf, isPostScript, err := f.initializeTables(offset, isDfont) if err != nil { return err } @@ -483,11 +591,15 @@ func (f *Font) initialize(offset int) error { // When implementing new parseXxx methods, take care not to call methods // such as Font.NumGlyphs that implicitly depend on f.cached fields. - buf, indexToLocFormat, unitsPerEm, err := f.parseHead(buf) + buf, bounds, indexToLocFormat, unitsPerEm, err := f.parseHead(buf) if err != nil { return err } - buf, numGlyphs, locations, gsubrs, subrs, err := f.parseMaxp(buf, indexToLocFormat, isPostScript) + buf, numGlyphs, err := f.parseMaxp(buf, isPostScript) + if err != nil { + return err + } + buf, glyphData, err := f.parseGlyphData(buf, numGlyphs, indexToLocFormat, isPostScript) if err != nil { return err } @@ -499,26 +611,34 @@ func (f *Font) initialize(offset int) error { if err != nil { return err } + buf, numHMetrics, err := f.parseHhea(buf, numGlyphs) + if err != nil { + return err + } + buf, err = f.parseHmtx(buf, numGlyphs, numHMetrics) + if err != nil { + return err + } buf, postTableVersion, err := f.parsePost(buf, numGlyphs) if err != nil { return err } + f.cached.glyphData = glyphData f.cached.glyphIndex = glyphIndex + f.cached.bounds = bounds f.cached.indexToLocFormat = indexToLocFormat f.cached.isPostScript = isPostScript f.cached.kernNumPairs = kernNumPairs f.cached.kernOffset = kernOffset + f.cached.numHMetrics = numHMetrics f.cached.postTableVersion = postTableVersion f.cached.unitsPerEm = unitsPerEm - f.cached.locations = locations - f.cached.gsubrs = gsubrs - f.cached.subrs = subrs return nil } -func (f *Font) initializeTables(offset int) (buf1 []byte, isPostScript bool, err error) { +func (f *Font) initializeTables(offset int, isDfont bool) (buf1 []byte, isPostScript bool, err error) { // https://www.microsoft.com/typography/otspec/otff.htm "Organization of an // OpenType Font" says that "The OpenType font starts with the Offset // Table", which is 12 bytes. @@ -531,6 +651,8 @@ func (f *Font) initializeTables(offset int) (buf1 []byte, isPostScript bool, err switch u32(buf) { default: return nil, false, errInvalidFont + case dfontResourceDataOffset: + return nil, false, errInvalidSingleFont case 0x00010000: // No-op. case 0x4f54544f: // "OTTO". @@ -559,6 +681,15 @@ func (f *Font) initializeTables(offset int) (buf1 []byte, isPostScript bool, err prevTag = tag o, n := u32(b[8:12]), u32(b[12:16]) + // For dfont files, the offset is relative to the resource, not the + // file. + if isDfont { + origO := o + o += uint32(offset) + if o < origO { + return nil, false, errUnsupportedTableOffsetLength + } + } if o > maxTableOffset || n > maxTableLength { return nil, false, errUnsupportedTableOffsetLength } @@ -662,26 +793,61 @@ func (f *Font) parseCmap(buf []byte) (buf1 []byte, glyphIndex glyphIndexFunc, er return f.makeCachedGlyphIndex(buf, bestOffset, bestLength, bestFormat) } -func (f *Font) parseHead(buf []byte) (buf1 []byte, indexToLocFormat bool, unitsPerEm Units, err error) { +func (f *Font) parseHead(buf []byte) (buf1 []byte, bounds [4]int16, indexToLocFormat bool, unitsPerEm Units, err error) { // https://www.microsoft.com/typography/otspec/head.htm if f.head.length != 54 { - return nil, false, 0, errInvalidHeadTable + return nil, [4]int16{}, false, 0, errInvalidHeadTable } + u, err := f.src.u16(buf, f.head, 18) if err != nil { - return nil, false, 0, err + return nil, [4]int16{}, false, 0, err } if u == 0 { - return nil, false, 0, errInvalidHeadTable + return nil, [4]int16{}, false, 0, errInvalidHeadTable } unitsPerEm = Units(u) + + for i := range bounds { + u, err := f.src.u16(buf, f.head, 36+2*i) + if err != nil { + return nil, [4]int16{}, false, 0, err + } + bounds[i] = int16(u) + } + u, err = f.src.u16(buf, f.head, 50) if err != nil { - return nil, false, 0, err + return nil, [4]int16{}, false, 0, err } indexToLocFormat = u != 0 - return buf, indexToLocFormat, unitsPerEm, nil + return buf, bounds, indexToLocFormat, unitsPerEm, nil +} + +func (f *Font) parseHhea(buf []byte, numGlyphs int32) (buf1 []byte, numHMetrics int32, err error) { + // https://www.microsoft.com/typography/OTSPEC/hhea.htm + + if f.hhea.length != 36 { + return nil, 0, errInvalidHheaTable + } + u, err := f.src.u16(buf, f.hhea, 34) + if err != nil { + return nil, 0, err + } + if int32(u) > numGlyphs || u == 0 { + return nil, 0, errInvalidHheaTable + } + return buf, int32(u), nil +} + +func (f *Font) parseHmtx(buf []byte, numGlyphs, numHMetrics int32) (buf1 []byte, err error) { + // https://www.microsoft.com/typography/OTSPEC/hmtx.htm + + if f.hmtx.length != uint32(2*numGlyphs+2*numHMetrics) { + return nil, errInvalidHmtxTable + } + return buf, nil } func (f *Font) parseKern(buf []byte) (buf1 []byte, kernNumPairs, kernOffset int32, err error) { @@ -778,24 +944,44 @@ func (f *Font) parseKernFormat0(buf []byte, offset, length int) (buf1 []byte, ke return buf, kernNumPairs, int32(offset) + headerSize, nil } -func (f *Font) parseMaxp(buf []byte, indexToLocFormat, isPostScript bool) (buf1 []byte, numGlyphs int, locations, gsubrs, subrs []uint32, err error) { +func (f *Font) parseMaxp(buf []byte, isPostScript bool) (buf1 []byte, numGlyphs int32, err error) { // https://www.microsoft.com/typography/otspec/maxp.htm if isPostScript { if f.maxp.length != 6 { - return nil, 0, nil, nil, nil, errInvalidMaxpTable + return nil, 0, errInvalidMaxpTable } } else { if f.maxp.length != 32 { - return nil, 0, nil, nil, nil, errInvalidMaxpTable + return nil, 0, errInvalidMaxpTable } } u, err := f.src.u16(buf, f.maxp, 4) if err != nil { - return nil, 0, nil, nil, nil, err + return nil, 0, err } - numGlyphs = int(u) + return buf, int32(u), nil +} + +type glyphData struct { + // The glyph data for the i'th glyph index is in + // src[locations[i+0]:locations[i+1]]. + // + // The slice length equals 1 plus the number of glyphs. + locations []uint32 + + // For PostScript fonts, the bytecode for the i'th global or local + // subroutine is in src[x[i+0]:x[i+1]]. + // + // The []uint32 slice length equals 1 plus the number of subroutines + gsubrs []uint32 + singleSubrs []uint32 + multiSubrs [][]uint32 + + fdSelect fdSelect +} +func (f *Font) parseGlyphData(buf []byte, numGlyphs int32, indexToLocFormat, isPostScript bool) (buf1 []byte, ret glyphData, err error) { if isPostScript { p := cffParser{ src: &f.src, @@ -803,24 +989,24 @@ func (f *Font) parseMaxp(buf []byte, indexToLocFormat, isPostScript bool) (buf1 offset: int(f.cff.offset), end: int(f.cff.offset + f.cff.length), } - locations, gsubrs, subrs, err = p.parse() + ret, err = p.parse(numGlyphs) if err != nil { - return nil, 0, nil, nil, nil, err + return nil, glyphData{}, err } } else { - locations, err = parseLoca(&f.src, f.loca, f.glyf.offset, indexToLocFormat, numGlyphs) + ret.locations, err = parseLoca(&f.src, f.loca, f.glyf.offset, indexToLocFormat, numGlyphs) if err != nil { - return nil, 0, nil, nil, nil, err + return nil, glyphData{}, err } } - if len(locations) != numGlyphs+1 { - return nil, 0, nil, nil, nil, errInvalidLocationData + if len(ret.locations) != int(numGlyphs+1) { + return nil, glyphData{}, errInvalidLocationData } - return buf, numGlyphs, locations, gsubrs, subrs, nil + return buf, ret, nil } -func (f *Font) parsePost(buf []byte, numGlyphs int) (buf1 []byte, postTableVersion uint32, err error) { +func (f *Font) parsePost(buf []byte, numGlyphs int32) (buf1 []byte, postTableVersion uint32, err error) { // https://www.microsoft.com/typography/otspec/post.htm const headerSize = 32 @@ -844,6 +1030,33 @@ func (f *Font) parsePost(buf []byte, numGlyphs int) (buf1 []byte, postTableVersi return buf, u, nil } +// Bounds returns the union of a Font's glyphs' bounds. +// +// In the returned Rectangle26_6's (x, y) coordinates, the Y axis increases +// down. +func (f *Font) Bounds(b *Buffer, ppem fixed.Int26_6, h font.Hinting) (fixed.Rectangle26_6, error) { + // The 0, 3, 2, 1 indices are to flip the Y coordinates. OpenType's Y axis + // increases up. Go's standard graphics libraries' Y axis increases down. + r := fixed.Rectangle26_6{ + Min: fixed.Point26_6{ + X: +scale(fixed.Int26_6(f.cached.bounds[0])*ppem, f.cached.unitsPerEm), + Y: -scale(fixed.Int26_6(f.cached.bounds[3])*ppem, f.cached.unitsPerEm), + }, + Max: fixed.Point26_6{ + X: +scale(fixed.Int26_6(f.cached.bounds[2])*ppem, f.cached.unitsPerEm), + Y: -scale(fixed.Int26_6(f.cached.bounds[1])*ppem, f.cached.unitsPerEm), + }, + } + if h == font.HintingFull { + // Quantize the Min down and Max up to a whole pixel. + r.Min.X = (r.Min.X + 0) &^ 63 + r.Min.Y = (r.Min.Y + 0) &^ 63 + r.Max.X = (r.Max.X + 63) &^ 63 + r.Max.Y = (r.Max.Y + 63) &^ 63 + } + return r, nil +} + // TODO: API for looking up glyph variants?? For example, some fonts may // provide both slashed and dotted zero glyphs ('0'), or regular and 'old // style' numerals, and users can direct software to choose a variant. @@ -866,8 +1079,8 @@ func (f *Font) viewGlyphData(b *Buffer, x GlyphIndex) (buf []byte, offset, lengt if f.NumGlyphs() <= xx { return nil, 0, 0, ErrNotFound } - i := f.cached.locations[xx+0] - j := f.cached.locations[xx+1] + i := f.cached.glyphData.locations[xx+0] + j := f.cached.glyphData.locations[xx+1] if j < i { return nil, 0, 0, errInvalidGlyphDataLength } @@ -888,6 +1101,8 @@ type LoadGlyphOptions struct { // // If b is non-nil, the segments become invalid to use once b is re-used. // +// In the returned Segments' (x, y) coordinates, the Y axis increases down. +// // It returns ErrNotFound if the glyph index is out of range. func (f *Font) LoadGlyph(b *Buffer, x GlyphIndex, ppem fixed.Int26_6, opts *LoadGlyphOptions) ([]Segment, error) { if b == nil { @@ -900,7 +1115,7 @@ func (f *Font) LoadGlyph(b *Buffer, x GlyphIndex, ppem fixed.Int26_6, opts *Load if err != nil { return nil, err } - b.psi.type2Charstrings.initialize(f, b) + b.psi.type2Charstrings.initialize(f, b, x) if err := b.psi.run(psContextType2Charstring, buf, offset, length); err != nil { return nil, err } @@ -918,10 +1133,14 @@ func (f *Font) LoadGlyph(b *Buffer, x GlyphIndex, ppem fixed.Int26_6, opts *Load // loading code, such as the appendGlyfSegments body, since TrueType // hinting bytecode works on the scaled glyph vectors. For now, though, // it's simpler to scale as a post-processing step. + // + // We also flip the Y coordinates. OpenType's Y axis increases up. Go's + // standard graphics libraries' Y axis increases down. for i := range b.segments { - s := &b.segments[i] - for j := range s.Args { - s.Args[j] = scale(s.Args[j]*ppem, f.cached.unitsPerEm) + a := &b.segments[i].Args + for j := range a { + a[j].X = +scale(a[j].X*ppem, f.cached.unitsPerEm) + a[j].Y = -scale(a[j].Y*ppem, f.cached.unitsPerEm) } } @@ -1002,6 +1221,39 @@ func (f *Font) GlyphName(b *Buffer, x GlyphIndex) (string, error) { } } +// GlyphAdvance returns the advance width for the x'th glyph. ppem is the +// number of pixels in 1 em. +// +// It returns ErrNotFound if the glyph index is out of range. +func (f *Font) GlyphAdvance(b *Buffer, x GlyphIndex, ppem fixed.Int26_6, h font.Hinting) (fixed.Int26_6, error) { + if int(x) >= f.NumGlyphs() { + return 0, ErrNotFound + } + if b == nil { + b = &Buffer{} + } + + // https://www.microsoft.com/typography/OTSPEC/hmtx.htm says that "As an + // optimization, the number of records can be less than the number of + // glyphs, in which case the advance width value of the last record applies + // to all remaining glyph IDs." + if n := GlyphIndex(f.cached.numHMetrics - 1); x > n { + x = n + } + + buf, err := b.view(&f.src, int(f.hmtx.offset)+int(4*x), 2) + if err != nil { + return 0, err + } + adv := fixed.Int26_6(u16(buf)) + adv = scale(adv*ppem, f.cached.unitsPerEm) + if h == font.HintingFull { + // Quantize the fixed.Int26_6 value to the nearest pixel. + adv = (adv + 32) &^ 63 + } + return adv, nil +} + // Kern returns the horizontal adjustment for the kerning pair (x0, x1). A // positive kern means to move the glyphs further apart. ppem is the number of // pixels in 1 em. @@ -1180,8 +1432,10 @@ func (b *Buffer) view(src *source, offset, length int) ([]byte, error) { // Segment is a segment of a vector path. type Segment struct { - Op SegmentOp - Args [6]fixed.Int26_6 + // Op is the operator. + Op SegmentOp + // Args is up to three (x, y) coordinates. The Y axis increases down. + Args [3]fixed.Point26_6 } // SegmentOp is a vector path segment's operator. @@ -1195,30 +1449,31 @@ const ( ) // translateArgs applies a translation to args. -func translateArgs(args *[6]fixed.Int26_6, dx, dy fixed.Int26_6) { - args[0] += dx - args[1] += dy - args[2] += dx - args[3] += dy - args[4] += dx - args[5] += dy +func translateArgs(args *[3]fixed.Point26_6, dx, dy fixed.Int26_6) { + args[0].X += dx + args[0].Y += dy + args[1].X += dx + args[1].Y += dy + args[2].X += dx + args[2].Y += dy } // transformArgs applies an affine transformation to args. The t?? arguments // are 2.14 fixed point values. -func transformArgs(args *[6]fixed.Int26_6, txx, txy, tyx, tyy int16, dx, dy fixed.Int26_6) { - args[0], args[1] = tform(txx, txy, tyx, tyy, dx, dy, args[0], args[1]) - args[2], args[3] = tform(txx, txy, tyx, tyy, dx, dy, args[2], args[3]) - args[4], args[5] = tform(txx, txy, tyx, tyy, dx, dy, args[4], args[5]) +func transformArgs(args *[3]fixed.Point26_6, txx, txy, tyx, tyy int16, dx, dy fixed.Int26_6) { + args[0] = tform(txx, txy, tyx, tyy, dx, dy, args[0]) + args[1] = tform(txx, txy, tyx, tyy, dx, dy, args[1]) + args[2] = tform(txx, txy, tyx, tyy, dx, dy, args[2]) } -func tform(txx, txy, tyx, tyy int16, dx, dy, x, y fixed.Int26_6) (newX, newY fixed.Int26_6) { +func tform(txx, txy, tyx, tyy int16, dx, dy fixed.Int26_6, p fixed.Point26_6) fixed.Point26_6 { const half = 1 << 13 - newX = dx + - fixed.Int26_6((int64(x)*int64(txx)+half)>>14) + - fixed.Int26_6((int64(y)*int64(tyx)+half)>>14) - newY = dy + - fixed.Int26_6((int64(x)*int64(txy)+half)>>14) + - fixed.Int26_6((int64(y)*int64(tyy)+half)>>14) - return newX, newY + return fixed.Point26_6{ + X: dx + + fixed.Int26_6((int64(p.X)*int64(txx)+half)>>14) + + fixed.Int26_6((int64(p.Y)*int64(tyx)+half)>>14), + Y: dy + + fixed.Int26_6((int64(p.X)*int64(txy)+half)>>14) + + fixed.Int26_6((int64(p.Y)*int64(tyy)+half)>>14), + } } -- cgit v1.2.3-1-g7c22