summaryrefslogtreecommitdiffstats
path: root/vendor/golang.org/x/image/font/sfnt
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/image/font/sfnt')
-rw-r--r--vendor/golang.org/x/image/font/sfnt/cmap.go259
-rw-r--r--vendor/golang.org/x/image/font/sfnt/data.go68
-rw-r--r--vendor/golang.org/x/image/font/sfnt/example_test.go131
-rw-r--r--vendor/golang.org/x/image/font/sfnt/gen.go321
-rw-r--r--vendor/golang.org/x/image/font/sfnt/postscript.go1414
-rw-r--r--vendor/golang.org/x/image/font/sfnt/proprietary_test.go1390
-rw-r--r--vendor/golang.org/x/image/font/sfnt/sfnt.go1538
-rw-r--r--vendor/golang.org/x/image/font/sfnt/sfnt_test.go839
-rw-r--r--vendor/golang.org/x/image/font/sfnt/truetype.go572
9 files changed, 0 insertions, 6532 deletions
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 <CJK Ideograph>, 中
- '\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 <CJK Ideograph> "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:
-//
-// <CharString name="cid00100" fdSelectIndex="15">
-// <CharString name="cid00101" fdSelectIndex="15">
-// <CharString name="cid00102" fdSelectIndex="3">
-// <CharString name="cid00103" fdSelectIndex="15">
-//
-// As for what the values like 3 or 15 actually mean, grepping that ttx file
-// for "FontName" gives this list:
-//
-// 0: <FontName value="SourceHanSansSC-Regular-Alphabetic"/>
-// 1: <FontName value="SourceHanSansSC-Regular-AlphabeticDigits"/>
-// 2: <FontName value="SourceHanSansSC-Regular-Bopomofo"/>
-// 3: <FontName value="SourceHanSansSC-Regular-Dingbats"/>
-// 4: <FontName value="SourceHanSansSC-Regular-DingbatsDigits"/>
-// 5: <FontName value="SourceHanSansSC-Regular-Generic"/>
-// 6: <FontName value="SourceHanSansSC-Regular-HDingbats"/>
-// 7: <FontName value="SourceHanSansSC-Regular-HHangul"/>
-// 8: <FontName value="SourceHanSansSC-Regular-HKana"/>
-// 9: <FontName value="SourceHanSansSC-Regular-HWidth"/>
-// 10: <FontName value="SourceHanSansSC-Regular-HWidthCJK"/>
-// 11: <FontName value="SourceHanSansSC-Regular-HWidthDigits"/>
-// 12: <FontName value="SourceHanSansSC-Regular-Hangul"/>
-// 13: <FontName value="SourceHanSansSC-Regular-Ideographs"/>
-// 14: <FontName value="SourceHanSansSC-Regular-Kana"/>
-// 15: <FontName value="SourceHanSansSC-Regular-Proportional"/>
-// 16: <FontName value="SourceHanSansSC-Regular-ProportionalCJK"/>
-// 17: <FontName value="SourceHanSansSC-Regular-ProportionalDigits"/>
-// 18: <FontName value="SourceHanSansSC-Regular-VKana"/>
-//
-// 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 <control>
- {'\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 <Private Use>
- {'\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
-}