font/sfnt: add tests for proprietary fonts.
Change-Id: I1886e24f726598654d2474f0219a8046ba184a9f Reviewed-on: https://go-review.googlesource.com/36370 Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
parent
c8ab450c16
commit
28d9a8b4a3
164
font/sfnt/proprietary_test.go
Normal file
164
font/sfnt/proprietary_test.go
Normal file
|
@ -0,0 +1,164 @@
|
|||
// 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=/foo/bar/aFonts -microsoftDir=/foo/bar/mFonts
|
||||
|
||||
To only run those tests for the Microsoft fonts:
|
||||
|
||||
go test golang.org/x/image/font/sfnt -test.run=ProprietaryMicrosoft -args -proprietary
|
||||
*/
|
||||
|
||||
// TODO: add Apple system fonts? Google fonts (Droid? Noto?)? Emoji fonts?
|
||||
|
||||
// TODO: enable Apple/Microsoft tests by default on Darwin/Windows?
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
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",
|
||||
)
|
||||
|
||||
microsoftDir = flag.String(
|
||||
"microsoftDir",
|
||||
"/usr/share/fonts/truetype/msttcorefonts",
|
||||
"directory name for the Microsoft proprietary fonts",
|
||||
)
|
||||
)
|
||||
|
||||
type proprietor int
|
||||
|
||||
const (
|
||||
adobe proprietor = iota
|
||||
microsoft
|
||||
)
|
||||
|
||||
func TestProprietaryAdobeSourceCodeProOTF(t *testing.T) {
|
||||
testProprietary(t, adobe, "SourceCodePro-Regular.otf", 1500, 2)
|
||||
}
|
||||
|
||||
func TestProprietaryAdobeSourceCodeProTTF(t *testing.T) {
|
||||
testProprietary(t, adobe, "SourceCodePro-Regular.ttf", 1500, 36)
|
||||
}
|
||||
|
||||
func TestProprietaryAdobeSourceHanSansSC(t *testing.T) {
|
||||
testProprietary(t, adobe, "SourceHanSansSC-Regular.otf", 65535, 2)
|
||||
}
|
||||
|
||||
func TestProprietaryAdobeSourceSansProOTF(t *testing.T) {
|
||||
testProprietary(t, adobe, "SourceSansPro-Regular.otf", 1800, 2)
|
||||
}
|
||||
|
||||
func TestProprietaryAdobeSourceSansProTTF(t *testing.T) {
|
||||
// The 1000 here is smaller than the 1800 above. For some reason, the TTF
|
||||
// version of the file has fewer glyphs than the (presumably canonical) OTF
|
||||
// version. The number of glyphs in the .otf and .ttf files can be verified
|
||||
// with the ttx tool.
|
||||
testProprietary(t, adobe, "SourceSansPro-Regular.ttf", 1000, 56)
|
||||
}
|
||||
|
||||
func TestProprietaryMicrosoftArial(t *testing.T) {
|
||||
testProprietary(t, microsoft, "Arial.ttf", 1200, 98)
|
||||
}
|
||||
|
||||
func TestProprietaryMicrosoftComicSansMS(t *testing.T) {
|
||||
testProprietary(t, microsoft, "Comic_Sans_MS.ttf", 550, 98)
|
||||
}
|
||||
|
||||
func TestProprietaryMicrosoftTimesNewRoman(t *testing.T) {
|
||||
testProprietary(t, microsoft, "Times_New_Roman.ttf", 1200, 98)
|
||||
}
|
||||
|
||||
func TestProprietaryMicrosoftWebdings(t *testing.T) {
|
||||
testProprietary(t, microsoft, "Webdings.ttf", 200, -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, p proprietor, filename string, minNumGlyphs, firstUnsupportedGlyph int) {
|
||||
if !*proprietary {
|
||||
t.Skip("skipping proprietary font test")
|
||||
}
|
||||
|
||||
file, err := []byte(nil), error(nil)
|
||||
switch p {
|
||||
case adobe:
|
||||
file, err = ioutil.ReadFile(filepath.Join(*adobeDir, filename))
|
||||
if err != nil {
|
||||
t.Fatalf("%v\nPerhaps you need to set the -adobeDir=%v flag?", err, *adobeDir)
|
||||
}
|
||||
case microsoft:
|
||||
file, err = ioutil.ReadFile(filepath.Join(*microsoftDir, filename))
|
||||
if err != nil {
|
||||
t.Fatalf("%v\nPerhaps you need to set the -microsoftDir=%v flag?", err, *microsoftDir)
|
||||
}
|
||||
}
|
||||
f, err := Parse(file)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse: %v", err)
|
||||
}
|
||||
|
||||
numGlyphs := f.NumGlyphs()
|
||||
if numGlyphs < minNumGlyphs {
|
||||
t.Fatalf("NumGlyphs: got %d, want at least %d", numGlyphs, minNumGlyphs)
|
||||
}
|
||||
|
||||
var buf Buffer
|
||||
iMax := numGlyphs
|
||||
if firstUnsupportedGlyph >= 0 {
|
||||
iMax = firstUnsupportedGlyph
|
||||
}
|
||||
for i, numErrors := 0, 0; i < iMax; i++ {
|
||||
if _, err := f.LoadGlyph(&buf, GlyphIndex(i), nil); err != nil {
|
||||
t.Errorf("LoadGlyph(%d): %v", i, err)
|
||||
numErrors++
|
||||
}
|
||||
if numErrors == 10 {
|
||||
t.Fatal("LoadGlyph: too many errors")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,7 +28,11 @@ import (
|
|||
// These constants are not part of the specifications, but are limitations used
|
||||
// by this implementation.
|
||||
const (
|
||||
maxCmapSegments = 1024
|
||||
// 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 1581 cmap segments.
|
||||
maxCmapSegments = 4096
|
||||
|
||||
maxGlyphDataLength = 64 * 1024
|
||||
maxHintBits = 256
|
||||
maxNumTables = 256
|
||||
|
|
|
@ -113,6 +113,11 @@ func appendGlyfSegments(dst []Segment, data []byte) ([]Segment, error) {
|
|||
return nil, errInvalidGlyphData
|
||||
}
|
||||
|
||||
// TODO: support compound glyphs.
|
||||
if numContours < 0 {
|
||||
return nil, errUnsupportedCompoundGlyph
|
||||
}
|
||||
|
||||
// Skip the hinting instructions.
|
||||
index += 2
|
||||
if index > len(data) {
|
||||
|
@ -124,11 +129,6 @@ func appendGlyfSegments(dst []Segment, data []byte) ([]Segment, error) {
|
|||
return nil, errInvalidGlyphData
|
||||
}
|
||||
|
||||
// TODO: support compound glyphs.
|
||||
if numContours < 0 {
|
||||
return nil, errUnsupportedCompoundGlyph
|
||||
}
|
||||
|
||||
// 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 co-ordinates,
|
||||
|
|
Loading…
Reference in New Issue
Block a user