font/sfnt: support cmap format 12.
Change-Id: I2791f5aec860bbb16c6c6945703827afd55c11dc Reviewed-on: https://go-review.googlesource.com/36291 Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
parent
55ae12acc9
commit
c8ab450c16
|
@ -80,7 +80,7 @@ var supportedCmapFormat = func(format, pid, psid uint16) bool {
|
||||||
case 4:
|
case 4:
|
||||||
return true
|
return true
|
||||||
case 12:
|
case 12:
|
||||||
// TODO: implement.
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ func (f *Font) makeCachedGlyphIndex(buf []byte, offset, length uint32, format ui
|
||||||
case 4:
|
case 4:
|
||||||
return f.makeCachedGlyphIndexFormat4(buf, offset, length)
|
return f.makeCachedGlyphIndexFormat4(buf, offset, length)
|
||||||
case 12:
|
case 12:
|
||||||
// TODO: implement, including a cmapEntry32 type (32, not 16).
|
return f.makeCachedGlyphIndexFormat12(buf, offset, length)
|
||||||
}
|
}
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
|
@ -196,6 +196,68 @@ func (f *Font) makeCachedGlyphIndexFormat4(buf []byte, offset, length uint32) ([
|
||||||
return buf, nil
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *Font) makeCachedGlyphIndexFormat12(buf []byte, offset, _ uint32) ([]byte, error) {
|
||||||
|
const headerSize = 16
|
||||||
|
if offset+headerSize > f.cmap.length {
|
||||||
|
return nil, errInvalidCmapTable
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
buf, err = f.src.view(buf, int(f.cmap.offset+offset), headerSize)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
offset += headerSize
|
||||||
|
|
||||||
|
length := u32(buf[4:])
|
||||||
|
numGroups := u32(buf[12:])
|
||||||
|
if f.cmap.length < offset || length > f.cmap.length-offset {
|
||||||
|
return nil, errInvalidCmapTable
|
||||||
|
}
|
||||||
|
if numGroups > maxCmapSegments {
|
||||||
|
return nil, errUnsupportedNumberOfCmapSegments
|
||||||
|
}
|
||||||
|
|
||||||
|
eLength := 12 * numGroups
|
||||||
|
if headerSize+eLength != length {
|
||||||
|
return nil, errInvalidCmapTable
|
||||||
|
}
|
||||||
|
buf, err = f.src.view(buf, int(f.cmap.offset+offset), int(eLength))
|
||||||
|
if err != nil {
|
||||||
|
return 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:]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f.cached.glyphIndex = 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
|
||||||
|
}
|
||||||
|
return buf, nil
|
||||||
|
}
|
||||||
|
|
||||||
type cmapEntry16 struct {
|
type cmapEntry16 struct {
|
||||||
end, start, delta, offset uint16
|
end, start, delta, offset uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type cmapEntry32 struct {
|
||||||
|
start, end, delta uint32
|
||||||
|
}
|
||||||
|
|
|
@ -94,7 +94,7 @@ func TestGlyphIndex(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, format := range []int{-1, 0, 4} {
|
for _, format := range []int{-1, 0, 4, 12} {
|
||||||
testGlyphIndex(t, data, format)
|
testGlyphIndex(t, data, format)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,26 +158,26 @@ func testGlyphIndex(t *testing.T, data []byte, cmapFormat int) {
|
||||||
{'\u4e2d', 12},
|
{'\u4e2d', 12},
|
||||||
{'\u4e2e', 0},
|
{'\u4e2e', 0},
|
||||||
|
|
||||||
/*
|
{'\U0001f0a0', 0},
|
||||||
TODO: support runes above U+FFFF, i.e. cmap format 12.
|
{'\U0001f0a1', 13},
|
||||||
|
{'\U0001f0a2', 0},
|
||||||
|
|
||||||
{'\U0001f0a0', 0},
|
{'\U0001f0b0', 0},
|
||||||
{'\U0001f0a1', 13},
|
{'\U0001f0b1', 14},
|
||||||
{'\U0001f0a2', 0},
|
{'\U0001f0b2', 15},
|
||||||
|
{'\U0001f0b3', 0},
|
||||||
{'\U0001f0b0', 0},
|
|
||||||
{'\U0001f0b1', 14},
|
|
||||||
{'\U0001f0b2', 15},
|
|
||||||
{'\U0001f0b3', 0},
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var b Buffer
|
var b Buffer
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
want := tc.want
|
want := tc.want
|
||||||
// cmap format 0, with the Macintosh Roman encoding, can only represent
|
switch {
|
||||||
// a limited set of non-ASCII runes, e.g. U+00FF.
|
case cmapFormat == 0 && tc.r > '\u007f' && tc.r != '\u00ff':
|
||||||
if 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
|
want = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user