From 54d3d47daf9190275bbdaf8703b84969a4593451 Mon Sep 17 00:00:00 2001 From: Corey Hulen Date: Fri, 24 Mar 2017 23:31:34 -0700 Subject: PLT-6076 Adding viper libs for config file changes (#5871) * Adding viper libs for config file changes * Removing the old fsnotify lib * updating some missing libs --- vendor/golang.org/x/image/font/sfnt/sfnt.go | 292 ++++++++++++++++++++++------ 1 file changed, 229 insertions(+), 63 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 02efd5f3a..356841db1 100644 --- a/vendor/golang.org/x/image/font/sfnt/sfnt.go +++ b/vendor/golang.org/x/image/font/sfnt/sfnt.go @@ -45,10 +45,17 @@ const ( // safe to call concurrently, as long as each call has a different *Buffer. maxCmapSegments = 20000 - maxGlyphDataLength = 64 * 1024 - maxHintBits = 256 - maxNumTables = 256 - maxRealNumberStrLen = 64 // Maximum length in bytes of the "-123.456E-7" representation. + // TODO: similarly, load subroutine locations lazily. Adobe's + // SourceHanSansSC-Regular.otf has up to 30000 subroutines. + maxNumSubroutines = 40000 + + maxCompoundRecursionDepth = 8 + maxCompoundStackSize = 64 + maxGlyphDataLength = 64 * 1024 + maxHintBits = 256 + maxNumFonts = 256 + maxNumTables = 256 + maxRealNumberStrLen = 64 // Maximum length in bytes of the "-123.456E-7" representation. // (maxTableOffset + maxTableLength) will not overflow an int32. maxTableLength = 1 << 29 @@ -59,22 +66,25 @@ var ( // ErrNotFound indicates that the requested value was not found. ErrNotFound = errors.New("sfnt: not found") - errInvalidBounds = errors.New("sfnt: invalid bounds") - errInvalidCFFTable = errors.New("sfnt: invalid CFF table") - errInvalidCmapTable = errors.New("sfnt: invalid cmap table") - errInvalidGlyphData = errors.New("sfnt: invalid glyph data") - errInvalidHeadTable = errors.New("sfnt: invalid head table") - errInvalidKernTable = errors.New("sfnt: invalid kern table") - errInvalidLocaTable = errors.New("sfnt: invalid loca table") - errInvalidLocationData = errors.New("sfnt: invalid location data") - errInvalidMaxpTable = errors.New("sfnt: invalid maxp table") - errInvalidNameTable = errors.New("sfnt: invalid name table") - errInvalidPostTable = errors.New("sfnt: invalid post table") - errInvalidSourceData = errors.New("sfnt: invalid source data") - errInvalidTableOffset = errors.New("sfnt: invalid table offset") - errInvalidTableTagOrder = errors.New("sfnt: invalid table tag order") - errInvalidUCS2String = errors.New("sfnt: invalid UCS-2 string") - errInvalidVersion = errors.New("sfnt: invalid version") + errInvalidBounds = errors.New("sfnt: invalid bounds") + errInvalidCFFTable = errors.New("sfnt: invalid CFF table") + errInvalidCmapTable = errors.New("sfnt: invalid cmap table") + 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") + errInvalidKernTable = errors.New("sfnt: invalid kern table") + errInvalidLocaTable = errors.New("sfnt: invalid loca table") + errInvalidLocationData = errors.New("sfnt: invalid location data") + errInvalidMaxpTable = errors.New("sfnt: invalid maxp table") + errInvalidNameTable = errors.New("sfnt: invalid name table") + errInvalidPostTable = errors.New("sfnt: invalid post table") + errInvalidSingleFont = errors.New("sfnt: invalid single font (data is a font collection)") + errInvalidSourceData = errors.New("sfnt: invalid source data") + errInvalidTableOffset = errors.New("sfnt: invalid table offset") + errInvalidTableTagOrder = errors.New("sfnt: invalid table tag order") + errInvalidUCS2String = errors.New("sfnt: invalid UCS-2 string") errUnsupportedCFFVersion = errors.New("sfnt: unsupported CFF version") errUnsupportedCmapEncodings = errors.New("sfnt: unsupported cmap encodings") @@ -83,7 +93,9 @@ 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") + errUnsupportedNumberOfFonts = errors.New("sfnt: unsupported number of fonts") errUnsupportedNumberOfHints = errors.New("sfnt: unsupported number of hints") + errUnsupportedNumberOfSubroutines = errors.New("sfnt: unsupported number of subroutines") errUnsupportedNumberOfTables = errors.New("sfnt: unsupported number of tables") errUnsupportedPlatformEncoding = errors.New("sfnt: unsupported platform encoding") errUnsupportedPostTable = errors.New("sfnt: unsupported post table") @@ -254,19 +266,105 @@ type table struct { offset, length uint32 } -// Parse parses an SFNT font from a []byte data source. +// ParseCollection parses an SFNT font collection, such as TTC or OTC data, +// from a []byte data source. +// +// If passed data for a single font, a TTF or OTF instead of a TTC or OTC, it +// will return a collection containing 1 font. +func ParseCollection(src []byte) (*Collection, error) { + c := &Collection{src: source{b: src}} + if err := c.initialize(); err != nil { + return nil, err + } + return c, nil +} + +// ParseCollectionReaderAt parses an SFNT collection, such as TTC or OTC data, +// from an io.ReaderAt data source. +// +// If passed data for a single font, a TTF or OTF instead of a TTC or OTC, it +// will return a collection containing 1 font. +func ParseCollectionReaderAt(src io.ReaderAt) (*Collection, error) { + c := &Collection{src: source{r: src}} + if err := c.initialize(); err != nil { + return nil, err + } + return c, nil +} + +// Collection is a collection of one or more fonts. +// +// All of the Collection methods are safe to call concurrently. +type Collection struct { + src source + offsets []uint32 +} + +// NumFonts returns the number of fonts in the collection. +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) + if err != nil { + return err + } + // These cases match the switch statement in Font.initializeTables. + switch u32(buf) { + default: + return errInvalidFontCollection + case 0x00010000, 0x4f54544f: + // Try parsing it as a single font instead of a collection. + c.offsets = []uint32{0} + case 0x74746366: // "ttcf". + numFonts := u32(buf[8:]) + if numFonts == 0 || numFonts > maxNumFonts { + return errUnsupportedNumberOfFonts + } + buf, err = c.src.view(nil, 12, int(4*numFonts)) + if err != nil { + return err + } + c.offsets = make([]uint32, numFonts) + for i := range c.offsets { + o := u32(buf[4*i:]) + if o > maxTableOffset { + return errUnsupportedTableOffsetLength + } + c.offsets[i] = o + } + } + 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 { + return nil, err + } + return f, nil +} + +// Parse parses an SFNT font, such as TTF or OTF data, from a []byte data +// source. func Parse(src []byte) (*Font, error) { f := &Font{src: source{b: src}} - if err := f.initialize(); err != nil { + if err := f.initialize(0); err != nil { return nil, err } return f, nil } -// ParseReaderAt parses an SFNT font from an io.ReaderAt data source. +// ParseReaderAt parses an SFNT font, such as TTF or OTF data, from an +// io.ReaderAt data source. func ParseReaderAt(src io.ReaderAt) (*Font, error) { f := &Font{src: source{r: src}} - if err := f.initialize(); err != nil { + if err := f.initialize(0); err != nil { return nil, err } return f, nil @@ -348,9 +446,17 @@ type Font struct { postTableVersion uint32 unitsPerEm Units - // The glyph data for the glyph index i is in + // 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 } } @@ -360,11 +466,11 @@ func (f *Font) NumGlyphs() int { return len(f.cached.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() error { +func (f *Font) initialize(offset int) error { if !f.src.valid() { return errInvalidSourceData } - buf, isPostScript, err := f.initializeTables(nil) + buf, isPostScript, err := f.initializeTables(offset) if err != nil { return err } @@ -381,7 +487,7 @@ func (f *Font) initialize() error { if err != nil { return err } - buf, numGlyphs, locations, err := f.parseMaxp(buf, indexToLocFormat, isPostScript) + buf, numGlyphs, locations, gsubrs, subrs, err := f.parseMaxp(buf, indexToLocFormat, isPostScript) if err != nil { return err } @@ -406,25 +512,31 @@ func (f *Font) initialize() error { 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(buf []byte) (buf1 []byte, isPostScript bool, err error) { +func (f *Font) initializeTables(offset int) (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. - buf, err = f.src.view(buf, 0, 12) + buf, err := f.src.view(nil, offset, 12) if err != nil { return nil, false, err } + // When updating the cases in this switch statement, also update the + // Collection.initialize method. switch u32(buf) { default: - return nil, false, errInvalidVersion + return nil, false, errInvalidFont case 0x00010000: // No-op. case 0x4f54544f: // "OTTO". isPostScript = true + case 0x74746366: // "ttcf". + return nil, false, errInvalidSingleFont } numTables := int(u16(buf[4:])) if numTables > maxNumTables { @@ -433,7 +545,7 @@ func (f *Font) initializeTables(buf []byte) (buf1 []byte, isPostScript bool, err // "The Offset Table is followed immediately by the Table Record entries... // sorted in ascending order by tag", 16 bytes each. - buf, err = f.src.view(buf, 12, 16*numTables) + buf, err = f.src.view(buf, offset+12, 16*numTables) if err != nil { return nil, false, err } @@ -597,10 +709,20 @@ func (f *Font) parseKern(buf []byte) (buf1 []byte, kernNumPairs, kernOffset int3 } return f.parseKernVersion0(buf, offset, length) case 1: - // TODO: find such a (proprietary?) font, and support it. Both of - // https://www.microsoft.com/typography/otspec/kern.htm + if buf[2] != 0 || buf[3] != 0 { + return nil, 0, 0, errUnsupportedKernTable + } + // Microsoft's https://www.microsoft.com/typography/otspec/kern.htm + // says that "Apple has extended the definition of the 'kern' table to + // provide additional functionality. The Apple extensions are not + // supported on Windows." + // + // The format is relatively complicated, including encoding a state + // machine, but rarely seen. We follow Microsoft's and FreeType's + // behavior and simply ignore it. Theoretically, we could follow // https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kern.html - // say that such fonts work on Mac OS but not on Windows. + // but it doesn't seem worth the effort. + return buf, 0, 0, nil } return nil, 0, 0, errUnsupportedKernTable } @@ -633,7 +755,9 @@ func (f *Font) parseKernVersion0(buf []byte, offset, length int) (buf1 []byte, k case 0: return f.parseKernFormat0(buf, offset, subtableLength) case 2: - // TODO: find such a (proprietary?) font, and support it. + // If we could find such a font, we could write code to support it, but + // a comment in the equivalent FreeType code (sfnt/ttkern.c) says that + // they've never seen such a font. } return nil, 0, 0, errUnsupportedKernTable } @@ -654,21 +778,21 @@ 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 []uint32, err error) { +func (f *Font) parseMaxp(buf []byte, indexToLocFormat, isPostScript bool) (buf1 []byte, numGlyphs int, locations, gsubrs, subrs []uint32, err error) { // https://www.microsoft.com/typography/otspec/maxp.htm if isPostScript { if f.maxp.length != 6 { - return nil, 0, nil, errInvalidMaxpTable + return nil, 0, nil, nil, nil, errInvalidMaxpTable } } else { if f.maxp.length != 32 { - return nil, 0, nil, errInvalidMaxpTable + return nil, 0, nil, nil, nil, errInvalidMaxpTable } } u, err := f.src.u16(buf, f.maxp, 4) if err != nil { - return nil, 0, nil, err + return nil, 0, nil, nil, nil, err } numGlyphs = int(u) @@ -679,21 +803,21 @@ func (f *Font) parseMaxp(buf []byte, indexToLocFormat, isPostScript bool) (buf1 offset: int(f.cff.offset), end: int(f.cff.offset + f.cff.length), } - locations, err = p.parse() + locations, gsubrs, subrs, err = p.parse() if err != nil { - return nil, 0, nil, err + return nil, 0, nil, nil, nil, err } } else { locations, err = parseLoca(&f.src, f.loca, f.glyf.offset, indexToLocFormat, numGlyphs) if err != nil { - return nil, 0, nil, err + return nil, 0, nil, nil, nil, err } } if len(locations) != numGlyphs+1 { - return nil, 0, nil, errInvalidLocationData + return nil, 0, nil, nil, nil, errInvalidLocationData } - return buf, numGlyphs, locations, nil + return buf, numGlyphs, locations, gsubrs, subrs, nil } func (f *Font) parsePost(buf []byte, numGlyphs int) (buf1 []byte, postTableVersion uint32, err error) { @@ -737,17 +861,21 @@ func (f *Font) GlyphIndex(b *Buffer, r rune) (GlyphIndex, error) { return f.cached.glyphIndex(f, b, r) } -func (f *Font) viewGlyphData(b *Buffer, x GlyphIndex) ([]byte, error) { +func (f *Font) viewGlyphData(b *Buffer, x GlyphIndex) (buf []byte, offset, length uint32, err error) { xx := int(x) if f.NumGlyphs() <= xx { - return nil, ErrNotFound + return nil, 0, 0, ErrNotFound } i := f.cached.locations[xx+0] j := f.cached.locations[xx+1] + if j < i { + return nil, 0, 0, errInvalidGlyphDataLength + } if j-i > maxGlyphDataLength { - return nil, errUnsupportedGlyphDataLength + return nil, 0, 0, errUnsupportedGlyphDataLength } - return b.view(&f.src, int(i), int(j-i)) + buf, err = b.view(&f.src, int(i), int(j-i)) + return buf, i, j - i, err } // LoadGlyphOptions are the options to the Font.LoadGlyph method. @@ -766,24 +894,23 @@ func (f *Font) LoadGlyph(b *Buffer, x GlyphIndex, ppem fixed.Int26_6, opts *Load b = &Buffer{} } - buf, err := f.viewGlyphData(b, x) - if err != nil { - return nil, err - } - b.segments = b.segments[:0] if f.cached.isPostScript { - b.psi.type2Charstrings.initialize(b.segments) - if err := b.psi.run(psContextType2Charstring, buf); err != nil { + buf, offset, length, err := f.viewGlyphData(b, x) + if err != nil { + return nil, err + } + b.psi.type2Charstrings.initialize(f, b) + if err := b.psi.run(psContextType2Charstring, buf, offset, length); err != nil { return nil, err } - b.segments = b.psi.type2Charstrings.segments + if !b.psi.type2Charstrings.ended { + return nil, errInvalidCFFTable + } } else { - segments, err := appendGlyfSegments(b.segments, buf) - if err != nil { + if err := loadGlyf(f, b, x, 0, 0); err != nil { return nil, err } - b.segments = segments } // Scale the segments. If we want to support hinting, we'll have to push @@ -889,9 +1016,9 @@ func (f *Font) Kern(b *Buffer, x0, x1 GlyphIndex, ppem fixed.Int26_6, h font.Hin if n := f.NumGlyphs(); int(x0) >= n || int(x1) >= n { return 0, ErrNotFound } - // Not every font has a kern table. If it doesn't, there's no need to - // allocate a Buffer. - if f.kern.length == 0 { + // Not every font has a kern table. If it doesn't, or if that table is + // ignored, there's no need to allocate a Buffer. + if f.cached.kernNumPairs == 0 { return 0, nil } if b == nil { @@ -1024,6 +1151,16 @@ type Buffer struct { buf []byte // segments holds glyph vector path segments. segments []Segment + // compoundStack holds the components of a TrueType compound glyph. + compoundStack [maxCompoundStackSize]struct { + glyphIndex GlyphIndex + dx, dy int16 + hasTransform bool + transformXX int16 + transformXY int16 + transformYX int16 + transformYY int16 + } // psi is a PostScript interpreter for when the Font is an OpenType/CFF // font. psi psInterpreter @@ -1056,3 +1193,32 @@ const ( SegmentOpQuadTo SegmentOpCubeTo ) + +// 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 +} + +// 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 tform(txx, txy, tyx, tyy int16, dx, dy, x, y fixed.Int26_6) (newX, newY fixed.Int26_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 +} -- cgit v1.2.3-1-g7c22