From 6e2cb00008cbf09e556b00f87603797fcaa47e09 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Mon, 16 Apr 2018 05:37:14 -0700 Subject: Depenancy upgrades and movign to dep. (#8630) --- vendor/golang.org/x/image/font/sfnt/cmap.go | 259 ---- vendor/golang.org/x/image/font/sfnt/data.go | 68 - .../golang.org/x/image/font/sfnt/example_test.go | 131 -- vendor/golang.org/x/image/font/sfnt/gen.go | 321 ---- vendor/golang.org/x/image/font/sfnt/postscript.go | 1414 ------------------ .../x/image/font/sfnt/proprietary_test.go | 1390 ------------------ vendor/golang.org/x/image/font/sfnt/sfnt.go | 1538 -------------------- vendor/golang.org/x/image/font/sfnt/sfnt_test.go | 839 ----------- vendor/golang.org/x/image/font/sfnt/truetype.go | 572 -------- 9 files changed, 6532 deletions(-) delete mode 100644 vendor/golang.org/x/image/font/sfnt/cmap.go delete mode 100644 vendor/golang.org/x/image/font/sfnt/data.go delete mode 100644 vendor/golang.org/x/image/font/sfnt/example_test.go delete mode 100644 vendor/golang.org/x/image/font/sfnt/gen.go delete mode 100644 vendor/golang.org/x/image/font/sfnt/postscript.go delete mode 100644 vendor/golang.org/x/image/font/sfnt/proprietary_test.go delete mode 100644 vendor/golang.org/x/image/font/sfnt/sfnt.go delete mode 100644 vendor/golang.org/x/image/font/sfnt/sfnt_test.go delete mode 100644 vendor/golang.org/x/image/font/sfnt/truetype.go (limited to 'vendor/golang.org/x/image/font/sfnt') diff --git a/vendor/golang.org/x/image/font/sfnt/cmap.go b/vendor/golang.org/x/image/font/sfnt/cmap.go deleted file mode 100644 index 797e9d190..000000000 --- a/vendor/golang.org/x/image/font/sfnt/cmap.go +++ /dev/null @@ -1,259 +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/text/encoding/charmap" -) - -// Platform IDs and Platform Specific IDs as per -// https://www.microsoft.com/typography/otspec/name.htm -const ( - pidUnicode = 0 - pidMacintosh = 1 - pidWindows = 3 - - psidUnicode2BMPOnly = 3 - psidUnicode2FullRepertoire = 4 - // Note that FontForge may generate a bogus Platform Specific ID (value 10) - // for the Unicode Platform ID (value 0). See - // https://github.com/fontforge/fontforge/issues/2728 - - psidMacintoshRoman = 0 - - psidWindowsSymbol = 0 - psidWindowsUCS2 = 1 - psidWindowsUCS4 = 10 -) - -// platformEncodingWidth returns the number of bytes per character assumed by -// the given Platform ID and Platform Specific ID. -// -// Very old fonts, from before Unicode was widely adopted, assume only 1 byte -// per character: a character map. -// -// Old fonts, from when Unicode meant the Basic Multilingual Plane (BMP), -// assume that 2 bytes per character is sufficient. -// -// Recent fonts naturally support the full range of Unicode code points, which -// can take up to 4 bytes per character. Such fonts might still choose one of -// the legacy encodings if e.g. their repertoire is limited to the BMP, for -// greater compatibility with older software, or because the resultant file -// size can be smaller. -func platformEncodingWidth(pid, psid uint16) int { - switch pid { - case pidUnicode: - switch psid { - case psidUnicode2BMPOnly: - return 2 - case psidUnicode2FullRepertoire: - return 4 - } - - case pidMacintosh: - switch psid { - case psidMacintoshRoman: - return 1 - } - - case pidWindows: - switch psid { - case psidWindowsSymbol: - return 2 - case psidWindowsUCS2: - return 2 - case psidWindowsUCS4: - return 4 - } - } - return 0 -} - -// The various cmap formats are described at -// https://www.microsoft.com/typography/otspec/cmap.htm - -var supportedCmapFormat = func(format, pid, psid uint16) bool { - switch format { - case 0: - return pid == pidMacintosh && psid == psidMacintoshRoman - case 4: - return true - case 12: - return true - } - return false -} - -func (f *Font) makeCachedGlyphIndex(buf []byte, offset, length uint32, format uint16) ([]byte, glyphIndexFunc, error) { - switch format { - case 0: - return f.makeCachedGlyphIndexFormat0(buf, offset, length) - case 4: - return f.makeCachedGlyphIndexFormat4(buf, offset, length) - case 12: - return f.makeCachedGlyphIndexFormat12(buf, offset, length) - } - panic("unreachable") -} - -func (f *Font) makeCachedGlyphIndexFormat0(buf []byte, offset, length uint32) ([]byte, glyphIndexFunc, error) { - if length != 6+256 || offset+length > f.cmap.length { - return nil, nil, errInvalidCmapTable - } - var err error - buf, err = f.src.view(buf, int(f.cmap.offset+offset), int(length)) - if err != nil { - return nil, nil, err - } - var table [256]byte - copy(table[:], buf[6:]) - return buf, func(f *Font, b *Buffer, r rune) (GlyphIndex, error) { - x, ok := charmap.Macintosh.EncodeRune(r) - if !ok { - // The source rune r is not representable in the Macintosh-Roman encoding. - return 0, nil - } - return GlyphIndex(table[x]), nil - }, nil -} - -func (f *Font) makeCachedGlyphIndexFormat4(buf []byte, offset, length uint32) ([]byte, glyphIndexFunc, error) { - const headerSize = 14 - if offset+headerSize > f.cmap.length { - return nil, nil, errInvalidCmapTable - } - var err error - buf, err = f.src.view(buf, int(f.cmap.offset+offset), headerSize) - if err != nil { - return nil, nil, err - } - offset += headerSize - - segCount := u16(buf[6:]) - if segCount&1 != 0 { - return nil, nil, errInvalidCmapTable - } - segCount /= 2 - if segCount > maxCmapSegments { - return nil, nil, errUnsupportedNumberOfCmapSegments - } - - eLength := 8*uint32(segCount) + 2 - if offset+eLength > f.cmap.length { - return nil, nil, errInvalidCmapTable - } - buf, err = f.src.view(buf, int(f.cmap.offset+offset), int(eLength)) - if err != nil { - return nil, nil, err - } - offset += eLength - - entries := make([]cmapEntry16, segCount) - for i := range entries { - entries[i] = cmapEntry16{ - end: u16(buf[0*len(entries)+0+2*i:]), - start: u16(buf[2*len(entries)+2+2*i:]), - delta: u16(buf[4*len(entries)+2+2*i:]), - offset: u16(buf[6*len(entries)+2+2*i:]), - } - } - indexesBase := f.cmap.offset + offset - indexesLength := f.cmap.length - offset - - return buf, func(f *Font, b *Buffer, r rune) (GlyphIndex, error) { - if uint32(r) > 0xffff { - return 0, nil - } - - c := uint16(r) - for i, j := 0, len(entries); i < j; { - h := i + (j-i)/2 - entry := &entries[h] - if c < entry.start { - j = h - } else if entry.end < c { - i = h + 1 - } else if entry.offset == 0 { - return GlyphIndex(c + entry.delta), nil - } else { - offset := uint32(entry.offset) + 2*uint32(h-len(entries)+int(c-entry.start)) - if offset > indexesLength || offset+2 > indexesLength { - return 0, errInvalidCmapTable - } - x, err := b.view(&f.src, int(indexesBase+offset), 2) - if err != nil { - return 0, err - } - return GlyphIndex(u16(x)), nil - } - } - return 0, nil - }, nil -} - -func (f *Font) makeCachedGlyphIndexFormat12(buf []byte, offset, _ uint32) ([]byte, glyphIndexFunc, error) { - const headerSize = 16 - if offset+headerSize > f.cmap.length { - return nil, nil, errInvalidCmapTable - } - var err error - buf, err = f.src.view(buf, int(f.cmap.offset+offset), headerSize) - if err != nil { - return nil, nil, err - } - length := u32(buf[4:]) - if f.cmap.length < offset || length > f.cmap.length-offset { - return nil, nil, errInvalidCmapTable - } - offset += headerSize - - numGroups := u32(buf[12:]) - if numGroups > maxCmapSegments { - return nil, nil, errUnsupportedNumberOfCmapSegments - } - - eLength := 12 * numGroups - if headerSize+eLength != length { - return nil, nil, errInvalidCmapTable - } - buf, err = f.src.view(buf, int(f.cmap.offset+offset), int(eLength)) - if err != nil { - return nil, nil, err - } - offset += eLength - - entries := make([]cmapEntry32, numGroups) - for i := range entries { - entries[i] = cmapEntry32{ - start: u32(buf[0+12*i:]), - end: u32(buf[4+12*i:]), - delta: u32(buf[8+12*i:]), - } - } - - return buf, func(f *Font, b *Buffer, r rune) (GlyphIndex, error) { - c := uint32(r) - for i, j := 0, len(entries); i < j; { - h := i + (j-i)/2 - entry := &entries[h] - if c < entry.start { - j = h - } else if entry.end < c { - i = h + 1 - } else { - return GlyphIndex(c - entry.start + entry.delta), nil - } - } - return 0, nil - }, nil -} - -type cmapEntry16 struct { - end, start, delta, offset uint16 -} - -type cmapEntry32 struct { - start, end, delta uint32 -} diff --git a/vendor/golang.org/x/image/font/sfnt/data.go b/vendor/golang.org/x/image/font/sfnt/data.go deleted file mode 100644 index ad0c139aa..000000000 --- a/vendor/golang.org/x/image/font/sfnt/data.go +++ /dev/null @@ -1,68 +0,0 @@ -// generated by go run gen.go; DO NOT EDIT - -package sfnt - -const numBuiltInPostNames = 258 - -const builtInPostNamesData = "" + - ".notdef.nullnonmarkingreturnspaceexclamquotedblnumbersigndollarp" + - "ercentampersandquotesingleparenleftparenrightasteriskpluscommahy" + - "phenperiodslashzeroonetwothreefourfivesixseveneightninecolonsemi" + - "colonlessequalgreaterquestionatABCDEFGHIJKLMNOPQRSTUVWXYZbracket" + - "leftbackslashbracketrightasciicircumunderscoregraveabcdefghijklm" + - "nopqrstuvwxyzbraceleftbarbracerightasciitildeAdieresisAringCcedi" + - "llaEacuteNtildeOdieresisUdieresisaacuteagraveacircumflexadieresi" + - "satildearingccedillaeacuteegraveecircumflexedieresisiacuteigrave" + - "icircumflexidieresisntildeoacuteograveocircumflexodieresisotilde" + - "uacuteugraveucircumflexudieresisdaggerdegreecentsterlingsectionb" + - "ulletparagraphgermandblsregisteredcopyrighttrademarkacutedieresi" + - "snotequalAEOslashinfinityplusminuslessequalgreaterequalyenmupart" + - "ialdiffsummationproductpiintegralordfeminineordmasculineOmegaaeo" + - "slashquestiondownexclamdownlogicalnotradicalflorinapproxequalDel" + - "taguillemotleftguillemotrightellipsisnonbreakingspaceAgraveAtild" + - "eOtildeOEoeendashemdashquotedblleftquotedblrightquoteleftquoteri" + - "ghtdividelozengeydieresisYdieresisfractioncurrencyguilsinglleftg" + - "uilsinglrightfifldaggerdblperiodcenteredquotesinglbasequotedblba" + - "seperthousandAcircumflexEcircumflexAacuteEdieresisEgraveIacuteIc" + - "ircumflexIdieresisIgraveOacuteOcircumflexappleOgraveUacuteUcircu" + - "mflexUgravedotlessicircumflextildemacronbrevedotaccentringcedill" + - "ahungarumlautogonekcaronLslashlslashScaronscaronZcaronzcaronbrok" + - "enbarEthethYacuteyacuteThornthornminusmultiplyonesuperiortwosupe" + - "riorthreesuperioronehalfonequarterthreequartersfrancGbrevegbreve" + - "IdotaccentScedillascedillaCacutecacuteCcaronccarondcroat" - -var builtInPostNamesOffsets = [...]uint16{ - 0x0000, 0x0007, 0x000c, 0x001c, 0x0021, 0x0027, 0x002f, 0x0039, - 0x003f, 0x0046, 0x004f, 0x005a, 0x0063, 0x006d, 0x0075, 0x0079, - 0x007e, 0x0084, 0x008a, 0x008f, 0x0093, 0x0096, 0x0099, 0x009e, - 0x00a2, 0x00a6, 0x00a9, 0x00ae, 0x00b3, 0x00b7, 0x00bc, 0x00c5, - 0x00c9, 0x00ce, 0x00d5, 0x00dd, 0x00df, 0x00e0, 0x00e1, 0x00e2, - 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, - 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2, - 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x0104, - 0x010d, 0x0119, 0x0124, 0x012e, 0x0133, 0x0134, 0x0135, 0x0136, - 0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e, - 0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, - 0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d, 0x0156, - 0x0159, 0x0163, 0x016d, 0x0176, 0x017b, 0x0183, 0x0189, 0x018f, - 0x0198, 0x01a1, 0x01a7, 0x01ad, 0x01b8, 0x01c1, 0x01c7, 0x01cc, - 0x01d4, 0x01da, 0x01e0, 0x01eb, 0x01f4, 0x01fa, 0x0200, 0x020b, - 0x0214, 0x021a, 0x0220, 0x0226, 0x0231, 0x023a, 0x0240, 0x0246, - 0x024c, 0x0257, 0x0260, 0x0266, 0x026c, 0x0270, 0x0278, 0x027f, - 0x0285, 0x028e, 0x0298, 0x02a2, 0x02ab, 0x02b4, 0x02b9, 0x02c1, - 0x02c9, 0x02cb, 0x02d1, 0x02d9, 0x02e2, 0x02eb, 0x02f7, 0x02fa, - 0x02fc, 0x0307, 0x0310, 0x0317, 0x0319, 0x0321, 0x032c, 0x0338, - 0x033d, 0x033f, 0x0345, 0x0351, 0x035b, 0x0365, 0x036c, 0x0372, - 0x037d, 0x0382, 0x038f, 0x039d, 0x03a5, 0x03b5, 0x03bb, 0x03c1, - 0x03c7, 0x03c9, 0x03cb, 0x03d1, 0x03d7, 0x03e3, 0x03f0, 0x03f9, - 0x0403, 0x0409, 0x0410, 0x0419, 0x0422, 0x042a, 0x0432, 0x043f, - 0x044d, 0x044f, 0x0451, 0x045a, 0x0468, 0x0476, 0x0482, 0x048d, - 0x0498, 0x04a3, 0x04a9, 0x04b2, 0x04b8, 0x04be, 0x04c9, 0x04d2, - 0x04d8, 0x04de, 0x04e9, 0x04ee, 0x04f4, 0x04fa, 0x0505, 0x050b, - 0x0513, 0x051d, 0x0522, 0x0528, 0x052d, 0x0536, 0x053a, 0x0541, - 0x054d, 0x0553, 0x0558, 0x055e, 0x0564, 0x056a, 0x0570, 0x0576, - 0x057c, 0x0585, 0x0588, 0x058b, 0x0591, 0x0597, 0x059c, 0x05a1, - 0x05a6, 0x05ae, 0x05b9, 0x05c4, 0x05d1, 0x05d8, 0x05e2, 0x05ef, - 0x05f4, 0x05fa, 0x0600, 0x060a, 0x0612, 0x061a, 0x0620, 0x0626, - 0x062c, 0x0632, 0x0638, -} diff --git a/vendor/golang.org/x/image/font/sfnt/example_test.go b/vendor/golang.org/x/image/font/sfnt/example_test.go deleted file mode 100644 index baddcfec0..000000000 --- a/vendor/golang.org/x/image/font/sfnt/example_test.go +++ /dev/null @@ -1,131 +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_test - -import ( - "image" - "image/draw" - "log" - "os" - - "golang.org/x/image/font/gofont/goregular" - "golang.org/x/image/font/sfnt" - "golang.org/x/image/math/fixed" - "golang.org/x/image/vector" -) - -func ExampleRasterizeGlyph() { - const ( - ppem = 32 - width = 24 - height = 36 - originX = 0 - originY = 32 - ) - - f, err := sfnt.Parse(goregular.TTF) - if err != nil { - log.Fatalf("Parse: %v", err) - } - var b sfnt.Buffer - x, err := f.GlyphIndex(&b, 'Ġ') - if err != nil { - log.Fatalf("GlyphIndex: %v", err) - } - if x == 0 { - log.Fatalf("GlyphIndex: no glyph index found for the rune 'Ġ'") - } - segments, err := f.LoadGlyph(&b, x, fixed.I(ppem), nil) - if err != nil { - log.Fatalf("LoadGlyph: %v", err) - } - - r := vector.NewRasterizer(width, height) - r.DrawOp = draw.Src - for _, seg := range segments { - // The divisions by 64 below is because the seg.Args values have type - // fixed.Int26_6, a 26.6 fixed point number, and 1<<6 == 64. - switch seg.Op { - case sfnt.SegmentOpMoveTo: - r.MoveTo( - originX+float32(seg.Args[0].X)/64, - originY+float32(seg.Args[0].Y)/64, - ) - case sfnt.SegmentOpLineTo: - r.LineTo( - originX+float32(seg.Args[0].X)/64, - originY+float32(seg.Args[0].Y)/64, - ) - case sfnt.SegmentOpQuadTo: - r.QuadTo( - originX+float32(seg.Args[0].X)/64, - originY+float32(seg.Args[0].Y)/64, - originX+float32(seg.Args[1].X)/64, - originY+float32(seg.Args[1].Y)/64, - ) - case sfnt.SegmentOpCubeTo: - r.CubeTo( - originX+float32(seg.Args[0].X)/64, - originY+float32(seg.Args[0].Y)/64, - originX+float32(seg.Args[1].X)/64, - originY+float32(seg.Args[1].Y)/64, - originX+float32(seg.Args[2].X)/64, - originY+float32(seg.Args[2].Y)/64, - ) - } - } - - dst := image.NewAlpha(image.Rect(0, 0, width, height)) - r.Draw(dst, dst.Bounds(), image.Opaque, image.Point{}) - - const asciiArt = ".++8" - buf := make([]byte, 0, height*(width+1)) - for y := 0; y < height; y++ { - for x := 0; x < width; x++ { - a := dst.AlphaAt(x, y).A - buf = append(buf, asciiArt[a>>6]) - } - buf = append(buf, '\n') - } - os.Stdout.Write(buf) - - // Output: - // ........................ - // ........................ - // ........................ - // ............888......... - // ............888......... - // ............888......... - // ............+++......... - // ........................ - // ..........+++++++++..... - // .......+8888888888888+.. - // ......8888888888888888.. - // ....+8888+........++88.. - // ....8888................ - // ...8888................. - // ..+888+................. - // ..+888.................. - // ..888+.................. - // .+888+.................. - // .+888................... - // .+888................... - // .+888................... - // .+888..........+++++++.. - // .+888..........8888888.. - // .+888+.........+++8888.. - // ..888+............+888.. - // ..8888............+888.. - // ..+888+...........+888.. - // ...8888+..........+888.. - // ...+8888+.........+888.. - // ....+88888+.......+888.. - // .....+8888888888888888.. - // .......+888888888888++.. - // ..........++++++++...... - // ........................ - // ........................ - // ........................ -} diff --git a/vendor/golang.org/x/image/font/sfnt/gen.go b/vendor/golang.org/x/image/font/sfnt/gen.go deleted file mode 100644 index 12587d446..000000000 --- a/vendor/golang.org/x/image/font/sfnt/gen.go +++ /dev/null @@ -1,321 +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. - -// +build ignore - -package main - -import ( - "bytes" - "fmt" - "go/format" - "io/ioutil" - "log" -) - -func main() { - data, offsets := []byte(nil), []int{0} - for _, name := range names { - data = append(data, name...) - offsets = append(offsets, len(data)) - } - - b := new(bytes.Buffer) - fmt.Fprintf(b, "// generated by go run gen.go; DO NOT EDIT\n\n") - fmt.Fprintf(b, "package sfnt\n\n") - - fmt.Fprintf(b, "const numBuiltInPostNames = %d\n\n", len(names)) - - fmt.Fprintf(b, "const builtInPostNamesData = \"\" +\n") - for s := data; ; { - if len(s) <= 64 { - fmt.Fprintf(b, "%q\n", s) - break - } - fmt.Fprintf(b, "%q +\n", s[:64]) - s = s[64:] - } - fmt.Fprintf(b, "\n") - - fmt.Fprintf(b, "var builtInPostNamesOffsets = [...]uint16{\n") - for i, o := range offsets { - fmt.Fprintf(b, "%#04x,", o) - if i%8 == 7 { - fmt.Fprintf(b, "\n") - } - } - fmt.Fprintf(b, "\n}\n") - - dstUnformatted := b.Bytes() - dst, err := format.Source(dstUnformatted) - if err != nil { - log.Fatalf("format.Source: %v\n\n----\n%s\n----", err, dstUnformatted) - } - if err := ioutil.WriteFile("data.go", dst, 0666); err != nil { - log.Fatalf("ioutil.WriteFile: %v", err) - } -} - -// names is the built-in post table names listed at -// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6post.html -var names = [258]string{ - ".notdef", - ".null", - "nonmarkingreturn", - "space", - "exclam", - "quotedbl", - "numbersign", - "dollar", - "percent", - "ampersand", - "quotesingle", - "parenleft", - "parenright", - "asterisk", - "plus", - "comma", - "hyphen", - "period", - "slash", - "zero", - "one", - "two", - "three", - "four", - "five", - "six", - "seven", - "eight", - "nine", - "colon", - "semicolon", - "less", - "equal", - "greater", - "question", - "at", - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K", - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", - "bracketleft", - "backslash", - "bracketright", - "asciicircum", - "underscore", - "grave", - "a", - "b", - "c", - "d", - "e", - "f", - "g", - "h", - "i", - "j", - "k", - "l", - "m", - "n", - "o", - "p", - "q", - "r", - "s", - "t", - "u", - "v", - "w", - "x", - "y", - "z", - "braceleft", - "bar", - "braceright", - "asciitilde", - "Adieresis", - "Aring", - "Ccedilla", - "Eacute", - "Ntilde", - "Odieresis", - "Udieresis", - "aacute", - "agrave", - "acircumflex", - "adieresis", - "atilde", - "aring", - "ccedilla", - "eacute", - "egrave", - "ecircumflex", - "edieresis", - "iacute", - "igrave", - "icircumflex", - "idieresis", - "ntilde", - "oacute", - "ograve", - "ocircumflex", - "odieresis", - "otilde", - "uacute", - "ugrave", - "ucircumflex", - "udieresis", - "dagger", - "degree", - "cent", - "sterling", - "section", - "bullet", - "paragraph", - "germandbls", - "registered", - "copyright", - "trademark", - "acute", - "dieresis", - "notequal", - "AE", - "Oslash", - "infinity", - "plusminus", - "lessequal", - "greaterequal", - "yen", - "mu", - "partialdiff", - "summation", - "product", - "pi", - "integral", - "ordfeminine", - "ordmasculine", - "Omega", - "ae", - "oslash", - "questiondown", - "exclamdown", - "logicalnot", - "radical", - "florin", - "approxequal", - "Delta", - "guillemotleft", - "guillemotright", - "ellipsis", - "nonbreakingspace", - "Agrave", - "Atilde", - "Otilde", - "OE", - "oe", - "endash", - "emdash", - "quotedblleft", - "quotedblright", - "quoteleft", - "quoteright", - "divide", - "lozenge", - "ydieresis", - "Ydieresis", - "fraction", - "currency", - "guilsinglleft", - "guilsinglright", - "fi", - "fl", - "daggerdbl", - "periodcentered", - "quotesinglbase", - "quotedblbase", - "perthousand", - "Acircumflex", - "Ecircumflex", - "Aacute", - "Edieresis", - "Egrave", - "Iacute", - "Icircumflex", - "Idieresis", - "Igrave", - "Oacute", - "Ocircumflex", - "apple", - "Ograve", - "Uacute", - "Ucircumflex", - "Ugrave", - "dotlessi", - "circumflex", - "tilde", - "macron", - "breve", - "dotaccent", - "ring", - "cedilla", - "hungarumlaut", - "ogonek", - "caron", - "Lslash", - "lslash", - "Scaron", - "scaron", - "Zcaron", - "zcaron", - "brokenbar", - "Eth", - "eth", - "Yacute", - "yacute", - "Thorn", - "thorn", - "minus", - "multiply", - "onesuperior", - "twosuperior", - "threesuperior", - "onehalf", - "onequarter", - "threequarters", - "franc", - "Gbreve", - "gbreve", - "Idotaccent", - "Scedilla", - "scedilla", - "Cacute", - "cacute", - "Ccaron", - "ccaron", - "dcroat", -} diff --git a/vendor/golang.org/x/image/font/sfnt/postscript.go b/vendor/golang.org/x/image/font/sfnt/postscript.go deleted file mode 100644 index b686e60ac..000000000 --- a/vendor/golang.org/x/image/font/sfnt/postscript.go +++ /dev/null @@ -1,1414 +0,0 @@ -// Copyright 2016 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 - -// Compact Font Format (CFF) fonts are written in PostScript, a stack-based -// programming language. -// -// A fundamental concept is a DICT, or a key-value map, expressed in reverse -// Polish notation. For example, this sequence of operations: -// - push the number 379 -// - version operator -// - push the number 392 -// - Notice operator -// - etc -// - push the number 100 -// - push the number 0 -// - push the number 500 -// - push the number 800 -// - FontBBox operator -// - etc -// defines a DICT that maps "version" to the String ID (SID) 379, "Notice" to -// the SID 392, "FontBBox" to the four numbers [100, 0, 500, 800], etc. -// -// The first 391 String IDs (starting at 0) are predefined as per the CFF spec -// Appendix A, in 5176.CFF.pdf referenced below. For example, 379 means -// "001.000". String ID 392 is not predefined, and is mapped by a separate -// structure, the "String INDEX", inside the CFF data. (String ID 391 is also -// not predefined. Specifically for ../testdata/CFFTest.otf, 391 means -// "uni4E2D", as this font contains a glyph for U+4E2D). -// -// The actual glyph vectors are similarly encoded (in PostScript), in a format -// called Type 2 Charstrings. The wire encoding is similar to but not exactly -// the same as CFF's. For example, the byte 0x05 means FontBBox for CFF DICTs, -// but means rlineto (relative line-to) for Type 2 Charstrings. See -// 5176.CFF.pdf Appendix H and 5177.Type2.pdf Appendix A in the PDF files -// referenced below. -// -// CFF is a stand-alone format, but CFF as used in SFNT fonts have further -// restrictions. For example, a stand-alone CFF can contain multiple fonts, but -// https://www.microsoft.com/typography/OTSPEC/cff.htm says that "The Name -// INDEX in the CFF must contain only one entry; that is, there must be only -// one font in the CFF FontSet". -// -// The relevant specifications are: -// - http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5176.CFF.pdf -// - http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/font/pdfs/5177.Type2.pdf - -import ( - "fmt" - "math" - "strconv" - - "golang.org/x/image/math/fixed" -) - -const ( - // psArgStackSize is the argument stack size for a PostScript interpreter. - // 5176.CFF.pdf section 4 "DICT Data" says that "An operator may be - // preceded by up to a maximum of 48 operands". 5177.Type2.pdf Appendix B - // "Type 2 Charstring Implementation Limits" says that "Argument stack 48". - psArgStackSize = 48 - - // Similarly, Appendix B says "Subr nesting, stack limit 10". - psCallStackSize = 10 -) - -func bigEndian(b []byte) uint32 { - switch len(b) { - case 1: - return uint32(b[0]) - case 2: - return uint32(b[0])<<8 | uint32(b[1]) - case 3: - return uint32(b[0])<<16 | uint32(b[1])<<8 | uint32(b[2]) - case 4: - return uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3]) - } - 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 - base int - offset int - end int - err error - - buf []byte - locBuf [2]uint32 - - psi psInterpreter -} - -func (p *cffParser) parse(numGlyphs int32) (ret glyphData, err error) { - // Parse the header. - { - if !p.read(4) { - return glyphData{}, p.err - } - if p.buf[0] != 1 || p.buf[1] != 0 || p.buf[2] != 4 { - return glyphData{}, errUnsupportedCFFVersion - } - } - - // Parse the Name INDEX. - { - count, offSize, ok := p.parseIndexHeader() - if !ok { - 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 glyphData{}, errInvalidCFFTable - } - if !p.parseIndexLocations(p.locBuf[:2], count, offSize) { - return glyphData{}, p.err - } - p.offset = int(p.locBuf[1]) - } - - // Parse the Top DICT INDEX. - p.psi.topDict.initialize() - { - count, offSize, ok := p.parseIndexHeader() - if !ok { - 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 glyphData{}, errInvalidCFFTable - } - if !p.parseIndexLocations(p.locBuf[:2], count, offSize) { - return glyphData{}, p.err - } - if !p.read(int(p.locBuf[1] - p.locBuf[0])) { - return glyphData{}, p.err - } - if p.err = p.psi.run(psContextTopDict, p.buf, 0, 0); p.err != nil { - return glyphData{}, p.err - } - } - - // Skip the String INDEX. - { - count, offSize, ok := p.parseIndexHeader() - if !ok { - 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 glyphData{}, p.err - } - if !p.read(int(offSize)) { - return glyphData{}, p.err - } - loc := bigEndian(p.buf) - 1 - // Check that locations are in bounds. - if uint32(p.end-p.offset) < loc { - return glyphData{}, errInvalidCFFTable - } - // Skip the index data. - if !p.skip(int(loc)) { - return glyphData{}, p.err - } - } - } - - // Parse the Global Subrs [Subroutines] INDEX. - { - count, offSize, ok := p.parseIndexHeader() - if !ok { - return glyphData{}, p.err - } - if count != 0 { - if count > maxNumSubroutines { - return glyphData{}, errUnsupportedNumberOfSubroutines - } - 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.seekFromBase(p.psi.topDict.charStringsOffset) { - return glyphData{}, errInvalidCFFTable - } - count, offSize, ok := p.parseIndexHeader() - if !ok { - 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 - } - - 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 - } - 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 -} - -func (p *cffParser) parsePrivateDICT(offset, length int32) (subrs []uint32, err error) { - p.psi.privateDict.initialize() - if length != 0 { - fullLength := int32(p.end - p.base) - if offset <= 0 || fullLength < offset || fullLength-offset < length || length < 0 { - return nil, errInvalidCFFTable - } - p.offset = p.base + int(offset) - if !p.read(int(length)) { - return nil, p.err - } - if p.err = p.psi.run(psContextPrivateDict, p.buf, 0, 0); p.err != nil { - return nil, p.err - } - } - - // Parse the Local Subrs [Subroutines] INDEX, whose location was found in - // the Private DICT. - if p.psi.privateDict.subrsOffset != 0 { - if !p.seekFromBase(offset + p.psi.privateDict.subrsOffset) { - return nil, errInvalidCFFTable - } - count, offSize, ok := p.parseIndexHeader() - if !ok { - return nil, p.err - } - if count != 0 { - if count > maxNumSubroutines { - return nil, errUnsupportedNumberOfSubroutines - } - subrs = make([]uint32, count+1) - if !p.parseIndexLocations(subrs, count, offSize) { - return nil, p.err - } - } - } - - return subrs, err -} - -// read sets p.buf to view the n bytes from p.offset to p.offset+n. It also -// advances p.offset by n. -// -// As per the source.view method, the caller should not modify the contents of -// p.buf after read returns, other than by calling read again. -// -// The caller should also avoid modifying the pointer / length / capacity of -// the p.buf slice, not just avoid modifying the slice's contents, in order to -// 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 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 -} - -func (p *cffParser) skip(n int) (ok bool) { - if p.end-p.offset < n { - p.err = errInvalidCFFTable - return false - } - p.offset += n - 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 - } - count = int32(u16(p.buf[:2])) - // 5176.CFF.pdf section 5 "INDEX Data" says that "An empty INDEX is - // represented by a count field with a 0 value and no additional fields. - // Thus, the total size of an empty INDEX is 2 bytes". - if count == 0 { - return count, 0, true - } - if !p.read(1) { - return 0, 0, false - } - offSize = int32(p.buf[0]) - if offSize < 1 || 4 < offSize { - p.err = errInvalidCFFTable - return 0, 0, false - } - return count, offSize, true -} - -func (p *cffParser) parseIndexLocations(dst []uint32, count, offSize int32) (ok bool) { - if count == 0 { - return true - } - if len(dst) != int(count+1) { - panic("unreachable") - } - if !p.read(len(dst) * int(offSize)) { - return false - } - - buf, prev := p.buf, uint32(0) - for i := range dst { - loc := bigEndian(buf[:offSize]) - buf = buf[offSize:] - - // Locations are off by 1 byte. 5176.CFF.pdf section 5 "INDEX Data" - // says that "Offsets in the offset array are relative to the byte that - // precedes the object data... This ensures that every object has a - // corresponding offset which is always nonzero". - if loc == 0 { - p.err = errInvalidCFFTable - return false - } - loc-- - - // In the same paragraph, "Therefore the first element of the offset - // array is always 1" before correcting for the off-by-1. - if i == 0 { - if loc != 0 { - p.err = errInvalidCFFTable - break - } - } else if loc <= prev { // Check that locations are increasing. - p.err = errInvalidCFFTable - break - } - - // Check that locations are in bounds. - if uint32(p.end-p.offset) < loc { - p.err = errInvalidCFFTable - break - } - - dst[i] = uint32(p.offset) + loc - prev = loc - } - return p.err == nil -} - -type psCallStackEntry struct { - offset, length uint32 -} - -type psContext uint32 - -const ( - psContextTopDict psContext = iota - psContextPrivateDict - psContextType2Charstring -) - -// psTopDictData contains fields specific to the Top DICT context. -type psTopDictData struct { - charStringsOffset int32 - fdArray int32 - fdSelect int32 - isCIDFont bool - privateDictOffset int32 - privateDictLength int32 -} - -func (d *psTopDictData) initialize() { - *d = psTopDictData{} -} - -// psPrivateDictData contains fields specific to the Private DICT context. -type psPrivateDictData struct { - subrsOffset int32 -} - -func (d *psPrivateDictData) initialize() { - *d = psPrivateDictData{} -} - -// psType2CharstringsData contains fields specific to the Type 2 Charstrings -// context. -type psType2CharstringsData struct { - 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, glyphIndex GlyphIndex) { - *d = psType2CharstringsData{ - 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 - instructions []byte - instrOffset uint32 - instrLength uint32 - argStack struct { - a [psArgStackSize]int32 - top int32 - } - callStack struct { - a [psCallStackSize]psCallStackEntry - top int32 - } - parseNumberBuf [maxRealNumberStrLen]byte - - topDict psTopDictData - privateDict psPrivateDictData - type2Charstrings psType2CharstringsData -} - -func (p *psInterpreter) hasMoreInstructions() bool { - if len(p.instructions) != 0 { - return true - } - for i := int32(0); i < p.callStack.top; i++ { - if p.callStack.a[i].length != 0 { - return true - } - } - return false -} - -// run runs the instructions in the given PostScript context. For the -// psContextType2Charstring context, offset and length give the location of the -// instructions in p.type2Charstrings.f.src. -func (p *psInterpreter) run(ctx psContext, instructions []byte, offset, length uint32) error { - p.ctx = ctx - p.instructions = instructions - p.instrOffset = offset - p.instrLength = length - p.argStack.top = 0 - p.callStack.top = 0 - -loop: - for len(p.instructions) > 0 { - // Push a numeric operand on the stack, if applicable. - if hasResult, err := p.parseNumber(); hasResult { - if err != nil { - return err - } - continue - } - - // Otherwise, execute an operator. - b := p.instructions[0] - p.instructions = p.instructions[1:] - - for escaped, ops := false, psOperators[ctx][0]; ; { - if b == escapeByte && !escaped { - if len(p.instructions) <= 0 { - return errInvalidCFFTable - } - b = p.instructions[0] - p.instructions = p.instructions[1:] - escaped = true - ops = psOperators[ctx][1] - continue - } - - if int(b) < len(ops) { - if op := ops[b]; op.name != "" { - if p.argStack.top < op.numPop { - return errInvalidCFFTable - } - if op.run != nil { - if err := op.run(p); err != nil { - return err - } - } - if op.numPop < 0 { - p.argStack.top = 0 - } else { - p.argStack.top -= op.numPop - } - continue loop - } - } - - if escaped { - return fmt.Errorf("sfnt: unrecognized CFF 2-byte operator (12 %d)", b) - } else { - return fmt.Errorf("sfnt: unrecognized CFF 1-byte operator (%d)", b) - } - } - } - return nil -} - -// See 5176.CFF.pdf section 4 "DICT Data". -func (p *psInterpreter) parseNumber() (hasResult bool, err error) { - number := int32(0) - switch b := p.instructions[0]; { - case b == 28: - if len(p.instructions) < 3 { - return true, errInvalidCFFTable - } - number, hasResult = int32(int16(u16(p.instructions[1:]))), true - p.instructions = p.instructions[3:] - - case b == 29 && p.ctx != psContextType2Charstring: - if len(p.instructions) < 5 { - return true, errInvalidCFFTable - } - number, hasResult = int32(u32(p.instructions[1:])), true - p.instructions = p.instructions[5:] - - case b == 30 && p.ctx != psContextType2Charstring: - // Parse a real number. This isn't listed in 5176.CFF.pdf Table 3 - // "Operand Encoding" but that table lists integer encodings. Further - // down the page it says "A real number operand is provided in addition - // to integer operands. This operand begins with a byte value of 30 - // followed by a variable-length sequence of bytes." - - s := p.parseNumberBuf[:0] - p.instructions = p.instructions[1:] - loop: - for { - if len(p.instructions) == 0 { - return true, errInvalidCFFTable - } - b := p.instructions[0] - p.instructions = p.instructions[1:] - // Process b's two nibbles, high then low. - for i := 0; i < 2; i++ { - nib := b >> 4 - b = b << 4 - if nib == 0x0f { - f, err := strconv.ParseFloat(string(s), 32) - if err != nil { - return true, errInvalidCFFTable - } - number, hasResult = int32(math.Float32bits(float32(f))), true - break loop - } - if nib == 0x0d { - return true, errInvalidCFFTable - } - if len(s)+maxNibbleDefsLength > len(p.parseNumberBuf) { - return true, errUnsupportedRealNumberEncoding - } - s = append(s, nibbleDefs[nib]...) - } - } - - case b < 32: - // No-op. - - case b < 247: - p.instructions = p.instructions[1:] - number, hasResult = int32(b)-139, true - - case b < 251: - if len(p.instructions) < 2 { - return true, errInvalidCFFTable - } - b1 := p.instructions[1] - p.instructions = p.instructions[2:] - number, hasResult = +int32(b-247)*256+int32(b1)+108, true - - case b < 255: - if len(p.instructions) < 2 { - return true, errInvalidCFFTable - } - b1 := p.instructions[1] - p.instructions = p.instructions[2:] - number, hasResult = -int32(b-251)*256-int32(b1)-108, true - - case b == 255 && p.ctx == psContextType2Charstring: - if len(p.instructions) < 5 { - return true, errInvalidCFFTable - } - number, hasResult = int32(u32(p.instructions[1:])), true - p.instructions = p.instructions[5:] - } - - if hasResult { - if p.argStack.top == psArgStackSize { - return true, errInvalidCFFTable - } - p.argStack.a[p.argStack.top] = number - p.argStack.top++ - } - return hasResult, nil -} - -const maxNibbleDefsLength = len("E-") - -// nibbleDefs encodes 5176.CFF.pdf Table 5 "Nibble Definitions". -var nibbleDefs = [16]string{ - 0x00: "0", - 0x01: "1", - 0x02: "2", - 0x03: "3", - 0x04: "4", - 0x05: "5", - 0x06: "6", - 0x07: "7", - 0x08: "8", - 0x09: "9", - 0x0a: ".", - 0x0b: "E", - 0x0c: "E-", - 0x0d: "", - 0x0e: "-", - 0x0f: "", -} - -type psOperator struct { - // numPop is the number of stack values to pop. -1 means "array" and -2 - // means "delta" as per 5176.CFF.pdf Table 6 "Operand Types". - numPop int32 - // name is the operator name. An empty name (i.e. the zero value for the - // struct overall) means an unrecognized 1-byte operator. - name string - // run is the function that implements the operator. Nil means that we - // ignore the operator, other than popping its arguments off the stack. - run func(*psInterpreter) error -} - -// psOperators holds the 1-byte and 2-byte operators for PostScript interpreter -// contexts. -var psOperators = [...][2][]psOperator{ - // The Top DICT operators are defined by 5176.CFF.pdf Table 9 "Top DICT - // Operator Entries" and Table 10 "CIDFont Operator Extensions". - psContextTopDict: {{ - // 1-byte operators. - 0: {+1, "version", nil}, - 1: {+1, "Notice", nil}, - 2: {+1, "FullName", nil}, - 3: {+1, "FamilyName", nil}, - 4: {+1, "Weight", nil}, - 5: {-1, "FontBBox", nil}, - 13: {+1, "UniqueID", nil}, - 14: {-1, "XUID", nil}, - 15: {+1, "charset", nil}, - 16: {+1, "Encoding", nil}, - 17: {+1, "CharStrings", func(p *psInterpreter) error { - p.topDict.charStringsOffset = p.argStack.a[p.argStack.top-1] - return nil - }}, - 18: {+2, "Private", func(p *psInterpreter) error { - p.topDict.privateDictLength = p.argStack.a[p.argStack.top-2] - p.topDict.privateDictOffset = p.argStack.a[p.argStack.top-1] - return nil - }}, - }, { - // 2-byte operators. The first byte is the escape byte. - 0: {+1, "Copyright", nil}, - 1: {+1, "isFixedPitch", nil}, - 2: {+1, "ItalicAngle", nil}, - 3: {+1, "UnderlinePosition", nil}, - 4: {+1, "UnderlineThickness", nil}, - 5: {+1, "PaintType", nil}, - 6: {+1, "CharstringType", nil}, - 7: {-1, "FontMatrix", nil}, - 8: {+1, "StrokeWidth", nil}, - 20: {+1, "SyntheticBase", nil}, - 21: {+1, "PostScript", nil}, - 22: {+1, "BaseFontName", nil}, - 23: {-2, "BaseFontBlend", 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", 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}, - }}, - - // The Private DICT operators are defined by 5176.CFF.pdf Table 23 "Private - // DICT Operators". - psContextPrivateDict: {{ - // 1-byte operators. - 6: {-2, "BlueValues", nil}, - 7: {-2, "OtherBlues", nil}, - 8: {-2, "FamilyBlues", nil}, - 9: {-2, "FamilyOtherBlues", nil}, - 10: {+1, "StdHW", nil}, - 11: {+1, "StdVW", nil}, - 19: {+1, "Subrs", func(p *psInterpreter) error { - p.privateDict.subrsOffset = p.argStack.a[p.argStack.top-1] - return nil - }}, - 20: {+1, "defaultWidthX", nil}, - 21: {+1, "nominalWidthX", nil}, - }, { - // 2-byte operators. The first byte is the escape byte. - 9: {+1, "BlueScale", nil}, - 10: {+1, "BlueShift", nil}, - 11: {+1, "BlueFuzz", nil}, - 12: {-2, "StemSnapH", nil}, - 13: {-2, "StemSnapV", nil}, - 14: {+1, "ForceBold", nil}, - 17: {+1, "LanguageGroup", nil}, - 18: {+1, "ExpansionFactor", nil}, - 19: {+1, "initialRandomSeed", nil}, - }}, - - // The Type 2 Charstring operators are defined by 5177.Type2.pdf Appendix A - // "Type 2 Charstring Command Codes". - psContextType2Charstring: {{ - // 1-byte operators. - 0: {}, // Reserved. - 1: {-1, "hstem", t2CStem}, - 2: {}, // Reserved. - 3: {-1, "vstem", t2CStem}, - 4: {-1, "vmoveto", t2CVmoveto}, - 5: {-1, "rlineto", t2CRlineto}, - 6: {-1, "hlineto", t2CHlineto}, - 7: {-1, "vlineto", t2CVlineto}, - 8: {-1, "rrcurveto", t2CRrcurveto}, - 9: {}, // Reserved. - 10: {+1, "callsubr", t2CCallsubr}, - 11: {+0, "return", t2CReturn}, - 12: {}, // escape. - 13: {}, // Reserved. - 14: {-1, "endchar", t2CEndchar}, - 15: {}, // Reserved. - 16: {}, // Reserved. - 17: {}, // Reserved. - 18: {-1, "hstemhm", t2CStem}, - 19: {-1, "hintmask", t2CMask}, - 20: {-1, "cntrmask", t2CMask}, - 21: {-1, "rmoveto", t2CRmoveto}, - 22: {-1, "hmoveto", t2CHmoveto}, - 23: {-1, "vstemhm", t2CStem}, - 24: {-1, "rcurveline", t2CRcurveline}, - 25: {-1, "rlinecurve", t2CRlinecurve}, - 26: {-1, "vvcurveto", t2CVvcurveto}, - 27: {-1, "hhcurveto", t2CHhcurveto}, - 28: {}, // shortint. - 29: {+1, "callgsubr", t2CCallgsubr}, - 30: {-1, "vhcurveto", t2CVhcurveto}, - 31: {-1, "hvcurveto", t2CHvcurveto}, - }, { - // 2-byte operators. The first byte is the escape byte. - 34: {+7, "hflex", t2CHflex}, - 36: {+9, "hflex1", t2CHflex1}, - // TODO: more operators. - }}, -} - -// 5176.CFF.pdf section 4 "DICT Data" says that "Two-byte operators have an -// initial escape byte of 12". -const escapeByte = 12 - -// t2CReadWidth reads the optional width adjustment. If present, it is on the -// 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, -// hmoveto, vmoveto, rmoveto, or endchar, takes an additional argument — the -// width... which may be expressed as zero or one numeric argument." -func t2CReadWidth(p *psInterpreter, nArgs int32) { - if p.type2Charstrings.seenWidth { - return - } - p.type2Charstrings.seenWidth = true - 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, - // if present, it is a delta to the font-global nominalWidthX value found - // in the Private DICT. If absent, the glyph's width is the defaultWidthX - // value in that dict. See 5176.CFF.pdf section 15 "Private DICT Data". - // - // For a CFF embedded in an SFNT font (i.e. an OpenType font), glyph widths - // are already stored in the hmtx table, separate to the CFF table, and it - // is simpler to parse that table for all OpenType fonts (PostScript and - // TrueType). We therefore ignore the width value here, and just remove it - // from the bottom of the argStack. - copy(p.argStack.a[:p.argStack.top-1], p.argStack.a[1:p.argStack.top]) - p.argStack.top-- -} - -func t2CStem(p *psInterpreter) error { - t2CReadWidth(p, -1) - if p.argStack.top%2 != 0 { - return errInvalidCFFTable - } - // We update the number of hintBits need to parse hintmask and cntrmask - // instructions, but this Type 2 Charstring implementation otherwise - // ignores the stem hints. - p.type2Charstrings.hintBits += p.argStack.top / 2 - if p.type2Charstrings.hintBits > maxHintBits { - return errUnsupportedNumberOfHints - } - return nil -} - -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 - if len(p.instructions) < int(hintBytes) { - return errInvalidCFFTable - } - p.instructions = p.instructions[hintBytes:] - return nil -} - -func t2CHmoveto(p *psInterpreter) error { - t2CReadWidth(p, 1) - if p.argStack.top != 1 { - return errInvalidCFFTable - } - p.type2Charstrings.moveTo(p.argStack.a[0], 0) - return nil -} - -func t2CVmoveto(p *psInterpreter) error { - t2CReadWidth(p, 1) - if p.argStack.top != 1 { - return errInvalidCFFTable - } - p.type2Charstrings.moveTo(0, p.argStack.a[0]) - return nil -} - -func t2CRmoveto(p *psInterpreter) error { - t2CReadWidth(p, 2) - if p.argStack.top != 2 { - return errInvalidCFFTable - } - p.type2Charstrings.moveTo(p.argStack.a[0], p.argStack.a[1]) - return nil -} - -func t2CHlineto(p *psInterpreter) error { return t2CLineto(p, false) } -func t2CVlineto(p *psInterpreter) error { return t2CLineto(p, true) } - -func t2CLineto(p *psInterpreter, vertical bool) error { - if !p.type2Charstrings.seenWidth || p.argStack.top < 1 { - 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 { - dx, dy = dy, dx - } - p.type2Charstrings.lineTo(dx, dy) - } - return nil -} - -func t2CRlineto(p *psInterpreter) error { - if !p.type2Charstrings.seenWidth || p.argStack.top < 2 || p.argStack.top%2 != 0 { - return errInvalidCFFTable - } - for i := int32(0); i < p.argStack.top; i += 2 { - p.type2Charstrings.lineTo(p.argStack.a[i], p.argStack.a[i+1]) - } - return nil -} - -// As per 5177.Type2.pdf section 4.1 "Path Construction Operators", -// -// rcurveline is: -// - {dxa dya dxb dyb dxc dyc}+ dxd dyd -// -// rlinecurve is: -// - {dxa dya}+ dxb dyb dxc dyc dxd dyd - -func t2CRcurveline(p *psInterpreter) error { - if !p.type2Charstrings.seenWidth || p.argStack.top < 8 || p.argStack.top%6 != 2 { - return errInvalidCFFTable - } - i := int32(0) - for iMax := p.argStack.top - 2; i < iMax; i += 6 { - p.type2Charstrings.cubeTo( - p.argStack.a[i+0], - p.argStack.a[i+1], - p.argStack.a[i+2], - p.argStack.a[i+3], - p.argStack.a[i+4], - p.argStack.a[i+5], - ) - } - p.type2Charstrings.lineTo(p.argStack.a[i], p.argStack.a[i+1]) - return nil -} - -func t2CRlinecurve(p *psInterpreter) error { - if !p.type2Charstrings.seenWidth || p.argStack.top < 8 || p.argStack.top%2 != 0 { - return errInvalidCFFTable - } - i := int32(0) - for iMax := p.argStack.top - 6; i < iMax; i += 2 { - p.type2Charstrings.lineTo(p.argStack.a[i], p.argStack.a[i+1]) - } - p.type2Charstrings.cubeTo( - p.argStack.a[i+0], - p.argStack.a[i+1], - p.argStack.a[i+2], - p.argStack.a[i+3], - p.argStack.a[i+4], - p.argStack.a[i+5], - ) - return nil -} - -// As per 5177.Type2.pdf section 4.1 "Path Construction Operators", -// -// hhcurveto is: -// - dy1 {dxa dxb dyb dxc}+ -// -// vvcurveto is: -// - dx1 {dya dxb dyb dyc}+ -// -// hvcurveto is one of: -// - dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf? -// - {dxa dxb dyb dyc dyd dxe dye dxf}+ dyf? -// -// vhcurveto is one of: -// - dy1 dx2 dy2 dx3 {dxa dxb dyb dyc dyd dxe dye dxf}* dyf? -// - {dya dxb dyb dxc dxd dxe dye dyf}+ dxf? - -func t2CHhcurveto(p *psInterpreter) error { return t2CCurveto(p, false, false) } -func t2CVvcurveto(p *psInterpreter) error { return t2CCurveto(p, false, true) } -func t2CHvcurveto(p *psInterpreter) error { return t2CCurveto(p, true, false) } -func t2CVhcurveto(p *psInterpreter) error { return t2CCurveto(p, true, true) } - -// t2CCurveto implements the hh / vv / hv / vh xxcurveto operators. N relative -// cubic curve requires 6*N control points, but only 4*N+0 or 4*N+1 are used -// here: all (or all but one) of the piecewise cubic curve's tangents are -// implicitly horizontal or vertical. -// -// swap is whether that implicit horizontal / vertical constraint swaps as you -// move along the piecewise cubic curve. If swap is false, the constraints are -// either all horizontal or all vertical. If swap is true, it alternates. -// -// vertical is whether the first implicit constraint is vertical. -func t2CCurveto(p *psInterpreter, swap, vertical bool) error { - if !p.type2Charstrings.seenWidth || p.argStack.top < 4 { - return errInvalidCFFTable - } - - i := int32(0) - switch p.argStack.top & 3 { - case 0: - // No-op. - case 1: - if swap { - break - } - i = 1 - if vertical { - p.type2Charstrings.x += p.argStack.a[0] - } else { - p.type2Charstrings.y += p.argStack.a[0] - } - default: - return errInvalidCFFTable - } - - for i != p.argStack.top { - i = t2CCurveto4(p, swap, vertical, i) - if i < 0 { - return errInvalidCFFTable - } - if swap { - vertical = !vertical - } - } - return nil -} - -func t2CCurveto4(p *psInterpreter, swap bool, vertical bool, i int32) (j int32) { - if i+4 > p.argStack.top { - return -1 - } - dxa := p.argStack.a[i+0] - dya := int32(0) - dxb := p.argStack.a[i+1] - dyb := p.argStack.a[i+2] - dxc := p.argStack.a[i+3] - dyc := int32(0) - i += 4 - - if vertical { - dxa, dya = dya, dxa - } - - if swap { - if i+1 == p.argStack.top { - dyc = p.argStack.a[i] - i++ - } - } - - if swap != vertical { - dxc, dyc = dyc, dxc - } - - p.type2Charstrings.cubeTo(dxa, dya, dxb, dyb, dxc, dyc) - return i -} - -func t2CRrcurveto(p *psInterpreter) error { - if !p.type2Charstrings.seenWidth || p.argStack.top < 6 || p.argStack.top%6 != 0 { - return errInvalidCFFTable - } - for i := int32(0); i != p.argStack.top; i += 6 { - p.type2Charstrings.cubeTo( - p.argStack.a[i+0], - p.argStack.a[i+1], - p.argStack.a[i+2], - p.argStack.a[i+3], - p.argStack.a[i+4], - p.argStack.a[i+5], - ) - } - return nil -} - -// For the flex operators, we ignore the flex depth and always produce cubic -// segments, not linear segments. It's not obvious why the Type 2 Charstring -// format cares about switching behavior based on a metric in pixels, not in -// ideal font units. The Go vector rasterizer has no problems with almost -// linear cubic segments. - -func t2CHflex(p *psInterpreter) error { - p.type2Charstrings.cubeTo( - p.argStack.a[0], 0, - p.argStack.a[1], +p.argStack.a[2], - p.argStack.a[3], 0, - ) - p.type2Charstrings.cubeTo( - p.argStack.a[4], 0, - p.argStack.a[5], -p.argStack.a[2], - p.argStack.a[6], 0, - ) - return nil -} - -func t2CHflex1(p *psInterpreter) error { - dy1 := p.argStack.a[1] - dy2 := p.argStack.a[3] - dy5 := p.argStack.a[7] - dy6 := -dy1 - dy2 - dy5 - p.type2Charstrings.cubeTo( - p.argStack.a[0], dy1, - p.argStack.a[2], dy2, - p.argStack.a[4], 0, - ) - p.type2Charstrings.cubeTo( - p.argStack.a[5], 0, - p.argStack.a[6], dy5, - p.argStack.a[8], dy6, - ) - return nil -} - -// subrBias returns the subroutine index bias as per 5177.Type2.pdf section 4.7 -// "Subroutine Operators". -func subrBias(numSubroutines int) int32 { - if numSubroutines < 1240 { - return 107 - } - if numSubroutines < 33900 { - return 1131 - } - return 32768 -} - -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 { - return errInvalidCFFTable - } - length := uint32(len(p.instructions)) - p.callStack.a[p.callStack.top] = psCallStackEntry{ - offset: p.instrOffset + p.instrLength - length, - length: length, - } - p.callStack.top++ - - subrIndex := p.argStack.a[p.argStack.top-1] + subrBias(len(subrs)-1) - if subrIndex < 0 || int32(len(subrs)-1) <= subrIndex { - return errInvalidCFFTable - } - i := subrs[subrIndex+0] - j := subrs[subrIndex+1] - if j < i { - return errInvalidCFFTable - } - if j-i > maxGlyphDataLength { - return errUnsupportedGlyphDataLength - } - buf, err := p.type2Charstrings.b.view(&p.type2Charstrings.f.src, int(i), int(j-i)) - if err != nil { - return err - } - - p.instructions = buf - p.instrOffset = i - p.instrLength = j - i - return nil -} - -func t2CReturn(p *psInterpreter) error { - if p.callStack.top <= 0 { - return errInvalidCFFTable - } - p.callStack.top-- - o := p.callStack.a[p.callStack.top].offset - n := p.callStack.a[p.callStack.top].length - buf, err := p.type2Charstrings.b.view(&p.type2Charstrings.f.src, int(o), int(n)) - if err != nil { - return err - } - - p.instructions = buf - p.instrOffset = o - p.instrLength = n - return nil -} - -func t2CEndchar(p *psInterpreter) error { - t2CReadWidth(p, 0) - if p.argStack.top != 0 || p.hasMoreInstructions() { - if p.argStack.top == 4 { - // TODO: process the implicit "seac" command as per 5177.Type2.pdf - // Appendix C "Compatibility and Deprecated Operators". - return errUnsupportedType2Charstring - } - return errInvalidCFFTable - } - p.type2Charstrings.closePath() - p.type2Charstrings.ended = true - return nil -} diff --git a/vendor/golang.org/x/image/font/sfnt/proprietary_test.go b/vendor/golang.org/x/image/font/sfnt/proprietary_test.go deleted file mode 100644 index bb14a34b5..000000000 --- a/vendor/golang.org/x/image/font/sfnt/proprietary_test.go +++ /dev/null @@ -1,1390 +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 - -/* -This file contains opt-in tests for popular, high quality, proprietary fonts, -made by companies such as Adobe and Microsoft. These fonts are generally -available, but copies are not explicitly included in this repository due to -licensing differences or file size concerns. To opt-in, run: - -go test golang.org/x/image/font/sfnt -args -proprietary - -Not all tests pass out-of-the-box on all systems. For example, the Microsoft -Times New Roman font is downloadable gratis even on non-Windows systems, but as -per the ttf-mscorefonts-installer Debian package, this requires accepting an -End User License Agreement (EULA) and a CAB format decoder. These tests assume -that such fonts have already been installed. You may need to specify the -directories for these fonts: - -go test golang.org/x/image/font/sfnt -args -proprietary \ - -adobeDir=$HOME/fonts/adobe \ - -appleDir=$HOME/fonts/apple \ - -dejavuDir=$HOME/fonts/dejavu \ - -microsoftDir=$HOME/fonts/microsoft \ - -notoDir=$HOME/fonts/noto - -To only run those tests for the Microsoft fonts: - -go test golang.org/x/image/font/sfnt -test.run=ProprietaryMicrosoft -args -proprietary etc -*/ - -// TODO: enable Apple/Microsoft tests by default on Darwin/Windows? - -import ( - "errors" - "flag" - "io/ioutil" - "path/filepath" - "strconv" - "strings" - "testing" - - "golang.org/x/image/font" - "golang.org/x/image/math/fixed" -) - -var ( - proprietary = flag.Bool("proprietary", false, "test proprietary fonts not included in this repository") - - adobeDir = flag.String( - "adobeDir", - // This needs to be set explicitly. There is no default dir on Debian: - // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=736680 - // - // Get the fonts from https://github.com/adobe-fonts, e.g.: - // - https://github.com/adobe-fonts/source-code-pro/releases/latest - // - https://github.com/adobe-fonts/source-han-sans/releases/latest - // - https://github.com/adobe-fonts/source-sans-pro/releases/latest - // - // Copy all of the TTF and OTF files to the one directory, such as - // $HOME/adobe-fonts, and pass that as the -adobeDir flag here. - "", - "directory name for the Adobe proprietary fonts", - ) - - appleDir = flag.String( - "appleDir", - // This needs to be set explicitly. These fonts come with macOS, which - // is widely available but not freely available. - // - // On a Mac, set this to "/System/Library/Fonts/". - "", - "directory name for the Apple proprietary fonts", - ) - - dejavuDir = flag.String( - "dejavuDir", - // Get the fonts from https://dejavu-fonts.github.io/ - "", - "directory name for the DejaVu proprietary fonts", - ) - - microsoftDir = flag.String( - "microsoftDir", - "/usr/share/fonts/truetype/msttcorefonts", - "directory name for the Microsoft proprietary fonts", - ) - - notoDir = flag.String( - "notoDir", - // Get the fonts from https://www.google.com/get/noto/ - "", - "directory name for the Noto proprietary fonts", - ) -) - -func TestProprietaryAdobeSourceCodeProRegularOTF(t *testing.T) { - testProprietary(t, "adobe", "SourceCodePro-Regular.otf", 1500, -1) -} - -func TestProprietaryAdobeSourceCodeProRegularTTF(t *testing.T) { - testProprietary(t, "adobe", "SourceCodePro-Regular.ttf", 1500, -1) -} - -func TestProprietaryAdobeSourceHanSansSCRegularOTF(t *testing.T) { - testProprietary(t, "adobe", "SourceHanSansSC-Regular.otf", 65535, -1) -} - -func TestProprietaryAdobeSourceSansProBlackOTF(t *testing.T) { - testProprietary(t, "adobe", "SourceSansPro-Black.otf", 1900, -1) -} - -func TestProprietaryAdobeSourceSansProBlackTTF(t *testing.T) { - testProprietary(t, "adobe", "SourceSansPro-Black.ttf", 1900, -1) -} - -func TestProprietaryAdobeSourceSansProRegularOTF(t *testing.T) { - testProprietary(t, "adobe", "SourceSansPro-Regular.otf", 1900, -1) -} - -func TestProprietaryAdobeSourceSansProRegularTTF(t *testing.T) { - testProprietary(t, "adobe", "SourceSansPro-Regular.ttf", 1900, -1) -} - -func TestProprietaryAppleAppleSymbols(t *testing.T) { - testProprietary(t, "apple", "Apple Symbols.ttf", 4600, -1) -} - -func TestProprietaryAppleGeezaPro0(t *testing.T) { - testProprietary(t, "apple", "GeezaPro.ttc?0", 1700, -1) -} - -func TestProprietaryAppleGeezaPro1(t *testing.T) { - testProprietary(t, "apple", "GeezaPro.ttc?1", 1700, -1) -} - -func TestProprietaryAppleHelvetica0(t *testing.T) { - testProprietary(t, "apple", "Helvetica.dfont?0", 2100, -1) -} - -func TestProprietaryAppleHelvetica1(t *testing.T) { - testProprietary(t, "apple", "Helvetica.dfont?1", 2100, -1) -} - -func TestProprietaryAppleHelvetica2(t *testing.T) { - testProprietary(t, "apple", "Helvetica.dfont?2", 2100, -1) -} - -func TestProprietaryAppleHelvetica3(t *testing.T) { - testProprietary(t, "apple", "Helvetica.dfont?3", 2100, -1) -} - -func TestProprietaryAppleHelvetica4(t *testing.T) { - testProprietary(t, "apple", "Helvetica.dfont?4", 1300, -1) -} - -func TestProprietaryAppleHelvetica5(t *testing.T) { - testProprietary(t, "apple", "Helvetica.dfont?5", 1300, -1) -} - -func TestProprietaryAppleHiragino0(t *testing.T) { - testProprietary(t, "apple", "ヒラギノ角ゴシック W0.ttc?0", 9000, -1) -} - -func TestProprietaryAppleHiragino1(t *testing.T) { - testProprietary(t, "apple", "ヒラギノ角ゴシック W0.ttc?1", 9000, -1) -} - -func TestProprietaryDejaVuSansExtraLight(t *testing.T) { - testProprietary(t, "dejavu", "DejaVuSans-ExtraLight.ttf", 2000, -1) -} - -func TestProprietaryDejaVuSansMono(t *testing.T) { - testProprietary(t, "dejavu", "DejaVuSansMono.ttf", 3300, -1) -} - -func TestProprietaryDejaVuSerif(t *testing.T) { - testProprietary(t, "dejavu", "DejaVuSerif.ttf", 3500, -1) -} - -func TestProprietaryMicrosoftArial(t *testing.T) { - testProprietary(t, "microsoft", "Arial.ttf", 1200, -1) -} - -func TestProprietaryMicrosoftArialAsACollection(t *testing.T) { - testProprietary(t, "microsoft", "Arial.ttf?0", 1200, -1) -} - -func TestProprietaryMicrosoftComicSansMS(t *testing.T) { - testProprietary(t, "microsoft", "Comic_Sans_MS.ttf", 550, -1) -} - -func TestProprietaryMicrosoftTimesNewRoman(t *testing.T) { - testProprietary(t, "microsoft", "Times_New_Roman.ttf", 1200, -1) -} - -func TestProprietaryMicrosoftWebdings(t *testing.T) { - testProprietary(t, "microsoft", "Webdings.ttf", 200, -1) -} - -func TestProprietaryNotoColorEmoji(t *testing.T) { - testProprietary(t, "noto", "NotoColorEmoji.ttf", 2300, -1) -} - -func TestProprietaryNotoSansRegular(t *testing.T) { - testProprietary(t, "noto", "NotoSans-Regular.ttf", 2400, -1) -} - -// testProprietary tests that we can load every glyph in the named font. -// -// The exact number of glyphs in the font can differ across its various -// versions, but as a sanity check, there should be at least minNumGlyphs. -// -// While this package is a work-in-progress, not every glyph can be loaded. The -// firstUnsupportedGlyph argument, if non-negative, is the index of the first -// unsupported glyph in the font. This number should increase over time (or set -// negative), as the TODO's in this package are done. -func testProprietary(t *testing.T, proprietor, filename string, minNumGlyphs, firstUnsupportedGlyph int) { - if !*proprietary { - t.Skip("skipping proprietary font test") - } - - basename, fontIndex, err := filename, -1, error(nil) - if i := strings.IndexByte(filename, '?'); i >= 0 { - fontIndex, err = strconv.Atoi(filename[i+1:]) - if err != nil { - t.Fatalf("could not parse collection font index from filename %q", filename) - } - basename = filename[:i] - } - - dir := "" - switch proprietor { - case "adobe": - dir = *adobeDir - case "apple": - dir = *appleDir - case "dejavu": - dir = *dejavuDir - case "microsoft": - dir = *microsoftDir - case "noto": - dir = *notoDir - default: - panic("unreachable") - } - file, err := ioutil.ReadFile(filepath.Join(dir, basename)) - if err != nil { - t.Fatalf("%v\nPerhaps you need to set the -%sDir flag?", err, proprietor) - } - qualifiedFilename := proprietor + "/" + filename - - f := (*Font)(nil) - if fontIndex >= 0 { - c, err := ParseCollection(file) - if err != nil { - t.Fatalf("ParseCollection: %v", err) - } - if want, ok := proprietaryNumFonts[qualifiedFilename]; ok { - if got := c.NumFonts(); got != want { - t.Fatalf("NumFonts: got %d, want %d", got, want) - } - } - f, err = c.Font(fontIndex) - if err != nil { - t.Fatalf("Font: %v", err) - } - } else { - f, err = Parse(file) - if err != nil { - t.Fatalf("Parse: %v", err) - } - } - - ppem := fixed.Int26_6(f.UnitsPerEm()) - var buf Buffer - - // Some of the tests below, such as which glyph index a particular rune - // maps to, can depend on the specific version of the proprietary font. If - // tested against a different version of that font, the test might (but not - // necessarily will) fail, even though the Go code is good. If so, log a - // message, but don't automatically fail (i.e. dont' call t.Fatalf). - gotVersion, err := f.Name(&buf, NameIDVersion) - if err != nil { - t.Fatalf("Name(Version): %v", err) - } - wantVersion := proprietaryVersions[qualifiedFilename] - if gotVersion != wantVersion { - t.Logf("font version provided differs from the one the tests were written against:"+ - "\ngot %q\nwant %q", gotVersion, wantVersion) - } - - gotFull, err := f.Name(&buf, NameIDFull) - if err != nil { - t.Fatalf("Name(Full): %v", err) - } - wantFull := proprietaryFullNames[qualifiedFilename] - if gotFull != wantFull { - t.Fatalf("Name(Full):\ngot %q\nwant %q", gotFull, wantFull) - } - - numGlyphs := f.NumGlyphs() - if numGlyphs < minNumGlyphs { - t.Fatalf("NumGlyphs: got %d, want at least %d", numGlyphs, minNumGlyphs) - } - - iMax := numGlyphs - if firstUnsupportedGlyph >= 0 { - iMax = firstUnsupportedGlyph - } - for i, numErrors := 0, 0; i < iMax; i++ { - if _, err := f.LoadGlyph(&buf, GlyphIndex(i), ppem, nil); err != nil && err != ErrColoredGlyph { - t.Errorf("LoadGlyph(%d): %v", i, err) - numErrors++ - } - if numErrors == 10 { - t.Fatal("LoadGlyph: too many errors") - } - } - - for r, want := range proprietaryGlyphIndexTestCases[qualifiedFilename] { - got, err := f.GlyphIndex(&buf, r) - if err != nil { - t.Errorf("GlyphIndex(%q): %v", r, err) - continue - } - if got != want { - t.Errorf("GlyphIndex(%q): got %d, want %d", r, got, want) - continue - } - } - - for r, want := range proprietaryGlyphTestCases[qualifiedFilename] { - x, err := f.GlyphIndex(&buf, r) - if err != nil { - t.Errorf("GlyphIndex(%q): %v", r, err) - continue - } - got, err := f.LoadGlyph(&buf, x, ppem, nil) - if err != nil { - t.Errorf("LoadGlyph(%q): %v", r, err) - continue - } - if err := checkSegmentsEqual(got, want); err != nil { - t.Errorf("LoadGlyph(%q): %v", r, err) - continue - } - } - -kernLoop: - for _, tc := range proprietaryKernTestCases[qualifiedFilename] { - var indexes [2]GlyphIndex - for i := range indexes { - x, err := f.GlyphIndex(&buf, tc.runes[i]) - if x == 0 && err == nil { - err = errors.New("no glyph index found") - } - if err != nil { - t.Errorf("GlyphIndex(%q): %v", tc.runes[0], err) - continue kernLoop - } - indexes[i] = x - } - kern, err := f.Kern(&buf, indexes[0], indexes[1], tc.ppem, tc.hinting) - if err != nil { - t.Errorf("Kern(%q, %q, ppem=%d, hinting=%v): %v", - tc.runes[0], tc.runes[1], tc.ppem, tc.hinting, err) - continue - } - if got := Units(kern); got != tc.want { - t.Errorf("Kern(%q, %q, ppem=%d, hinting=%v): got %d, want %d", - tc.runes[0], tc.runes[1], tc.ppem, tc.hinting, got, tc.want) - continue - } - } - - for x, want := range proprietaryFDSelectTestCases[qualifiedFilename] { - got, err := f.cached.glyphData.fdSelect.lookup(f, &buf, x) - if err != nil { - t.Errorf("fdSelect.lookup(%d): %v", x, err) - continue - } - if got != want { - t.Errorf("fdSelect.lookup(%d): got %d, want %d", x, got, want) - continue - } - } -} - -// proprietaryNumFonts holds the expected number of fonts in each collection, -// or 1 for a single font. It is not necessarily an exhaustive list of all -// proprietary fonts tested. -var proprietaryNumFonts = map[string]int{ - "apple/Helvetica.dfont?0": 6, - "apple/ヒラギノ角ゴシック W0.ttc?0": 2, - "microsoft/Arial.ttf?0": 1, -} - -// proprietaryVersions holds the expected version string of each proprietary -// font tested. If third parties such as Adobe or Microsoft update their fonts, -// and the tests subsequently fail, these versions should be updated too. -// -// Updates are expected to be infrequent. For example, as of 2017, the fonts -// installed by the Debian ttf-mscorefonts-installer package have last modified -// times no later than 2001. -var proprietaryVersions = map[string]string{ - "adobe/SourceCodePro-Regular.otf": "Version 2.030;PS 1.0;hotconv 16.6.51;makeotf.lib2.5.65220", - "adobe/SourceCodePro-Regular.ttf": "Version 2.030;PS 1.000;hotconv 16.6.51;makeotf.lib2.5.65220", - "adobe/SourceHanSansSC-Regular.otf": "Version 1.004;PS 1.004;hotconv 1.0.82;makeotf.lib2.5.63406", - "adobe/SourceSansPro-Black.otf": "Version 2.020;PS 2.0;hotconv 1.0.86;makeotf.lib2.5.63406", - "adobe/SourceSansPro-Black.ttf": "Version 2.020;PS 2.000;hotconv 1.0.86;makeotf.lib2.5.63406", - "adobe/SourceSansPro-Regular.otf": "Version 2.020;PS 2.0;hotconv 1.0.86;makeotf.lib2.5.63406", - "adobe/SourceSansPro-Regular.ttf": "Version 2.020;PS 2.000;hotconv 1.0.86;makeotf.lib2.5.63406", - - "apple/Apple Symbols.ttf": "12.0d3e10", - "apple/GeezaPro.ttc?0": "12.0d1e3", - "apple/GeezaPro.ttc?1": "12.0d1e3", - "apple/Helvetica.dfont?0": "12.0d1e3", - "apple/Helvetica.dfont?1": "12.0d1e3", - "apple/Helvetica.dfont?2": "12.0d1e3", - "apple/Helvetica.dfont?3": "12.0d1e3", - "apple/Helvetica.dfont?4": "12.0d1e3", - "apple/Helvetica.dfont?5": "12.0d1e3", - "apple/ヒラギノ角ゴシック W0.ttc?0": "11.0d7e1", - "apple/ヒラギノ角ゴシック W0.ttc?1": "11.0d7e1", - - "dejavu/DejaVuSans-ExtraLight.ttf": "Version 2.37", - "dejavu/DejaVuSansMono.ttf": "Version 2.37", - "dejavu/DejaVuSerif.ttf": "Version 2.37", - - "microsoft/Arial.ttf": "Version 2.82", - "microsoft/Arial.ttf?0": "Version 2.82", - "microsoft/Comic_Sans_MS.ttf": "Version 2.10", - "microsoft/Times_New_Roman.ttf": "Version 2.82", - "microsoft/Webdings.ttf": "Version 1.03", - - "noto/NotoColorEmoji.ttf": "Version 1.33", - "noto/NotoSans-Regular.ttf": "Version 1.06", -} - -// proprietaryFullNames holds the expected full name of each proprietary font -// tested. -var proprietaryFullNames = map[string]string{ - "adobe/SourceCodePro-Regular.otf": "Source Code Pro", - "adobe/SourceCodePro-Regular.ttf": "Source Code Pro", - "adobe/SourceHanSansSC-Regular.otf": "Source Han Sans SC Regular", - "adobe/SourceSansPro-Black.otf": "Source Sans Pro Black", - "adobe/SourceSansPro-Black.ttf": "Source Sans Pro Black", - "adobe/SourceSansPro-Regular.otf": "Source Sans Pro", - "adobe/SourceSansPro-Regular.ttf": "Source Sans Pro", - - "apple/Apple Symbols.ttf": "Apple Symbols", - "apple/GeezaPro.ttc?0": "Geeza Pro Regular", - "apple/GeezaPro.ttc?1": "Geeza Pro Bold", - "apple/Helvetica.dfont?0": "Helvetica", - "apple/Helvetica.dfont?1": "Helvetica Bold", - "apple/Helvetica.dfont?2": "Helvetica Oblique", - "apple/Helvetica.dfont?3": "Helvetica Bold Oblique", - "apple/Helvetica.dfont?4": "Helvetica Light", - "apple/Helvetica.dfont?5": "Helvetica Light Oblique", - "apple/ヒラギノ角ゴシック W0.ttc?0": "Hiragino Sans W0", - "apple/ヒラギノ角ゴシック W0.ttc?1": ".Hiragino Kaku Gothic Interface W0", - - "dejavu/DejaVuSans-ExtraLight.ttf": "DejaVu Sans ExtraLight", - "dejavu/DejaVuSansMono.ttf": "DejaVu Sans Mono", - "dejavu/DejaVuSerif.ttf": "DejaVu Serif", - - "microsoft/Arial.ttf": "Arial", - "microsoft/Arial.ttf?0": "Arial", - "microsoft/Comic_Sans_MS.ttf": "Comic Sans MS", - "microsoft/Times_New_Roman.ttf": "Times New Roman", - "microsoft/Webdings.ttf": "Webdings", - - "noto/NotoColorEmoji.ttf": "Noto Color Emoji", - "noto/NotoSans-Regular.ttf": "Noto Sans", -} - -// proprietaryGlyphIndexTestCases hold a sample of each font's rune to glyph -// index cmap. The numerical values can be verified by running the ttx tool. -var proprietaryGlyphIndexTestCases = map[string]map[rune]GlyphIndex{ - "adobe/SourceCodePro-Regular.otf": { - '\u0030': 877, // U+0030 DIGIT ZERO - '\u0041': 2, // U+0041 LATIN CAPITAL LETTER A - '\u0061': 28, // U+0061 LATIN SMALL LETTER A - '\u0104': 64, // U+0104 LATIN CAPITAL LETTER A WITH OGONEK - '\u0125': 323, // U+0125 LATIN SMALL LETTER H WITH CIRCUMFLEX - '\u01f4': 111, // U+01F4 LATIN CAPITAL LETTER G WITH ACUTE - '\u03a3': 623, // U+03A3 GREEK CAPITAL LETTER SIGMA - '\u2569': 1500, // U+2569 BOX DRAWINGS DOUBLE UP AND HORIZONTAL - '\U0001f100': 0, // U+0001F100 DIGIT ZERO FULL STOP - }, - "adobe/SourceCodePro-Regular.ttf": { - '\u0030': 877, // U+0030 DIGIT ZERO - '\u0041': 2, // U+0041 LATIN CAPITAL LETTER A - '\u01f4': 111, // U+01F4 LATIN CAPITAL LETTER G WITH ACUTE - }, - "adobe/SourceHanSansSC-Regular.otf": { - '\u0030': 17, // U+0030 DIGIT ZERO - '\u0041': 34, // U+0041 LATIN CAPITAL LETTER A - '\u00d7': 150, // U+00D7 MULTIPLICATION SIGN - '\u1100': 365, // U+1100 HANGUL CHOSEONG KIYEOK - '\u25ca': 1254, // U+25CA LOZENGE - '\u2e9c': 1359, // U+2E9C CJK RADICAL SUN - '\u304b': 1463, // U+304B HIRAGANA LETTER KA - '\u4e2d': 9893, // U+4E2D , 中 - '\ua960': 47537, // U+A960 HANGUL CHOSEONG TIKEUT-MIEUM - '\ufb00': 58919, // U+FB00 LATIN SMALL LIGATURE FF - '\uffee': 59213, // U+FFEE HALFWIDTH WHITE CIRCLE - '\U0001f100': 59214, // U+0001F100 DIGIT ZERO FULL STOP - '\U0001f248': 59449, // U+0001F248 TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557 - '\U0002f9f4': 61768, // U+0002F9F4 CJK COMPATIBILITY IDEOGRAPH-2F9F4 - }, - "adobe/SourceSansPro-Regular.otf": { - '\u0041': 2, // U+0041 LATIN CAPITAL LETTER A - '\u03a3': 592, // U+03A3 GREEK CAPITAL LETTER SIGMA - '\u0435': 999, // U+0435 CYRILLIC SMALL LETTER IE - '\u2030': 1728, // U+2030 PER MILLE SIGN - }, - "adobe/SourceSansPro-Regular.ttf": { - '\u0041': 2, // U+0041 LATIN CAPITAL LETTER A - '\u03a3': 592, // U+03A3 GREEK CAPITAL LETTER SIGMA - '\u0435': 999, // U+0435 CYRILLIC SMALL LETTER IE - '\u2030': 1728, // U+2030 PER MILLE SIGN - }, - - "apple/Helvetica.dfont?0": { - '\u0041': 36, // U+0041 LATIN CAPITAL LETTER A - '\u00f1': 120, // U+00F1 LATIN SMALL LETTER N WITH TILDE - '\u0401': 473, // U+0401 CYRILLIC CAPITAL LETTER IO - '\u200d': 611, // U+200D ZERO WIDTH JOINER - '\u20ab': 1743, // U+20AB DONG SIGN - '\u2229': 0, // U+2229 INTERSECTION - '\u04e9': 1208, // U+04E9 CYRILLIC SMALL LETTER BARRED O - '\U0001f100': 0, // U+0001F100 DIGIT ZERO FULL STOP - }, - - "dejavu/DejaVuSerif.ttf": { - '\u0041': 36, // U+0041 LATIN CAPITAL LETTER A - '\u1e00': 1418, // U+1E00 LATIN CAPITAL LETTER A WITH RING BELOW - }, - - "microsoft/Arial.ttf": { - '\u0041': 36, // U+0041 LATIN CAPITAL LETTER A - '\u00f1': 120, // U+00F1 LATIN SMALL LETTER N WITH TILDE - '\u0401': 556, // U+0401 CYRILLIC CAPITAL LETTER IO - '\u200d': 745, // U+200D ZERO WIDTH JOINER - '\u20ab': 1150, // U+20AB DONG SIGN - '\u2229': 320, // U+2229 INTERSECTION - '\u04e9': 1319, // U+04E9 CYRILLIC SMALL LETTER BARRED O - '\U0001f100': 0, // U+0001F100 DIGIT ZERO FULL STOP - }, - "microsoft/Comic_Sans_MS.ttf": { - '\u0041': 36, // U+0041 LATIN CAPITAL LETTER A - '\u03af': 573, // U+03AF GREEK SMALL LETTER IOTA WITH TONOS - }, - "microsoft/Times_New_Roman.ttf": { - '\u0041': 36, // U+0041 LATIN CAPITAL LETTER A - '\u0042': 37, // U+0041 LATIN CAPITAL LETTER B - '\u266a': 392, // U+266A EIGHTH NOTE - '\uf041': 0, // PRIVATE USE AREA - '\uf042': 0, // PRIVATE USE AREA - }, - "microsoft/Webdings.ttf": { - '\u0041': 0, // U+0041 LATIN CAPITAL LETTER A - '\u0042': 0, // U+0041 LATIN CAPITAL LETTER B - '\u266a': 0, // U+266A EIGHTH NOTE - '\uf041': 36, // PRIVATE USE AREA - '\uf042': 37, // PRIVATE USE AREA - }, -} - -// proprietaryGlyphTestCases hold a sample of each font's glyph vectors. The -// numerical values can be verified by running the ttx tool, remembering that: -// - for PostScript glyphs, ttx coordinates are relative. -// - for TrueType glyphs, ttx coordinates are absolute, and consecutive -// off-curve points implies an on-curve point at the midpoint. -var proprietaryGlyphTestCases = map[string]map[rune][]Segment{ - "adobe/SourceHanSansSC-Regular.otf": { - '!': { - // -312 123 callsubr # 123 + bias = 230 - // : # Arg stack is [-312]. - // : -13 140 -119 -21 return - // : # Arg stack is [-312 -13 140 -119 -21]. - // 120 callsubr # 120 + bias = 227 - // : # Arg stack is [-312 -13 140 -119 -21]. - // : hstemhm - // : 95 132 -103 75 return - // : # Arg stack is [95 132 -103 75]. - // hintmask 01010000 - // 8 callsubr # 8 + bias = 115 - // : # Arg stack is []. - // : 130 221 rmoveto - moveTo(130, 221), - // : 63 hlineto - lineTo(193, 221), - // : 12 424 3 -735 callgsubr # -735 + bias = 396 - // : : # Arg stack is [12 424 3]. - // : : 104 rlineto - lineTo(205, 645), - lineTo(208, 749), - // : : -93 hlineto - lineTo(115, 749), - // : : 3 -104 rlineto - lineTo(118, 645), - // : : return - // : : # Arg stack is []. - // : return - // : # Arg stack is []. - // hintmask 01100000 - // 106 callsubr # 106 + bias = 213 - // : # Arg stack is []. - // : 43 -658 rmoveto - lineTo(130, 221), - moveTo(161, -13), - // : 37 29 28 41 return - // : # Arg stack is [37 29 28 41]. - // hvcurveto - cubeTo(198, -13, 227, 15, 227, 56), - // hintmask 10100000 - // 41 -29 30 -37 -36 -30 -30 -41 vhcurveto - cubeTo(227, 97, 198, 127, 161, 127), - cubeTo(125, 127, 95, 97, 95, 56), - // hintmask 01100000 - // 111 callsubr # 111 + bias = 218 - // : # Arg stack is []. - // : -41 30 -28 36 vhcurveto - cubeTo(95, 15, 125, -13, 161, -13), - // : endchar - }, - - '二': { // U+4E8C "two; twice" - // 23 81 510 79 hstem - // 60 881 cntrmask 11000000 - // 144 693 rmoveto - moveTo(144, 693), - // -79 713 79 vlineto - lineTo(144, 614), - lineTo(857, 614), - lineTo(857, 693), - // -797 -589 rmoveto - lineTo(144, 693), - moveTo(60, 104), - // -81 881 81 vlineto - lineTo(60, 23), - lineTo(941, 23), - lineTo(941, 104), - // endchar - lineTo(60, 104), - }, - }, - - "adobe/SourceSansPro-Black.otf": { - '¤': { // U+00A4 CURRENCY SIGN - // -45 147 99 168 98 hstem - // 44 152 148 152 vstem - // 102 76 rmoveto - moveTo(102, 76), - // 71 71 rlineto - lineTo(173, 147), - // 31 -13 33 -6 33 32 34 6 31 hflex1 - cubeTo(204, 134, 237, 128, 270, 128), - cubeTo(302, 128, 336, 134, 367, 147), - // 71 -71 85 85 -61 60 rlineto - lineTo(438, 76), - lineTo(523, 161), - lineTo(462, 221), - // 21 30 13 36 43 vvcurveto - cubeTo(483, 251, 496, 287, 496, 330), - // 42 -12 36 -21 29 vhcurveto - cubeTo(496, 372, 484, 408, 463, 437), - // 60 60 -85 85 -70 -70 rlineto - lineTo(523, 497), - lineTo(438, 582), - lineTo(368, 512), - // -31 13 -34 7 -33 -33 -34 -7 -31 hflex1 - cubeTo(337, 525, 303, 532, 270, 532), - cubeTo(237, 532, 203, 525, 172, 512), - // -70 70 -85 -85 59 -60 rlineto - lineTo(102, 582), - lineTo(17, 497), - lineTo(76, 437), - // -20 -29 -12 -36 -42 vvcurveto - cubeTo(56, 408, 44, 372, 44, 330), - // -43 12 -36 21 -30 vhcurveto - cubeTo(44, 287, 56, 251, 77, 221), - // -60 -60 rlineto - lineTo(17, 161), - // 253 85 rmoveto - lineTo(102, 76), - moveTo(270, 246), - // -42 -32 32 52 52 32 32 42 42 32 -32 -52 -52 -32 -32 -42 hvcurveto - cubeTo(228, 246, 196, 278, 196, 330), - cubeTo(196, 382, 228, 414, 270, 414), - cubeTo(312, 414, 344, 382, 344, 330), - cubeTo(344, 278, 312, 246, 270, 246), - // endchar - }, - }, - - "adobe/SourceSansPro-Regular.otf": { - ',': { - // -309 -1 115 hstem - // 137 61 vstem - // 67 -170 rmoveto - moveTo(67, -170), - // 81 34 50 67 86 vvcurveto - cubeTo(148, -136, 198, -69, 198, 17), - // 60 -26 37 -43 -33 -28 -22 -36 -37 27 -20 32 3 4 0 1 3 vhcurveto - cubeTo(198, 77, 172, 114, 129, 114), - cubeTo(96, 114, 68, 92, 68, 56), - cubeTo(68, 19, 95, -1, 127, -1), - cubeTo(130, -1, 134, -1, 137, 0), - // 1 -53 -34 -44 -57 -25 rrcurveto - cubeTo(138, -53, 104, -97, 47, -122), - // endchar - lineTo(67, -170), - }, - - 'Q': { - // 106 -165 70 87 65 538 73 hstem - // 52 86 388 87 vstem - // 332 57 rmoveto - moveTo(332, 57), - // -117 -77 106 168 163 77 101 117 117 77 -101 -163 -168 -77 -106 -117 hvcurveto - cubeTo(215, 57, 138, 163, 138, 331), - cubeTo(138, 494, 215, 595, 332, 595), - cubeTo(449, 595, 526, 494, 526, 331), - cubeTo(526, 163, 449, 57, 332, 57), - // 201 -222 rmoveto - moveTo(533, -165), - // 39 35 7 8 20 hvcurveto - cubeTo(572, -165, 607, -158, 627, -150), - // -16 64 rlineto - lineTo(611, -86), - // -5 -18 -22 -4 -29 hhcurveto - cubeTo(593, -91, 571, -95, 542, -95), - // -71 -60 29 58 -30 hvcurveto - cubeTo(471, -95, 411, -66, 381, -8), - // 139 24 93 126 189 vvcurveto - cubeTo(520, 16, 613, 142, 613, 331), - // 209 -116 128 -165 -165 -115 -127 -210 -193 96 -127 143 -20 vhcurveto - cubeTo(613, 540, 497, 668, 332, 668), - cubeTo(167, 668, 52, 541, 52, 331), - cubeTo(52, 138, 148, 11, 291, -9), - // -90 38 83 -66 121 hhcurveto - cubeTo(329, -99, 412, -165, 533, -165), - // endchar - }, - - 'ĩ': { // U+0129 LATIN SMALL LETTER I WITH TILDE - // 92 callgsubr # 92 + bias = 199. - // : # Arg stack is []. - // : -312 21 85 callgsubr # 85 + bias = 192. - // : : # Arg stack is [-312 21]. - // : : -21 486 -20 return - // : : # Arg stack is [-312 21 -21 486 -20]. - // : return - // : # Arg stack is [-312 21 -21 486 -20]. - // 111 45 callsubr # 45 + bias = 152 - // : # Arg stack is [-312 21 -21 486 -20 111]. - // : 60 24 60 -9 216 callgsubr # 216 + bias = 323 - // : : # Arg stack is [-312 21 -21 486 -20 111 60 24 60 -9]. - // : : -20 24 -20 hstemhm - // : : return - // : : # Arg stack is []. - // : return - // : # Arg stack is []. - // -50 55 77 82 77 55 hintmask 1101000100000000 - // 134 callsubr # 134 + bias = 241 - // : # Arg stack is []. - // : 82 hmoveto - moveTo(82, 0), - // : 82 127 callsubr # 127 + bias = 234 - // : : # Arg stack is [82]. - // : : 486 -82 hlineto - lineTo(164, 0), - lineTo(164, 486), - lineTo(82, 486), - // : : return - // : : # Arg stack is []. - // : return - // : # Arg stack is []. - // hintmask 1110100110000000 - // 113 91 15 callgsubr # 15 + bias = 122 - // : # Arg stack is [113 91]. - // : rmoveto - lineTo(82, 0), - moveTo(195, 577), - // : 69 29 58 77 3 hvcurveto - cubeTo(264, 577, 293, 635, 296, 712), - // : return - // : # Arg stack is []. - // hintmask 1110010110000000 - // -58 callsubr # -58 + bias = 49 - // : # Arg stack is []. - // : -55 4 rlineto - lineTo(241, 716), - // : -46 -3 -14 -33 -29 -47 -26 84 -71 hhcurveto - cubeTo(238, 670, 224, 637, 195, 637), - cubeTo(148, 637, 122, 721, 51, 721), - // : return - // : # Arg stack is []. - // hintmask 1101001100000000 - // -70 callgsubr # -70 + bias = 37 - // : # Arg stack is []. - // : -69 -29 -58 -78 -3 hvcurveto - cubeTo(-18, 721, -47, 663, -50, 585), - // : 55 -3 rlineto - lineTo(5, 582), - // : 47 3 14 32 30 hhcurveto - cubeTo(8, 629, 22, 661, 52, 661), - // : return - // : # Arg stack is []. - // hintmask 1110100110000000 - // 51 callsubr # 51 + bias = 158 - // : # Arg stack is []. - // : 46 26 -84 71 hhcurveto - cubeTo(98, 661, 124, 577, 195, 577), - // : endchar - }, - - 'ī': { // U+012B LATIN SMALL LETTER I WITH MACRON - // 92 callgsubr # 92 + bias = 199. - // : # Arg stack is []. - // : -312 21 85 callgsubr # 85 + bias = 192. - // : : # Arg stack is [-312 21]. - // : : -21 486 -20 return - // : : # Arg stack is [-312 21 -21 486 -20]. - // : return - // : # Arg stack is [-312 21 -21 486 -20]. - // 135 57 112 callgsubr # 112 + bias = 219 - // : # Arg stack is [-312 21 -21 486 -20 135 57]. - // : hstem - // : 82 82 vstem - // : 134 callsubr # 134 + bias = 241 - // : : # Arg stack is []. - // : : 82 hmoveto - moveTo(82, 0), - // : : 82 127 callsubr # 127 + bias = 234 - // : : : # Arg stack is [82]. - // : : : 486 -82 hlineto - lineTo(164, 0), - lineTo(164, 486), - lineTo(82, 486), - // : : : return - // : : : # Arg stack is []. - // : : return - // : : # Arg stack is []. - // : return - // : # Arg stack is []. - // -92 115 -60 callgsubr # -60 + bias = 47 - // : # Arg stack is [-92 115]. - // : rmoveto - lineTo(82, 0), - moveTo(-10, 601), - // : 266 57 -266 hlineto - lineTo(256, 601), - lineTo(256, 658), - lineTo(-10, 658), - // : endchar - lineTo(-10, 601), - }, - - 'ĭ': { // U+012D LATIN SMALL LETTER I WITH BREVE - // 92 callgsubr # 92 + bias = 199. - // : # Arg stack is []. - // : -312 21 85 callgsubr # 85 + bias = 192. - // : : # Arg stack is [-312 21]. - // : : -21 486 -20 return - // : : # Arg stack is [-312 21 -21 486 -20]. - // : return - // : # Arg stack is [-312 21 -21 486 -20]. - // 105 55 96 -20 hstem - // -32 51 63 82 65 51 vstem - // 134 callsubr # 134 + bias = 241 - // : # Arg stack is []. - // : 82 hmoveto - moveTo(82, 0), - // : 82 127 callsubr # 127 + bias = 234 - // : : # Arg stack is [82]. - // : : 486 -82 hlineto - lineTo(164, 0), - lineTo(164, 486), - lineTo(82, 486), - // : : return - // : : # Arg stack is []. - // : return - // : # Arg stack is []. - // 42 85 143 callsubr # 143 + bias = 250 - // : # Arg stack is [42 85]. - // : rmoveto - lineTo(82, 0), - moveTo(124, 571), - // : -84 callsubr # -84 + bias = 23 - // : : # Arg stack is []. - // : : 107 44 77 74 5 hvcurveto - cubeTo(231, 571, 275, 648, 280, 722), - // : : -51 8 rlineto - lineTo(229, 730), - // : : -51 -8 -32 -53 -65 hhcurveto - cubeTo(221, 679, 189, 626, 124, 626), - // : : -65 -32 53 51 -8 hvcurveto - cubeTo(59, 626, 27, 679, 19, 730), - // : : -51 -22 callsubr # -22 + bias = 85 - // : : : # Arg stack is [-51]. - // : : : -8 rlineto - lineTo(-32, 722), - // : : : -74 5 44 -77 107 hhcurveto - cubeTo(-27, 648, 17, 571, 124, 571), - // : : : return - // : : : # Arg stack is []. - // : : return - // : : # Arg stack is []. - // : return - // : # Arg stack is []. - // endchar - }, - - 'Λ': { // U+039B GREEK CAPITAL LETTER LAMDA - // -43 21 -21 572 84 hstem - // 0 515 vstem - // 0 vmoveto - moveTo(0, 0), - // 85 hlineto - lineTo(85, 0), - // 105 355 23 77 16 63 24 77 rlinecurve - lineTo(190, 355), - cubeTo(213, 432, 229, 495, 253, 572), - // 4 hlineto - lineTo(257, 572), - // 25 -77 16 -63 23 -77 106 -355 rcurveline - cubeTo(282, 495, 298, 432, 321, 355), - lineTo(427, 0), - // 88 hlineto - lineTo(515, 0), - // -210 656 rlineto - lineTo(305, 656), - // -96 hlineto - lineTo(209, 656), - // endchar - lineTo(0, 0), - }, - - 'Ḫ': { // U+1E2A LATIN CAPITAL LETTER H WITH BREVE BELOW - // 94 -231 55 197 157 callgsubr # 157 + bias = 264 - // : # Arg stack is [94 -231 55 197]. - // : -21 309 72 return - // : # Arg stack is [94 -231 55 197 -21 309 72]. - // 275 254 callgsubr # 254 + bias = 361 - // : # Arg stack is [94 -231 55 197 -21 309 72 275]. - // : -20 hstemhm - // : 90 83 return - // : # Arg stack is [90 83]. - // -4 352 callsubr # 352 + bias = 459 - // : # Arg stack is [90 83 -4]. - // : 51 210 51 return - // : # Arg stack is [90 83 -4 51 210 51]. - // -3 84 hintmask 11111001 - // 90 -40 callsubr # -40 + bias = 67 - // : # Arg stack is [90]. - // : -27 callgsubr # -27 + bias = 80 - // : : # Arg stack is [90]. - // : : hmoveto - moveTo(90, 0), - // : : 83 309 305 -309 84 return - // : : # Arg stack is [83 309 305 -309 84]. - // : -41 callgsubr # -41 + bias = 66 - // : : # Arg stack is [83 309 305 -309 84]. - // : : 656 -84 -275 -305 275 -83 return - // : : # Arg stack is [83 309 305 -309 84 656 -84 -275 -305 275 -83]. - // : hlineto - lineTo(173, 0), - lineTo(173, 309), - lineTo(478, 309), - lineTo(478, 0), - lineTo(562, 0), - lineTo(562, 656), - lineTo(478, 656), - lineTo(478, 381), - lineTo(173, 381), - lineTo(173, 656), - lineTo(90, 656), - // : return - // : # Arg stack is []. - // hintmask 11110110 - // 235 -887 143 callsubr # 143 + bias = 250 - // : # Arg stack is [235 -887]. - // : rmoveto - lineTo(90, 0), - moveTo(325, -231), - // : -84 callsubr # -84 + bias = 23 - // : : # Arg stack is []. - // : : 107 44 77 74 5 hvcurveto - cubeTo(432, -231, 476, -154, 481, -80), - // : : -51 8 rlineto - lineTo(430, -72), - // : : -51 -8 -32 -53 -65 hhcurveto - cubeTo(422, -123, 390, -176, 325, -176), - // : : -65 -32 53 51 -8 hvcurveto - cubeTo(260, -176, 228, -123, 220, -72), - // : : -51 -22 callsubr # -22 + bias = 85 - // : : : # Arg stack is [-51]. - // : : : -8 rlineto - lineTo(169, -80), - // : : : -74 5 44 -77 107 hhcurveto - cubeTo(174, -154, 218, -231, 325, -231), - // : : : return - // : : : # Arg stack is []. - // : : return - // : : # Arg stack is []. - // : return - // : # Arg stack is []. - // endchar - }, - }, - - "apple/Helvetica.dfont?0": { - 'i': { - // - contour #0 - moveTo(132, 1066), - lineTo(315, 1066), - lineTo(315, 0), - lineTo(132, 0), - lineTo(132, 1066), - // - contour #1 - moveTo(132, 1469), - lineTo(315, 1469), - lineTo(315, 1265), - lineTo(132, 1265), - lineTo(132, 1469), - }, - }, - - "apple/Helvetica.dfont?1": { - 'i': { - // - contour #0 - moveTo(426, 1220), - lineTo(137, 1220), - lineTo(137, 1483), - lineTo(426, 1483), - lineTo(426, 1220), - // - contour #1 - moveTo(137, 1090), - lineTo(426, 1090), - lineTo(426, 0), - lineTo(137, 0), - lineTo(137, 1090), - }, - }, - - "dejavu/DejaVuSans-ExtraLight.ttf": { - 'i': { - // - contour #0 - moveTo(230, 1120), - lineTo(322, 1120), - lineTo(322, 0), - lineTo(230, 0), - lineTo(230, 1120), - // - contour #1 - moveTo(230, 1556), - lineTo(322, 1556), - lineTo(322, 1430), - lineTo(230, 1430), - lineTo(230, 1556), - }, - }, - - "microsoft/Arial.ttf": { - ',': { - // - contour #0 - moveTo(182, 0), - lineTo(182, 205), - lineTo(387, 205), - lineTo(387, 0), - quadTo(387, -113, 347, -182), - quadTo(307, -252, 220, -290), - lineTo(170, -213), - quadTo(227, -188, 254, -139), - quadTo(281, -91, 284, 0), - lineTo(182, 0), - }, - - 'i': { - // - contour #0 - moveTo(136, 1259), - lineTo(136, 1466), - lineTo(316, 1466), - lineTo(316, 1259), - lineTo(136, 1259), - // - contour #1 - moveTo(136, 0), - lineTo(136, 1062), - lineTo(316, 1062), - lineTo(316, 0), - lineTo(136, 0), - }, - - 'o': { - // - contour #0 - moveTo(68, 531), - quadTo(68, 826, 232, 968), - quadTo(369, 1086, 566, 1086), - quadTo(785, 1086, 924, 942), - quadTo(1063, 799, 1063, 546), - quadTo(1063, 341, 1001, 223), - quadTo(940, 106, 822, 41), - quadTo(705, -24, 566, -24), - quadTo(343, -24, 205, 119), - quadTo(68, 262, 68, 531), - // - contour #1 - moveTo(253, 531), - quadTo(253, 327, 342, 225), - quadTo(431, 124, 566, 124), - quadTo(700, 124, 789, 226), - quadTo(878, 328, 878, 537), - quadTo(878, 734, 788, 835), - quadTo(699, 937, 566, 937), - quadTo(431, 937, 342, 836), - quadTo(253, 735, 253, 531), - }, - - 'í': { // U+00ED LATIN SMALL LETTER I WITH ACUTE - // - contour #0 - translate(0, 0, moveTo(198, 0)), - translate(0, 0, lineTo(198, 1062)), - translate(0, 0, lineTo(378, 1062)), - translate(0, 0, lineTo(378, 0)), - translate(0, 0, lineTo(198, 0)), - // - contour #1 - translate(-33, 0, moveTo(222, 1194)), - translate(-33, 0, lineTo(355, 1474)), - translate(-33, 0, lineTo(591, 1474)), - translate(-33, 0, lineTo(371, 1194)), - translate(-33, 0, lineTo(222, 1194)), - }, - - 'Ī': { // U+012A LATIN CAPITAL LETTER I WITH MACRON - // - contour #0 - translate(0, 0, moveTo(191, 0)), - translate(0, 0, lineTo(191, 1466)), - translate(0, 0, lineTo(385, 1466)), - translate(0, 0, lineTo(385, 0)), - translate(0, 0, lineTo(191, 0)), - // - contour #1 - translate(-57, 336, moveTo(29, 1227)), - translate(-57, 336, lineTo(29, 1375)), - translate(-57, 336, lineTo(653, 1375)), - translate(-57, 336, lineTo(653, 1227)), - translate(-57, 336, lineTo(29, 1227)), - }, - - // Ǻ is a compound glyph whose elements are also compound glyphs. - 'Ǻ': { // U+01FA LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE - // - contour #0 - translate(0, 0, moveTo(-3, 0)), - translate(0, 0, lineTo(560, 1466)), - translate(0, 0, lineTo(769, 1466)), - translate(0, 0, lineTo(1369, 0)), - translate(0, 0, lineTo(1148, 0)), - translate(0, 0, lineTo(977, 444)), - translate(0, 0, lineTo(364, 444)), - translate(0, 0, lineTo(203, 0)), - translate(0, 0, lineTo(-3, 0)), - // - contour #1 - translate(0, 0, moveTo(420, 602)), - translate(0, 0, lineTo(917, 602)), - translate(0, 0, lineTo(764, 1008)), - translate(0, 0, quadTo(694, 1193, 660, 1312)), - translate(0, 0, quadTo(632, 1171, 581, 1032)), - translate(0, 0, lineTo(420, 602)), - // - contour #2 - translate(319, 263, moveTo(162, 1338)), - translate(319, 263, quadTo(162, 1411, 215, 1464)), - translate(319, 263, quadTo(269, 1517, 342, 1517)), - translate(319, 263, quadTo(416, 1517, 469, 1463)), - translate(319, 263, quadTo(522, 1410, 522, 1334)), - translate(319, 263, quadTo(522, 1257, 469, 1204)), - translate(319, 263, quadTo(416, 1151, 343, 1151)), - translate(319, 263, quadTo(268, 1151, 215, 1204)), - translate(319, 263, quadTo(162, 1258, 162, 1338)), - // - contour #3 - translate(319, 263, moveTo(238, 1337)), - translate(319, 263, quadTo(238, 1290, 269, 1258)), - translate(319, 263, quadTo(301, 1226, 344, 1226)), - translate(319, 263, quadTo(387, 1226, 418, 1258)), - translate(319, 263, quadTo(450, 1290, 450, 1335)), - translate(319, 263, quadTo(450, 1380, 419, 1412)), - translate(319, 263, quadTo(388, 1444, 344, 1444)), - translate(319, 263, quadTo(301, 1444, 269, 1412)), - translate(319, 263, quadTo(238, 1381, 238, 1337)), - // - contour #4 - translate(339, 650, moveTo(222, 1194)), - translate(339, 650, lineTo(355, 1474)), - translate(339, 650, lineTo(591, 1474)), - translate(339, 650, lineTo(371, 1194)), - translate(339, 650, lineTo(222, 1194)), - }, - - '﴾': { // U+FD3E ORNATE LEFT PARENTHESIS. - // - contour #0 - moveTo(560, -384), - lineTo(516, -429), - quadTo(412, -304, 361, -226), - quadTo(258, -68, 201, 106), - quadTo(127, 334, 127, 595), - quadTo(127, 845, 201, 1069), - quadTo(259, 1246, 361, 1404), - quadTo(414, 1487, 514, 1608), - lineTo(560, 1566), - quadTo(452, 1328, 396, 1094), - quadTo(336, 845, 336, 603), - quadTo(336, 359, 370, 165), - quadTo(398, 8, 454, -142), - quadTo(482, -217, 560, -384), - }, - - '﴿': { // U+FD3F ORNATE RIGHT PARENTHESIS - // - contour #0 - transform(-1<<14, 0, 0, +1<<14, 653, 0, moveTo(560, -384)), - transform(-1<<14, 0, 0, +1<<14, 653, 0, lineTo(516, -429)), - transform(-1<<14, 0, 0, +1<<14, 653, 0, quadTo(412, -304, 361, -226)), - transform(-1<<14, 0, 0, +1<<14, 653, 0, quadTo(258, -68, 201, 106)), - transform(-1<<14, 0, 0, +1<<14, 653, 0, quadTo(127, 334, 127, 595)), - transform(-1<<14, 0, 0, +1<<14, 653, 0, quadTo(127, 845, 201, 1069)), - transform(-1<<14, 0, 0, +1<<14, 653, 0, quadTo(259, 1246, 361, 1404)), - transform(-1<<14, 0, 0, +1<<14, 653, 0, quadTo(414, 1487, 514, 1608)), - transform(-1<<14, 0, 0, +1<<14, 653, 0, lineTo(560, 1566)), - transform(-1<<14, 0, 0, +1<<14, 653, 0, quadTo(452, 1328, 396, 1094)), - transform(-1<<14, 0, 0, +1<<14, 653, 0, quadTo(336, 845, 336, 603)), - transform(-1<<14, 0, 0, +1<<14, 653, 0, quadTo(336, 359, 370, 165)), - transform(-1<<14, 0, 0, +1<<14, 653, 0, quadTo(398, 8, 454, -142)), - transform(-1<<14, 0, 0, +1<<14, 653, 0, quadTo(482, -217, 560, -384)), - }, - }, - - "noto/NotoSans-Regular.ttf": { - 'i': { - // - contour #0 - moveTo(354, 0), - lineTo(174, 0), - lineTo(174, 1098), - lineTo(354, 1098), - lineTo(354, 0), - // - contour #1 - moveTo(160, 1395), - quadTo(160, 1455, 190, 1482), - quadTo(221, 1509, 266, 1509), - quadTo(308, 1509, 339, 1482), - quadTo(371, 1455, 371, 1395), - quadTo(371, 1336, 339, 1308), - quadTo(308, 1280, 266, 1280), - quadTo(221, 1280, 190, 1308), - quadTo(160, 1336, 160, 1395), - }, - }, -} - -type kernTestCase struct { - ppem fixed.Int26_6 - hinting font.Hinting - runes [2]rune - want Units -} - -// proprietaryKernTestCases hold a sample of each font's kerning pairs. The -// numerical values can be verified by running the ttx tool. -var proprietaryKernTestCases = map[string][]kernTestCase{ - "dejavu/DejaVuSans-ExtraLight.ttf": { - {2048, font.HintingNone, [2]rune{'A', 'A'}, 57}, - {2048, font.HintingNone, [2]rune{'W', 'A'}, -112}, - // U+00C1 LATIN CAPITAL LETTER A WITH ACUTE - // U+01FA LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE - // U+1E82 LATIN CAPITAL LETTER W WITH ACUTE - {2048, font.HintingNone, [2]rune{'\u00c1', 'A'}, 57}, - // TODO: enable these next two test cases, when we support multiple - // kern subtables. - // {2048, font.HintingNone, [2]rune{'\u01fa', 'A'}, 57}, - // {2048, font.HintingNone, [2]rune{'\u1e82', 'A'}, -112}, - }, - "microsoft/Arial.ttf": { - {2048, font.HintingNone, [2]rune{'A', 'V'}, -152}, - // U+03B8 GREEK SMALL LETTER THETA - // U+03BB GREEK SMALL LETTER LAMDA - {2048, font.HintingNone, [2]rune{'\u03b8', '\u03bb'}, -39}, - {2048, font.HintingNone, [2]rune{'\u03bb', '\u03b8'}, -0}, - }, - "microsoft/Comic_Sans_MS.ttf": { - {2048, font.HintingNone, [2]rune{'A', 'V'}, 0}, - }, - "microsoft/Times_New_Roman.ttf": { - {768, font.HintingNone, [2]rune{'A', 'V'}, -99}, - {768, font.HintingFull, [2]rune{'A', 'V'}, -128}, - {2048, font.HintingNone, [2]rune{'A', 'A'}, 0}, - {2048, font.HintingNone, [2]rune{'A', 'T'}, -227}, - {2048, font.HintingNone, [2]rune{'A', 'V'}, -264}, - {2048, font.HintingNone, [2]rune{'T', 'A'}, -164}, - {2048, font.HintingNone, [2]rune{'T', 'T'}, 0}, - {2048, font.HintingNone, [2]rune{'T', 'V'}, 0}, - {2048, font.HintingNone, [2]rune{'V', 'A'}, -264}, - {2048, font.HintingNone, [2]rune{'V', 'T'}, 0}, - {2048, font.HintingNone, [2]rune{'V', 'V'}, 0}, - // U+0390 GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS - // U+0393 GREEK CAPITAL LETTER GAMMA - {2048, font.HintingNone, [2]rune{'\u0390', '\u0393'}, 0}, - {2048, font.HintingNone, [2]rune{'\u0393', '\u0390'}, 76}, - }, - "microsoft/Webdings.ttf": { - {2048, font.HintingNone, [2]rune{'\uf041', '\uf042'}, 0}, - }, -} - -// proprietaryFDSelectTestCases hold a sample of each font's Font Dict Select -// (FDSelect) map. The numerical values can be verified by grepping the output -// of the ttx tool: -// -// grep CharString.*fdSelectIndex SourceHanSansSC-Regular.ttx -// -// will print lines like this: -// -// -// -// -// -// -// As for what the values like 3 or 15 actually mean, grepping that ttx file -// for "FontName" gives this list: -// -// 0: -// 1: -// 2: -// 3: -// 4: -// 5: -// 6: -// 7: -// 8: -// 9: -// 10: -// 11: -// 12: -// 13: -// 14: -// 15: -// 16: -// 17: -// 18: -// -// As a sanity check, the cmap table maps U+3127 BOPOMOFO LETTER I to the glyph -// named "cid65353", proprietaryFDSelectTestCases here maps 65353 to Font Dict -// 2, and the list immediately above maps 2 to "Bopomofo". -var proprietaryFDSelectTestCases = map[string]map[GlyphIndex]int{ - "adobe/SourceHanSansSC-Regular.otf": { - 0: 5, - 1: 15, - 2: 15, - 16: 15, - 17: 17, - 26: 17, - 27: 15, - 100: 15, - 101: 15, - 102: 3, - 103: 15, - 777: 4, - 1000: 3, - 2000: 3, - 3000: 13, - 4000: 13, - 20000: 13, - 48000: 12, - 59007: 1, - 59024: 0, - 59087: 8, - 59200: 7, - 59211: 6, - 60000: 13, - 63000: 16, - 63039: 9, - 63060: 11, - 63137: 10, - 65353: 2, - 65486: 14, - 65505: 18, - 65506: 5, - 65533: 5, - 65534: 5, - }, -} diff --git a/vendor/golang.org/x/image/font/sfnt/sfnt.go b/vendor/golang.org/x/image/font/sfnt/sfnt.go deleted file mode 100644 index cc4ceac6f..000000000 --- a/vendor/golang.org/x/image/font/sfnt/sfnt.go +++ /dev/null @@ -1,1538 +0,0 @@ -// Copyright 2016 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. - -//go:generate go run gen.go - -// Package sfnt implements a decoder for SFNT font file formats, including -// TrueType and OpenType. -package sfnt // import "golang.org/x/image/font/sfnt" - -// This implementation was written primarily to the -// https://www.microsoft.com/en-us/Typography/OpenTypeSpecification.aspx -// specification. Additional documentation is at -// http://developer.apple.com/fonts/TTRefMan/ -// -// The pyftinspect tool from https://github.com/fonttools/fonttools is useful -// for inspecting SFNT fonts. -// -// The ttfdump tool is also useful. For example: -// ttfdump -t cmap ../testdata/CFFTest.otf dump.txt - -import ( - "errors" - "io" - - "golang.org/x/image/font" - "golang.org/x/image/math/fixed" - "golang.org/x/text/encoding/charmap" -) - -// These constants are not part of the specifications, but are limitations used -// by this implementation. -const ( - // This value is arbitrary, but defends against parsing malicious font - // files causing excessive memory allocations. For reference, Adobe's - // SourceHanSansSC-Regular.otf has 65535 glyphs and: - // - its format-4 cmap table has 1581 segments. - // - its format-12 cmap table has 16498 segments. - // - // TODO: eliminate this constraint? If the cmap table is very large, load - // some or all of it lazily (at the time Font.GlyphIndex is called) instead - // of all of it eagerly (at the time Font.initialize is called), while - // keeping an upper bound on the memory used? This will make the code in - // cmap.go more complicated, considering that all of the Font methods are - // safe to call concurrently, as long as each call has a different *Buffer. - maxCmapSegments = 20000 - - // 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 - maxNumFontDicts = 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 - maxTableOffset = 1 << 29 -) - -var ( - // ErrColoredGlyph indicates that the requested glyph is not a monochrome - // vector glyph, such as a colored (bitmap or vector) emoji glyph. - ErrColoredGlyph = errors.New("sfnt: colored glyph") - // 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") - 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") - 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") - - 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") - errUnsupportedGlyphDataLength = errors.New("sfnt: unsupported glyph data length") - 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") - errUnsupportedNumberOfTables = errors.New("sfnt: unsupported number of tables") - errUnsupportedPlatformEncoding = errors.New("sfnt: unsupported platform encoding") - errUnsupportedPostTable = errors.New("sfnt: unsupported post table") - errUnsupportedTableOffsetLength = errors.New("sfnt: unsupported table offset or length") - errUnsupportedType2Charstring = errors.New("sfnt: unsupported Type 2 Charstring") -) - -// GlyphIndex is a glyph index in a Font. -type GlyphIndex uint16 - -// NameID identifies a name table entry. -// -// See the "Name IDs" section of -// https://www.microsoft.com/typography/otspec/name.htm -type NameID uint16 - -const ( - NameIDCopyright NameID = 0 - NameIDFamily = 1 - NameIDSubfamily = 2 - NameIDUniqueIdentifier = 3 - NameIDFull = 4 - NameIDVersion = 5 - NameIDPostScript = 6 - NameIDTrademark = 7 - NameIDManufacturer = 8 - NameIDDesigner = 9 - NameIDDescription = 10 - NameIDVendorURL = 11 - NameIDDesignerURL = 12 - NameIDLicense = 13 - NameIDLicenseURL = 14 - NameIDTypographicFamily = 16 - NameIDTypographicSubfamily = 17 - NameIDCompatibleFull = 18 - NameIDSampleText = 19 - NameIDPostScriptCID = 20 - NameIDWWSFamily = 21 - NameIDWWSSubfamily = 22 - NameIDLightBackgroundPalette = 23 - NameIDDarkBackgroundPalette = 24 - NameIDVariationsPostScriptPrefix = 25 -) - -// Units are an integral number of abstract, scalable "font units". The em -// square is typically 1000 or 2048 "font units". This would map to a certain -// number (e.g. 30 pixels) of physical pixels, depending on things like the -// display resolution (DPI) and font size (e.g. a 12 point font). -type Units int32 - -// scale returns x divided by unitsPerEm, rounded to the nearest fixed.Int26_6 -// value (1/64th of a pixel). -func scale(x fixed.Int26_6, unitsPerEm Units) fixed.Int26_6 { - if x >= 0 { - x += fixed.Int26_6(unitsPerEm) / 2 - } else { - x -= fixed.Int26_6(unitsPerEm) / 2 - } - return x / fixed.Int26_6(unitsPerEm) -} - -func u16(b []byte) uint16 { - _ = b[1] // Bounds check hint to compiler. - return uint16(b[0])<<8 | uint16(b[1])<<0 -} - -func u32(b []byte) uint32 { - _ = b[3] // Bounds check hint to compiler. - return uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])<<0 -} - -// source is a source of byte data. Conceptually, it is like an io.ReaderAt, -// except that a common source of SFNT font data is in-memory instead of -// on-disk: a []byte containing the entire data, either as a global variable -// (e.g. "goregular.TTF") or the result of an ioutil.ReadFile call. In such -// cases, as an optimization, we skip the io.Reader / io.ReaderAt model of -// copying from the source to a caller-supplied buffer, and instead provide -// direct access to the underlying []byte data. -type source struct { - b []byte - r io.ReaderAt - - // TODO: add a caching layer, if we're using the io.ReaderAt? Note that - // this might make a source no longer safe to use concurrently. -} - -// valid returns whether exactly one of s.b and s.r is nil. -func (s *source) valid() bool { - return (s.b == nil) != (s.r == nil) -} - -// viewBufferWritable returns whether the []byte returned by source.view can be -// written to by the caller, including by passing it to the same method -// (source.view) on other receivers (i.e. different sources). -// -// In other words, it returns whether the source's underlying data is an -// io.ReaderAt, not a []byte. -func (s *source) viewBufferWritable() bool { - return s.b == nil -} - -// view returns the length bytes at the given offset. buf is an optional -// scratch buffer to reduce allocations when calling view multiple times. A nil -// buf is valid. The []byte returned may be a sub-slice of buf[:cap(buf)], or -// it may be an unrelated slice. In any case, the caller should not modify the -// contents of the returned []byte, other than passing that []byte back to this -// method on the same source s. -func (s *source) view(buf []byte, offset, length int) ([]byte, error) { - if 0 > offset || offset > offset+length { - return nil, errInvalidBounds - } - - // Try reading from the []byte. - if s.b != nil { - if offset+length > len(s.b) { - return nil, errInvalidBounds - } - return s.b[offset : offset+length], nil - } - - // Read from the io.ReaderAt. - if length <= cap(buf) { - buf = buf[:length] - } else { - // Round length up to the nearest KiB. The slack can lead to fewer - // allocations if the buffer is re-used for multiple source.view calls. - n := length - n += 1023 - n &^= 1023 - buf = make([]byte, length, n) - } - if n, err := s.r.ReadAt(buf, int64(offset)); n != length { - return nil, err - } - return buf, nil -} - -// u16 returns the uint16 in the table t at the relative offset i. -// -// buf is an optional scratch buffer as per the source.view method. -func (s *source) u16(buf []byte, t table, i int) (uint16, error) { - if i < 0 || uint(t.length) < uint(i+2) { - return 0, errInvalidBounds - } - buf, err := s.view(buf, int(t.offset)+i, 2) - if err != nil { - return 0, err - } - return u16(buf), nil -} - -// u32 returns the uint32 in the table t at the relative offset i. -// -// buf is an optional scratch buffer as per the source.view method. -func (s *source) u32(buf []byte, t table, i int) (uint32, error) { - if i < 0 || uint(t.length) < uint(i+4) { - return 0, errInvalidBounds - } - buf, err := s.view(buf, int(t.offset)+i, 4) - if err != nil { - return 0, err - } - return u32(buf), nil -} - -// table is a section of the font data. -type table struct { - offset, length uint32 -} - -// 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 - isDfont bool -} - -// 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. - // - // 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 - } - // These cases match the switch statement in Font.initializeTables. - 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} - 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 -} - -// 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]), c.isDfont); 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(0, false); err != nil { - return nil, err - } - return f, nil -} - -// 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(0, false); err != nil { - return nil, err - } - return f, nil -} - -// Font is an SFNT font. -// -// Many of its methods take a *Buffer argument, as re-using buffers can reduce -// the total memory allocation of repeated Font method calls, such as measuring -// and rasterizing every unique glyph in a string of text. If efficiency is not -// a concern, passing a nil *Buffer is valid, and implies using a temporary -// buffer for a single call. -// -// It is valid to re-use a *Buffer with multiple Font method calls, even with -// different *Font receivers, as long as they are not concurrent calls. -// -// All of the Font methods are safe to call concurrently, as long as each call -// has a different *Buffer (or nil). -// -// The Font methods that don't take a *Buffer argument are always safe to call -// concurrently. -// -// Some methods provide lengths or coordinates, e.g. bounds, font metrics and -// control points. All of these methods take a ppem parameter, which is the -// number of pixels in 1 em, expressed as a 26.6 fixed point value. For -// example, if 1 em is 10 pixels then ppem is fixed.I(10), which equals -// fixed.Int26_6(10 << 6). -// -// To get those lengths or coordinates in terms of font units instead of -// pixels, use ppem = fixed.Int26_6(f.UnitsPerEm()) and if those methods take a -// font.Hinting parameter, use font.HintingNone. The return values will have -// type fixed.Int26_6, but those numbers can be converted back to Units with no -// further scaling necessary. -type Font struct { - src source - - // https://www.microsoft.com/typography/otspec/otff.htm#otttables - // "Required Tables". - cmap table - head table - hhea table - hmtx table - maxp table - name table - os2 table - post table - - // https://www.microsoft.com/typography/otspec/otff.htm#otttables - // "Tables Related to TrueType Outlines". - // - // This implementation does not support hinting, so it does not read the - // cvt, fpgm gasp or prep tables. - glyf table - loca table - - // https://www.microsoft.com/typography/otspec/otff.htm#otttables - // "Tables Related to PostScript Outlines". - // - // TODO: cff2, vorg? - cff table - - // https://www.microsoft.com/typography/otspec/otff.htm#otttables - // "Tables Related to Bitmap Glyphs". - // - // TODO: Others? - cblc table - - // https://www.microsoft.com/typography/otspec/otff.htm#otttables - // "Advanced Typographic Tables". - // - // TODO: base, gdef, gpos, gsub, jstf, math? - - // https://www.microsoft.com/typography/otspec/otff.htm#otttables - // "Other OpenType Tables". - // - // TODO: hdmx, vmtx? Others? - kern table - - cached struct { - ascent int32 - glyphData glyphData - glyphIndex glyphIndexFunc - bounds [4]int16 - descent int32 - indexToLocFormat bool // false means short, true means long. - isColorBitmap bool - isPostScript bool - kernNumPairs int32 - kernOffset int32 - lineGap int32 - numHMetrics int32 - postTableVersion uint32 - unitsPerEm Units - } -} - -// NumGlyphs returns the number of glyphs in f. -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, isDfont bool) error { - if !f.src.valid() { - return errInvalidSourceData - } - buf, isPostScript, err := f.initializeTables(offset, isDfont) - if err != nil { - return err - } - - // The order of these parseXxx calls matters. Later calls may depend on - // information parsed by earlier calls, such as the maxp table's numGlyphs. - // To enforce these dependencies, such information is passed and returned - // explicitly, and the f.cached fields are only set afterwards. - // - // When implementing new parseXxx methods, take care not to call methods - // such as Font.NumGlyphs that implicitly depend on f.cached fields. - - buf, bounds, indexToLocFormat, unitsPerEm, err := f.parseHead(buf) - if err != nil { - return err - } - buf, numGlyphs, err := f.parseMaxp(buf, isPostScript) - if err != nil { - return err - } - buf, glyphData, isColorBitmap, err := f.parseGlyphData(buf, numGlyphs, indexToLocFormat, isPostScript) - if err != nil { - return err - } - buf, glyphIndex, err := f.parseCmap(buf) - if err != nil { - return err - } - buf, kernNumPairs, kernOffset, err := f.parseKern(buf) - if err != nil { - return err - } - buf, ascent, descent, lineGap, 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.ascent = ascent - f.cached.glyphData = glyphData - f.cached.glyphIndex = glyphIndex - f.cached.bounds = bounds - f.cached.descent = descent - f.cached.indexToLocFormat = indexToLocFormat - f.cached.isColorBitmap = isColorBitmap - f.cached.isPostScript = isPostScript - f.cached.kernNumPairs = kernNumPairs - f.cached.kernOffset = kernOffset - f.cached.lineGap = lineGap - f.cached.numHMetrics = numHMetrics - f.cached.postTableVersion = postTableVersion - f.cached.unitsPerEm = unitsPerEm - - return nil -} - -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. - 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, errInvalidFont - case dfontResourceDataOffset: - return nil, false, errInvalidSingleFont - case 0x00010000: - // No-op. - case 0x4f54544f: // "OTTO". - isPostScript = true - case 0x74746366: // "ttcf". - return nil, false, errInvalidSingleFont - } - numTables := int(u16(buf[4:])) - if numTables > maxNumTables { - return nil, false, errUnsupportedNumberOfTables - } - - // "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, offset+12, 16*numTables) - if err != nil { - return nil, false, err - } - for b, first, prevTag := buf, true, uint32(0); len(b) > 0; b = b[16:] { - tag := u32(b) - if first { - first = false - } else if tag <= prevTag { - return nil, false, errInvalidTableTagOrder - } - 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 - } - // We ignore the checksums, but "all tables must begin on four byte - // boundries [sic]". - if o&3 != 0 { - return nil, false, errInvalidTableOffset - } - - // Match the 4-byte tag as a uint32. For example, "OS/2" is 0x4f532f32. - switch tag { - case 0x43424c43: - f.cblc = table{o, n} - case 0x43464620: - f.cff = table{o, n} - case 0x4f532f32: - f.os2 = table{o, n} - case 0x636d6170: - f.cmap = table{o, n} - case 0x676c7966: - f.glyf = table{o, n} - case 0x68656164: - f.head = table{o, n} - case 0x68686561: - f.hhea = table{o, n} - case 0x686d7478: - f.hmtx = table{o, n} - case 0x6b65726e: - f.kern = table{o, n} - case 0x6c6f6361: - f.loca = table{o, n} - case 0x6d617870: - f.maxp = table{o, n} - case 0x6e616d65: - f.name = table{o, n} - case 0x706f7374: - f.post = table{o, n} - } - } - return buf, isPostScript, nil -} - -func (f *Font) parseCmap(buf []byte) (buf1 []byte, glyphIndex glyphIndexFunc, err error) { - // https://www.microsoft.com/typography/OTSPEC/cmap.htm - - const headerSize, entrySize = 4, 8 - if f.cmap.length < headerSize { - return nil, nil, errInvalidCmapTable - } - u, err := f.src.u16(buf, f.cmap, 2) - if err != nil { - return nil, nil, err - } - numSubtables := int(u) - if f.cmap.length < headerSize+entrySize*uint32(numSubtables) { - return nil, nil, errInvalidCmapTable - } - - var ( - bestWidth int - bestOffset uint32 - bestLength uint32 - bestFormat uint16 - ) - - // Scan all of the subtables, picking the widest supported one. See the - // platformEncodingWidth comment for more discussion of width. - for i := 0; i < numSubtables; i++ { - buf, err = f.src.view(buf, int(f.cmap.offset)+headerSize+entrySize*i, entrySize) - if err != nil { - return nil, nil, err - } - pid := u16(buf) - psid := u16(buf[2:]) - width := platformEncodingWidth(pid, psid) - if width <= bestWidth { - continue - } - offset := u32(buf[4:]) - - if offset > f.cmap.length-4 { - return nil, nil, errInvalidCmapTable - } - buf, err = f.src.view(buf, int(f.cmap.offset+offset), 4) - if err != nil { - return nil, nil, err - } - format := u16(buf) - if !supportedCmapFormat(format, pid, psid) { - continue - } - length := uint32(u16(buf[2:])) - - bestWidth = width - bestOffset = offset - bestLength = length - bestFormat = format - } - - if bestWidth == 0 { - return nil, nil, errUnsupportedCmapEncodings - } - return f.makeCachedGlyphIndex(buf, bestOffset, bestLength, bestFormat) -} - -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, [4]int16{}, false, 0, errInvalidHeadTable - } - - u, err := f.src.u16(buf, f.head, 18) - if err != nil { - return nil, [4]int16{}, false, 0, err - } - if u == 0 { - 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, [4]int16{}, false, 0, err - } - indexToLocFormat = u != 0 - return buf, bounds, indexToLocFormat, unitsPerEm, nil -} - -func (f *Font) parseHhea(buf []byte, numGlyphs int32) (buf1 []byte, ascent, descent, lineGap, numHMetrics int32, err error) { - // https://www.microsoft.com/typography/OTSPEC/hhea.htm - - if f.hhea.length != 36 { - return nil, 0, 0, 0, 0, errInvalidHheaTable - } - u, err := f.src.u16(buf, f.hhea, 34) - if err != nil { - return nil, 0, 0, 0, 0, err - } - if int32(u) > numGlyphs || u == 0 { - return nil, 0, 0, 0, 0, errInvalidHheaTable - } - a, err := f.src.u16(buf, f.hhea, 4) - if err != nil { - return nil, 0, 0, 0, 0, err - } - d, err := f.src.u16(buf, f.hhea, 6) - if err != nil { - return nil, 0, 0, 0, 0, err - } - l, err := f.src.u16(buf, f.hhea, 8) - if err != nil { - return nil, 0, 0, 0, 0, err - } - return buf, int32(int16(a)), int32(int16(d)), int32(int16(l)), 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) { - // https://www.microsoft.com/typography/otspec/kern.htm - - if f.kern.length == 0 { - return buf, 0, 0, nil - } - const headerSize = 4 - if f.kern.length < headerSize { - return nil, 0, 0, errInvalidKernTable - } - buf, err = f.src.view(buf, int(f.kern.offset), headerSize) - if err != nil { - return nil, 0, 0, err - } - offset := int(f.kern.offset) + headerSize - length := int(f.kern.length) - headerSize - - switch version := u16(buf); version { - case 0: - if numTables := int(u16(buf[2:])); numTables == 0 { - return buf, 0, 0, nil - } else if numTables > 1 { - // TODO: support multiple subtables. For now, fall through and use - // only the first one. - } - return f.parseKernVersion0(buf, offset, length) - case 1: - 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 - // but it doesn't seem worth the effort. - return buf, 0, 0, nil - } - return nil, 0, 0, errUnsupportedKernTable -} - -func (f *Font) parseKernVersion0(buf []byte, offset, length int) (buf1 []byte, kernNumPairs, kernOffset int32, err error) { - const headerSize = 6 - if length < headerSize { - return nil, 0, 0, errInvalidKernTable - } - buf, err = f.src.view(buf, offset, headerSize) - if err != nil { - return nil, 0, 0, err - } - if version := u16(buf); version != 0 { - return nil, 0, 0, errUnsupportedKernTable - } - subtableLength := int(u16(buf[2:])) - if subtableLength < headerSize || length < subtableLength { - return nil, 0, 0, errInvalidKernTable - } - if coverageBits := buf[5]; coverageBits != 0x01 { - // We only support horizontal kerning. - return nil, 0, 0, errUnsupportedKernTable - } - offset += headerSize - length -= headerSize - subtableLength -= headerSize - - switch format := buf[4]; format { - case 0: - return f.parseKernFormat0(buf, offset, subtableLength) - case 2: - // 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 -} - -func (f *Font) parseKernFormat0(buf []byte, offset, length int) (buf1 []byte, kernNumPairs, kernOffset int32, err error) { - const headerSize, entrySize = 8, 6 - if length < headerSize { - return nil, 0, 0, errInvalidKernTable - } - buf, err = f.src.view(buf, offset, headerSize) - if err != nil { - return nil, 0, 0, err - } - kernNumPairs = int32(u16(buf)) - if length != headerSize+entrySize*int(kernNumPairs) { - return nil, 0, 0, errInvalidKernTable - } - return buf, kernNumPairs, int32(offset) + headerSize, nil -} - -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, errInvalidMaxpTable - } - } else { - if f.maxp.length != 32 { - return nil, 0, errInvalidMaxpTable - } - } - u, err := f.src.u16(buf, f.maxp, 4) - if err != nil { - return nil, 0, err - } - 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, isColorBitmap bool, err error) { - if isPostScript { - p := cffParser{ - src: &f.src, - base: int(f.cff.offset), - offset: int(f.cff.offset), - end: int(f.cff.offset + f.cff.length), - } - ret, err = p.parse(numGlyphs) - if err != nil { - return nil, glyphData{}, false, err - } - } else if f.loca.length != 0 { - ret.locations, err = parseLoca(&f.src, f.loca, f.glyf.offset, indexToLocFormat, numGlyphs) - if err != nil { - return nil, glyphData{}, false, err - } - } else if f.cblc.length != 0 { - isColorBitmap = true - // TODO: parse the CBLC (and CBDT) tables. For now, we return a font - // with empty glyphs. - ret.locations = make([]uint32, numGlyphs+1) - } - - if len(ret.locations) != int(numGlyphs+1) { - return nil, glyphData{}, false, errInvalidLocationData - } - - return buf, ret, isColorBitmap, nil -} - -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 - if f.post.length < headerSize { - return nil, 0, errInvalidPostTable - } - u, err := f.src.u32(buf, f.post, 0) - if err != nil { - return nil, 0, err - } - switch u { - case 0x20000: - if f.post.length < headerSize+2+2*uint32(numGlyphs) { - return nil, 0, errInvalidPostTable - } - case 0x30000: - // No-op. - default: - return nil, 0, errUnsupportedPostTable - } - 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. - -type glyphIndexFunc func(f *Font, b *Buffer, r rune) (GlyphIndex, error) - -// GlyphIndex returns the glyph index for the given rune. -// -// It returns (0, nil) if there is no glyph for r. -// https://www.microsoft.com/typography/OTSPEC/cmap.htm says that "Character -// codes that do not correspond to any glyph in the font should be mapped to -// glyph index 0. The glyph at this location must be a special glyph -// representing a missing character, commonly known as .notdef." -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) (buf []byte, offset, length uint32, err error) { - xx := int(x) - if f.NumGlyphs() <= xx { - return nil, 0, 0, ErrNotFound - } - i := f.cached.glyphData.locations[xx+0] - j := f.cached.glyphData.locations[xx+1] - if j < i { - return nil, 0, 0, errInvalidGlyphDataLength - } - if j-i > maxGlyphDataLength { - return nil, 0, 0, errUnsupportedGlyphDataLength - } - 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. -type LoadGlyphOptions struct { - // TODO: transform / hinting. -} - -// LoadGlyph returns the vector segments for the x'th glyph. ppem is the number -// of pixels in 1 em. -// -// 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. It returns -// ErrColoredGlyph if the glyph is not a monochrome vector glyph, such as a -// colored (bitmap or vector) emoji glyph. -func (f *Font) LoadGlyph(b *Buffer, x GlyphIndex, ppem fixed.Int26_6, opts *LoadGlyphOptions) ([]Segment, error) { - if b == nil { - b = &Buffer{} - } - - b.segments = b.segments[:0] - if f.cached.isColorBitmap { - return nil, ErrColoredGlyph - } - if f.cached.isPostScript { - buf, offset, length, err := f.viewGlyphData(b, x) - if err != nil { - return nil, err - } - b.psi.type2Charstrings.initialize(f, b, x) - if err := b.psi.run(psContextType2Charstring, buf, offset, length); err != nil { - return nil, err - } - if !b.psi.type2Charstrings.ended { - return nil, errInvalidCFFTable - } - } else if err := loadGlyf(f, b, x, 0, 0); err != nil { - return nil, err - } - - // Scale the segments. If we want to support hinting, we'll have to push - // the scaling computation into the PostScript / TrueType specific glyph - // 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 { - 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) - } - } - - // TODO: look at opts to transform / hint the Buffer.segments. - - return b.segments, nil -} - -// GlyphName returns the name of the x'th glyph. -// -// Not every font contains glyph names. If not present, GlyphName will return -// ("", nil). -// -// If present, the glyph name, provided by the font, is assumed to follow the -// Adobe Glyph List Specification: -// https://github.com/adobe-type-tools/agl-specification/blob/master/README.md -// -// This is also known as the "Adobe Glyph Naming convention", the "Adobe -// document [for] Unicode and Glyph Names" or "PostScript glyph names". -// -// It returns ErrNotFound if the glyph index is out of range. -func (f *Font) GlyphName(b *Buffer, x GlyphIndex) (string, error) { - if int(x) >= f.NumGlyphs() { - return "", ErrNotFound - } - if f.cached.postTableVersion != 0x20000 { - return "", nil - } - if b == nil { - b = &Buffer{} - } - - // The wire format for a Version 2 post table is documented at: - // https://www.microsoft.com/typography/otspec/post.htm - const glyphNameIndexOffset = 34 - - buf, err := b.view(&f.src, int(f.post.offset)+glyphNameIndexOffset+2*int(x), 2) - if err != nil { - return "", err - } - u := u16(buf) - if u < numBuiltInPostNames { - i := builtInPostNamesOffsets[u+0] - j := builtInPostNamesOffsets[u+1] - return builtInPostNamesData[i:j], nil - } - // https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6post.html - // says that "32768 through 65535 are reserved for future use". - if u > 32767 { - return "", errUnsupportedPostTable - } - u -= numBuiltInPostNames - - // Iterate through the list of Pascal-formatted strings. A linear scan is - // clearly O(u), which isn't great (as the obvious loop, calling - // Font.GlyphName, to get all of the glyph names in a font has quadratic - // complexity), but the wire format doesn't suggest a better alternative. - - offset := glyphNameIndexOffset + 2*f.NumGlyphs() - buf, err = b.view(&f.src, int(f.post.offset)+offset, int(f.post.length)-offset) - if err != nil { - return "", err - } - - for { - if len(buf) == 0 { - return "", errInvalidPostTable - } - n := 1 + int(buf[0]) - if len(buf) < n { - return "", errInvalidPostTable - } - if u == 0 { - return string(buf[1:n]), nil - } - buf = buf[n:] - u-- - } -} - -// 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. -// -// It returns ErrNotFound if either glyph index is out of range. -func (f *Font) Kern(b *Buffer, x0, x1 GlyphIndex, ppem fixed.Int26_6, h font.Hinting) (fixed.Int26_6, error) { - // TODO: how should this work with the GPOS table and CFF fonts? - // https://www.microsoft.com/typography/otspec/kern.htm says that - // "OpenType™ fonts containing CFF outlines are not supported by the 'kern' - // table and must use the 'GPOS' OpenType Layout table." - - if n := f.NumGlyphs(); int(x0) >= n || int(x1) >= n { - return 0, ErrNotFound - } - // 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 { - b = &Buffer{} - } - - key := uint32(x0)<<16 | uint32(x1) - lo, hi := int32(0), f.cached.kernNumPairs - for lo < hi { - i := (lo + hi) / 2 - - // TODO: this view call inside the inner loop can lead to many small - // reads instead of fewer larger reads, which can be expensive. We - // should be able to do better, although we don't want to make (one) - // arbitrarily large read. Perhaps we should round up reads to 4K or 8K - // chunks. For reference, Arial.ttf's kern table is 5472 bytes. - // Times_New_Roman.ttf's kern table is 5220 bytes. - const entrySize = 6 - buf, err := b.view(&f.src, int(f.cached.kernOffset+i*entrySize), entrySize) - if err != nil { - return 0, err - } - - k := u32(buf) - if k < key { - lo = i + 1 - } else if k > key { - hi = i - } else { - kern := fixed.Int26_6(int16(u16(buf[4:]))) - kern = scale(kern*ppem, f.cached.unitsPerEm) - if h == font.HintingFull { - // Quantize the fixed.Int26_6 value to the nearest pixel. - kern = (kern + 32) &^ 63 - } - return kern, nil - } - } - return 0, nil -} - -// Metrics returns the metrics of this font. -func (f *Font) Metrics(b *Buffer, ppem fixed.Int26_6, h font.Hinting) (font.Metrics, error) { - m := font.Metrics{ - // TODO: is adding lineGap correct? - Height: ppem + scale(fixed.Int26_6(f.cached.lineGap)*ppem, f.cached.unitsPerEm), - Ascent: +scale(fixed.Int26_6(f.cached.ascent)*ppem, f.cached.unitsPerEm), - Descent: -scale(fixed.Int26_6(f.cached.descent)*ppem, f.cached.unitsPerEm), - } - if h == font.HintingFull { - // Quantize up to a whole pixel. - m.Height = (m.Height + 63) &^ 63 - m.Ascent = (m.Ascent + 63) &^ 63 - m.Descent = (m.Descent + 63) &^ 63 - } - return m, nil -} - -// Name returns the name value keyed by the given NameID. -// -// It returns ErrNotFound if there is no value for that key. -func (f *Font) Name(b *Buffer, id NameID) (string, error) { - if b == nil { - b = &Buffer{} - } - - const headerSize, entrySize = 6, 12 - if f.name.length < headerSize { - return "", errInvalidNameTable - } - buf, err := b.view(&f.src, int(f.name.offset), headerSize) - if err != nil { - return "", err - } - numSubtables := u16(buf[2:]) - if f.name.length < headerSize+entrySize*uint32(numSubtables) { - return "", errInvalidNameTable - } - stringOffset := u16(buf[4:]) - - seen := false - for i, n := 0, int(numSubtables); i < n; i++ { - buf, err := b.view(&f.src, int(f.name.offset)+headerSize+entrySize*i, entrySize) - if err != nil { - return "", err - } - if u16(buf[6:]) != uint16(id) { - continue - } - seen = true - - var stringify func([]byte) (string, error) - switch u32(buf) { - default: - continue - case pidMacintosh<<16 | psidMacintoshRoman: - stringify = stringifyMacintosh - case pidWindows<<16 | psidWindowsUCS2: - stringify = stringifyUCS2 - } - - nameLength := u16(buf[8:]) - nameOffset := u16(buf[10:]) - buf, err = b.view(&f.src, int(f.name.offset)+int(nameOffset)+int(stringOffset), int(nameLength)) - if err != nil { - return "", err - } - return stringify(buf) - } - - if seen { - return "", errUnsupportedPlatformEncoding - } - return "", ErrNotFound -} - -func stringifyMacintosh(b []byte) (string, error) { - for _, c := range b { - if c >= 0x80 { - // b contains some non-ASCII bytes. - s, _ := charmap.Macintosh.NewDecoder().Bytes(b) - return string(s), nil - } - } - // b contains only ASCII bytes. - return string(b), nil -} - -func stringifyUCS2(b []byte) (string, error) { - if len(b)&1 != 0 { - return "", errInvalidUCS2String - } - r := make([]rune, len(b)/2) - for i := range r { - r[i] = rune(u16(b)) - b = b[2:] - } - return string(r), nil -} - -// Buffer holds re-usable buffers that can reduce the total memory allocation -// of repeated Font method calls. -// -// See the Font type's documentation comment for more details. -type Buffer struct { - // buf is a byte buffer for when a Font's source is an io.ReaderAt. - 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 -} - -func (b *Buffer) view(src *source, offset, length int) ([]byte, error) { - buf, err := src.view(b.buf, offset, length) - if err != nil { - return nil, err - } - // Only update b.buf if it is safe to re-use buf. - if src.viewBufferWritable() { - b.buf = buf - } - return buf, nil -} - -// Segment is a segment of a vector path. -type Segment struct { - // 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. -type SegmentOp uint32 - -const ( - SegmentOpMoveTo SegmentOp = iota - SegmentOpLineTo - SegmentOpQuadTo - SegmentOpCubeTo -) - -// translateArgs applies a translation to args. -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 *[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 fixed.Int26_6, p fixed.Point26_6) fixed.Point26_6 { - const half = 1 << 13 - 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), - } -} diff --git a/vendor/golang.org/x/image/font/sfnt/sfnt_test.go b/vendor/golang.org/x/image/font/sfnt/sfnt_test.go deleted file mode 100644 index b9b66a786..000000000 --- a/vendor/golang.org/x/image/font/sfnt/sfnt_test.go +++ /dev/null @@ -1,839 +0,0 @@ -// Copyright 2016 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 ( - "bytes" - "fmt" - "io/ioutil" - "path/filepath" - "testing" - - "golang.org/x/image/font" - "golang.org/x/image/font/gofont/gobold" - "golang.org/x/image/font/gofont/gomono" - "golang.org/x/image/font/gofont/goregular" - "golang.org/x/image/math/fixed" -) - -func pt(x, y fixed.Int26_6) fixed.Point26_6 { - return fixed.Point26_6{X: x, Y: y} -} - -func moveTo(xa, ya fixed.Int26_6) Segment { - return Segment{ - Op: SegmentOpMoveTo, - Args: [3]fixed.Point26_6{pt(xa, ya)}, - } -} - -func lineTo(xa, ya fixed.Int26_6) Segment { - return Segment{ - Op: SegmentOpLineTo, - Args: [3]fixed.Point26_6{pt(xa, ya)}, - } -} - -func quadTo(xa, ya, xb, yb fixed.Int26_6) Segment { - return Segment{ - Op: SegmentOpQuadTo, - Args: [3]fixed.Point26_6{pt(xa, ya), pt(xb, yb)}, - } -} - -func cubeTo(xa, ya, xb, yb, xc, yc fixed.Int26_6) Segment { - return Segment{ - Op: SegmentOpCubeTo, - Args: [3]fixed.Point26_6{pt(xa, ya), pt(xb, yb), pt(xc, yc)}, - } -} - -func translate(dx, dy fixed.Int26_6, s Segment) Segment { - translateArgs(&s.Args, dx, dy) - return s -} - -func transform(txx, txy, tyx, tyy int16, dx, dy fixed.Int26_6, s Segment) Segment { - transformArgs(&s.Args, txx, txy, tyx, tyy, dx, dy) - return s -} - -func checkSegmentsEqual(got, want []Segment) error { - // Flip got's Y axis. The test cases' coordinates are given with the Y axis - // increasing up, as that is what the ttx tool gives, and is the model for - // the underlying font format. The Go API returns coordinates with the Y - // axis increasing down, the same as the standard graphics libraries. - for i := range got { - for j := range got[i].Args { - got[i].Args[j].Y *= -1 - } - } - - if len(got) != len(want) { - return fmt.Errorf("got %d elements, want %d\noverall:\ngot %v\nwant %v", - len(got), len(want), got, want) - } - for i, g := range got { - if w := want[i]; g != w { - return fmt.Errorf("element %d:\ngot %v\nwant %v\noverall:\ngot %v\nwant %v", - i, g, w, got, want) - } - } - - // Check that every contour is closed. - if len(got) == 0 { - return nil - } - if got[0].Op != SegmentOpMoveTo { - return fmt.Errorf("segments do not start with a moveTo") - } - var ( - first, last fixed.Point26_6 - firstI int - ) - checkClosed := func(lastI int) error { - if first != last { - return fmt.Errorf("segments[%d:%d] not closed:\nfirst %v\nlast %v", firstI, lastI, first, last) - } - return nil - } - for i, g := range got { - switch g.Op { - case SegmentOpMoveTo: - if i != 0 { - if err := checkClosed(i); err != nil { - return err - } - } - firstI, first, last = i, g.Args[0], g.Args[0] - case SegmentOpLineTo: - last = g.Args[0] - case SegmentOpQuadTo: - last = g.Args[1] - case SegmentOpCubeTo: - last = g.Args[2] - } - } - return checkClosed(len(got)) -} - -func TestTrueTypeParse(t *testing.T) { - f, err := Parse(goregular.TTF) - if err != nil { - t.Fatalf("Parse: %v", err) - } - testTrueType(t, f) -} - -func TestTrueTypeParseReaderAt(t *testing.T) { - f, err := ParseReaderAt(bytes.NewReader(goregular.TTF)) - if err != nil { - t.Fatalf("ParseReaderAt: %v", err) - } - testTrueType(t, f) -} - -func testTrueType(t *testing.T, f *Font) { - if got, want := f.UnitsPerEm(), Units(2048); got != want { - t.Errorf("UnitsPerEm: got %d, want %d", got, want) - } - // The exact number of glyphs in goregular.TTF can vary, and future - // versions may add more glyphs, but https://blog.golang.org/go-fonts says - // that "The WGL4 character set... [has] more than 650 characters in all. - if got, want := f.NumGlyphs(), 650; got <= want { - t.Errorf("NumGlyphs: got %d, want > %d", got, want) - } -} - -func fontData(name string) []byte { - switch name { - case "gobold": - return gobold.TTF - case "gomono": - return gomono.TTF - case "goregular": - return goregular.TTF - } - panic("unreachable") -} - -func TestBounds(t *testing.T) { - testCases := map[string]fixed.Rectangle26_6{ - "gobold": { - Min: fixed.Point26_6{ - X: -452, - Y: -2193, - }, - Max: fixed.Point26_6{ - X: 2190, - Y: 432, - }, - }, - "gomono": { - Min: fixed.Point26_6{ - X: 0, - Y: -2227, - }, - Max: fixed.Point26_6{ - X: 1229, - Y: 432, - }, - }, - "goregular": { - Min: fixed.Point26_6{ - X: -440, - Y: -2118, - }, - Max: fixed.Point26_6{ - X: 2160, - Y: 543, - }, - }, - } - - var b Buffer - for name, want := range testCases { - f, err := Parse(fontData(name)) - if err != nil { - t.Errorf("Parse(%q): %v", name, err) - continue - } - ppem := fixed.Int26_6(f.UnitsPerEm()) - - got, err := f.Bounds(&b, ppem, font.HintingNone) - if err != nil { - t.Errorf("name=%q: Bounds: %v", name, err) - continue - } - if got != want { - t.Errorf("name=%q: Bounds: got %v, want %v", name, got, want) - continue - } - } -} - -func TestMetrics(t *testing.T) { - cmapFont, err := ioutil.ReadFile(filepath.FromSlash("../testdata/cmapTest.ttf")) - if err != nil { - t.Fatal(err) - } - testCases := map[string]struct { - font []byte - want font.Metrics - }{ - "goregular": {goregular.TTF, font.Metrics{Height: 2048, Ascent: 1935, Descent: 432}}, - // cmapTest.ttf has a non-zero lineGap. - "cmapTest": {cmapFont, font.Metrics{Height: 2232, Ascent: 1365, Descent: 0}}, - } - var b Buffer - for name, tc := range testCases { - f, err := Parse(tc.font) - if err != nil { - t.Errorf("name=%q: Parse: %v", name, err) - continue - } - ppem := fixed.Int26_6(f.UnitsPerEm()) - - got, err := f.Metrics(&b, ppem, font.HintingNone) - if err != nil { - t.Errorf("name=%q: Metrics: %v", name, err) - continue - } - if got != tc.want { - t.Errorf("name=%q: Metrics: got %v, want %v", name, got, tc.want) - continue - } - } -} - -func TestGlyphAdvance(t *testing.T) { - testCases := map[string][]struct { - r rune - want fixed.Int26_6 - }{ - "gobold": { - {' ', 569}, - {'A', 1479}, - {'Á', 1479}, - {'Æ', 2048}, - {'i', 592}, - {'x', 1139}, - }, - "gomono": { - {' ', 1229}, - {'A', 1229}, - {'Á', 1229}, - {'Æ', 1229}, - {'i', 1229}, - {'x', 1229}, - }, - "goregular": { - {' ', 569}, - {'A', 1366}, - {'Á', 1366}, - {'Æ', 2048}, - {'i', 505}, - {'x', 1024}, - }, - } - - var b Buffer - for name, testCases1 := range testCases { - f, err := Parse(fontData(name)) - if err != nil { - t.Errorf("Parse(%q): %v", name, err) - continue - } - ppem := fixed.Int26_6(f.UnitsPerEm()) - - for _, tc := range testCases1 { - x, err := f.GlyphIndex(&b, tc.r) - if err != nil { - t.Errorf("name=%q, r=%q: GlyphIndex: %v", name, tc.r, err) - continue - } - got, err := f.GlyphAdvance(&b, x, ppem, font.HintingNone) - if err != nil { - t.Errorf("name=%q, r=%q: GlyphAdvance: %v", name, tc.r, err) - continue - } - if got != tc.want { - t.Errorf("name=%q, r=%q: GlyphAdvance: got %d, want %d", name, tc.r, got, tc.want) - continue - } - } - } -} - -func TestGoRegularGlyphIndex(t *testing.T) { - f, err := Parse(goregular.TTF) - if err != nil { - t.Fatalf("Parse: %v", err) - } - - testCases := []struct { - r rune - want GlyphIndex - }{ - // Glyphs that aren't present in Go Regular. - {'\u001f', 0}, // U+001F - {'\u0200', 0}, // U+0200 LATIN CAPITAL LETTER A WITH DOUBLE GRAVE - {'\u2000', 0}, // U+2000 EN QUAD - - // The want values below can be verified by running the ttx tool on - // Go-Regular.ttf. - // - // The actual values are ad hoc, and result from whatever tools the - // Bigelow & Holmes type foundry used and the order in which they - // crafted the glyphs. They may change over time as newer versions of - // the font are released. - - {'\u0020', 3}, // U+0020 SPACE - {'\u0021', 4}, // U+0021 EXCLAMATION MARK - {'\u0022', 5}, // U+0022 QUOTATION MARK - {'\u0023', 6}, // U+0023 NUMBER SIGN - {'\u0024', 7}, // U+0024 DOLLAR SIGN - {'\u0025', 8}, // U+0025 PERCENT SIGN - {'\u0026', 9}, // U+0026 AMPERSAND - {'\u0027', 10}, // U+0027 APOSTROPHE - - {'\u03bd', 396}, // U+03BD GREEK SMALL LETTER NU - {'\u03be', 397}, // U+03BE GREEK SMALL LETTER XI - {'\u03bf', 398}, // U+03BF GREEK SMALL LETTER OMICRON - {'\u03c0', 399}, // U+03C0 GREEK SMALL LETTER PI - {'\u03c1', 400}, // U+03C1 GREEK SMALL LETTER RHO - {'\u03c2', 401}, // U+03C2 GREEK SMALL LETTER FINAL SIGMA - } - - var b Buffer - for _, tc := range testCases { - got, err := f.GlyphIndex(&b, tc.r) - if err != nil { - t.Errorf("r=%q: %v", tc.r, err) - continue - } - if got != tc.want { - t.Errorf("r=%q: got %d, want %d", tc.r, got, tc.want) - continue - } - } -} - -func TestGlyphIndex(t *testing.T) { - data, err := ioutil.ReadFile(filepath.FromSlash("../testdata/cmapTest.ttf")) - if err != nil { - t.Fatal(err) - } - - for _, format := range []int{-1, 0, 4, 12} { - testGlyphIndex(t, data, format) - } -} - -func testGlyphIndex(t *testing.T, data []byte, cmapFormat int) { - if cmapFormat >= 0 { - originalSupportedCmapFormat := supportedCmapFormat - defer func() { - supportedCmapFormat = originalSupportedCmapFormat - }() - supportedCmapFormat = func(format, pid, psid uint16) bool { - return int(format) == cmapFormat && originalSupportedCmapFormat(format, pid, psid) - } - } - - f, err := Parse(data) - if err != nil { - t.Errorf("cmapFormat=%d: %v", cmapFormat, err) - return - } - - testCases := []struct { - r rune - want GlyphIndex - }{ - // Glyphs that aren't present in cmapTest.ttf. - {'?', 0}, - {'\ufffd', 0}, - {'\U0001f4a9', 0}, - - // For a .TTF file, FontForge maps: - // - ".notdef" to glyph index 0. - // - ".null" to glyph index 1. - // - "nonmarkingreturn" to glyph index 2. - - {'/', 0}, - {'0', 3}, - {'1', 4}, - {'2', 5}, - {'3', 0}, - - {'@', 0}, - {'A', 6}, - {'B', 7}, - {'C', 0}, - - {'`', 0}, - {'a', 8}, - {'b', 0}, - - // Of the remaining runes, only U+00FF LATIN SMALL LETTER Y WITH - // DIAERESIS is in both the Mac Roman encoding and the cmapTest.ttf - // font file. - {'\u00fe', 0}, - {'\u00ff', 9}, - {'\u0100', 10}, - {'\u0101', 11}, - {'\u0102', 0}, - - {'\u4e2c', 0}, - {'\u4e2d', 12}, - {'\u4e2e', 0}, - - {'\U0001f0a0', 0}, - {'\U0001f0a1', 13}, - {'\U0001f0a2', 0}, - - {'\U0001f0b0', 0}, - {'\U0001f0b1', 14}, - {'\U0001f0b2', 15}, - {'\U0001f0b3', 0}, - } - - var b Buffer - for _, tc := range testCases { - want := tc.want - switch { - case cmapFormat == 0 && tc.r > '\u007f' && tc.r != '\u00ff': - // cmap format 0, with the Macintosh Roman encoding, can only - // represent a limited set of non-ASCII runes, e.g. U+00FF. - want = 0 - case cmapFormat == 4 && tc.r > '\uffff': - // cmap format 4 only supports the Basic Multilingual Plane (BMP). - want = 0 - } - - got, err := f.GlyphIndex(&b, tc.r) - if err != nil { - t.Errorf("cmapFormat=%d, r=%q: %v", cmapFormat, tc.r, err) - continue - } - if got != want { - t.Errorf("cmapFormat=%d, r=%q: got %d, want %d", cmapFormat, tc.r, got, want) - continue - } - } -} - -func TestPostScriptSegments(t *testing.T) { - // wants' vectors correspond 1-to-1 to what's in the CFFTest.sfd file, - // although OpenType/CFF and FontForge's SFD have reversed orders. - // https://fontforge.github.io/validation.html says that "All paths must be - // drawn in a consistent direction. Clockwise for external paths, - // anti-clockwise for internal paths. (Actually PostScript requires the - // exact opposite, but FontForge reverses PostScript contours when it loads - // them so that everything is consistant internally -- and reverses them - // again when it saves them, of course)." - // - // The .notdef glyph isn't explicitly in the SFD file, but for some unknown - // reason, FontForge generates it in the OpenType/CFF file. - wants := [][]Segment{{ - // .notdef - // - contour #0 - moveTo(50, 0), - lineTo(450, 0), - lineTo(450, 533), - lineTo(50, 533), - lineTo(50, 0), - // - contour #1 - moveTo(100, 50), - lineTo(100, 483), - lineTo(400, 483), - lineTo(400, 50), - lineTo(100, 50), - }, { - // zero - // - contour #0 - moveTo(300, 700), - cubeTo(380, 700, 420, 580, 420, 500), - cubeTo(420, 350, 390, 100, 300, 100), - cubeTo(220, 100, 180, 220, 180, 300), - cubeTo(180, 450, 210, 700, 300, 700), - // - contour #1 - moveTo(300, 800), - cubeTo(200, 800, 100, 580, 100, 400), - cubeTo(100, 220, 200, 0, 300, 0), - cubeTo(400, 0, 500, 220, 500, 400), - cubeTo(500, 580, 400, 800, 300, 800), - }, { - // one - // - contour #0 - moveTo(100, 0), - lineTo(300, 0), - lineTo(300, 800), - lineTo(100, 800), - lineTo(100, 0), - }, { - // Q - // - contour #0 - moveTo(657, 237), - lineTo(289, 387), - lineTo(519, 615), - lineTo(657, 237), - // - contour #1 - moveTo(792, 169), - cubeTo(867, 263, 926, 502, 791, 665), - cubeTo(645, 840, 380, 831, 228, 673), - cubeTo(71, 509, 110, 231, 242, 93), - cubeTo(369, -39, 641, 18, 722, 93), - lineTo(802, 3), - lineTo(864, 83), - lineTo(792, 169), - }, { - // uni4E2D - // - contour #0 - moveTo(141, 520), - lineTo(137, 356), - lineTo(245, 400), - lineTo(331, 26), - lineTo(355, 414), - lineTo(463, 434), - lineTo(453, 620), - lineTo(341, 592), - lineTo(331, 758), - lineTo(243, 752), - lineTo(235, 562), - lineTo(141, 520), - }} - - testSegments(t, "CFFTest.otf", wants) -} - -func TestTrueTypeSegments(t *testing.T) { - // wants' vectors correspond 1-to-1 to what's in the glyfTest.sfd file, - // although FontForge's SFD format stores quadratic Bézier curves as cubics - // with duplicated off-curve points. quadTo(bx, by, cx, cy) is stored as - // "bx by bx by cx cy". - // - // The .notdef, .null and nonmarkingreturn glyphs aren't explicitly in the - // SFD file, but for some unknown reason, FontForge generates them in the - // TrueType file. - wants := [][]Segment{{ - // .notdef - // - contour #0 - moveTo(68, 0), - lineTo(68, 1365), - lineTo(612, 1365), - lineTo(612, 0), - lineTo(68, 0), - // - contour #1 - moveTo(136, 68), - lineTo(544, 68), - lineTo(544, 1297), - lineTo(136, 1297), - lineTo(136, 68), - }, { - // .null - // Empty glyph. - }, { - // nonmarkingreturn - // Empty glyph. - }, { - // zero - // - contour #0 - moveTo(614, 1434), - quadTo(369, 1434, 369, 614), - quadTo(369, 471, 435, 338), - quadTo(502, 205, 614, 205), - quadTo(860, 205, 860, 1024), - quadTo(860, 1167, 793, 1300), - quadTo(727, 1434, 614, 1434), - // - contour #1 - moveTo(614, 1638), - quadTo(1024, 1638, 1024, 819), - quadTo(1024, 0, 614, 0), - quadTo(205, 0, 205, 819), - quadTo(205, 1638, 614, 1638), - }, { - // one - // - contour #0 - moveTo(205, 0), - lineTo(205, 1638), - lineTo(614, 1638), - lineTo(614, 0), - lineTo(205, 0), - }, { - // five - // - contour #0 - moveTo(0, 0), - lineTo(0, 100), - lineTo(400, 100), - lineTo(400, 0), - lineTo(0, 0), - }, { - // six - // - contour #0 - moveTo(0, 0), - lineTo(0, 100), - lineTo(400, 100), - lineTo(400, 0), - lineTo(0, 0), - // - contour #1 - translate(111, 234, moveTo(205, 0)), - translate(111, 234, lineTo(205, 1638)), - translate(111, 234, lineTo(614, 1638)), - translate(111, 234, lineTo(614, 0)), - translate(111, 234, lineTo(205, 0)), - }, { - // seven - // - contour #0 - moveTo(0, 0), - lineTo(0, 100), - lineTo(400, 100), - lineTo(400, 0), - lineTo(0, 0), - // - contour #1 - transform(1<<13, 0, 0, 1<<13, 56, 117, moveTo(205, 0)), - transform(1<<13, 0, 0, 1<<13, 56, 117, lineTo(205, 1638)), - transform(1<<13, 0, 0, 1<<13, 56, 117, lineTo(614, 1638)), - transform(1<<13, 0, 0, 1<<13, 56, 117, lineTo(614, 0)), - transform(1<<13, 0, 0, 1<<13, 56, 117, lineTo(205, 0)), - }, { - // eight - // - contour #0 - moveTo(0, 0), - lineTo(0, 100), - lineTo(400, 100), - lineTo(400, 0), - lineTo(0, 0), - // - contour #1 - transform(3<<13, 0, 0, 1<<13, 56, 117, moveTo(205, 0)), - transform(3<<13, 0, 0, 1<<13, 56, 117, lineTo(205, 1638)), - transform(3<<13, 0, 0, 1<<13, 56, 117, lineTo(614, 1638)), - transform(3<<13, 0, 0, 1<<13, 56, 117, lineTo(614, 0)), - transform(3<<13, 0, 0, 1<<13, 56, 117, lineTo(205, 0)), - }, { - // nine - // - contour #0 - moveTo(0, 0), - lineTo(0, 100), - lineTo(400, 100), - lineTo(400, 0), - lineTo(0, 0), - // - contour #1 - transform(22381, 8192, 5996, 14188, 237, 258, moveTo(205, 0)), - transform(22381, 8192, 5996, 14188, 237, 258, lineTo(205, 1638)), - transform(22381, 8192, 5996, 14188, 237, 258, lineTo(614, 1638)), - transform(22381, 8192, 5996, 14188, 237, 258, lineTo(614, 0)), - transform(22381, 8192, 5996, 14188, 237, 258, lineTo(205, 0)), - }} - - testSegments(t, "glyfTest.ttf", wants) -} - -func testSegments(t *testing.T, filename string, wants [][]Segment) { - data, err := ioutil.ReadFile(filepath.FromSlash("../testdata/" + filename)) - if err != nil { - t.Fatalf("ReadFile: %v", err) - } - f, err := Parse(data) - if err != nil { - t.Fatalf("Parse: %v", err) - } - ppem := fixed.Int26_6(f.UnitsPerEm()) - - if ng := f.NumGlyphs(); ng != len(wants) { - t.Fatalf("NumGlyphs: got %d, want %d", ng, len(wants)) - } - var b Buffer - for i, want := range wants { - got, err := f.LoadGlyph(&b, GlyphIndex(i), ppem, nil) - if err != nil { - t.Errorf("i=%d: LoadGlyph: %v", i, err) - continue - } - if err := checkSegmentsEqual(got, want); err != nil { - t.Errorf("i=%d: %v", i, err) - continue - } - } - if _, err := f.LoadGlyph(nil, 0xffff, ppem, nil); err != ErrNotFound { - t.Errorf("LoadGlyph(..., 0xffff, ...):\ngot %v\nwant %v", err, ErrNotFound) - } - - name, err := f.Name(nil, NameIDFamily) - if err != nil { - t.Errorf("Name: %v", err) - } else if want := filename[:len(filename)-len(".ttf")]; name != want { - t.Errorf("Name:\ngot %q\nwant %q", name, want) - } -} - -func TestPPEM(t *testing.T) { - data, err := ioutil.ReadFile(filepath.FromSlash("../testdata/glyfTest.ttf")) - if err != nil { - t.Fatalf("ReadFile: %v", err) - } - f, err := Parse(data) - if err != nil { - t.Fatalf("Parse: %v", err) - } - var b Buffer - x, err := f.GlyphIndex(&b, '1') - if err != nil { - t.Fatalf("GlyphIndex: %v", err) - } - if x == 0 { - t.Fatalf("GlyphIndex: no glyph index found for the rune '1'") - } - - testCases := []struct { - ppem fixed.Int26_6 - want []Segment - }{{ - ppem: fixed.Int26_6(12 << 6), - want: []Segment{ - moveTo(77, 0), - lineTo(77, 614), - lineTo(230, 614), - lineTo(230, 0), - lineTo(77, 0), - }, - }, { - ppem: fixed.Int26_6(2048), - want: []Segment{ - moveTo(205, 0), - lineTo(205, 1638), - lineTo(614, 1638), - lineTo(614, 0), - lineTo(205, 0), - }, - }} - - for i, tc := range testCases { - got, err := f.LoadGlyph(&b, x, tc.ppem, nil) - if err != nil { - t.Errorf("i=%d: LoadGlyph: %v", i, err) - continue - } - if err := checkSegmentsEqual(got, tc.want); err != nil { - t.Errorf("i=%d: %v", i, err) - continue - } - } -} - -func TestGlyphName(t *testing.T) { - f, err := Parse(goregular.TTF) - if err != nil { - t.Fatalf("Parse: %v", err) - } - - testCases := []struct { - r rune - want string - }{ - {'\x00', "uni0000"}, - {'!', "exclam"}, - {'A', "A"}, - {'{', "braceleft"}, - {'\u00c4', "Adieresis"}, // U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS - {'\u2020', "dagger"}, // U+2020 DAGGER - {'\u2660', "spade"}, // U+2660 BLACK SPADE SUIT - {'\uf800', "gopher"}, // U+F800 - {'\ufffe', ".notdef"}, // Not in the Go Regular font, so GlyphIndex returns (0, nil). - } - - var b Buffer - for _, tc := range testCases { - x, err := f.GlyphIndex(&b, tc.r) - if err != nil { - t.Errorf("r=%q: GlyphIndex: %v", tc.r, err) - continue - } - got, err := f.GlyphName(&b, x) - if err != nil { - t.Errorf("r=%q: GlyphName: %v", tc.r, err) - continue - } - if got != tc.want { - t.Errorf("r=%q: got %q, want %q", tc.r, got, tc.want) - continue - } - } -} - -func TestBuiltInPostNames(t *testing.T) { - testCases := []struct { - x GlyphIndex - want string - }{ - {0, ".notdef"}, - {1, ".null"}, - {2, "nonmarkingreturn"}, - {13, "asterisk"}, - {36, "A"}, - {93, "z"}, - {123, "ocircumflex"}, - {202, "Edieresis"}, - {255, "Ccaron"}, - {256, "ccaron"}, - {257, "dcroat"}, - {258, ""}, - {999, ""}, - {0xffff, ""}, - } - - for _, tc := range testCases { - if tc.x >= numBuiltInPostNames { - continue - } - i := builtInPostNamesOffsets[tc.x+0] - j := builtInPostNamesOffsets[tc.x+1] - got := builtInPostNamesData[i:j] - if got != tc.want { - t.Errorf("x=%d: got %q, want %q", tc.x, got, tc.want) - } - } -} 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 ab27f5b2c..000000000 --- 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 -} -- cgit v1.2.3-1-g7c22