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
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// 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
|
// Package sfnt implements a decoder for SFNT font file formats, including
|
||||||
// TrueType and OpenType.
|
// TrueType and OpenType.
|
||||||
package sfnt // import "golang.org/x/image/font/sfnt"
|
package sfnt // import "golang.org/x/image/font/sfnt"
|
||||||
|
@ -65,6 +67,7 @@ var (
|
||||||
errInvalidLocationData = errors.New("sfnt: invalid location data")
|
errInvalidLocationData = errors.New("sfnt: invalid location data")
|
||||||
errInvalidMaxpTable = errors.New("sfnt: invalid maxp table")
|
errInvalidMaxpTable = errors.New("sfnt: invalid maxp table")
|
||||||
errInvalidNameTable = errors.New("sfnt: invalid name table")
|
errInvalidNameTable = errors.New("sfnt: invalid name table")
|
||||||
|
errInvalidPostTable = errors.New("sfnt: invalid post table")
|
||||||
errInvalidSourceData = errors.New("sfnt: invalid source data")
|
errInvalidSourceData = errors.New("sfnt: invalid source data")
|
||||||
errInvalidTableOffset = errors.New("sfnt: invalid table offset")
|
errInvalidTableOffset = errors.New("sfnt: invalid table offset")
|
||||||
errInvalidTableTagOrder = errors.New("sfnt: invalid table tag order")
|
errInvalidTableTagOrder = errors.New("sfnt: invalid table tag order")
|
||||||
|
@ -80,6 +83,7 @@ var (
|
||||||
errUnsupportedNumberOfHints = errors.New("sfnt: unsupported number of hints")
|
errUnsupportedNumberOfHints = errors.New("sfnt: unsupported number of hints")
|
||||||
errUnsupportedNumberOfTables = errors.New("sfnt: unsupported number of tables")
|
errUnsupportedNumberOfTables = errors.New("sfnt: unsupported number of tables")
|
||||||
errUnsupportedPlatformEncoding = errors.New("sfnt: unsupported platform encoding")
|
errUnsupportedPlatformEncoding = errors.New("sfnt: unsupported platform encoding")
|
||||||
|
errUnsupportedPostTable = errors.New("sfnt: unsupported post table")
|
||||||
errUnsupportedTableOffsetLength = errors.New("sfnt: unsupported table offset or length")
|
errUnsupportedTableOffsetLength = errors.New("sfnt: unsupported table offset or length")
|
||||||
errUnsupportedType2Charstring = errors.New("sfnt: unsupported Type 2 Charstring")
|
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
|
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.
|
// table is a section of the font data.
|
||||||
type table struct {
|
type table struct {
|
||||||
offset, length uint32
|
offset, length uint32
|
||||||
|
@ -298,6 +316,7 @@ type Font struct {
|
||||||
glyphIndex func(f *Font, b *Buffer, r rune) (GlyphIndex, error)
|
glyphIndex func(f *Font, b *Buffer, r rune) (GlyphIndex, error)
|
||||||
indexToLocFormat bool // false means short, true means long.
|
indexToLocFormat bool // false means short, true means long.
|
||||||
isPostScript bool
|
isPostScript bool
|
||||||
|
postTableVersion uint32
|
||||||
unitsPerEm Units
|
unitsPerEm Units
|
||||||
|
|
||||||
// The glyph data for the glyph index i is in
|
// The glyph data for the glyph index i is in
|
||||||
|
@ -320,6 +339,13 @@ func (f *Font) initialize() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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)
|
buf, err = f.parseHead(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -332,6 +358,10 @@ func (f *Font) initialize() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
buf, err = f.parsePost(buf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -538,6 +568,31 @@ func (f *Font) parseMaxp(buf []byte) ([]byte, error) {
|
||||||
return buf, nil
|
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
|
// TODO: API for looking up glyph variants?? For example, some fonts may
|
||||||
// provide both slashed and dotted zero glyphs ('0'), or regular and 'old
|
// provide both slashed and dotted zero glyphs ('0'), or regular and 'old
|
||||||
// style' numerals, and users can direct software to choose a variant.
|
// 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
|
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.
|
// Name returns the name value keyed by the given NameID.
|
||||||
//
|
//
|
||||||
// It returns ErrNotFound if there is no value for that key.
|
// 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)
|
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