font/sfnt: implement implicit vstem before hintmask.
Change-Id: I811bcf94b518dabcfbebd085ad3c6a47c17ef38e Reviewed-on: https://go-review.googlesource.com/38288 Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
parent
ecc1a9abb6
commit
59d151bf14
|
@ -762,7 +762,8 @@ var psOperators = [...][2][]psOperator{
|
||||||
const escapeByte = 12
|
const escapeByte = 12
|
||||||
|
|
||||||
// t2CReadWidth reads the optional width adjustment. If present, it is on the
|
// t2CReadWidth reads the optional width adjustment. If present, it is on the
|
||||||
// bottom of the stack.
|
// 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,
|
// 5177.Type2.pdf page 16 Note 4 says: "The first stack-clearing operator,
|
||||||
// which must be one of hstem, hstemhm, vstem, vstemhm, cntrmask, hintmask,
|
// which must be one of hstem, hstemhm, vstem, vstemhm, cntrmask, hintmask,
|
||||||
|
@ -773,20 +774,13 @@ func t2CReadWidth(p *psInterpreter, nArgs int32) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p.type2Charstrings.seenWidth = true
|
p.type2Charstrings.seenWidth = true
|
||||||
switch nArgs {
|
if nArgs >= 0 {
|
||||||
case 0:
|
if p.argStack.top != nArgs+1 {
|
||||||
if p.argStack.top != 1 {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
case 1:
|
} else if p.argStack.top&1 == 0 {
|
||||||
if p.argStack.top <= 1 {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
if p.argStack.top%nArgs != 1 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// When parsing a standalone CFF, we'd save the value of p.argStack.a[0]
|
// 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,
|
// here as it defines the glyph's width (horizontal advance). Specifically,
|
||||||
// if present, it is a delta to the font-global nominalWidthX value found
|
// if present, it is a delta to the font-global nominalWidthX value found
|
||||||
|
@ -803,7 +797,7 @@ func t2CReadWidth(p *psInterpreter, nArgs int32) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func t2CStem(p *psInterpreter) error {
|
func t2CStem(p *psInterpreter) error {
|
||||||
t2CReadWidth(p, 2)
|
t2CReadWidth(p, -1)
|
||||||
if p.argStack.top%2 != 0 {
|
if p.argStack.top%2 != 0 {
|
||||||
return errInvalidCFFTable
|
return errInvalidCFFTable
|
||||||
}
|
}
|
||||||
|
@ -818,8 +812,27 @@ func t2CStem(p *psInterpreter) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func t2CMask(p *psInterpreter) error {
|
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
|
hintBytes := (p.type2Charstrings.hintBits + 7) / 8
|
||||||
t2CReadWidth(p, hintBytes)
|
|
||||||
if len(p.instructions) < int(hintBytes) {
|
if len(p.instructions) < int(hintBytes) {
|
||||||
return errInvalidCFFTable
|
return errInvalidCFFTable
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestProprietaryAdobeSourceCodeProOTF(t *testing.T) {
|
func TestProprietaryAdobeSourceCodeProOTF(t *testing.T) {
|
||||||
testProprietary(t, "adobe", "SourceCodePro-Regular.otf", 1500, 34)
|
testProprietary(t, "adobe", "SourceCodePro-Regular.otf", 1500, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProprietaryAdobeSourceCodeProTTF(t *testing.T) {
|
func TestProprietaryAdobeSourceCodeProTTF(t *testing.T) {
|
||||||
|
@ -92,7 +92,7 @@ func TestProprietaryAdobeSourceHanSansSC(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProprietaryAdobeSourceSansProOTF(t *testing.T) {
|
func TestProprietaryAdobeSourceSansProOTF(t *testing.T) {
|
||||||
testProprietary(t, "adobe", "SourceSansPro-Regular.otf", 1800, 34)
|
testProprietary(t, "adobe", "SourceSansPro-Regular.otf", 1800, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProprietaryAdobeSourceSansProTTF(t *testing.T) {
|
func TestProprietaryAdobeSourceSansProTTF(t *testing.T) {
|
||||||
|
@ -112,11 +112,11 @@ func TestProprietaryAppleGeezaPro1(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProprietaryAppleHiragino0(t *testing.T) {
|
func TestProprietaryAppleHiragino0(t *testing.T) {
|
||||||
testProprietary(t, "apple", "ヒラギノ角ゴシック W0.ttc?0", 9000, 6)
|
testProprietary(t, "apple", "ヒラギノ角ゴシック W0.ttc?0", 9000, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProprietaryAppleHiragino1(t *testing.T) {
|
func TestProprietaryAppleHiragino1(t *testing.T) {
|
||||||
testProprietary(t, "apple", "ヒラギノ角ゴシック W0.ttc?1", 9000, 6)
|
testProprietary(t, "apple", "ヒラギノ角ゴシック W0.ttc?1", 9000, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProprietaryMicrosoftArial(t *testing.T) {
|
func TestProprietaryMicrosoftArial(t *testing.T) {
|
||||||
|
@ -442,13 +442,14 @@ var proprietaryGlyphIndexTestCases = map[string]map[rune]GlyphIndex{
|
||||||
|
|
||||||
// proprietaryGlyphTestCases hold a sample of each font's glyph vectors. The
|
// proprietaryGlyphTestCases hold a sample of each font's glyph vectors. The
|
||||||
// numerical values can be verified by running the ttx tool, remembering that:
|
// numerical values can be verified by running the ttx tool, remembering that:
|
||||||
// - for PostScript glyphs, ttx coordinates are relative, and hstem / vstem
|
// - for PostScript glyphs, ttx coordinates are relative.
|
||||||
// operators are hinting-related and can be ignored.
|
|
||||||
// - for TrueType glyphs, ttx coordinates are absolute, and consecutive
|
// - for TrueType glyphs, ttx coordinates are absolute, and consecutive
|
||||||
// off-curve points implies an on-curve point at the midpoint.
|
// off-curve points implies an on-curve point at the midpoint.
|
||||||
var proprietaryGlyphTestCases = map[string]map[rune][]Segment{
|
var proprietaryGlyphTestCases = map[string]map[rune][]Segment{
|
||||||
"adobe/SourceSansPro-Regular.otf": {
|
"adobe/SourceSansPro-Regular.otf": {
|
||||||
',': {
|
',': {
|
||||||
|
// -309 -1 115 hstem
|
||||||
|
// 137 61 vstem
|
||||||
// 67 -170 rmoveto
|
// 67 -170 rmoveto
|
||||||
moveTo(67, -170),
|
moveTo(67, -170),
|
||||||
// 81 34 50 67 86 vvcurveto
|
// 81 34 50 67 86 vvcurveto
|
||||||
|
@ -464,6 +465,8 @@ var proprietaryGlyphTestCases = map[string]map[rune][]Segment{
|
||||||
},
|
},
|
||||||
|
|
||||||
'Q': {
|
'Q': {
|
||||||
|
// 106 -165 70 87 65 538 73 hstem
|
||||||
|
// 52 86 388 87 vstem
|
||||||
// 332 57 rmoveto
|
// 332 57 rmoveto
|
||||||
moveTo(332, 57),
|
moveTo(332, 57),
|
||||||
// -117 -77 106 168 163 77 101 117 117 77 -101 -163 -168 -77 -106 -117 hvcurveto
|
// -117 -77 106 168 163 77 101 117 117 77 -101 -163 -168 -77 -106 -117 hvcurveto
|
||||||
|
@ -492,6 +495,77 @@ var proprietaryGlyphTestCases = map[string]map[rune][]Segment{
|
||||||
// endchar
|
// 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
|
||||||
|
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
|
'ī': { // U+012B LATIN SMALL LETTER I WITH MACRON
|
||||||
// 92 callgsubr # 92 + bias = 199.
|
// 92 callgsubr # 92 + bias = 199.
|
||||||
// : # Arg stack is [].
|
// : # Arg stack is [].
|
||||||
|
@ -587,6 +661,8 @@ var proprietaryGlyphTestCases = map[string]map[rune][]Segment{
|
||||||
},
|
},
|
||||||
|
|
||||||
'Λ': { // U+039B GREEK CAPITAL LETTER LAMDA
|
'Λ': { // U+039B GREEK CAPITAL LETTER LAMDA
|
||||||
|
// -43 21 -21 572 84 hstem
|
||||||
|
// 0 515 vstem
|
||||||
// 0 vmoveto
|
// 0 vmoveto
|
||||||
moveTo(0, 0),
|
moveTo(0, 0),
|
||||||
// 85 hlineto
|
// 85 hlineto
|
||||||
|
@ -607,6 +683,77 @@ var proprietaryGlyphTestCases = map[string]map[rune][]Segment{
|
||||||
lineTo(209, 656),
|
lineTo(209, 656),
|
||||||
// endchar
|
// endchar
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'Ḫ': { // 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
|
||||||
|
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
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
"microsoft/Arial.ttf": {
|
"microsoft/Arial.ttf": {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user