font/sfnt: implement Font.GlyphName.
This is based on the post table in the sfnt file. Change-Id: I11f7a9bd9024cfc8f92adc5abb4d5356521f0df7 Reviewed-on: https://go-review.googlesource.com/36972 Reviewed-by: David Crawshaw <crawshaw@golang.org>
This commit is contained in:
parent
153d857a8f
commit
8491f88afc
68
font/sfnt/data.go
Normal file
68
font/sfnt/data.go
Normal file
|
@ -0,0 +1,68 @@
|
|||
// generated by go run gen.go; DO NOT EDIT
|
||||
|
||||
package sfnt
|
||||
|
||||
const numBuiltInPostNames = 258
|
||||
|
||||
const builtInPostNamesData = "" +
|
||||
".notdef.nullnonmarkingreturnspaceexclamquotedblnumbersigndollarp" +
|
||||
"ercentampersandquotesingleparenleftparenrightasteriskpluscommahy" +
|
||||
"phenperiodslashzeroonetwothreefourfivesixseveneightninecolonsemi" +
|
||||
"colonlessequalgreaterquestionatABCDEFGHIJKLMNOPQRSTUVWXYZbracket" +
|
||||
"leftbackslashbracketrightasciicircumunderscoregraveabcdefghijklm" +
|
||||
"nopqrstuvwxyzbraceleftbarbracerightasciitildeAdieresisAringCcedi" +
|
||||
"llaEacuteNtildeOdieresisUdieresisaacuteagraveacircumflexadieresi" +
|
||||
"satildearingccedillaeacuteegraveecircumflexedieresisiacuteigrave" +
|
||||
"icircumflexidieresisntildeoacuteograveocircumflexodieresisotilde" +
|
||||
"uacuteugraveucircumflexudieresisdaggerdegreecentsterlingsectionb" +
|
||||
"ulletparagraphgermandblsregisteredcopyrighttrademarkacutedieresi" +
|
||||
"snotequalAEOslashinfinityplusminuslessequalgreaterequalyenmupart" +
|
||||
"ialdiffsummationproductpiintegralordfeminineordmasculineOmegaaeo" +
|
||||
"slashquestiondownexclamdownlogicalnotradicalflorinapproxequalDel" +
|
||||
"taguillemotleftguillemotrightellipsisnonbreakingspaceAgraveAtild" +
|
||||
"eOtildeOEoeendashemdashquotedblleftquotedblrightquoteleftquoteri" +
|
||||
"ghtdividelozengeydieresisYdieresisfractioncurrencyguilsinglleftg" +
|
||||
"uilsinglrightfifldaggerdblperiodcenteredquotesinglbasequotedblba" +
|
||||
"seperthousandAcircumflexEcircumflexAacuteEdieresisEgraveIacuteIc" +
|
||||
"ircumflexIdieresisIgraveOacuteOcircumflexappleOgraveUacuteUcircu" +
|
||||
"mflexUgravedotlessicircumflextildemacronbrevedotaccentringcedill" +
|
||||
"ahungarumlautogonekcaronLslashlslashScaronscaronZcaronzcaronbrok" +
|
||||
"enbarEthethYacuteyacuteThornthornminusmultiplyonesuperiortwosupe" +
|
||||
"riorthreesuperioronehalfonequarterthreequartersfrancGbrevegbreve" +
|
||||
"IdotaccentScedillascedillaCacutecacuteCcaronccarondcroat"
|
||||
|
||||
var builtInPostNamesOffsets = [...]uint16{
|
||||
0x0000, 0x0007, 0x000c, 0x001c, 0x0021, 0x0027, 0x002f, 0x0039,
|
||||
0x003f, 0x0046, 0x004f, 0x005a, 0x0063, 0x006d, 0x0075, 0x0079,
|
||||
0x007e, 0x0084, 0x008a, 0x008f, 0x0093, 0x0096, 0x0099, 0x009e,
|
||||
0x00a2, 0x00a6, 0x00a9, 0x00ae, 0x00b3, 0x00b7, 0x00bc, 0x00c5,
|
||||
0x00c9, 0x00ce, 0x00d5, 0x00dd, 0x00df, 0x00e0, 0x00e1, 0x00e2,
|
||||
0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea,
|
||||
0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2,
|
||||
0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x0104,
|
||||
0x010d, 0x0119, 0x0124, 0x012e, 0x0133, 0x0134, 0x0135, 0x0136,
|
||||
0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e,
|
||||
0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146,
|
||||
0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d, 0x0156,
|
||||
0x0159, 0x0163, 0x016d, 0x0176, 0x017b, 0x0183, 0x0189, 0x018f,
|
||||
0x0198, 0x01a1, 0x01a7, 0x01ad, 0x01b8, 0x01c1, 0x01c7, 0x01cc,
|
||||
0x01d4, 0x01da, 0x01e0, 0x01eb, 0x01f4, 0x01fa, 0x0200, 0x020b,
|
||||
0x0214, 0x021a, 0x0220, 0x0226, 0x0231, 0x023a, 0x0240, 0x0246,
|
||||
0x024c, 0x0257, 0x0260, 0x0266, 0x026c, 0x0270, 0x0278, 0x027f,
|
||||
0x0285, 0x028e, 0x0298, 0x02a2, 0x02ab, 0x02b4, 0x02b9, 0x02c1,
|
||||
0x02c9, 0x02cb, 0x02d1, 0x02d9, 0x02e2, 0x02eb, 0x02f7, 0x02fa,
|
||||
0x02fc, 0x0307, 0x0310, 0x0317, 0x0319, 0x0321, 0x032c, 0x0338,
|
||||
0x033d, 0x033f, 0x0345, 0x0351, 0x035b, 0x0365, 0x036c, 0x0372,
|
||||
0x037d, 0x0382, 0x038f, 0x039d, 0x03a5, 0x03b5, 0x03bb, 0x03c1,
|
||||
0x03c7, 0x03c9, 0x03cb, 0x03d1, 0x03d7, 0x03e3, 0x03f0, 0x03f9,
|
||||
0x0403, 0x0409, 0x0410, 0x0419, 0x0422, 0x042a, 0x0432, 0x043f,
|
||||
0x044d, 0x044f, 0x0451, 0x045a, 0x0468, 0x0476, 0x0482, 0x048d,
|
||||
0x0498, 0x04a3, 0x04a9, 0x04b2, 0x04b8, 0x04be, 0x04c9, 0x04d2,
|
||||
0x04d8, 0x04de, 0x04e9, 0x04ee, 0x04f4, 0x04fa, 0x0505, 0x050b,
|
||||
0x0513, 0x051d, 0x0522, 0x0528, 0x052d, 0x0536, 0x053a, 0x0541,
|
||||
0x054d, 0x0553, 0x0558, 0x055e, 0x0564, 0x056a, 0x0570, 0x0576,
|
||||
0x057c, 0x0585, 0x0588, 0x058b, 0x0591, 0x0597, 0x059c, 0x05a1,
|
||||
0x05a6, 0x05ae, 0x05b9, 0x05c4, 0x05d1, 0x05d8, 0x05e2, 0x05ef,
|
||||
0x05f4, 0x05fa, 0x0600, 0x060a, 0x0612, 0x061a, 0x0620, 0x0626,
|
||||
0x062c, 0x0632, 0x0638,
|
||||
}
|
321
font/sfnt/gen.go
Normal file
321
font/sfnt/gen.go
Normal file
|
@ -0,0 +1,321 @@
|
|||
// 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.
|
||||
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data, offsets := []byte(nil), []int{0}
|
||||
for _, name := range names {
|
||||
data = append(data, name...)
|
||||
offsets = append(offsets, len(data))
|
||||
}
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
fmt.Fprintf(b, "// generated by go run gen.go; DO NOT EDIT\n\n")
|
||||
fmt.Fprintf(b, "package sfnt\n\n")
|
||||
|
||||
fmt.Fprintf(b, "const numBuiltInPostNames = %d\n\n", len(names))
|
||||
|
||||
fmt.Fprintf(b, "const builtInPostNamesData = \"\" +\n")
|
||||
for s := data; ; {
|
||||
if len(s) <= 64 {
|
||||
fmt.Fprintf(b, "%q\n", s)
|
||||
break
|
||||
}
|
||||
fmt.Fprintf(b, "%q +\n", s[:64])
|
||||
s = s[64:]
|
||||
}
|
||||
fmt.Fprintf(b, "\n")
|
||||
|
||||
fmt.Fprintf(b, "var builtInPostNamesOffsets = [...]uint16{\n")
|
||||
for i, o := range offsets {
|
||||
fmt.Fprintf(b, "%#04x,", o)
|
||||
if i%8 == 7 {
|
||||
fmt.Fprintf(b, "\n")
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(b, "\n}\n")
|
||||
|
||||
dstUnformatted := b.Bytes()
|
||||
dst, err := format.Source(dstUnformatted)
|
||||
if err != nil {
|
||||
log.Fatalf("format.Source: %v\n\n----\n%s\n----", err, dstUnformatted)
|
||||
}
|
||||
if err := ioutil.WriteFile("data.go", dst, 0666); err != nil {
|
||||
log.Fatalf("ioutil.WriteFile: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// names is the built-in post table names listed at
|
||||
// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6post.html
|
||||
var names = [258]string{
|
||||
".notdef",
|
||||
".null",
|
||||
"nonmarkingreturn",
|
||||
"space",
|
||||
"exclam",
|
||||
"quotedbl",
|
||||
"numbersign",
|
||||
"dollar",
|
||||
"percent",
|
||||
"ampersand",
|
||||
"quotesingle",
|
||||
"parenleft",
|
||||
"parenright",
|
||||
"asterisk",
|
||||
"plus",
|
||||
"comma",
|
||||
"hyphen",
|
||||
"period",
|
||||
"slash",
|
||||
"zero",
|
||||
"one",
|
||||
"two",
|
||||
"three",
|
||||
"four",
|
||||
"five",
|
||||
"six",
|
||||
"seven",
|
||||
"eight",
|
||||
"nine",
|
||||
"colon",
|
||||
"semicolon",
|
||||
"less",
|
||||
"equal",
|
||||
"greater",
|
||||
"question",
|
||||
"at",
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F",
|
||||
"G",
|
||||
"H",
|
||||
"I",
|
||||
"J",
|
||||
"K",
|
||||
"L",
|
||||
"M",
|
||||
"N",
|
||||
"O",
|
||||
"P",
|
||||
"Q",
|
||||
"R",
|
||||
"S",
|
||||
"T",
|
||||
"U",
|
||||
"V",
|
||||
"W",
|
||||
"X",
|
||||
"Y",
|
||||
"Z",
|
||||
"bracketleft",
|
||||
"backslash",
|
||||
"bracketright",
|
||||
"asciicircum",
|
||||
"underscore",
|
||||
"grave",
|
||||
"a",
|
||||
"b",
|
||||
"c",
|
||||
"d",
|
||||
"e",
|
||||
"f",
|
||||
"g",
|
||||
"h",
|
||||
"i",
|
||||
"j",
|
||||
"k",
|
||||
"l",
|
||||
"m",
|
||||
"n",
|
||||
"o",
|
||||
"p",
|
||||
"q",
|
||||
"r",
|
||||
"s",
|
||||
"t",
|
||||
"u",
|
||||
"v",
|
||||
"w",
|
||||
"x",
|
||||
"y",
|
||||
"z",
|
||||
"braceleft",
|
||||
"bar",
|
||||
"braceright",
|
||||
"asciitilde",
|
||||
"Adieresis",
|
||||
"Aring",
|
||||
"Ccedilla",
|
||||
"Eacute",
|
||||
"Ntilde",
|
||||
"Odieresis",
|
||||
"Udieresis",
|
||||
"aacute",
|
||||
"agrave",
|
||||
"acircumflex",
|
||||
"adieresis",
|
||||
"atilde",
|
||||
"aring",
|
||||
"ccedilla",
|
||||
"eacute",
|
||||
"egrave",
|
||||
"ecircumflex",
|
||||
"edieresis",
|
||||
"iacute",
|
||||
"igrave",
|
||||
"icircumflex",
|
||||
"idieresis",
|
||||
"ntilde",
|
||||
"oacute",
|
||||
"ograve",
|
||||
"ocircumflex",
|
||||
"odieresis",
|
||||
"otilde",
|
||||
"uacute",
|
||||
"ugrave",
|
||||
"ucircumflex",
|
||||
"udieresis",
|
||||
"dagger",
|
||||
"degree",
|
||||
"cent",
|
||||
"sterling",
|
||||
"section",
|
||||
"bullet",
|
||||
"paragraph",
|
||||
"germandbls",
|
||||
"registered",
|
||||
"copyright",
|
||||
"trademark",
|
||||
"acute",
|
||||
"dieresis",
|
||||
"notequal",
|
||||
"AE",
|
||||
"Oslash",
|
||||
"infinity",
|
||||
"plusminus",
|
||||
"lessequal",
|
||||
"greaterequal",
|
||||
"yen",
|
||||
"mu",
|
||||
"partialdiff",
|
||||
"summation",
|
||||
"product",
|
||||
"pi",
|
||||
"integral",
|
||||
"ordfeminine",
|
||||
"ordmasculine",
|
||||
"Omega",
|
||||
"ae",
|
||||
"oslash",
|
||||
"questiondown",
|
||||
"exclamdown",
|
||||
"logicalnot",
|
||||
"radical",
|
||||
"florin",
|
||||
"approxequal",
|
||||
"Delta",
|
||||
"guillemotleft",
|
||||
"guillemotright",
|
||||
"ellipsis",
|
||||
"nonbreakingspace",
|
||||
"Agrave",
|
||||
"Atilde",
|
||||
"Otilde",
|
||||
"OE",
|
||||
"oe",
|
||||
"endash",
|
||||
"emdash",
|
||||
"quotedblleft",
|
||||
"quotedblright",
|
||||
"quoteleft",
|
||||
"quoteright",
|
||||
"divide",
|
||||
"lozenge",
|
||||
"ydieresis",
|
||||
"Ydieresis",
|
||||
"fraction",
|
||||
"currency",
|
||||
"guilsinglleft",
|
||||
"guilsinglright",
|
||||
"fi",
|
||||
"fl",
|
||||
"daggerdbl",
|
||||
"periodcentered",
|
||||
"quotesinglbase",
|
||||
"quotedblbase",
|
||||
"perthousand",
|
||||
"Acircumflex",
|
||||
"Ecircumflex",
|
||||
"Aacute",
|
||||
"Edieresis",
|
||||
"Egrave",
|
||||
"Iacute",
|
||||
"Icircumflex",
|
||||
"Idieresis",
|
||||
"Igrave",
|
||||
"Oacute",
|
||||
"Ocircumflex",
|
||||
"apple",
|
||||
"Ograve",
|
||||
"Uacute",
|
||||
"Ucircumflex",
|
||||
"Ugrave",
|
||||
"dotlessi",
|
||||
"circumflex",
|
||||
"tilde",
|
||||
"macron",
|
||||
"breve",
|
||||
"dotaccent",
|
||||
"ring",
|
||||
"cedilla",
|
||||
"hungarumlaut",
|
||||
"ogonek",
|
||||
"caron",
|
||||
"Lslash",
|
||||
"lslash",
|
||||
"Scaron",
|
||||
"scaron",
|
||||
"Zcaron",
|
||||
"zcaron",
|
||||
"brokenbar",
|
||||
"Eth",
|
||||
"eth",
|
||||
"Yacute",
|
||||
"yacute",
|
||||
"Thorn",
|
||||
"thorn",
|
||||
"minus",
|
||||
"multiply",
|
||||
"onesuperior",
|
||||
"twosuperior",
|
||||
"threesuperior",
|
||||
"onehalf",
|
||||
"onequarter",
|
||||
"threequarters",
|
||||
"franc",
|
||||
"Gbreve",
|
||||
"gbreve",
|
||||
"Idotaccent",
|
||||
"Scedilla",
|
||||
"scedilla",
|
||||
"Cacute",
|
||||
"cacute",
|
||||
"Ccaron",
|
||||
"ccaron",
|
||||
"dcroat",
|
||||
}
|
|
@ -2,6 +2,8 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go run gen.go
|
||||
|
||||
// Package sfnt implements a decoder for SFNT font file formats, including
|
||||
// TrueType and OpenType.
|
||||
package sfnt // import "golang.org/x/image/font/sfnt"
|
||||
|
@ -65,6 +67,7 @@ var (
|
|||
errInvalidLocationData = errors.New("sfnt: invalid location data")
|
||||
errInvalidMaxpTable = errors.New("sfnt: invalid maxp table")
|
||||
errInvalidNameTable = errors.New("sfnt: invalid name table")
|
||||
errInvalidPostTable = errors.New("sfnt: invalid post table")
|
||||
errInvalidSourceData = errors.New("sfnt: invalid source data")
|
||||
errInvalidTableOffset = errors.New("sfnt: invalid table offset")
|
||||
errInvalidTableTagOrder = errors.New("sfnt: invalid table tag order")
|
||||
|
@ -80,6 +83,7 @@ var (
|
|||
errUnsupportedNumberOfHints = errors.New("sfnt: unsupported number of hints")
|
||||
errUnsupportedNumberOfTables = errors.New("sfnt: unsupported number of tables")
|
||||
errUnsupportedPlatformEncoding = errors.New("sfnt: unsupported platform encoding")
|
||||
errUnsupportedPostTable = errors.New("sfnt: unsupported post table")
|
||||
errUnsupportedTableOffsetLength = errors.New("sfnt: unsupported table offset or length")
|
||||
errUnsupportedType2Charstring = errors.New("sfnt: unsupported Type 2 Charstring")
|
||||
)
|
||||
|
@ -217,6 +221,20 @@ func (s *source) u16(buf []byte, t table, i int) (uint16, error) {
|
|||
return u16(buf), nil
|
||||
}
|
||||
|
||||
// u32 returns the uint32 in the table t at the relative offset i.
|
||||
//
|
||||
// buf is an optional scratch buffer as per the source.view method.
|
||||
func (s *source) u32(buf []byte, t table, i int) (uint32, error) {
|
||||
if i < 0 || uint(t.length) < uint(i+4) {
|
||||
return 0, errInvalidBounds
|
||||
}
|
||||
buf, err := s.view(buf, int(t.offset)+i, 4)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return u32(buf), nil
|
||||
}
|
||||
|
||||
// table is a section of the font data.
|
||||
type table struct {
|
||||
offset, length uint32
|
||||
|
@ -298,6 +316,7 @@ type Font struct {
|
|||
glyphIndex func(f *Font, b *Buffer, r rune) (GlyphIndex, error)
|
||||
indexToLocFormat bool // false means short, true means long.
|
||||
isPostScript bool
|
||||
postTableVersion uint32
|
||||
unitsPerEm Units
|
||||
|
||||
// The glyph data for the glyph index i is in
|
||||
|
@ -320,6 +339,13 @@ func (f *Font) initialize() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// The order of these parseXxx calls matters. Later calls may depend on
|
||||
// f.cached state set up by earlier calls, such as the number of glyphs in
|
||||
// the font being parsed by parseMaxp.
|
||||
|
||||
// TODO: make state dependencies explicit instead of implicit.
|
||||
|
||||
buf, err = f.parseHead(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -332,6 +358,10 @@ func (f *Font) initialize() error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf, err = f.parsePost(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -538,6 +568,31 @@ func (f *Font) parseMaxp(buf []byte) ([]byte, error) {
|
|||
return buf, nil
|
||||
}
|
||||
|
||||
func (f *Font) parsePost(buf []byte) ([]byte, error) {
|
||||
// https://www.microsoft.com/typography/otspec/post.htm
|
||||
|
||||
const headerSize = 32
|
||||
if f.post.length < headerSize {
|
||||
return nil, errInvalidPostTable
|
||||
}
|
||||
u, err := f.src.u32(buf, f.post, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch u {
|
||||
case 0x20000:
|
||||
if f.post.length < headerSize+2+2*uint32(f.NumGlyphs()) {
|
||||
return nil, errInvalidPostTable
|
||||
}
|
||||
case 0x30000:
|
||||
// No-op.
|
||||
default:
|
||||
return nil, errUnsupportedPostTable
|
||||
}
|
||||
f.cached.postTableVersion = u
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
// TODO: API for looking up glyph variants?? For example, some fonts may
|
||||
// provide both slashed and dotted zero glyphs ('0'), or regular and 'old
|
||||
// style' numerals, and users can direct software to choose a variant.
|
||||
|
@ -606,6 +661,78 @@ func (f *Font) LoadGlyph(b *Buffer, x GlyphIndex, opts *LoadGlyphOptions) ([]Seg
|
|||
return b.segments, nil
|
||||
}
|
||||
|
||||
// GlyphName returns the name of the x'th glyph.
|
||||
//
|
||||
// Not every font contains glyph names. If not present, GlyphName will return
|
||||
// ("", nil).
|
||||
//
|
||||
// If present, the glyph name, provided by the font, is assumed to follow the
|
||||
// Adobe Glyph List Specification:
|
||||
// https://github.com/adobe-type-tools/agl-specification/blob/master/README.md
|
||||
//
|
||||
// This is also known as the "Adobe Glyph Naming convention", the "Adobe
|
||||
// document [for] Unicode and Glyph Names" or "PostScript glyph names".
|
||||
//
|
||||
// It returns ErrNotFound if the glyph index is out of range.
|
||||
func (f *Font) GlyphName(b *Buffer, x GlyphIndex) (string, error) {
|
||||
if int(x) >= f.NumGlyphs() {
|
||||
return "", ErrNotFound
|
||||
}
|
||||
if f.cached.postTableVersion != 0x20000 {
|
||||
return "", nil
|
||||
}
|
||||
if b == nil {
|
||||
b = &Buffer{}
|
||||
}
|
||||
|
||||
// The wire format for a Version 2 post table is documented at:
|
||||
// https://www.microsoft.com/typography/otspec/post.htm
|
||||
const glyphNameIndexOffset = 34
|
||||
|
||||
buf, err := b.view(&f.src, int(f.post.offset)+glyphNameIndexOffset+2*int(x), 2)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
u := u16(buf)
|
||||
if u < numBuiltInPostNames {
|
||||
i := builtInPostNamesOffsets[u+0]
|
||||
j := builtInPostNamesOffsets[u+1]
|
||||
return builtInPostNamesData[i:j], nil
|
||||
}
|
||||
// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6post.html
|
||||
// says that "32768 through 65535 are reserved for future use".
|
||||
if u > 32767 {
|
||||
return "", errUnsupportedPostTable
|
||||
}
|
||||
u -= numBuiltInPostNames
|
||||
|
||||
// Iterate through the list of Pascal-formatted strings. A linear scan is
|
||||
// clearly O(u), which isn't great (as the obvious loop, calling
|
||||
// Font.GlyphName, to get all of the glyph names in a font has quadratic
|
||||
// complexity), but the wire format doesn't suggest a better alternative.
|
||||
|
||||
offset := glyphNameIndexOffset + 2*f.NumGlyphs()
|
||||
buf, err = b.view(&f.src, int(f.post.offset)+offset, int(f.post.length)-offset)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for {
|
||||
if len(buf) == 0 {
|
||||
return "", errInvalidPostTable
|
||||
}
|
||||
n := 1 + int(buf[0])
|
||||
if len(buf) < n {
|
||||
return "", errInvalidPostTable
|
||||
}
|
||||
if u == 0 {
|
||||
return string(buf[1:n]), nil
|
||||
}
|
||||
buf = buf[n:]
|
||||
u--
|
||||
}
|
||||
}
|
||||
|
||||
// Name returns the name value keyed by the given NameID.
|
||||
//
|
||||
// It returns ErrNotFound if there is no value for that key.
|
||||
|
|
|
@ -431,3 +431,77 @@ loop:
|
|||
t.Errorf("Name:\ngot %q\nwant %q", name, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGlyphName(t *testing.T) {
|
||||
f, err := Parse(goregular.TTF)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse: %v", err)
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
r rune
|
||||
want string
|
||||
}{
|
||||
{'\x00', "NULL"},
|
||||
{'!', "exclam"},
|
||||
{'A', "A"},
|
||||
{'{', "braceleft"},
|
||||
{'\u00c4', "Adieresis"}, // U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS
|
||||
{'\u2020', "dagger"}, // U+2020 DAGGER
|
||||
{'\u2660', "spade"}, // U+2660 BLACK SPADE SUIT
|
||||
{'\uf800', "gopher"}, // U+F800 <Private Use>
|
||||
{'\ufffe', ".notdef"}, // Not in the Go Regular font, so GlyphIndex returns (0, nil).
|
||||
}
|
||||
|
||||
var b Buffer
|
||||
for _, tc := range testCases {
|
||||
x, err := f.GlyphIndex(&b, tc.r)
|
||||
if err != nil {
|
||||
t.Errorf("r=%q: GlyphIndex: %v", tc.r, err)
|
||||
continue
|
||||
}
|
||||
got, err := f.GlyphName(&b, x)
|
||||
if err != nil {
|
||||
t.Errorf("r=%q: GlyphName: %v", tc.r, err)
|
||||
continue
|
||||
}
|
||||
if got != tc.want {
|
||||
t.Errorf("r=%q: got %q, want %q", tc.r, got, tc.want)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuiltInPostNames(t *testing.T) {
|
||||
testCases := []struct {
|
||||
x GlyphIndex
|
||||
want string
|
||||
}{
|
||||
{0, ".notdef"},
|
||||
{1, ".null"},
|
||||
{2, "nonmarkingreturn"},
|
||||
{13, "asterisk"},
|
||||
{36, "A"},
|
||||
{93, "z"},
|
||||
{123, "ocircumflex"},
|
||||
{202, "Edieresis"},
|
||||
{255, "Ccaron"},
|
||||
{256, "ccaron"},
|
||||
{257, "dcroat"},
|
||||
{258, ""},
|
||||
{999, ""},
|
||||
{0xffff, ""},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
if tc.x >= numBuiltInPostNames {
|
||||
continue
|
||||
}
|
||||
i := builtInPostNamesOffsets[tc.x+0]
|
||||
j := builtInPostNamesOffsets[tc.x+1]
|
||||
got := builtInPostNamesData[i:j]
|
||||
if got != tc.want {
|
||||
t.Errorf("x=%d: got %q, want %q", tc.x, got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user