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/postscript.go41
-rw-r--r--vendor/golang.org/x/image/font/sfnt/proprietary_test.go125
-rw-r--r--vendor/golang.org/x/image/font/sfnt/sfnt.go46
3 files changed, 188 insertions, 24 deletions
diff --git a/vendor/golang.org/x/image/font/sfnt/postscript.go b/vendor/golang.org/x/image/font/sfnt/postscript.go
index 7c5db789d..b686e60ac 100644
--- a/vendor/golang.org/x/image/font/sfnt/postscript.go
+++ b/vendor/golang.org/x/image/font/sfnt/postscript.go
@@ -969,7 +969,8 @@ var psOperators = [...][2][]psOperator{
31: {-1, "hvcurveto", t2CHvcurveto},
}, {
// 2-byte operators. The first byte is the escape byte.
- 0: {}, // Reserved.
+ 34: {+7, "hflex", t2CHflex},
+ 36: {+9, "hflex1", t2CHflex1},
// TODO: more operators.
}},
}
@@ -1271,6 +1272,44 @@ func t2CRrcurveto(p *psInterpreter) error {
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 {
diff --git a/vendor/golang.org/x/image/font/sfnt/proprietary_test.go b/vendor/golang.org/x/image/font/sfnt/proprietary_test.go
index dcafdd4c7..bb14a34b5 100644
--- a/vendor/golang.org/x/image/font/sfnt/proprietary_test.go
+++ b/vendor/golang.org/x/image/font/sfnt/proprietary_test.go
@@ -23,15 +23,14 @@ 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
+ -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: add Google fonts (Droid? Noto?)? Emoji fonts?
-
// TODO: enable Apple/Microsoft tests by default on Darwin/Windows?
import (
@@ -88,26 +87,41 @@ var (
"/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 TestProprietaryAdobeSourceCodeProOTF(t *testing.T) {
+func TestProprietaryAdobeSourceCodeProRegularOTF(t *testing.T) {
testProprietary(t, "adobe", "SourceCodePro-Regular.otf", 1500, -1)
}
-func TestProprietaryAdobeSourceCodeProTTF(t *testing.T) {
+func TestProprietaryAdobeSourceCodeProRegularTTF(t *testing.T) {
testProprietary(t, "adobe", "SourceCodePro-Regular.ttf", 1500, -1)
}
-func TestProprietaryAdobeSourceHanSansSC(t *testing.T) {
+func TestProprietaryAdobeSourceHanSansSCRegularOTF(t *testing.T) {
testProprietary(t, "adobe", "SourceHanSansSC-Regular.otf", 65535, -1)
}
-func TestProprietaryAdobeSourceSansProOTF(t *testing.T) {
- testProprietary(t, "adobe", "SourceSansPro-Regular.otf", 1800, -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 TestProprietaryAdobeSourceSansProTTF(t *testing.T) {
- testProprietary(t, "adobe", "SourceSansPro-Regular.ttf", 1800, -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) {
@@ -186,6 +200,14 @@ 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
@@ -219,6 +241,8 @@ func testProprietary(t *testing.T, proprietor, filename string, minNumGlyphs, fi
dir = *dejavuDir
case "microsoft":
dir = *microsoftDir
+ case "noto":
+ dir = *notoDir
default:
panic("unreachable")
}
@@ -287,7 +311,7 @@ func testProprietary(t *testing.T, proprietor, filename string, minNumGlyphs, fi
iMax = firstUnsupportedGlyph
}
for i, numErrors := 0, 0; i < iMax; i++ {
- if _, err := f.LoadGlyph(&buf, GlyphIndex(i), ppem, nil); err != nil {
+ if _, err := f.LoadGlyph(&buf, GlyphIndex(i), ppem, nil); err != nil && err != ErrColoredGlyph {
t.Errorf("LoadGlyph(%d): %v", i, err)
numErrors++
}
@@ -385,6 +409,8 @@ 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",
@@ -409,6 +435,9 @@ var proprietaryVersions = map[string]string{
"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
@@ -417,6 +446,8 @@ 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",
@@ -441,6 +472,9 @@ var proprietaryFullNames = map[string]string{
"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
@@ -617,6 +651,54 @@ var proprietaryGlyphTestCases = map[string]map[rune][]Segment{
},
},
+ "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
@@ -1152,6 +1234,27 @@ var proprietaryGlyphTestCases = map[string]map[rune][]Segment{
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 {
diff --git a/vendor/golang.org/x/image/font/sfnt/sfnt.go b/vendor/golang.org/x/image/font/sfnt/sfnt.go
index 34587da75..53ac94b8e 100644
--- a/vendor/golang.org/x/image/font/sfnt/sfnt.go
+++ b/vendor/golang.org/x/image/font/sfnt/sfnt.go
@@ -64,6 +64,9 @@ const (
)
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")
@@ -544,6 +547,12 @@ type Font struct {
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?
@@ -559,6 +568,7 @@ type Font struct {
glyphIndex glyphIndexFunc
bounds [4]int16
indexToLocFormat bool // false means short, true means long.
+ isColorBitmap bool
isPostScript bool
kernNumPairs int32
kernOffset int32
@@ -599,7 +609,7 @@ func (f *Font) initialize(offset int, isDfont bool) error {
if err != nil {
return err
}
- buf, glyphData, err := f.parseGlyphData(buf, numGlyphs, indexToLocFormat, isPostScript)
+ buf, glyphData, isColorBitmap, err := f.parseGlyphData(buf, numGlyphs, indexToLocFormat, isPostScript)
if err != nil {
return err
}
@@ -628,6 +638,7 @@ func (f *Font) initialize(offset int, isDfont bool) error {
f.cached.glyphIndex = glyphIndex
f.cached.bounds = bounds
f.cached.indexToLocFormat = indexToLocFormat
+ f.cached.isColorBitmap = isColorBitmap
f.cached.isPostScript = isPostScript
f.cached.kernNumPairs = kernNumPairs
f.cached.kernOffset = kernOffset
@@ -701,6 +712,8 @@ func (f *Font) initializeTables(offset int, isDfont bool) (buf1 []byte, isPostSc
// 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:
@@ -983,7 +996,7 @@ type glyphData struct {
fdSelect fdSelect
}
-func (f *Font) parseGlyphData(buf []byte, numGlyphs int32, indexToLocFormat, isPostScript bool) (buf1 []byte, ret glyphData, err error) {
+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,
@@ -993,19 +1006,25 @@ func (f *Font) parseGlyphData(buf []byte, numGlyphs int32, indexToLocFormat, isP
}
ret, err = p.parse(numGlyphs)
if err != nil {
- return nil, glyphData{}, err
+ return nil, glyphData{}, false, err
}
- } else {
+ } 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{}, err
+ 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{}, errInvalidLocationData
+ return nil, glyphData{}, false, errInvalidLocationData
}
- return buf, ret, nil
+ return buf, ret, isColorBitmap, nil
}
func (f *Font) parsePost(buf []byte, numGlyphs int32) (buf1 []byte, postTableVersion uint32, err error) {
@@ -1105,13 +1124,18 @@ type LoadGlyphOptions struct {
//
// 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 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 {
@@ -1124,10 +1148,8 @@ func (f *Font) LoadGlyph(b *Buffer, x GlyphIndex, ppem fixed.Int26_6, opts *Load
if !b.psi.type2Charstrings.ended {
return nil, errInvalidCFFTable
}
- } else {
- if err := loadGlyf(f, b, x, 0, 0); err != nil {
- return nil, err
- }
+ } 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