font/sfnt: support parsing legacy fonts with OS2 table version <= 1
Library assumes that OS/2 header size is at least 96 bytes, which is not the case for fonts with OS/2 table version <= 1. This CL adds a version test and handles the legacy header. Fixes golang/go#28339 Change-Id: I79bd8f8bbf262c1caaf4e66888446159b5e4fb43 Reviewed-on: https://go-review.googlesource.com/c/144079 Reviewed-by: Nigel Tao <nigeltao@golang.org> Reviewed-by: Elias Naur <elias.naur@gmail.com>
This commit is contained in:
parent
9b1e201e7c
commit
2a2258ff36
|
@ -637,7 +637,7 @@ func (f *Font) initialize(offset int, isDfont bool) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
buf, xHeight, capHeight, err := f.parseOS2(buf)
|
buf, os2Vers, xHeight, capHeight, err := f.parseOS2(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -664,6 +664,15 @@ func (f *Font) initialize(offset int, isDfont bool) error {
|
||||||
f.cached.unitsPerEm = unitsPerEm
|
f.cached.unitsPerEm = unitsPerEm
|
||||||
f.cached.xHeight = xHeight
|
f.cached.xHeight = xHeight
|
||||||
|
|
||||||
|
if os2Vers <= 1 {
|
||||||
|
xh, ch, err := f.initOS2Version1()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f.cached.xHeight = xh
|
||||||
|
f.cached.capHeight = ch
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1065,22 +1074,80 @@ func (f *Font) parseGlyphData(buf []byte, numGlyphs int32, indexToLocFormat, isP
|
||||||
return buf, ret, isColorBitmap, nil
|
return buf, ret, isColorBitmap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Font) parseOS2(buf []byte) (buf1 []byte, xHeight, capHeight int32, err error) {
|
func (f *Font) glyphTopOS2(b *Buffer, ppem fixed.Int26_6, r rune) (int32, error) {
|
||||||
// https://docs.microsoft.com/da-dk/typography/opentype/spec/os2
|
ind, err := f.GlyphIndex(b, r)
|
||||||
|
if err != nil && err != ErrNotFound {
|
||||||
|
return 0, err
|
||||||
|
} else if ind == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
// Y axis points down
|
||||||
|
var min fixed.Int26_6
|
||||||
|
seg, err := f.LoadGlyph(b, ind, ppem, nil)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
for _, s := range seg {
|
||||||
|
for _, p := range s.Args {
|
||||||
|
if p.Y < min {
|
||||||
|
min = p.Y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return int32(min), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Font) initOS2Version1() (xHeight, capHeight int32, err error) {
|
||||||
|
ppem := fixed.Int26_6(f.UnitsPerEm())
|
||||||
|
var b Buffer
|
||||||
|
|
||||||
|
// sxHeight equal to the top of the unscaled and unhinted glyph bounding box
|
||||||
|
// of the glyph encoded at U+0078 (LATIN SMALL LETTER X).
|
||||||
|
xh, err := f.glyphTopOS2(&b, ppem, 'x')
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// sCapHeight may be set equal to the top of the unscaled and unhinted glyph
|
||||||
|
// bounding box of the glyph encoded at U+0048 (LATIN CAPITAL LETTER H).
|
||||||
|
ch, err := f.glyphTopOS2(&b, ppem, 'H')
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return int32(xh), int32(ch), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Font) parseOS2(buf []byte) (buf1 []byte, version uint16, xHeight, capHeight int32, err error) {
|
||||||
|
// https://docs.microsoft.com/da-dk/typography/opentype/spec/os2
|
||||||
|
if f.os2.length < 2 {
|
||||||
|
return nil, 0, 0, 0, errInvalidOS2Table
|
||||||
|
}
|
||||||
|
vers, err := f.src.u16(buf, f.os2, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, 0, 0, err
|
||||||
|
}
|
||||||
|
if vers <= 1 {
|
||||||
|
const headerSize = 86
|
||||||
|
if f.os2.length < headerSize {
|
||||||
|
return nil, 0, 0, 0, errInvalidOS2Table
|
||||||
|
}
|
||||||
|
// Will resolve xHeight and capHeight later, see initOS2Version1.
|
||||||
|
return buf, vers, 0, 0, nil
|
||||||
|
}
|
||||||
const headerSize = 96
|
const headerSize = 96
|
||||||
if f.os2.length < headerSize {
|
if f.os2.length < headerSize {
|
||||||
return nil, 0, 0, errInvalidOS2Table
|
return nil, 0, 0, 0, errInvalidOS2Table
|
||||||
}
|
}
|
||||||
xh, err := f.src.u16(buf, f.os2, 86)
|
xh, err := f.src.u16(buf, f.os2, 86)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, 0, err
|
return nil, 0, 0, 0, err
|
||||||
}
|
}
|
||||||
ch, err := f.src.u16(buf, f.os2, 88)
|
ch, err := f.src.u16(buf, f.os2, 88)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, 0, err
|
return nil, 0, 0, 0, err
|
||||||
}
|
}
|
||||||
return buf, int32(int16(xh)), int32(int16(ch)), nil
|
return buf, vers, int32(int16(xh)), int32(int16(ch)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Font) parsePost(buf []byte, numGlyphs int32) (buf1 []byte, postTableVersion uint32, err error) {
|
func (f *Font) parsePost(buf []byte, numGlyphs int32) (buf1 []byte, postTableVersion uint32, err error) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user