font/sfnt: support cmap format 6

The library provides support for CMap formats 2, 4 and 12, but
does not support CMap format 6.

CL adds support for CMap format 6 (trimmed table mapping).

Change-Id: I40657c4805c14017367af17596023da96b2c7483
Reviewed-on: https://go-review.googlesource.com/c/146079
Reviewed-by: Nigel Tao <nigeltao@golang.org>
Run-TryBot: Nigel Tao <nigeltao@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/font/sfnt/cmap.go b/font/sfnt/cmap.go
index 797e9d1..55b4ead 100644
--- a/font/sfnt/cmap.go
+++ b/font/sfnt/cmap.go
@@ -80,6 +80,8 @@
 		return pid == pidMacintosh && psid == psidMacintoshRoman
 	case 4:
 		return true
+	case 6:
+		return true
 	case 12:
 		return true
 	}
@@ -92,6 +94,8 @@
 		return f.makeCachedGlyphIndexFormat0(buf, offset, length)
 	case 4:
 		return f.makeCachedGlyphIndexFormat4(buf, offset, length)
+	case 6:
+		return f.makeCachedGlyphIndexFormat6(buf, offset, length)
 	case 12:
 		return f.makeCachedGlyphIndexFormat12(buf, offset, length)
 	}
@@ -193,6 +197,52 @@
 	}, nil
 }
 
+func (f *Font) makeCachedGlyphIndexFormat6(buf []byte, offset, length uint32) ([]byte, glyphIndexFunc, error) {
+	const headerSize = 10
+	if offset+headerSize > f.cmap.length {
+		return nil, nil, errInvalidCmapTable
+	}
+	var err error
+	buf, err = f.src.view(buf, int(f.cmap.offset+offset), headerSize)
+	if err != nil {
+		return nil, nil, err
+	}
+	offset += headerSize
+
+	firstCode := u16(buf[6:])
+	entryCount := u16(buf[8:])
+
+	eLength := 2 * uint32(entryCount)
+	if offset+eLength > f.cmap.length {
+		return nil, nil, errInvalidCmapTable
+	}
+
+	if entryCount != 0 {
+		buf, err = f.src.view(buf, int(f.cmap.offset+offset), int(eLength))
+		if err != nil {
+			return nil, nil, err
+		}
+		offset += eLength
+	}
+
+	entries := make([]uint16, entryCount)
+	for i := range entries {
+		entries[i] = u16(buf[2*i:])
+	}
+
+	return buf, func(f *Font, b *Buffer, r rune) (GlyphIndex, error) {
+		if uint16(r) < firstCode {
+			return 0, nil
+		}
+
+		c := int(uint16(r) - firstCode)
+		if c >= len(entries) {
+			return 0, nil
+		}
+		return GlyphIndex(entries[c]), nil
+	}, nil
+}
+
 func (f *Font) makeCachedGlyphIndexFormat12(buf []byte, offset, _ uint32) ([]byte, glyphIndexFunc, error) {
 	const headerSize = 16
 	if offset+headerSize > f.cmap.length {