font-cff.lua /size: 86 Kb    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
font-cff
'
]
=
{
2
version
=
1
.
001
,
3
comment
=
"
companion to font-ini.mkiv
"
,
4
author
=
"
Hans Hagen, PRAGMA-ADE, Hasselt NL
"
,
5
copyright
=
"
PRAGMA ADE / ConTeXt Development Team
"
,
6
license
=
"
see context related readme files
"
7
}
8 9
-- todo: option.outlines
10
-- todo: option.boundingbox
11
-- per charstring (less memory)
12 13
-- This is a heavy one as it is a rather packed format. We don't need al the information
14
-- now but we might need it later (who know what magic we can do with metapost). So at
15
-- some point this might become a module. We just follow Adobe Technical Notes #5176 and
16
-- #5177. In case of doubt I looked in the fontforge code that comes with LuaTeX but
17
-- it's not the easiest source to read (and doesn't cover cff2).
18 19
-- For now we save the segments in a list of segments with the operator last in an entry
20
-- because that reflects the original. But it might make more sense to use a single array
21
-- per segment. For pdf a simple concat works ok, but for other purposes a operator first
22
-- flush is nicer.
23
--
24
-- In retrospect I could have looked into the backend code of LuaTeX but it never
25
-- occurred to me that parsing charstrings was needed there (which has to to
26
-- with merging subroutines and flattening, not so much with calculations.) On
27
-- the other hand, we can now feed back cff2 stuff.
28 29
local
next
,
type
,
tonumber
,
rawget
=
next
,
type
,
tonumber
,
rawget
30
local
byte
,
char
,
gmatch
,
sub
=
string
.
byte
,
string
.
char
,
string
.
gmatch
,
string
.
sub
31
local
concat
,
remove
,
unpack
=
table
.
concat
,
table
.
remove
,
table
.
unpack
32
local
floor
,
abs
,
round
,
ceil
,
min
,
max
=
math
.
floor
,
math
.
abs
,
math
.
round
,
math
.
ceil
,
math
.
min
,
math
.
max
33
local
P
,
C
,
R
,
S
,
C
,
Cs
,
Ct
=
lpeg
.
P
,
lpeg
.
C
,
lpeg
.
R
,
lpeg
.
S
,
lpeg
.
C
,
lpeg
.
Cs
,
lpeg
.
Ct
34
local
lpegmatch
=
lpeg
.
match
35
local
formatters
=
string
.
formatters
36
local
bytetable
=
string
.
bytetable
37
local
idiv
=
number
.
idiv
38
local
rshift
,
band
,
extract
=
bit32
.
rshift
,
bit32
.
band
,
bit32
.
extract
39 40
local
readers
=
fonts
.
handlers
.
otf
.
readers
41
local
streamreader
=
readers
.
streamreader
42 43
local
readstring
=
streamreader
.
readstring
44
local
readbyte
=
streamreader
.
readcardinal1
-- 8-bit unsigned integer
45
local
readushort
=
streamreader
.
readcardinal2
-- 16-bit unsigned integer
46
local
readuint
=
streamreader
.
readcardinal3
-- 24-bit unsigned integer
47
local
readulong
=
streamreader
.
readcardinal4
-- 32-bit unsigned integer
48
local
setposition
=
streamreader
.
setposition
49
local
getposition
=
streamreader
.
getposition
50
local
readbytetable
=
streamreader
.
readbytetable
51 52
directives
.
register
(
"
fonts.streamreader
"
,
function
(
)
53 54
streamreader
=
utilities
.
streams
55 56
readstring
=
streamreader
.
readstring
57
readbyte
=
streamreader
.
readcardinal1
58
readushort
=
streamreader
.
readcardinal2
59
readuint
=
streamreader
.
readcardinal3
60
readulong
=
streamreader
.
readcardinal4
61
setposition
=
streamreader
.
setposition
62
getposition
=
streamreader
.
getposition
63
readbytetable
=
streamreader
.
readbytetable
64 65
end
)
66 67
local
setmetatableindex
=
table
.
setmetatableindex
68 69
local
trace_charstrings
=
false
trackers
.
register
(
"
fonts.cff.charstrings
"
,
function
(
v
)
trace_charstrings
=
v
end
)
70
local
report
=
logs
.
reporter
(
"
otf reader
"
,
"
cff
"
)
71 72
local
parsedictionaries
73
local
parsecharstring
74
local
parsecharstrings
75
local
resetcharstrings
76
local
parseprivates
77
local
startparsing
78
local
stopparsing
79 80
local
defaultstrings
=
{
[
0
]
=
-- taken from ff
81
"
.notdef
"
,
"
space
"
,
"
exclam
"
,
"
quotedbl
"
,
"
numbersign
"
,
"
dollar
"
,
"
percent
"
,
82
"
ampersand
"
,
"
quoteright
"
,
"
parenleft
"
,
"
parenright
"
,
"
asterisk
"
,
"
plus
"
,
83
"
comma
"
,
"
hyphen
"
,
"
period
"
,
"
slash
"
,
"
zero
"
,
"
one
"
,
"
two
"
,
"
three
"
,
"
four
"
,
84
"
five
"
,
"
six
"
,
"
seven
"
,
"
eight
"
,
"
nine
"
,
"
colon
"
,
"
semicolon
"
,
"
less
"
,
85
"
equal
"
,
"
greater
"
,
"
question
"
,
"
at
"
,
"
A
"
,
"
B
"
,
"
C
"
,
"
D
"
,
"
E
"
,
"
F
"
,
"
G
"
,
"
H
"
,
86
"
I
"
,
"
J
"
,
"
K
"
,
"
L
"
,
"
M
"
,
"
N
"
,
"
O
"
,
"
P
"
,
"
Q
"
,
"
R
"
,
"
S
"
,
"
T
"
,
"
U
"
,
"
V
"
,
"
W
"
,
87
"
X
"
,
"
Y
"
,
"
Z
"
,
"
bracketleft
"
,
"
backslash
"
,
"
bracketright
"
,
"
asciicircum
"
,
88
"
underscore
"
,
"
quoteleft
"
,
"
a
"
,
"
b
"
,
"
c
"
,
"
d
"
,
"
e
"
,
"
f
"
,
"
g
"
,
"
h
"
,
"
i
"
,
"
j
"
,
89
"
k
"
,
"
l
"
,
"
m
"
,
"
n
"
,
"
o
"
,
"
p
"
,
"
q
"
,
"
r
"
,
"
s
"
,
"
t
"
,
"
u
"
,
"
v
"
,
"
w
"
,
"
x
"
,
"
y
"
,
90
"
z
"
,
"
braceleft
"
,
"
bar
"
,
"
braceright
"
,
"
asciitilde
"
,
"
exclamdown
"
,
"
cent
"
,
91
"
sterling
"
,
"
fraction
"
,
"
yen
"
,
"
florin
"
,
"
section
"
,
"
currency
"
,
92
"
quotesingle
"
,
"
quotedblleft
"
,
"
guillemotleft
"
,
"
guilsinglleft
"
,
93
"
guilsinglright
"
,
"
fi
"
,
"
fl
"
,
"
endash
"
,
"
dagger
"
,
"
daggerdbl
"
,
94
"
periodcentered
"
,
"
paragraph
"
,
"
bullet
"
,
"
quotesinglbase
"
,
"
quotedblbase
"
,
95
"
quotedblright
"
,
"
guillemotright
"
,
"
ellipsis
"
,
"
perthousand
"
,
"
questiondown
"
,
96
"
grave
"
,
"
acute
"
,
"
circumflex
"
,
"
tilde
"
,
"
macron
"
,
"
breve
"
,
"
dotaccent
"
,
97
"
dieresis
"
,
"
ring
"
,
"
cedilla
"
,
"
hungarumlaut
"
,
"
ogonek
"
,
"
caron
"
,
"
emdash
"
,
98
"
AE
"
,
"
ordfeminine
"
,
"
Lslash
"
,
"
Oslash
"
,
"
OE
"
,
"
ordmasculine
"
,
"
ae
"
,
99
"
dotlessi
"
,
"
lslash
"
,
"
oslash
"
,
"
oe
"
,
"
germandbls
"
,
"
onesuperior
"
,
100
"
logicalnot
"
,
"
mu
"
,
"
trademark
"
,
"
Eth
"
,
"
onehalf
"
,
"
plusminus
"
,
"
Thorn
"
,
101
"
onequarter
"
,
"
divide
"
,
"
brokenbar
"
,
"
degree
"
,
"
thorn
"
,
"
threequarters
"
,
102
"
twosuperior
"
,
"
registered
"
,
"
minus
"
,
"
eth
"
,
"
multiply
"
,
"
threesuperior
"
,
103
"
copyright
"
,
"
Aacute
"
,
"
Acircumflex
"
,
"
Adieresis
"
,
"
Agrave
"
,
"
Aring
"
,
104
"
Atilde
"
,
"
Ccedilla
"
,
"
Eacute
"
,
"
Ecircumflex
"
,
"
Edieresis
"
,
"
Egrave
"
,
105
"
Iacute
"
,
"
Icircumflex
"
,
"
Idieresis
"
,
"
Igrave
"
,
"
Ntilde
"
,
"
Oacute
"
,
106
"
Ocircumflex
"
,
"
Odieresis
"
,
"
Ograve
"
,
"
Otilde
"
,
"
Scaron
"
,
"
Uacute
"
,
107
"
Ucircumflex
"
,
"
Udieresis
"
,
"
Ugrave
"
,
"
Yacute
"
,
"
Ydieresis
"
,
"
Zcaron
"
,
108
"
aacute
"
,
"
acircumflex
"
,
"
adieresis
"
,
"
agrave
"
,
"
aring
"
,
"
atilde
"
,
109
"
ccedilla
"
,
"
eacute
"
,
"
ecircumflex
"
,
"
edieresis
"
,
"
egrave
"
,
"
iacute
"
,
110
"
icircumflex
"
,
"
idieresis
"
,
"
igrave
"
,
"
ntilde
"
,
"
oacute
"
,
"
ocircumflex
"
,
111
"
odieresis
"
,
"
ograve
"
,
"
otilde
"
,
"
scaron
"
,
"
uacute
"
,
"
ucircumflex
"
,
112
"
udieresis
"
,
"
ugrave
"
,
"
yacute
"
,
"
ydieresis
"
,
"
zcaron
"
,
"
exclamsmall
"
,
113
"
Hungarumlautsmall
"
,
"
dollaroldstyle
"
,
"
dollarsuperior
"
,
"
ampersandsmall
"
,
114
"
Acutesmall
"
,
"
parenleftsuperior
"
,
"
parenrightsuperior
"
,
"
twodotenleader
"
,
115
"
onedotenleader
"
,
"
zerooldstyle
"
,
"
oneoldstyle
"
,
"
twooldstyle
"
,
116
"
threeoldstyle
"
,
"
fouroldstyle
"
,
"
fiveoldstyle
"
,
"
sixoldstyle
"
,
117
"
sevenoldstyle
"
,
"
eightoldstyle
"
,
"
nineoldstyle
"
,
"
commasuperior
"
,
118
"
threequartersemdash
"
,
"
periodsuperior
"
,
"
questionsmall
"
,
"
asuperior
"
,
119
"
bsuperior
"
,
"
centsuperior
"
,
"
dsuperior
"
,
"
esuperior
"
,
"
isuperior
"
,
120
"
lsuperior
"
,
"
msuperior
"
,
"
nsuperior
"
,
"
osuperior
"
,
"
rsuperior
"
,
"
ssuperior
"
,
121
"
tsuperior
"
,
"
ff
"
,
"
ffi
"
,
"
ffl
"
,
"
parenleftinferior
"
,
"
parenrightinferior
"
,
122
"
Circumflexsmall
"
,
"
hyphensuperior
"
,
"
Gravesmall
"
,
"
Asmall
"
,
"
Bsmall
"
,
123
"
Csmall
"
,
"
Dsmall
"
,
"
Esmall
"
,
"
Fsmall
"
,
"
Gsmall
"
,
"
Hsmall
"
,
"
Ismall
"
,
124
"
Jsmall
"
,
"
Ksmall
"
,
"
Lsmall
"
,
"
Msmall
"
,
"
Nsmall
"
,
"
Osmall
"
,
"
Psmall
"
,
125
"
Qsmall
"
,
"
Rsmall
"
,
"
Ssmall
"
,
"
Tsmall
"
,
"
Usmall
"
,
"
Vsmall
"
,
"
Wsmall
"
,
126
"
Xsmall
"
,
"
Ysmall
"
,
"
Zsmall
"
,
"
colonmonetary
"
,
"
onefitted
"
,
"
rupiah
"
,
127
"
Tildesmall
"
,
"
exclamdownsmall
"
,
"
centoldstyle
"
,
"
Lslashsmall
"
,
128
"
Scaronsmall
"
,
"
Zcaronsmall
"
,
"
Dieresissmall
"
,
"
Brevesmall
"
,
"
Caronsmall
"
,
129
"
Dotaccentsmall
"
,
"
Macronsmall
"
,
"
figuredash
"
,
"
hypheninferior
"
,
130
"
Ogoneksmall
"
,
"
Ringsmall
"
,
"
Cedillasmall
"
,
"
questiondownsmall
"
,
"
oneeighth
"
,
131
"
threeeighths
"
,
"
fiveeighths
"
,
"
seveneighths
"
,
"
onethird
"
,
"
twothirds
"
,
132
"
zerosuperior
"
,
"
foursuperior
"
,
"
fivesuperior
"
,
"
sixsuperior
"
,
133
"
sevensuperior
"
,
"
eightsuperior
"
,
"
ninesuperior
"
,
"
zeroinferior
"
,
134
"
oneinferior
"
,
"
twoinferior
"
,
"
threeinferior
"
,
"
fourinferior
"
,
135
"
fiveinferior
"
,
"
sixinferior
"
,
"
seveninferior
"
,
"
eightinferior
"
,
136
"
nineinferior
"
,
"
centinferior
"
,
"
dollarinferior
"
,
"
periodinferior
"
,
137
"
commainferior
"
,
"
Agravesmall
"
,
"
Aacutesmall
"
,
"
Acircumflexsmall
"
,
138
"
Atildesmall
"
,
"
Adieresissmall
"
,
"
Aringsmall
"
,
"
AEsmall
"
,
"
Ccedillasmall
"
,
139
"
Egravesmall
"
,
"
Eacutesmall
"
,
"
Ecircumflexsmall
"
,
"
Edieresissmall
"
,
140
"
Igravesmall
"
,
"
Iacutesmall
"
,
"
Icircumflexsmall
"
,
"
Idieresissmall
"
,
141
"
Ethsmall
"
,
"
Ntildesmall
"
,
"
Ogravesmall
"
,
"
Oacutesmall
"
,
"
Ocircumflexsmall
"
,
142
"
Otildesmall
"
,
"
Odieresissmall
"
,
"
OEsmall
"
,
"
Oslashsmall
"
,
"
Ugravesmall
"
,
143
"
Uacutesmall
"
,
"
Ucircumflexsmall
"
,
"
Udieresissmall
"
,
"
Yacutesmall
"
,
144
"
Thornsmall
"
,
"
Ydieresissmall
"
,
"
001.000
"
,
"
001.001
"
,
"
001.002
"
,
"
001.003
"
,
145
"
Black
"
,
"
Bold
"
,
"
Book
"
,
"
Light
"
,
"
Medium
"
,
"
Regular
"
,
"
Roman
"
,
"
Semibold
"
,
146
}
147 148
local
standardnames
=
{
[
0
]
=
-- needed for seac
149
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
150
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
151
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
152
"
space
"
,
"
exclam
"
,
"
quotedbl
"
,
"
numbersign
"
,
"
dollar
"
,
"
percent
"
,
153
"
ampersand
"
,
"
quoteright
"
,
"
parenleft
"
,
"
parenright
"
,
"
asterisk
"
,
"
plus
"
,
154
"
comma
"
,
"
hyphen
"
,
"
period
"
,
"
slash
"
,
"
zero
"
,
"
one
"
,
"
two
"
,
"
three
"
,
"
four
"
,
155
"
five
"
,
"
six
"
,
"
seven
"
,
"
eight
"
,
"
nine
"
,
"
colon
"
,
"
semicolon
"
,
"
less
"
,
156
"
equal
"
,
"
greater
"
,
"
question
"
,
"
at
"
,
"
A
"
,
"
B
"
,
"
C
"
,
"
D
"
,
"
E
"
,
"
F
"
,
"
G
"
,
"
H
"
,
157
"
I
"
,
"
J
"
,
"
K
"
,
"
L
"
,
"
M
"
,
"
N
"
,
"
O
"
,
"
P
"
,
"
Q
"
,
"
R
"
,
"
S
"
,
"
T
"
,
"
U
"
,
"
V
"
,
"
W
"
,
158
"
X
"
,
"
Y
"
,
"
Z
"
,
"
bracketleft
"
,
"
backslash
"
,
"
bracketright
"
,
"
asciicircum
"
,
159
"
underscore
"
,
"
quoteleft
"
,
"
a
"
,
"
b
"
,
"
c
"
,
"
d
"
,
"
e
"
,
"
f
"
,
"
g
"
,
"
h
"
,
"
i
"
,
"
j
"
,
160
"
k
"
,
"
l
"
,
"
m
"
,
"
n
"
,
"
o
"
,
"
p
"
,
"
q
"
,
"
r
"
,
"
s
"
,
"
t
"
,
"
u
"
,
"
v
"
,
"
w
"
,
"
x
"
,
"
y
"
,
161
"
z
"
,
"
braceleft
"
,
"
bar
"
,
"
braceright
"
,
"
asciitilde
"
,
false
,
false
,
false
,
162
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
163
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
164
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
"
exclamdown
"
,
165
"
cent
"
,
"
sterling
"
,
"
fraction
"
,
"
yen
"
,
"
florin
"
,
"
section
"
,
"
currency
"
,
166
"
quotesingle
"
,
"
quotedblleft
"
,
"
guillemotleft
"
,
"
guilsinglleft
"
,
167
"
guilsinglright
"
,
"
fi
"
,
"
fl
"
,
false
,
"
endash
"
,
"
dagger
"
,
"
daggerdbl
"
,
168
"
periodcentered
"
,
false
,
"
paragraph
"
,
"
bullet
"
,
"
quotesinglbase
"
,
169
"
quotedblbase
"
,
"
quotedblright
"
,
"
guillemotright
"
,
"
ellipsis
"
,
"
perthousand
"
,
170
false
,
"
questiondown
"
,
false
,
"
grave
"
,
"
acute
"
,
"
circumflex
"
,
"
tilde
"
,
171
"
macron
"
,
"
breve
"
,
"
dotaccent
"
,
"
dieresis
"
,
false
,
"
ring
"
,
"
cedilla
"
,
false
,
172
"
hungarumlaut
"
,
"
ogonek
"
,
"
caron
"
,
"
emdash
"
,
false
,
false
,
false
,
false
,
173
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
false
,
174
false
,
"
AE
"
,
false
,
"
ordfeminine
"
,
false
,
false
,
false
,
false
,
"
Lslash
"
,
175
"
Oslash
"
,
"
OE
"
,
"
ordmasculine
"
,
false
,
false
,
false
,
false
,
false
,
"
ae
"
,
176
false
,
false
,
false
,
"
dotlessi
"
,
false
,
false
,
"
lslash
"
,
"
oslash
"
,
"
oe
"
,
177
"
germandbls
"
,
false
,
false
,
false
,
false
178
}
179 180
local
cffreaders
=
{
181
readbyte
,
182
readushort
,
183
readuint
,
184
readulong
,
185
}
186 187
directives
.
register
(
"
fonts.streamreader
"
,
function
(
)
188
cffreaders
=
{
189
readbyte
,
190
readushort
,
191
readuint
,
192
readulong
,
193
}
194
end
)
195 196
-- The header contains information about its own size.
197 198
local
function
readheader
(
f
)
199
local
offset
=
getposition
(
f
)
200
local
major
=
readbyte
(
f
)
201
local
header
=
{
202
offset
=
offset
,
203
major
=
major
,
204
minor
=
readbyte
(
f
)
,
205
size
=
readbyte
(
f
)
,
-- headersize
206
}
207
if
major
=
=
1
then
208
header
.
dsize
=
readbyte
(
f
)
-- list of dict offsets
209
elseif
major
=
=
2
then
210
header
.
dsize
=
readushort
(
f
)
-- topdict size
211
else
212
-- I'm probably no longer around by then and we use AI's to
213
-- handle this kind of stuff, if we typeset documents at all.
214
end
215
setposition
(
f
,
offset
+
header
.
size
)
216
return
header
217
end
218 219
-- The indexes all look the same, so we share a loader. We could pass a handler
220
-- and run over the array but why bother, we only have a few uses.
221 222
local
function
readlengths
(
f
,
longcount
)
223
local
count
=
longcount
and
readulong
(
f
)
or
readushort
(
f
)
224
if
count
=
=
0
then
225
return
{
}
226
end
227
local
osize
=
readbyte
(
f
)
228
local
read
=
cffreaders
[
osize
]
229
if
not
read
then
230
report
(
"
bad offset size: %i
"
,
osize
)
231
return
{
}
232
end
233
local
lengths
=
{
}
234
local
previous
=
read
(
f
)
235
for
i
=
1
,
count
do
236
local
offset
=
read
(
f
)
237
local
length
=
offset
-
previous
238
if
length
<
0
then
239
report
(
"
bad offset: %i
"
,
length
)
240
length
=
0
241
end
242
lengths
[
i
]
=
length
243
previous
=
offset
244
end
245
return
lengths
246
end
247 248
-- There can be subfonts so names is an array. However, in our case it's always
249
-- one font. The same is true for the top dictionaries. Watch how we only load
250
-- the dictionary string as for interpretation we need to have the strings loaded
251
-- as well.
252 253
local
function
readfontnames
(
f
)
254
local
names
=
readlengths
(
f
)
255
for
i
=
1
,
#
names
do
256
names
[
i
]
=
readstring
(
f
,
names
[
i
]
)
257
end
258
return
names
259
end
260 261
local
function
readtopdictionaries
(
f
)
262
local
dictionaries
=
readlengths
(
f
)
263
for
i
=
1
,
#
dictionaries
do
264
dictionaries
[
i
]
=
readstring
(
f
,
dictionaries
[
i
]
)
265
end
266
return
dictionaries
267
end
268 269
-- Strings are added to a list of standard strings so we start the font specific
270
-- one with an offset. Strings are shared so we have one table.
271 272
local
function
readstrings
(
f
)
273
local
lengths
=
readlengths
(
f
)
274
local
strings
=
setmetatableindex
(
{
}
,
defaultstrings
)
275
local
index
=
#
defaultstrings
276
for
i
=
1
,
#
lengths
do
277
index
=
index
+
1
278
strings
[
index
]
=
readstring
(
f
,
lengths
[
i
]
)
279
end
280
return
strings
281
end
282 283
-- Parsing the dictionaries is delayed till we have the strings loaded. The parser
284
-- is stack based so the operands come before the operator (like in postscript).
285 286
-- local function delta(t)
287
-- local n = #t
288
-- if n > 1 then
289
-- local p = t[1]
290
-- for i=2,n do
291
-- local c = t[i]
292
-- t[i] = c + p
293
-- p = c
294
-- end
295
-- end
296
-- end
297 298
do
299 300
-- We use a closure so that we don't need to pass too much around. For cff2 we can
301
-- at some point use a simple version as there is less.
302 303
local
stack
=
{
}
304
local
top
=
0
305
local
result
=
{
}
306
local
strings
=
{
}
307 308
local
p_single
=
309
P
(
"
\00
"
)
/
function
(
)
310
result
.
version
=
strings
[
stack
[
top
]
]
or
"
unset
"
311
top
=
0
312
end
313
+
P
(
"
\01
"
)
/
function
(
)
314
result
.
notice
=
strings
[
stack
[
top
]
]
or
"
unset
"
315
top
=
0
316
end
317
+
P
(
"
\02
"
)
/
function
(
)
318
result
.
fullname
=
strings
[
stack
[
top
]
]
or
"
unset
"
319
top
=
0
320
end
321
+
P
(
"
\03
"
)
/
function
(
)
322
result
.
familyname
=
strings
[
stack
[
top
]
]
or
"
unset
"
323
top
=
0
324
end
325
+
P
(
"
\04
"
)
/
function
(
)
326
result
.
weight
=
strings
[
stack
[
top
]
]
or
"
unset
"
327
top
=
0
328
end
329
+
P
(
"
\05
"
)
/
function
(
)
330
result
.
fontbbox
=
{
unpack
(
stack
,
1
,
4
)
}
331
top
=
0
332
end
333
+
P
(
"
\06
"
)
/
function
(
)
334
result
.
bluevalues
=
{
unpack
(
stack
,
1
,
top
)
}
335
top
=
0
336
end
337
+
P
(
"
\07
"
)
/
function
(
)
338
result
.
otherblues
=
{
unpack
(
stack
,
1
,
top
)
}
339
top
=
0
340
end
341
+
P
(
"
\08
"
)
/
function
(
)
342
result
.
familyblues
=
{
unpack
(
stack
,
1
,
top
)
}
343
top
=
0
344
end
345
+
P
(
"
\09
"
)
/
function
(
)
346
result
.
familyotherblues
=
{
unpack
(
stack
,
1
,
top
)
}
347
top
=
0
348
end
349
+
P
(
"
\10
"
)
/
function
(
)
350
result
.
strhw
=
stack
[
top
]
351
top
=
0
352
end
353
+
P
(
"
\11
"
)
/
function
(
)
354
result
.
strvw
=
stack
[
top
]
355
top
=
0
356
end
357
+
P
(
"
\13
"
)
/
function
(
)
358
result
.
uniqueid
=
stack
[
top
]
359
top
=
0
360
end
361
+
P
(
"
\14
"
)
/
function
(
)
362
result
.
xuid
=
concat
(
stack
,
"
"
,
1
,
top
)
363
top
=
0
364
end
365
+
P
(
"
\15
"
)
/
function
(
)
366
result
.
charset
=
stack
[
top
]
367
top
=
0
368
end
369
+
P
(
"
\16
"
)
/
function
(
)
370
result
.
encoding
=
stack
[
top
]
371
top
=
0
372
end
373
+
P
(
"
\17
"
)
/
function
(
)
-- valid cff2
374
result
.
charstrings
=
stack
[
top
]
375
top
=
0
376
end
377
+
P
(
"
\18
"
)
/
function
(
)
378
result
.
private
=
{
379
size
=
stack
[
top
-1
]
,
380
offset
=
stack
[
top
]
,
381
}
382
top
=
0
383
end
384
+
P
(
"
\19
"
)
/
function
(
)
385
result
.
subroutines
=
stack
[
top
]
386
top
=
0
-- new, forgotten ?
387
end
388
+
P
(
"
\20
"
)
/
function
(
)
389
result
.
defaultwidthx
=
stack
[
top
]
390
top
=
0
-- new, forgotten ?
391
end
392
+
P
(
"
\21
"
)
/
function
(
)
393
result
.
nominalwidthx
=
stack
[
top
]
394
top
=
0
-- new, forgotten ?
395
end
396
-- + P("\22") / function() -- reserved
397
-- end
398
-- + P("\23") / function() -- reserved
399
-- end
400
+
P
(
"
\24
"
)
/
function
(
)
-- new in cff2
401
result
.
vstore
=
stack
[
top
]
402
top
=
0
403
end
404
+
P
(
"
\25
"
)
/
function
(
)
-- new in cff2
405
result
.
maxstack
=
stack
[
top
]
406
top
=
0
407
end
408
-- + P("\26") / function() -- reserved
409
-- end
410
-- + P("\27") / function() -- reserved
411
-- end
412 413
local
p_double
=
P
(
"
\12
"
)
*
(
414
P
(
"
\00
"
)
/
function
(
)
415
result
.
copyright
=
stack
[
top
]
416
top
=
0
417
end
418
+
P
(
"
\01
"
)
/
function
(
)
419
result
.
monospaced
=
stack
[
top
]
=
=
1
and
true
or
false
-- isfixedpitch
420
top
=
0
421
end
422
+
P
(
"
\02
"
)
/
function
(
)
423
result
.
italicangle
=
stack
[
top
]
424
top
=
0
425
end
426
+
P
(
"
\03
"
)
/
function
(
)
427
result
.
underlineposition
=
stack
[
top
]
428
top
=
0
429
end
430
+
P
(
"
\04
"
)
/
function
(
)
431
result
.
underlinethickness
=
stack
[
top
]
432
top
=
0
433
end
434
+
P
(
"
\05
"
)
/
function
(
)
435
result
.
painttype
=
stack
[
top
]
436
top
=
0
437
end
438
+
P
(
"
\06
"
)
/
function
(
)
439
result
.
charstringtype
=
stack
[
top
]
440
top
=
0
441
end
442
+
P
(
"
\07
"
)
/
function
(
)
-- valid cff2
443
result
.
fontmatrix
=
{
unpack
(
stack
,
1
,
6
)
}
444
top
=
0
445
end
446
+
P
(
"
\08
"
)
/
function
(
)
447
result
.
strokewidth
=
stack
[
top
]
448
top
=
0
449
end
450
+
P
(
"
\09
"
)
/
function
(
)
451
result
.
bluescale
=
stack
[
top
]
452
top
=
0
453
end
454
+
P
(
"
\10
"
)
/
function
(
)
455
result
.
bluesnap
=
stack
[
top
]
456
top
=
0
457
end
458
+
P
(
"
\11
"
)
/
function
(
)
459
result
.
bluefuzz
=
stack
[
top
]
460
top
=
0
461
end
462
+
P
(
"
\12
"
)
/
function
(
)
463
result
.
stemsnaph
=
{
unpack
(
stack
,
1
,
top
)
}
464
top
=
0
465
end
466
+
P
(
"
\13
"
)
/
function
(
)
467
result
.
stemsnapv
=
{
unpack
(
stack
,
1
,
top
)
}
468
top
=
0
469
end
470
+
P
(
"
\20
"
)
/
function
(
)
471
result
.
syntheticbase
=
stack
[
top
]
472
top
=
0
473
end
474
+
P
(
"
\21
"
)
/
function
(
)
475
result
.
postscript
=
strings
[
stack
[
top
]
]
or
"
unset
"
476
top
=
0
477
end
478
+
P
(
"
\22
"
)
/
function
(
)
479
result
.
basefontname
=
strings
[
stack
[
top
]
]
or
"
unset
"
480
top
=
0
481
end
482
+
P
(
"
\21
"
)
/
function
(
)
483
result
.
basefontblend
=
stack
[
top
]
484
top
=
0
485
end
486
+
P
(
"
\30
"
)
/
function
(
)
487
result
.
cid
.
registry
=
strings
[
stack
[
top
-2
]
]
or
"
unset
"
488
result
.
cid
.
ordering
=
strings
[
stack
[
top
-1
]
]
or
"
unset
"
489
result
.
cid
.
supplement
=
stack
[
top
]
490
top
=
0
491
end
492
+
P
(
"
\31
"
)
/
function
(
)
493
result
.
cid
.
fontversion
=
stack
[
top
]
494
top
=
0
495
end
496
+
P
(
"
\32
"
)
/
function
(
)
497
result
.
cid
.
fontrevision
=
stack
[
top
]
498
top
=
0
499
end
500
+
P
(
"
\33
"
)
/
function
(
)
501
result
.
cid
.
fonttype
=
stack
[
top
]
502
top
=
0
503
end
504
+
P
(
"
\34
"
)
/
function
(
)
505
result
.
cid
.
count
=
stack
[
top
]
506
top
=
0
507
end
508
+
P
(
"
\35
"
)
/
function
(
)
509
result
.
cid
.
uidbase
=
stack
[
top
]
510
top
=
0
511
end
512
+
P
(
"
\36
"
)
/
function
(
)
-- valid cff2
513
result
.
cid
.
fdarray
=
stack
[
top
]
514
top
=
0
515
end
516
+
P
(
"
\37
"
)
/
function
(
)
-- valid cff2
517
result
.
cid
.
fdselect
=
stack
[
top
]
518
top
=
0
519
end
520
+
P
(
"
\38
"
)
/
function
(
)
521
result
.
cid
.
fontname
=
strings
[
stack
[
top
]
]
or
"
unset
"
522
top
=
0
523
end
524
)
525 526
-- Some lpeg fun ... a first variant split the byte and made a new string but
527
-- the second variant is much faster. Not that it matters much as we don't see
528
-- such numbers often.
529 530
local
remap
=
{
531
[
"
\x00
"
]
=
"
00
"
,
[
"
\x01
"
]
=
"
01
"
,
[
"
\x02
"
]
=
"
02
"
,
[
"
\x03
"
]
=
"
03
"
,
[
"
\x04
"
]
=
"
04
"
,
[
"
\x05
"
]
=
"
05
"
,
[
"
\x06
"
]
=
"
06
"
,
[
"
\x07
"
]
=
"
07
"
,
[
"
\x08
"
]
=
"
08
"
,
[
"
\x09
"
]
=
"
09
"
,
[
"
\x0A
"
]
=
"
0.
"
,
[
"
\x0B
"
]
=
"
0E
"
,
[
"
\x0C
"
]
=
"
0E-
"
,
[
"
\x0D
"
]
=
"
0
"
,
[
"
\x0E
"
]
=
"
0-
"
,
[
"
\x0F
"
]
=
"
0
"
,
532
[
"
\x10
"
]
=
"
10
"
,
[
"
\x11
"
]
=
"
11
"
,
[
"
\x12
"
]
=
"
12
"
,
[
"
\x13
"
]
=
"
13
"
,
[
"
\x14
"
]
=
"
14
"
,
[
"
\x15
"
]
=
"
15
"
,
[
"
\x16
"
]
=
"
16
"
,
[
"
\x17
"
]
=
"
17
"
,
[
"
\x18
"
]
=
"
18
"
,
[
"
\x19
"
]
=
"
19
"
,
[
"
\x1A
"
]
=
"
1.
"
,
[
"
\x1B
"
]
=
"
1E
"
,
[
"
\x1C
"
]
=
"
1E-
"
,
[
"
\x1D
"
]
=
"
1
"
,
[
"
\x1E
"
]
=
"
1-
"
,
[
"
\x1F
"
]
=
"
1
"
,
533
[
"
\x20
"
]
=
"
20
"
,
[
"
\x21
"
]
=
"
21
"
,
[
"
\x22
"
]
=
"
22
"
,
[
"
\x23
"
]
=
"
23
"
,
[
"
\x24
"
]
=
"
24
"
,
[
"
\x25
"
]
=
"
25
"
,
[
"
\x26
"
]
=
"
26
"
,
[
"
\x27
"
]
=
"
27
"
,
[
"
\x28
"
]
=
"
28
"
,
[
"
\x29
"
]
=
"
29
"
,
[
"
\x2A
"
]
=
"
2.
"
,
[
"
\x2B
"
]
=
"
2E
"
,
[
"
\x2C
"
]
=
"
2E-
"
,
[
"
\x2D
"
]
=
"
2
"
,
[
"
\x2E
"
]
=
"
2-
"
,
[
"
\x2F
"
]
=
"
2
"
,
534
[
"
\x30
"
]
=
"
30
"
,
[
"
\x31
"
]
=
"
31
"
,
[
"
\x32
"
]
=
"
32
"
,
[
"
\x33
"
]
=
"
33
"
,
[
"
\x34
"
]
=
"
34
"
,
[
"
\x35
"
]
=
"
35
"
,
[
"
\x36
"
]
=
"
36
"
,
[
"
\x37
"
]
=
"
37
"
,
[
"
\x38
"
]
=
"
38
"
,
[
"
\x39
"
]
=
"
39
"
,
[
"
\x3A
"
]
=
"
3.
"
,
[
"
\x3B
"
]
=
"
3E
"
,
[
"
\x3C
"
]
=
"
3E-
"
,
[
"
\x3D
"
]
=
"
3
"
,
[
"
\x3E
"
]
=
"
3-
"
,
[
"
\x3F
"
]
=
"
3
"
,
535
[
"
\x40
"
]
=
"
40
"
,
[
"
\x41
"
]
=
"
41
"
,
[
"
\x42
"
]
=
"
42
"
,
[
"
\x43
"
]
=
"
43
"
,
[
"
\x44
"
]
=
"
44
"
,
[
"
\x45
"
]
=
"
45
"
,
[
"
\x46
"
]
=
"
46
"
,
[
"
\x47
"
]
=
"
47
"
,
[
"
\x48
"
]
=
"
48
"
,
[
"
\x49
"
]
=
"
49
"
,
[
"
\x4A
"
]
=
"
4.
"
,
[
"
\x4B
"
]
=
"
4E
"
,
[
"
\x4C
"
]
=
"
4E-
"
,
[
"
\x4D
"
]
=
"
4
"
,
[
"
\x4E
"
]
=
"
4-
"
,
[
"
\x4F
"
]
=
"
4
"
,
536
[
"
\x50
"
]
=
"
50
"
,
[
"
\x51
"
]
=
"
51
"
,
[
"
\x52
"
]
=
"
52
"
,
[
"
\x53
"
]
=
"
53
"
,
[
"
\x54
"
]
=
"
54
"
,
[
"
\x55
"
]
=
"
55
"
,
[
"
\x56
"
]
=
"
56
"
,
[
"
\x57
"
]
=
"
57
"
,
[
"
\x58
"
]
=
"
58
"
,
[
"
\x59
"
]
=
"
59
"
,
[
"
\x5A
"
]
=
"
5.
"
,
[
"
\x5B
"
]
=
"
5E
"
,
[
"
\x5C
"
]
=
"
5E-
"
,
[
"
\x5D
"
]
=
"
5
"
,
[
"
\x5E
"
]
=
"
5-
"
,
[
"
\x5F
"
]
=
"
5
"
,
537
[
"
\x60
"
]
=
"
60
"
,
[
"
\x61
"
]
=
"
61
"
,
[
"
\x62
"
]
=
"
62
"
,
[
"
\x63
"
]
=
"
63
"
,
[
"
\x64
"
]
=
"
64
"
,
[
"
\x65
"
]
=
"
65
"
,
[
"
\x66
"
]
=
"
66
"
,
[
"
\x67
"
]
=
"
67
"
,
[
"
\x68
"
]
=
"
68
"
,
[
"
\x69
"
]
=
"
69
"
,
[
"
\x6A
"
]
=
"
6.
"
,
[
"
\x6B
"
]
=
"
6E
"
,
[
"
\x6C
"
]
=
"
6E-
"
,
[
"
\x6D
"
]
=
"
6
"
,
[
"
\x6E
"
]
=
"
6-
"
,
[
"
\x6F
"
]
=
"
6
"
,
538
[
"
\x70
"
]
=
"
70
"
,
[
"
\x71
"
]
=
"
71
"
,
[
"
\x72
"
]
=
"
72
"
,
[
"
\x73
"
]
=
"
73
"
,
[
"
\x74
"
]
=
"
74
"
,
[
"
\x75
"
]
=
"
75
"
,
[
"
\x76
"
]
=
"
76
"
,
[
"
\x77
"
]
=
"
77
"
,
[
"
\x78
"
]
=
"
78
"
,
[
"
\x79
"
]
=
"
79
"
,
[
"
\x7A
"
]
=
"
7.
"
,
[
"
\x7B
"
]
=
"
7E
"
,
[
"
\x7C
"
]
=
"
7E-
"
,
[
"
\x7D
"
]
=
"
7
"
,
[
"
\x7E
"
]
=
"
7-
"
,
[
"
\x7F
"
]
=
"
7
"
,
539
[
"
\x80
"
]
=
"
80
"
,
[
"
\x81
"
]
=
"
81
"
,
[
"
\x82
"
]
=
"
82
"
,
[
"
\x83
"
]
=
"
83
"
,
[
"
\x84
"
]
=
"
84
"
,
[
"
\x85
"
]
=
"
85
"
,
[
"
\x86
"
]
=
"
86
"
,
[
"
\x87
"
]
=
"
87
"
,
[
"
\x88
"
]
=
"
88
"
,
[
"
\x89
"
]
=
"
89
"
,
[
"
\x8A
"
]
=
"
8.
"
,
[
"
\x8B
"
]
=
"
8E
"
,
[
"
\x8C
"
]
=
"
8E-
"
,
[
"
\x8D
"
]
=
"
8
"
,
[
"
\x8E
"
]
=
"
8-
"
,
[
"
\x8F
"
]
=
"
8
"
,
540
[
"
\x90
"
]
=
"
90
"
,
[
"
\x91
"
]
=
"
91
"
,
[
"
\x92
"
]
=
"
92
"
,
[
"
\x93
"
]
=
"
93
"
,
[
"
\x94
"
]
=
"
94
"
,
[
"
\x95
"
]
=
"
95
"
,
[
"
\x96
"
]
=
"
96
"
,
[
"
\x97
"
]
=
"
97
"
,
[
"
\x98
"
]
=
"
98
"
,
[
"
\x99
"
]
=
"
99
"
,
[
"
\x9A
"
]
=
"
9.
"
,
[
"
\x9B
"
]
=
"
9E
"
,
[
"
\x9C
"
]
=
"
9E-
"
,
[
"
\x9D
"
]
=
"
9
"
,
[
"
\x9E
"
]
=
"
9-
"
,
[
"
\x9F
"
]
=
"
9
"
,
541
[
"
\xA0
"
]
=
"
.0
"
,
[
"
\xA1
"
]
=
"
.1
"
,
[
"
\xA2
"
]
=
"
.2
"
,
[
"
\xA3
"
]
=
"
.3
"
,
[
"
\xA4
"
]
=
"
.4
"
,
[
"
\xA5
"
]
=
"
.5
"
,
[
"
\xA6
"
]
=
"
.6
"
,
[
"
\xA7
"
]
=
"
.7
"
,
[
"
\xA8
"
]
=
"
.8
"
,
[
"
\xA9
"
]
=
"
.9
"
,
[
"
\xAA
"
]
=
"
..
"
,
[
"
\xAB
"
]
=
"
.E
"
,
[
"
\xAC
"
]
=
"
.E-
"
,
[
"
\xAD
"
]
=
"
.
"
,
[
"
\xAE
"
]
=
"
.-
"
,
[
"
\xAF
"
]
=
"
.
"
,
542
[
"
\xB0
"
]
=
"
E0
"
,
[
"
\xB1
"
]
=
"
E1
"
,
[
"
\xB2
"
]
=
"
E2
"
,
[
"
\xB3
"
]
=
"
E3
"
,
[
"
\xB4
"
]
=
"
E4
"
,
[
"
\xB5
"
]
=
"
E5
"
,
[
"
\xB6
"
]
=
"
E6
"
,
[
"
\xB7
"
]
=
"
E7
"
,
[
"
\xB8
"
]
=
"
E8
"
,
[
"
\xB9
"
]
=
"
E9
"
,
[
"
\xBA
"
]
=
"
E.
"
,
[
"
\xBB
"
]
=
"
EE
"
,
[
"
\xBC
"
]
=
"
EE-
"
,
[
"
\xBD
"
]
=
"
E
"
,
[
"
\xBE
"
]
=
"
E-
"
,
[
"
\xBF
"
]
=
"
E
"
,
543
[
"
\xC0
"
]
=
"
E-0
"
,
[
"
\xC1
"
]
=
"
E-1
"
,
[
"
\xC2
"
]
=
"
E-2
"
,
[
"
\xC3
"
]
=
"
E-3
"
,
[
"
\xC4
"
]
=
"
E-4
"
,
[
"
\xC5
"
]
=
"
E-5
"
,
[
"
\xC6
"
]
=
"
E-6
"
,
[
"
\xC7
"
]
=
"
E-7
"
,
[
"
\xC8
"
]
=
"
E-8
"
,
[
"
\xC9
"
]
=
"
E-9
"
,
[
"
\xCA
"
]
=
"
E-.
"
,
[
"
\xCB
"
]
=
"
E-E
"
,
[
"
\xCC
"
]
=
"
E-E-
"
,
[
"
\xCD
"
]
=
"
E-
"
,
[
"
\xCE
"
]
=
"
E--
"
,
[
"
\xCF
"
]
=
"
E-
"
,
544
[
"
\xD0
"
]
=
"
-0
"
,
[
"
\xD1
"
]
=
"
-1
"
,
[
"
\xD2
"
]
=
"
-2
"
,
[
"
\xD3
"
]
=
"
-3
"
,
[
"
\xD4
"
]
=
"
-4
"
,
[
"
\xD5
"
]
=
"
-5
"
,
[
"
\xD6
"
]
=
"
-6
"
,
[
"
\xD7
"
]
=
"
-7
"
,
[
"
\xD8
"
]
=
"
-8
"
,
[
"
\xD9
"
]
=
"
-9
"
,
[
"
\xDA
"
]
=
"
-.
"
,
[
"
\xDB
"
]
=
"
-E
"
,
[
"
\xDC
"
]
=
"
-E-
"
,
[
"
\xDD
"
]
=
"
-
"
,
[
"
\xDE
"
]
=
"
--
"
,
[
"
\xDF
"
]
=
"
-
"
,
545
}
546 547
local
p_last
=
S
(
"
\x0F\x1F\x2F\x3F\x4F\x5F\x6F\x7F\x8F\x9F\xAF\xBF
"
)
548
+
R
(
"
\xF0\xFF
"
)
549 550
local
p_nibbles
=
P
(
"
\30
"
)
*
Cs
(
(
(
1
-
p_last
)
/
remap
)
^
0
*
(
P
(
1
)
/
remap
)
)
/
function
(
n
)
551
-- 0-9=digit a=. b=E c=E- d=reserved e=- f=finish
552
top
=
top
+
1
553
stack
[
top
]
=
tonumber
(
n
)
or
0
554
end
555 556
local
p_byte
=
C
(
R
(
"
\32\246
"
)
)
/
function
(
b0
)
557
-- -107 .. +107
558
top
=
top
+
1
559
stack
[
top
]
=
byte
(
b0
)
-
139
560
end
561 562
local
p_positive
=
C
(
R
(
"
\247\250
"
)
)
*
C
(
1
)
/
function
(
b0
,
b1
)
563
-- +108 .. +1131
564
top
=
top
+
1
565
stack
[
top
]
=
(
byte
(
b0
)
-247
)
*
256
+
byte
(
b1
)
+
108
566
end
567 568
local
p_negative
=
C
(
R
(
"
\251\254
"
)
)
*
C
(
1
)
/
function
(
b0
,
b1
)
569
-- -1131 .. -108
570
top
=
top
+
1
571
stack
[
top
]
=
-
(
byte
(
b0
)
-251
)
*
256
-
byte
(
b1
)
-
108
572
end
573 574
local
p_short
=
P
(
"
\28
"
)
*
C
(
1
)
*
C
(
1
)
/
function
(
b1
,
b2
)
575
-- -32768 .. +32767 : b1<<8 | b2
576
top
=
top
+
1
577
local
n
=
0x100
*
byte
(
b1
)
+
byte
(
b2
)
578
if
n
>
=
0x8000
then
579
stack
[
top
]
=
n
-
0xFFFF
-
1
580
else
581
stack
[
top
]
=
n
582
end
583
end
584 585
local
p_long
=
P
(
"
\29
"
)
*
C
(
1
)
*
C
(
1
)
*
C
(
1
)
*
C
(
1
)
/
function
(
b1
,
b2
,
b3
,
b4
)
586
-- -2^31 .. +2^31-1 : b1<<24 | b2<<16 | b3<<8 | b4
587
top
=
top
+
1
588
local
n
=
0x1000000
*
byte
(
b1
)
+
0x10000
*
byte
(
b2
)
+
0x100
*
byte
(
b3
)
+
byte
(
b4
)
589
if
n
>
=
0x8000000
then
590
stack
[
top
]
=
n
-
0xFFFFFFFF
-
1
591
else
592
stack
[
top
]
=
n
593
end
594
end
595 596
local
p_unsupported
=
P
(
1
)
/
function
(
detail
)
597
top
=
0
598
end
599 600
local
p_dictionary
=
(
601
p_byte
602
+
p_positive
603
+
p_negative
604
+
p_short
605
+
p_long
606
+
p_nibbles
607
+
p_single
608
+
p_double
609
+
p_unsupported
610
)
^
1
611 612
parsedictionaries
=
function
(
data
,
dictionaries
,
what
)
613
stack
=
{
}
614
strings
=
data
.
strings
615
if
trace_charstrings
then
616
report
(
"
charstring format %a
"
,
what
)
617
end
618
for
i
=
1
,
#
dictionaries
do
619
top
=
0
620
result
=
what
=
=
"
cff
"
and
{
621
monospaced
=
false
,
622
italicangle
=
0
,
623
underlineposition
=
-100
,
624
underlinethickness
=
50
,
625
painttype
=
0
,
626
charstringtype
=
2
,
627
fontmatrix
=
{
0
.
001
,
0
,
0
,
0
.
001
,
0
,
0
}
,
628
fontbbox
=
{
0
,
0
,
0
,
0
}
,
629
strokewidth
=
0
,
630
charset
=
0
,
631
encoding
=
0
,
632
cid
=
{
633
fontversion
=
0
,
634
fontrevision
=
0
,
635
fonttype
=
0
,
636
count
=
8720
,
637
}
638
}
or
{
639
charstringtype
=
2
,
640
charset
=
0
,
641
vstore
=
0
,
642
cid
=
{
643
-- nothing yet
644
}
,
645
}
646
lpegmatch
(
p_dictionary
,
dictionaries
[
i
]
)
647
dictionaries
[
i
]
=
result
648
end
649
--
650
result
=
{
}
651
top
=
0
652
stack
=
{
}
653
end
654 655
parseprivates
=
function
(
data
,
dictionaries
)
656
stack
=
{
}
657
strings
=
data
.
strings
658
for
i
=
1
,
#
dictionaries
do
659
local
private
=
dictionaries
[
i
]
.
private
660
if
private
and
private
.
data
then
661
top
=
0
662
result
=
{
663
forcebold
=
false
,
664
languagegroup
=
0
,
665
expansionfactor
=
0
.
06
,
666
initialrandomseed
=
0
,
667
subroutines
=
0
,
668
defaultwidthx
=
0
,
669
nominalwidthx
=
0
,
670
cid
=
{
671
-- actually an error
672
}
,
673
}
674
lpegmatch
(
p_dictionary
,
private
.
data
)
675
private
.
data
=
result
676
end
677
end
678
result
=
{
}
679
top
=
0
680
stack
=
{
}
681
end
682 683
-- All bezier curves have 6 points with successive pairs relative to
684
-- the previous pair. Some can be left out and are then copied or zero
685
-- (optimization).
686
--
687
-- We are not really interested in all the details of a glyph because we
688
-- only need to calculate the boundingbox. So, todo: a quick no result but
689
-- calculate only variant.
690
--
691
-- The conversion is straightforward and the specification os clear once
692
-- you understand that the x and y needs to be updates each step. It's also
693
-- quite easy to test because in mp a shape will look bad when a few variables
694
-- are swapped. But still there might be bugs down here because not all
695
-- variants are seen in a font so far. We are less compact that the ff code
696
-- because there quite some variants are done in one helper with a lot of
697
-- testing for states.
698 699
local
x
=
0
700
local
y
=
0
701
local
width
=
false
702
local
lsb
=
0
703
local
r
=
0
704
local
stems
=
0
705
local
globalbias
=
0
706
local
localbias
=
0
707
local
nominalwidth
=
0
708
local
defaultwidth
=
0
709
local
charset
=
false
710
local
globals
=
false
711
local
locals
=
false
712
local
depth
=
1
713
local
xmin
=
0
714
local
xmax
=
0
715
local
ymin
=
0
716
local
ymax
=
0
717
local
checked
=
false
718
local
keepcurve
=
false
719
local
version
=
2
720
local
regions
=
false
721
local
nofregions
=
0
722
local
region
=
false
723
local
factors
=
false
724
local
axis
=
false
725
local
vsindex
=
0
726
local
justpass
=
false
727
local
seacs
=
{
}
728
local
procidx
=
nil
729 730
local
function
showstate
(
where
)
731
report
(
"
%w%-10s : [%s] n=%i
"
,
depth
*
2
,
where
,
concat
(
stack
,
"
"
,
1
,
top
)
,
top
)
732
end
733 734
local
function
showvalue
(
where
,
value
,
showstack
)
735
if
showstack
then
736
report
(
"
%w%-10s : %s : [%s] n=%i
"
,
depth
*
2
,
where
,
tostring
(
value
)
,
concat
(
stack
,
"
"
,
1
,
top
)
,
top
)
737
else
738
report
(
"
%w%-10s : %s
"
,
depth
*
2
,
where
,
tostring
(
value
)
)
739
end
740
end
741 742
-- All these indirect calls make this run slower but it's cleaner this way
743
-- and we cache the result. As we moved the boundingbox code inline we gain
744
-- some back. I inlined some of then and a bit speed can be gained by more
745
-- inlining but not that much.
746 747
local
function
xymoveto
(
)
748
if
keepcurve
then
749
r
=
r
+
1
750
result
[
r
]
=
{
x
,
y
,
"
m
"
}
751
end
752
if
checked
then
753
if
x
>
xmax
then
xmax
=
x
elseif
x
<
xmin
then
xmin
=
x
end
754
if
y
>
ymax
then
ymax
=
y
elseif
y
<
ymin
then
ymin
=
y
end
755
else
756
xmin
=
x
757
ymin
=
y
758
xmax
=
x
759
ymax
=
y
760
checked
=
true
761
end
762
end
763 764
local
function
xmoveto
(
)
-- slight speedup
765
if
keepcurve
then
766
r
=
r
+
1
767
result
[
r
]
=
{
x
,
y
,
"
m
"
}
768
end
769
if
not
checked
then
770
xmin
=
x
771
ymin
=
y
772
xmax
=
x
773
ymax
=
y
774
checked
=
true
775
elseif
x
>
xmax
then
776
xmax
=
x
777
elseif
x
<
xmin
then
778
xmin
=
x
779
end
780
end
781 782
local
function
ymoveto
(
)
-- slight speedup
783
if
keepcurve
then
784
r
=
r
+
1
785
result
[
r
]
=
{
x
,
y
,
"
m
"
}
786
end
787
if
not
checked
then
788
xmin
=
x
789
ymin
=
y
790
xmax
=
x
791
ymax
=
y
792
checked
=
true
793
elseif
y
>
ymax
then
794
ymax
=
y
795
elseif
y
<
ymin
then
796
ymin
=
y
797
end
798
end
799 800
local
function
moveto
(
)
801
if
trace_charstrings
then
802
showstate
(
"
moveto
"
)
803
end
804
top
=
0
-- forgotten
805
xymoveto
(
)
806
end
807 808
local
function
xylineto
(
)
-- we could inline, no blend
809
if
keepcurve
then
810
r
=
r
+
1
811
result
[
r
]
=
{
x
,
y
,
"
l
"
}
812
end
813
if
checked
then
814
if
x
>
xmax
then
xmax
=
x
elseif
x
<
xmin
then
xmin
=
x
end
815
if
y
>
ymax
then
ymax
=
y
elseif
y
<
ymin
then
ymin
=
y
end
816
else
817
xmin
=
x
818
ymin
=
y
819
xmax
=
x
820
ymax
=
y
821
checked
=
true
822
end
823
end
824 825
local
function
xlineto
(
)
-- slight speedup
826
if
keepcurve
then
827
r
=
r
+
1
828
result
[
r
]
=
{
x
,
y
,
"
l
"
}
829
end
830
if
not
checked
then
831
xmin
=
x
832
ymin
=
y
833
xmax
=
x
834
ymax
=
y
835
checked
=
true
836
elseif
x
>
xmax
then
837
xmax
=
x
838
elseif
x
<
xmin
then
839
xmin
=
x
840
end
841
end
842 843
local
function
ylineto
(
)
-- slight speedup
844
if
keepcurve
then
845
r
=
r
+
1
846
result
[
r
]
=
{
x
,
y
,
"
l
"
}
847
end
848
if
not
checked
then
849
xmin
=
x
850
ymin
=
y
851
xmax
=
x
852
ymax
=
y
853
checked
=
true
854
elseif
y
>
ymax
then
855
ymax
=
y
856
elseif
y
<
ymin
then
857
ymin
=
y
858
end
859
end
860 861
local
function
xycurveto
(
x1
,
y1
,
x2
,
y2
,
x3
,
y3
)
-- called local so no blend here
862
if
trace_charstrings
then
863
showstate
(
"
curveto
"
)
864
end
865
if
keepcurve
then
866
r
=
r
+
1
867
result
[
r
]
=
{
x1
,
y1
,
x2
,
y2
,
x3
,
y3
,
"
c
"
}
868
end
869
if
checked
then
870
if
x1
>
xmax
then
xmax
=
x1
elseif
x1
<
xmin
then
xmin
=
x1
end
871
if
y1
>
ymax
then
ymax
=
y1
elseif
y1
<
ymin
then
ymin
=
y1
end
872
else
873
xmin
=
x1
874
ymin
=
y1
875
xmax
=
x1
876
ymax
=
y1
877
checked
=
true
878
end
879
if
x2
>
xmax
then
xmax
=
x2
elseif
x2
<
xmin
then
xmin
=
x2
end
880
if
y2
>
ymax
then
ymax
=
y2
elseif
y2
<
ymin
then
ymin
=
y2
end
881
if
x3
>
xmax
then
xmax
=
x3
elseif
x3
<
xmin
then
xmin
=
x3
end
882
if
y3
>
ymax
then
ymax
=
y3
elseif
y3
<
ymin
then
ymin
=
y3
end
883
end
884 885
local
function
rmoveto
(
)
886
if
not
width
then
887
if
top
>
2
then
888
width
=
stack
[
1
]
889
if
trace_charstrings
then
890
showvalue
(
"
backtrack width
"
,
width
)
891
end
892
else
893
width
=
true
894
end
895
end
896
if
trace_charstrings
then
897
showstate
(
"
rmoveto
"
)
898
end
899
x
=
x
+
stack
[
top
-1
]
-- dx1
900
y
=
y
+
stack
[
top
]
-- dy1
901
top
=
0
902
xymoveto
(
)
903
end
904 905
local
function
hmoveto
(
)
906
if
not
width
then
907
if
top
>
1
then
908
width
=
stack
[
1
]
909
if
trace_charstrings
then
910
showvalue
(
"
backtrack width
"
,
width
)
911
end
912
else
913
width
=
true
914
end
915
end
916
if
trace_charstrings
then
917
showstate
(
"
hmoveto
"
)
918
end
919
x
=
x
+
stack
[
top
]
-- dx1
920
top
=
0
921
xmoveto
(
)
922
end
923 924
local
function
vmoveto
(
)
925
if
not
width
then
926
if
top
>
1
then
927
width
=
stack
[
1
]
928
if
trace_charstrings
then
929
showvalue
(
"
backtrack width
"
,
width
)
930
end
931
else
932
width
=
true
933
end
934
end
935
if
trace_charstrings
then
936
showstate
(
"
vmoveto
"
)
937
end
938
y
=
y
+
stack
[
top
]
-- dy1
939
top
=
0
940
ymoveto
(
)
941
end
942 943
local
function
rlineto
(
)
944
if
trace_charstrings
then
945
showstate
(
"
rlineto
"
)
946
end
947
for
i
=
1
,
top
,
2
do
948
x
=
x
+
stack
[
i
]
-- dxa
949
y
=
y
+
stack
[
i
+
1
]
-- dya
950
xylineto
(
)
951
end
952
top
=
0
953
end
954 955
local
function
hlineto
(
)
-- x (y,x)+ | (x,y)+
956
if
trace_charstrings
then
957
showstate
(
"
hlineto
"
)
958
end
959
if
top
=
=
1
then
960
x
=
x
+
stack
[
1
]
961
xlineto
(
)
962
else
963
local
swap
=
true
964
for
i
=
1
,
top
do
965
if
swap
then
966
x
=
x
+
stack
[
i
]
967
xlineto
(
)
968
swap
=
false
969
else
970
y
=
y
+
stack
[
i
]
971
ylineto
(
)
972
swap
=
true
973
end
974
end
975
end
976
top
=
0
977
end
978 979
local
function
vlineto
(
)
-- y (x,y)+ | (y,x)+
980
if
trace_charstrings
then
981
showstate
(
"
vlineto
"
)
982
end
983
if
top
=
=
1
then
984
y
=
y
+
stack
[
1
]
985
ylineto
(
)
986
else
987
local
swap
=
false
988
for
i
=
1
,
top
do
989
if
swap
then
990
x
=
x
+
stack
[
i
]
991
xlineto
(
)
992
swap
=
false
993
else
994
y
=
y
+
stack
[
i
]
995
ylineto
(
)
996
swap
=
true
997
end
998
end
999
end
1000
top
=
0
1001
end
1002 1003
local
function
rrcurveto
(
)
1004
if
trace_charstrings
then
1005
showstate
(
"
rrcurveto
"
)
1006
end
1007
for
i
=
1
,
top
,
6
do
1008
local
ax
=
x
+
stack
[
i
]
-- dxa
1009
local
ay
=
y
+
stack
[
i
+
1
]
-- dya
1010
local
bx
=
ax
+
stack
[
i
+
2
]
-- dxb
1011
local
by
=
ay
+
stack
[
i
+
3
]
-- dyb
1012
x
=
bx
+
stack
[
i
+
4
]
-- dxc
1013
y
=
by
+
stack
[
i
+
5
]
-- dyc
1014
xycurveto
(
ax
,
ay
,
bx
,
by
,
x
,
y
)
1015
end
1016
top
=
0
1017
end
1018 1019
local
function
hhcurveto
(
)
1020
if
trace_charstrings
then
1021
showstate
(
"
hhcurveto
"
)
1022
end
1023
local
s
=
1
1024
if
top
%
2
~
=
0
then
1025
y
=
y
+
stack
[
1
]
-- dy1
1026
s
=
2
1027
end
1028
for
i
=
s
,
top
,
4
do
1029
local
ax
=
x
+
stack
[
i
]
-- dxa
1030
local
ay
=
y
1031
local
bx
=
ax
+
stack
[
i
+
1
]
-- dxb
1032
local
by
=
ay
+
stack
[
i
+
2
]
-- dyb
1033
x
=
bx
+
stack
[
i
+
3
]
-- dxc
1034
y
=
by
1035
xycurveto
(
ax
,
ay
,
bx
,
by
,
x
,
y
)
1036
end
1037
top
=
0
1038
end
1039 1040
local
function
vvcurveto
(
)
1041
if
trace_charstrings
then
1042
showstate
(
"
vvcurveto
"
)
1043
end
1044
local
s
=
1
1045
local
d
=
0
1046
if
top
%
2
~
=
0
then
1047
d
=
stack
[
1
]
-- dx1
1048
s
=
2
1049
end
1050
for
i
=
s
,
top
,
4
do
1051
local
ax
=
x
+
d
1052
local
ay
=
y
+
stack
[
i
]
-- dya
1053
local
bx
=
ax
+
stack
[
i
+
1
]
-- dxb
1054
local
by
=
ay
+
stack
[
i
+
2
]
-- dyb
1055
x
=
bx
1056
y
=
by
+
stack
[
i
+
3
]
-- dyc
1057
xycurveto
(
ax
,
ay
,
bx
,
by
,
x
,
y
)
1058
d
=
0
1059
end
1060
top
=
0
1061
end
1062 1063
local
function
xxcurveto
(
swap
)
1064
local
last
=
top
%
4
~
=
0
and
stack
[
top
]
1065
if
last
then
1066
top
=
top
-
1
1067
end
1068
for
i
=
1
,
top
,
4
do
1069
local
ax
,
ay
,
bx
,
by
1070
if
swap
then
1071
ax
=
x
+
stack
[
i
]
1072
ay
=
y
1073
bx
=
ax
+
stack
[
i
+
1
]
1074
by
=
ay
+
stack
[
i
+
2
]
1075
y
=
by
+
stack
[
i
+
3
]
1076
if
last
and
i
+
3
=
=
top
then
1077
x
=
bx
+
last
1078
else
1079
x
=
bx
1080
end
1081
swap
=
false
1082
else
1083
ax
=
x
1084
ay
=
y
+
stack
[
i
]
1085
bx
=
ax
+
stack
[
i
+
1
]
1086
by
=
ay
+
stack
[
i
+
2
]
1087
x
=
bx
+
stack
[
i
+
3
]
1088
if
last
and
i
+
3
=
=
top
then
1089
y
=
by
+
last
1090
else
1091
y
=
by
1092
end
1093
swap
=
true
1094
end
1095
xycurveto
(
ax
,
ay
,
bx
,
by
,
x
,
y
)
1096
end
1097
top
=
0
1098
end
1099 1100
local
function
hvcurveto
(
)
1101
if
trace_charstrings
then
1102
showstate
(
"
hvcurveto
"
)
1103
end
1104
xxcurveto
(
true
)
1105
end
1106 1107
local
function
vhcurveto
(
)
1108
if
trace_charstrings
then
1109
showstate
(
"
vhcurveto
"
)
1110
end
1111
xxcurveto
(
false
)
1112
end
1113 1114
local
function
rcurveline
(
)
1115
if
trace_charstrings
then
1116
showstate
(
"
rcurveline
"
)
1117
end
1118
for
i
=
1
,
top
-2
,
6
do
1119
local
ax
=
x
+
stack
[
i
]
-- dxa
1120
local
ay
=
y
+
stack
[
i
+
1
]
-- dya
1121
local
bx
=
ax
+
stack
[
i
+
2
]
-- dxb
1122
local
by
=
ay
+
stack
[
i
+
3
]
-- dyb
1123
x
=
bx
+
stack
[
i
+
4
]
-- dxc
1124
y
=
by
+
stack
[
i
+
5
]
-- dyc
1125
xycurveto
(
ax
,
ay
,
bx
,
by
,
x
,
y
)
1126
end
1127
x
=
x
+
stack
[
top
-1
]
-- dxc
1128
y
=
y
+
stack
[
top
]
-- dyc
1129
xylineto
(
)
1130
top
=
0
1131
end
1132 1133
local
function
rlinecurve
(
)
1134
if
trace_charstrings
then
1135
showstate
(
"
rlinecurve
"
)
1136
end
1137
if
top
>
6
then
1138
for
i
=
1
,
top
-6
,
2
do
1139
x
=
x
+
stack
[
i
]
1140
y
=
y
+
stack
[
i
+
1
]
1141
xylineto
(
)
1142
end
1143
end
1144
local
ax
=
x
+
stack
[
top
-5
]
1145
local
ay
=
y
+
stack
[
top
-4
]
1146
local
bx
=
ax
+
stack
[
top
-3
]
1147
local
by
=
ay
+
stack
[
top
-2
]
1148
x
=
bx
+
stack
[
top
-1
]
1149
y
=
by
+
stack
[
top
]
1150
xycurveto
(
ax
,
ay
,
bx
,
by
,
x
,
y
)
1151
top
=
0
1152
end
1153 1154
-- flex is not yet tested! no loop
1155 1156
local
function
flex
(
)
-- fd not used
1157
if
trace_charstrings
then
1158
showstate
(
"
flex
"
)
1159
end
1160
local
ax
=
x
+
stack
[
1
]
-- dx1
1161
local
ay
=
y
+
stack
[
2
]
-- dy1
1162
local
bx
=
ax
+
stack
[
3
]
-- dx2
1163
local
by
=
ay
+
stack
[
4
]
-- dy2
1164
local
cx
=
bx
+
stack
[
5
]
-- dx3
1165
local
cy
=
by
+
stack
[
6
]
-- dy3
1166
xycurveto
(
ax
,
ay
,
bx
,
by
,
cx
,
cy
)
1167
local
dx
=
cx
+
stack
[
7
]
-- dx4
1168
local
dy
=
cy
+
stack
[
8
]
-- dy4
1169
local
ex
=
dx
+
stack
[
9
]
-- dx5
1170
local
ey
=
dy
+
stack
[
10
]
-- dy5
1171
x
=
ex
+
stack
[
11
]
-- dx6
1172
y
=
ey
+
stack
[
12
]
-- dy6
1173
xycurveto
(
dx
,
dy
,
ex
,
ey
,
x
,
y
)
1174
top
=
0
1175
end
1176 1177
local
function
hflex
(
)
1178
if
trace_charstrings
then
1179
showstate
(
"
hflex
"
)
1180
end
1181
local
ax
=
x
+
stack
[
1
]
-- dx1
1182
local
ay
=
y
1183
local
bx
=
ax
+
stack
[
2
]
-- dx2
1184
local
by
=
ay
+
stack
[
3
]
-- dy2
1185
local
cx
=
bx
+
stack
[
4
]
-- dx3
1186
local
cy
=
by
1187
xycurveto
(
ax
,
ay
,
bx
,
by
,
cx
,
cy
)
1188
local
dx
=
cx
+
stack
[
5
]
-- dx4
1189
local
dy
=
by
1190
local
ex
=
dx
+
stack
[
6
]
-- dx5
1191
local
ey
=
y
1192
x
=
ex
+
stack
[
7
]
-- dx6
1193
xycurveto
(
dx
,
dy
,
ex
,
ey
,
x
,
y
)
1194
top
=
0
1195
end
1196 1197
local
function
hflex1
(
)
1198
if
trace_charstrings
then
1199
showstate
(
"
hflex1
"
)
1200
end
1201
local
ax
=
x
+
stack
[
1
]
-- dx1
1202
local
ay
=
y
+
stack
[
2
]
-- dy1
1203
local
bx
=
ax
+
stack
[
3
]
-- dx2
1204
local
by
=
ay
+
stack
[
4
]
-- dy2
1205
local
cx
=
bx
+
stack
[
5
]
-- dx3
1206
local
cy
=
by
1207
xycurveto
(
ax
,
ay
,
bx
,
by
,
cx
,
cy
)
1208
local
dx
=
cx
+
stack
[
6
]
-- dx4
1209
local
dy
=
by
1210
local
ex
=
dx
+
stack
[
7
]
-- dx5
1211
local
ey
=
dy
+
stack
[
8
]
-- dy5
1212
x
=
ex
+
stack
[
9
]
-- dx6
1213
xycurveto
(
dx
,
dy
,
ex
,
ey
,
x
,
y
)
1214
top
=
0
1215
end
1216 1217
local
function
flex1
(
)
1218
if
trace_charstrings
then
1219
showstate
(
"
flex1
"
)
1220
end
1221
local
ax
=
x
+
stack
[
1
]
--dx1
1222
local
ay
=
y
+
stack
[
2
]
--dy1
1223
local
bx
=
ax
+
stack
[
3
]
--dx2
1224
local
by
=
ay
+
stack
[
4
]
--dy2
1225
local
cx
=
bx
+
stack
[
5
]
--dx3
1226
local
cy
=
by
+
stack
[
6
]
--dy3
1227
xycurveto
(
ax
,
ay
,
bx
,
by
,
cx
,
cy
)
1228
local
dx
=
cx
+
stack
[
7
]
--dx4
1229
local
dy
=
cy
+
stack
[
8
]
--dy4
1230
local
ex
=
dx
+
stack
[
9
]
--dx5
1231
local
ey
=
dy
+
stack
[
10
]
--dy5
1232
if
abs
(
ex
-
x
)
>
abs
(
ey
-
y
)
then
-- spec: abs(dx) > abs(dy)
1233
x
=
ex
+
stack
[
11
]
1234
else
1235
y
=
ey
+
stack
[
11
]
1236
end
1237
xycurveto
(
dx
,
dy
,
ex
,
ey
,
x
,
y
)
1238
top
=
0
1239
end
1240 1241
local
function
getstem
(
)
1242
if
top
=
=
0
then
1243
-- bad
1244
elseif
top
%
2
~
=
0
then
1245
if
width
then
1246
remove
(
stack
,
1
)
1247
else
1248
width
=
remove
(
stack
,
1
)
1249
if
trace_charstrings
then
1250
showvalue
(
"
width
"
,
width
)
1251
end
1252
end
1253
top
=
top
-
1
1254
end
1255
if
trace_charstrings
then
1256
showstate
(
"
stem
"
)
1257
end
1258
stems
=
stems
+
idiv
(
top
,
2
)
1259
top
=
0
1260
end
1261 1262
local
function
getmask
(
)
1263
if
top
=
=
0
then
1264
-- bad
1265
elseif
top
%
2
~
=
0
then
1266
if
width
then
1267
remove
(
stack
,
1
)
1268
else
1269
width
=
remove
(
stack
,
1
)
1270
if
trace_charstrings
then
1271
showvalue
(
"
width
"
,
width
)
1272
end
1273
end
1274
top
=
top
-
1
1275
end
1276
if
trace_charstrings
then
1277
showstate
(
operator
=
=
19
and
"
hintmark
"
or
"
cntrmask
"
)
1278
end
1279
stems
=
stems
+
idiv
(
top
,
2
)
1280
top
=
0
1281
if
stems
=
=
0
then
1282
-- forget about it
1283
elseif
stems
<
=
8
then
1284
return
1
1285
else
1286
-- return floor((stems+7)/8)
1287
return
idiv
(
stems
+
7
,
8
)
1288
end
1289
end
1290 1291
local
function
unsupported
(
t
)
1292
if
trace_charstrings
then
1293
showstate
(
"
unsupported
"
.
.
t
)
1294
end
1295
top
=
0
1296
end
1297 1298
local
function
unsupportedsub
(
t
)
1299
if
trace_charstrings
then
1300
showstate
(
"
unsupported sub
"
.
.
t
)
1301
end
1302
top
=
0
1303
end
1304 1305
-- type 1 (not used in type 2)
1306 1307
local
function
getstem3
(
)
1308
if
trace_charstrings
then
1309
showstate
(
"
stem3
"
)
1310
end
1311
top
=
0
1312
end
1313 1314
local
function
divide
(
)
1315
if
version
=
=
"
cff
"
then
1316
local
d
=
stack
[
top
]
1317
top
=
top
-
1
1318
stack
[
top
]
=
stack
[
top
]
/
d
1319
end
1320
end
1321 1322
local
function
closepath
(
)
1323
if
version
=
=
"
cff
"
then
1324
if
trace_charstrings
then
1325
showstate
(
"
closepath
"
)
1326
end
1327
end
1328
top
=
0
1329
end
1330 1331
local
function
hsbw
(
)
1332
if
version
=
=
"
cff
"
then
1333
if
trace_charstrings
then
1334
showstate
(
"
hsbw
"
)
1335
end
1336
lsb
=
stack
[
top
-1
]
or
0
1337
width
=
stack
[
top
]
1338
end
1339
top
=
0
1340
end
1341 1342
local
function
sbw
(
)
1343
if
version
=
=
"
cff
"
then
1344
if
trace_charstrings
then
1345
showstate
(
"
sbw
"
)
1346
end
1347
lsb
=
stack
[
top
-3
]
1348
width
=
stack
[
top
-1
]
1349
end
1350
top
=
0
1351
end
1352 1353
-- asb adx ady bchar achar seac (accented characters)
1354 1355
local
function
seac
(
)
1356
if
version
=
=
"
cff
"
then
1357
if
trace_charstrings
then
1358
showstate
(
"
seac
"
)
1359
end
1360
end
1361
top
=
0
1362
end
1363 1364
-- These are probably used for special cases i.e. call out to the
1365
-- postscript interpreter (p 61 of the spec as well as chapter 8).
1366
--
1367
-- This needs checking (I have to ask Taco next time we meet.)
1368 1369
local
popped
=
3
1370
local
hints
=
3
1371 1372
-- arg1 ... argn n othersubr# <callothersubr> (on postscript stack)
1373 1374
local
function
callothersubr
(
)
1375
if
version
=
=
"
cff
"
then
1376
if
trace_charstrings
then
1377
showstate
(
"
callothersubr
"
)
1378
end
1379
if
stack
[
top
]
=
=
hints
then
1380
popped
=
stack
[
top
-2
]
1381
else
1382
popped
=
3
1383
end
1384
local
t
=
stack
[
top
-1
]
1385
if
t
then
1386
top
=
top
-
(
t
+
2
)
1387
if
top
<
0
then
1388
top
=
0
1389
end
1390
else
1391
top
=
0
1392
end
1393
else
1394
top
=
0
1395
end
1396
end
1397 1398
-- <pop> number (from postscript stack)
1399 1400
local
function
pop
(
)
1401
if
version
=
=
"
cff
"
then
1402
if
trace_charstrings
then
1403
showstate
(
"
pop
"
)
1404
end
1405
top
=
top
+
1
1406
stack
[
top
]
=
popped
1407
else
1408
top
=
0
1409
end
1410
end
1411 1412
local
function
setcurrentpoint
(
)
1413
if
version
=
=
"
cff
"
then
1414
if
trace_charstrings
then
1415
showstate
(
"
setcurrentpoint (unsupported)
"
)
1416
end
1417
x
=
x
+
stack
[
top
-1
]
1418
y
=
y
+
stack
[
top
]
1419
end
1420
top
=
0
1421
end
1422 1423
-- So far for unsupported postscript. Now some cff2 magic. As I still need
1424
-- to wrap my head around the rather complex variable font specification
1425
-- with regions and axis, the following approach kind of works but is more
1426
-- some trial and error trick. It's still not clear how much of the complex
1427
-- truetype description applies to cff.
1428 1429
local
reginit
=
false
1430 1431
local
function
updateregions
(
n
)
-- n + 1
1432
if
regions
then
1433
local
current
=
regions
[
n
]
or
regions
[
1
]
1434
nofregions
=
#
current
1435
if
axis
and
n
~
=
reginit
then
1436
factors
=
{
}
1437
for
i
=
1
,
nofregions
do
1438
local
region
=
current
[
i
]
1439
local
s
=
1
1440
for
j
=
1
,
#
axis
do
1441
local
f
=
axis
[
j
]
1442
local
r
=
region
[
j
]
1443
local
start
=
r
.
start
1444
local
peak
=
r
.
peak
1445
local
stop
=
r
.
stop
1446
if
start
>
peak
or
peak
>
stop
then
1447
-- * 1
1448
elseif
start
<
0
and
stop
>
0
and
peak
~
=
0
then
1449
-- * 1
1450
elseif
peak
=
=
0
then
1451
-- * 1
1452
elseif
f
<
start
or
f
>
stop
then
1453
-- * 0
1454
s
=
0
1455
break
1456
elseif
f
<
peak
then
1457
s
=
s
*
(
f
-
start
)
/
(
peak
-
start
)
1458
elseif
f
>
peak
then
1459
s
=
s
*
(
stop
-
f
)
/
(
stop
-
peak
)
1460
else
1461
-- * 1
1462
end
1463
end
1464
factors
[
i
]
=
s
1465
end
1466
end
1467
end
1468
reginit
=
n
1469
end
1470 1471
local
function
setvsindex
(
)
1472
local
vsindex
=
stack
[
top
]
1473
if
trace_charstrings
then
1474
showstate
(
formatters
[
"
vsindex %i
"
]
(
vsindex
)
)
1475
end
1476
updateregions
(
vsindex
)
1477
top
=
top
-
1
1478
end
1479 1480
local
function
blend
(
)
1481
local
n
=
stack
[
top
]
1482
top
=
top
-
1
1483
if
axis
then
1484
-- x (r1x,r2x,r3x)
1485
-- (x,y) (r1x,r2x,r3x) (r1y,r2y,r3y)
1486
if
trace_charstrings
then
1487
local
t
=
top
-
nofregions
*
n
1488
local
m
=
t
-
n
1489
for
i
=
1
,
n
do
1490
local
k
=
m
+
i
1491
local
d
=
m
+
n
+
(
i
-1
)
*
nofregions
1492
local
old
=
stack
[
k
]
1493
local
new
=
old
1494
for
r
=
1
,
nofregions
do
1495
new
=
new
+
stack
[
d
+
r
]
*
factors
[
r
]
1496
end
1497
stack
[
k
]
=
new
1498
showstate
(
formatters
[
"
blend %i of %i: %s -> %s
"
]
(
i
,
n
,
old
,
new
)
)
1499
end
1500
top
=
t
1501
elseif
n
=
=
1
then
1502
top
=
top
-
nofregions
1503
local
v
=
stack
[
top
]
1504
for
r
=
1
,
nofregions
do
1505
v
=
v
+
stack
[
top
+
r
]
*
factors
[
r
]
1506
end
1507
stack
[
top
]
=
v
1508
else
1509
top
=
top
-
nofregions
*
n
1510
local
d
=
top
1511
local
k
=
top
-
n
1512
for
i
=
1
,
n
do
1513
k
=
k
+
1
1514
local
v
=
stack
[
k
]
1515
for
r
=
1
,
nofregions
do
1516
v
=
v
+
stack
[
d
+
r
]
*
factors
[
r
]
1517
end
1518
stack
[
k
]
=
v
1519
d
=
d
+
nofregions
1520
end
1521
end
1522
else
1523
top
=
top
-
nofregions
*
n
1524
end
1525
end
1526 1527
-- Bah, we cannot use a fast lpeg because a hint has an unknown size and a
1528
-- runtime capture cannot handle that well.
1529 1530
local
actions
=
{
[
0
]
=
1531
unsupported
,
-- 0
1532
getstem
,
-- 1 -- hstem
1533
unsupported
,
-- 2
1534
getstem
,
-- 3 -- vstem
1535
vmoveto
,
-- 4
1536
rlineto
,
-- 5
1537
hlineto
,
-- 6
1538
vlineto
,
-- 7
1539
rrcurveto
,
-- 8
1540
unsupported
,
-- 9 -- closepath
1541
unsupported
,
-- 10 -- calllocal,
1542
unsupported
,
-- 11 -- callreturn,
1543
unsupported
,
-- 12 -- elsewhere
1544
hsbw
,
-- 13 -- hsbw (type 1 cff)
1545
unsupported
,
-- 14 -- endchar,
1546
setvsindex
,
-- 15 -- cff2
1547
blend
,
-- 16 -- cff2
1548
unsupported
,
-- 17
1549
getstem
,
-- 18 -- hstemhm
1550
getmask
,
-- 19 -- hintmask
1551
getmask
,
-- 20 -- cntrmask
1552
rmoveto
,
-- 21
1553
hmoveto
,
-- 22
1554
getstem
,
-- 23 -- vstemhm
1555
rcurveline
,
-- 24
1556
rlinecurve
,
-- 25
1557
vvcurveto
,
-- 26
1558
hhcurveto
,
-- 27
1559
unsupported
,
-- 28 -- elsewhere
1560
unsupported
,
-- 29 -- elsewhere
1561
vhcurveto
,
-- 30
1562
hvcurveto
,
-- 31
1563
}
1564 1565
local
reverse
=
{
[
0
]
=
1566
"
unsupported
"
,
1567
"
getstem
"
,
1568
"
unsupported
"
,
1569
"
getstem
"
,
1570
"
vmoveto
"
,
1571
"
rlineto
"
,
1572
"
hlineto
"
,
1573
"
vlineto
"
,
1574
"
rrcurveto
"
,
1575
"
unsupported
"
,
1576
"
unsupported
"
,
1577
"
unsupported
"
,
1578
"
unsupported
"
,
1579
"
hsbw
"
,
1580
"
unsupported
"
,
1581
"
setvsindex
"
,
1582
"
blend
"
,
1583
"
unsupported
"
,
1584
"
getstem
"
,
1585
"
getmask
"
,
1586
"
getmask
"
,
1587
"
rmoveto
"
,
1588
"
hmoveto
"
,
1589
"
getstem
"
,
1590
"
rcurveline
"
,
1591
"
rlinecurve
"
,
1592
"
vvcurveto
"
,
1593
"
hhcurveto
"
,
1594
"
unsupported
"
,
1595
"
unsupported
"
,
1596
"
vhcurveto
"
,
1597
"
hvcurveto
"
,
1598
}
1599 1600
local
subactions
=
{
1601
-- cff 1
1602
[
000
]
=
dotsection
,
1603
[
001
]
=
getstem3
,
1604
[
002
]
=
getstem3
,
1605
[
006
]
=
seac
,
1606
[
007
]
=
sbw
,
1607
[
012
]
=
divide
,
1608
[
016
]
=
callothersubr
,
1609
[
017
]
=
pop
,
1610
[
033
]
=
setcurrentpoint
,
1611
-- cff 2
1612
[
034
]
=
hflex
,
1613
[
035
]
=
flex
,
1614
[
036
]
=
hflex1
,
1615
[
037
]
=
flex1
,
1616
}
1617 1618
local
chars
=
setmetatableindex
(
function
(
t
,
k
)
1619
local
v
=
char
(
k
)
1620
t
[
k
]
=
v
1621
return
v
1622
end
)
1623 1624
local
c_endchar
=
chars
[
14
]
1625 1626
-- todo: round in blend
1627 1628
local
encode
=
{
}
1629 1630
-- this eventually can become a helper
1631 1632
setmetatableindex
(
encode
,
function
(
t
,
i
)
1633
for
i
=
-2048
,
-1130
do
1634
t
[
i
]
=
char
(
28
,
band
(
rshift
(
i
,
8
)
,
0xFF
)
,
band
(
i
,
0xFF
)
)
1635
end
1636
for
i
=
-1131
,
-108
do
1637
local
v
=
0xFB00
-
i
-
108
1638
t
[
i
]
=
char
(
band
(
rshift
(
v
,
8
)
,
0xFF
)
,
band
(
v
,
0xFF
)
)
1639
end
1640
for
i
=
-107
,
107
do
1641
t
[
i
]
=
chars
[
i
+
139
]
1642
end
1643
for
i
=
108
,
1131
do
1644
local
v
=
0xF700
+
i
-
108
1645
-- t[i] = char(band(rshift(v,8),0xFF),band(v,0xFF))
1646
t
[
i
]
=
char
(
extract
(
v
,
8
,
8
)
,
extract
(
v
,
0
,
8
)
)
1647
end
1648
for
i
=
1132
,
2048
do
1649
t
[
i
]
=
char
(
28
,
band
(
rshift
(
i
,
8
)
,
0xFF
)
,
band
(
i
,
0xFF
)
)
1650
end
1651
-- we could inline some ...
1652
setmetatableindex
(
encode
,
function
(
t
,
k
)
1653
-- 16.16-bit signed fixed value
1654
local
r
=
round
(
k
)
1655
local
v
=
rawget
(
t
,
r
)
1656
if
v
then
1657
return
v
1658
end
1659
local
v1
=
floor
(
k
)
1660
local
v2
=
floor
(
(
k
-
v1
)
*
0x10000
)
1661
return
char
(
255
,
extract
(
v1
,
8
,
8
)
,
extract
(
v1
,
0
,
8
)
,
extract
(
v2
,
8
,
8
)
,
extract
(
v2
,
0
,
8
)
)
1662
end
)
1663
return
t
[
i
]
1664
end
)
1665 1666
readers
.
cffencoder
=
encode
1667 1668
local
function
p_setvsindex
(
)
1669
local
vsindex
=
stack
[
top
]
1670
updateregions
(
vsindex
)
1671
top
=
top
-
1
1672
end
1673 1674
local
function
p_blend
(
)
1675
-- leaves n values on stack
1676
local
n
=
stack
[
top
]
1677
top
=
top
-
1
1678
if
not
axis
then
1679
-- fatal error
1680
elseif
n
=
=
1
then
1681
top
=
top
-
nofregions
1682
local
v
=
stack
[
top
]
1683
for
r
=
1
,
nofregions
do
1684
v
=
v
+
stack
[
top
+
r
]
*
factors
[
r
]
1685
end
1686
stack
[
top
]
=
round
(
v
)
1687
else
1688
top
=
top
-
nofregions
*
n
1689
local
d
=
top
1690
local
k
=
top
-
n
1691
for
i
=
1
,
n
do
1692
k
=
k
+
1
1693
local
v
=
stack
[
k
]
1694
for
r
=
1
,
nofregions
do
1695
v
=
v
+
stack
[
d
+
r
]
*
factors
[
r
]
1696
end
1697
stack
[
k
]
=
round
(
v
)
1698
d
=
d
+
nofregions
1699
end
1700
end
1701
end
1702 1703
local
function
p_getstem
(
)
1704
local
n
=
0
1705
if
top
%
2
~
=
0
then
1706
n
=
1
1707
end
1708
if
top
>
n
then
1709
stems
=
stems
+
idiv
(
top
-
n
,
2
)
1710
end
1711
end
1712 1713
local
function
p_getmask
(
)
1714
local
n
=
0
1715
if
top
%
2
~
=
0
then
1716
n
=
1
1717
end
1718
if
top
>
n
then
1719
stems
=
stems
+
idiv
(
top
-
n
,
2
)
1720
end
1721
if
stems
=
=
0
then
1722
return
0
1723
elseif
stems
<
=
8
then
1724
return
1
1725
else
1726
return
idiv
(
stems
+
7
,
8
)
1727
end
1728
end
1729 1730
-- end of experiment
1731 1732
local
process
1733 1734
local
function
call
(
scope
,
list
,
bias
)
-- ,process)
1735
depth
=
depth
+
1
1736
if
top
=
=
0
then
1737
showstate
(
formatters
[
"
unknown %s call %s, case %s
"
]
(
scope
,
"
?
"
,
1
)
)
1738
top
=
0
1739
else
1740
local
index
=
stack
[
top
]
+
bias
1741
top
=
top
-
1
1742
if
trace_charstrings
then
1743
showvalue
(
scope
,
index
,
true
)
1744
end
1745
local
tab
=
list
[
index
]
1746
if
tab
then
1747
process
(
tab
)
1748
else
1749
showstate
(
formatters
[
"
unknown %s call %s, case %s
"
]
(
scope
,
index
,
2
)
)
1750
top
=
0
1751
end
1752
end
1753
depth
=
depth
-
1
1754
end
1755 1756
-- precompiling and reuse is much slower than redoing the calls
1757 1758
-- local function decode(str)
1759
-- local a, b, c, d, e = byte(str,1,5)
1760
-- if a == 28 then
1761
-- if c then
1762
-- local n = 0x100 * b + c
1763
-- if n >= 0x8000 then
1764
-- return n - 0x10000
1765
-- else
1766
-- return n
1767
-- end
1768
-- end
1769
-- elseif a < 32 then
1770
-- return false
1771
-- elseif a <= 246 then
1772
-- return a - 139
1773
-- elseif a <= 250 then
1774
-- if b then
1775
-- return a*256 - 63124 + b
1776
-- end
1777
-- elseif a <= 254 then
1778
-- if b then
1779
-- return -a*256 + 64148 - b
1780
-- end
1781
-- else
1782
-- if e then
1783
-- local n = 0x100 * b + c
1784
-- if n >= 0x8000 then
1785
-- return n - 0x10000 + (0x100 * d + e)/0xFFFF
1786
-- else
1787
-- return n + (0x100 * d + e)/0xFFFF
1788
-- end
1789
-- end
1790
-- end
1791
-- return false
1792
-- end
1793 1794
process
=
function
(
tab
)
1795
local
i
=
1
1796
local
n
=
#
tab
1797
while
i
<
=
n
do
1798
local
t
=
tab
[
i
]
1799
if
t
>
=
32
then
1800
top
=
top
+
1
1801
if
t
<
=
246
then
1802
-- -107 .. +107
1803
stack
[
top
]
=
t
-
139
1804
i
=
i
+
1
1805
elseif
t
<
=
250
then
1806
-- +108 .. +1131
1807
-- stack[top] = (t-247)*256 + tab[i+1] + 108
1808
-- stack[top] = t*256 - 247*256 + tab[i+1] + 108
1809
stack
[
top
]
=
t
*
256
-
63124
+
tab
[
i
+
1
]
1810
i
=
i
+
2
1811
elseif
t
<
=
254
then
1812
-- -1131 .. -108
1813
-- stack[top] = -(t-251)*256 - tab[i+1] - 108
1814
-- stack[top] = -t*256 + 251*256 - tab[i+1] - 108
1815
stack
[
top
]
=
-
t
*
256
+
64148
-
tab
[
i
+
1
]
1816
i
=
i
+
2
1817
else
1818
-- a 16.16 float
1819
local
n
=
0x100
*
tab
[
i
+
1
]
+
tab
[
i
+
2
]
1820
if
n
>
=
0x8000
then
1821
stack
[
top
]
=
n
-
0x10000
+
(
0x100
*
tab
[
i
+
3
]
+
tab
[
i
+
4
]
)
/
0xFFFF
1822
else
1823
stack
[
top
]
=
n
+
(
0x100
*
tab
[
i
+
3
]
+
tab
[
i
+
4
]
)
/
0xFFFF
1824
end
1825
i
=
i
+
5
1826
end
1827
elseif
t
=
=
28
then
1828
-- -32768 .. +32767 : b1<<8 | b2
1829
top
=
top
+
1
1830
local
n
=
0x100
*
tab
[
i
+
1
]
+
tab
[
i
+
2
]
1831
if
n
>
=
0x8000
then
1832
-- stack[top] = n - 0xFFFF - 1
1833
stack
[
top
]
=
n
-
0x10000
1834
else
1835
stack
[
top
]
=
n
1836
end
1837
i
=
i
+
3
1838
elseif
t
=
=
11
then
-- not in cff2
1839
if
trace_charstrings
then
1840
showstate
(
"
return
"
)
1841
end
1842
return
1843
elseif
t
=
=
10
then
1844
call
(
"
local
"
,
locals
,
localbias
)
-- ,process)
1845
i
=
i
+
1
1846
elseif
t
=
=
14
then
-- not in cff2
1847
if
width
then
1848
-- okay
1849
elseif
top
>
0
then
1850
width
=
stack
[
1
]
1851
if
trace_charstrings
then
1852
showvalue
(
"
width
"
,
width
)
1853
end
1854
else
1855
width
=
true
1856
end
1857
if
trace_charstrings
then
1858
showstate
(
"
endchar
"
)
1859
end
1860
return
1861
elseif
t
=
=
29
then
1862
call
(
"
global
"
,
globals
,
globalbias
)
-- ,process)
1863
i
=
i
+
1
1864
elseif
t
=
=
12
then
1865
i
=
i
+
1
1866
local
t
=
tab
[
i
]
1867
if
justpass
then
1868
if
t
>
=
34
and
t
<
=
37
then
-- flexes
1869
for
i
=
1
,
top
do
1870
r
=
r
+
1
;
result
[
r
]
=
encode
[
stack
[
i
]
]
1871
end
1872
r
=
r
+
1
;
result
[
r
]
=
chars
[
12
]
1873
r
=
r
+
1
;
result
[
r
]
=
chars
[
t
]
1874
top
=
0
1875
elseif
t
=
=
6
then
1876
seacs
[
procidx
]
=
{
1877
asb
=
stack
[
1
]
,
1878
adx
=
stack
[
2
]
,
1879
ady
=
stack
[
3
]
,
1880
base
=
stack
[
4
]
,
1881
accent
=
stack
[
5
]
,
1882
width
=
width
,
1883
lsb
=
lsb
,
1884
}
1885
top
=
0
1886
else
1887
local
a
=
subactions
[
t
]
1888
if
a
then
1889
a
(
t
)
1890
else
1891
top
=
0
1892
end
1893
end
1894
else
1895
local
a
=
subactions
[
t
]
1896
if
a
then
1897
a
(
t
)
1898
else
1899
if
trace_charstrings
then
1900
showvalue
(
"
<subaction>
"
,
t
)
1901
end
1902
top
=
0
1903
end
1904
end
1905
i
=
i
+
1
1906
elseif
justpass
then
1907
-- todo: local a = passactions
1908
if
t
=
=
15
then
1909
p_setvsindex
(
)
1910
i
=
i
+
1
1911
elseif
t
=
=
16
then
1912
local
s
=
p_blend
(
)
or
0
1913
i
=
i
+
s
+
1
1914
-- cff 1: (when cff2 strip them)
1915
elseif
t
=
=
1
or
t
=
=
3
or
t
=
=
18
or
operation
=
=
23
then
1916
p_getstem
(
)
-- at the start
1917
if
true
then
1918
if
top
>
0
then
1919
for
i
=
1
,
top
do
1920
r
=
r
+
1
;
result
[
r
]
=
encode
[
stack
[
i
]
]
1921
end
1922
top
=
0
1923
end
1924
r
=
r
+
1
;
result
[
r
]
=
chars
[
t
]
1925
else
1926
top
=
0
1927
end
1928
i
=
i
+
1
1929
-- cff 1: (when cff2 strip them)
1930
elseif
t
=
=
19
or
t
=
=
20
then
1931
local
s
=
p_getmask
(
)
or
0
-- after the stems
1932
if
true
then
1933
if
top
>
0
then
1934
for
i
=
1
,
top
do
1935
r
=
r
+
1
;
result
[
r
]
=
encode
[
stack
[
i
]
]
1936
end
1937
top
=
0
1938
end
1939
r
=
r
+
1
;
result
[
r
]
=
chars
[
t
]
1940
for
j
=
1
,
s
do
1941
i
=
i
+
1
1942
r
=
r
+
1
;
result
[
r
]
=
chars
[
tab
[
i
]
]
1943
end
1944
else
1945
i
=
i
+
s
1946
top
=
0
1947
end
1948
i
=
i
+
1
1949
-- cff 1: closepath
1950
elseif
t
=
=
9
then
1951
top
=
0
1952
i
=
i
+
1
1953
elseif
t
=
=
13
then
1954
hsbw
(
)
1955
if
version
=
=
"
cff
"
then
1956
-- we do a moveto over lsb
1957
r
=
r
+
1
;
result
[
r
]
=
encode
[
lsb
]
1958
r
=
r
+
1
;
result
[
r
]
=
chars
[
22
]
1959
else
1960
-- lsb is supposed to be zero
1961
end
1962
i
=
i
+
1
1963
else
1964
if
trace_charstrings
then
1965
showstate
(
reverse
[
t
]
or
"
<action>
"
)
1966
end
1967
if
top
>
0
then
1968
for
i
=
1
,
top
do
1969
r
=
r
+
1
;
result
[
r
]
=
encode
[
stack
[
i
]
]
1970
end
1971
top
=
0
1972
end
1973
r
=
r
+
1
;
result
[
r
]
=
chars
[
t
]
1974
i
=
i
+
1
1975
end
1976
else
1977
local
a
=
actions
[
t
]
1978
if
a
then
1979
local
s
=
a
(
t
)
1980
if
s
then
1981
i
=
i
+
s
+
1
1982
else
1983
i
=
i
+
1
1984
end
1985
else
1986
if
trace_charstrings
then
1987
showstate
(
reverse
[
t
]
or
"
<action>
"
)
1988
end
1989
top
=
0
1990
i
=
i
+
1
1991
end
1992
end
1993
end
1994
end
1995 1996
-- local function calculatebounds(segments,x,y)
1997
-- local nofsegments = #segments
1998
-- if nofsegments == 0 then
1999
-- return { x, y, x, y }
2000
-- else
2001
-- local xmin = 10000
2002
-- local xmax = -10000
2003
-- local ymin = 10000
2004
-- local ymax = -10000
2005
-- if x < xmin then xmin = x end
2006
-- if x > xmax then xmax = x end
2007
-- if y < ymin then ymin = y end
2008
-- if y > ymax then ymax = y end
2009
-- -- we now have a reasonable start so we could
2010
-- -- simplify the next checks
2011
-- for i=1,nofsegments do
2012
-- local s = segments[i]
2013
-- local x = s[1]
2014
-- local y = s[2]
2015
-- if x < xmin then xmin = x end
2016
-- if x > xmax then xmax = x end
2017
-- if y < ymin then ymin = y end
2018
-- if y > ymax then ymax = y end
2019
-- if s[#s] == "c" then -- "curveto"
2020
-- local x = s[3]
2021
-- local y = s[4]
2022
-- if x < xmin then xmin = x elseif x > xmax then xmax = x end
2023
-- if y < ymin then ymin = y elseif y > ymax then ymax = y end
2024
-- local x = s[5]
2025
-- local y = s[6]
2026
-- if x < xmin then xmin = x elseif x > xmax then xmax = x end
2027
-- if y < ymin then ymin = y elseif y > ymax then ymax = y end
2028
-- end
2029
-- end
2030
-- return { round(xmin), round(ymin), round(xmax), round(ymax) } -- doesn't make ceil more sense
2031
-- end
2032
-- end
2033 2034
local
function
setbias
(
globals
,
locals
,
nobias
)
2035
if
nobias
then
2036
return
0
,
0
2037
else
2038
local
g
=
#
globals
2039
local
l
=
#
locals
2040
return
2041
(
(
g
<
1240
and
107
)
or
(
g
<
33900
and
1131
)
or
32768
)
+
1
,
2042
(
(
l
<
1240
and
107
)
or
(
l
<
33900
and
1131
)
or
32768
)
+
1
2043
end
2044
end
2045 2046
local
function
processshape
(
tab
,
index
,
hack
)
2047 2048
if
not
tab
then
2049
glyphs
[
index
]
=
{
2050
boundingbox
=
{
0
,
0
,
0
,
0
}
,
2051
width
=
0
,
2052
name
=
charset
and
charset
[
index
]
or
nil
,
2053
}
2054
return
2055
end
2056 2057
tab
=
bytetable
(
tab
)
2058 2059
x
=
0
2060
y
=
0
2061
width
=
false
2062
lsb
=
0
2063
r
=
0
2064
top
=
0
2065
stems
=
0
2066
result
=
{
}
-- we could reuse it when only boundingbox calculations are needed
2067
popped
=
3
2068
procidx
=
index
2069 2070
xmin
=
0
2071
xmax
=
0
2072
ymin
=
0
2073
ymax
=
0
2074
checked
=
false
2075
if
trace_charstrings
then
2076
report
(
"
glyph: %i
"
,
index
)
2077
report
(
"
data : % t
"
,
tab
)
2078
end
2079 2080
if
regions
then
2081
updateregions
(
vsindex
)
2082
end
2083 2084
process
(
tab
)
2085 2086
if
hack
then
2087
return
x
,
y
2088
end
2089 2090
local
boundingbox
=
{
2091
round
(
xmin
)
,
2092
round
(
ymin
)
,
2093
round
(
xmax
)
,
2094
round
(
ymax
)
,
2095
}
2096 2097
if
width
=
=
true
or
width
=
=
false
then
2098
width
=
defaultwidth
2099
else
2100
width
=
nominalwidth
+
width
2101
end
2102 2103
local
glyph
=
glyphs
[
index
]
-- can be autodefined in otr
2104
if
justpass
then
2105
r
=
r
+
1
2106
result
[
r
]
=
c_endchar
2107
local
stream
=
concat
(
result
)
2108
-- if trace_charstrings then
2109
-- report("vdata: %s",stream)
2110
-- end
2111
if
glyph
then
2112
glyph
.
stream
=
stream
2113
else
2114
glyphs
[
index
]
=
{
stream
=
stream
}
2115
end
2116
elseif
glyph
then
2117
glyph
.
segments
=
keepcurve
~
=
false
and
result
or
nil
2118
glyph
.
boundingbox
=
boundingbox
2119
if
not
glyph
.
width
then
2120
glyph
.
width
=
width
2121
end
2122
if
charset
and
not
glyph
.
name
then
2123
glyph
.
name
=
charset
[
index
]
2124
end
2125
-- glyph.sidebearing = 0 -- todo
2126
elseif
keepcurve
then
2127
glyphs
[
index
]
=
{
2128
segments
=
result
,
2129
boundingbox
=
boundingbox
,
2130
width
=
width
,
2131
name
=
charset
and
charset
[
index
]
or
nil
,
2132
-- sidebearing = 0,
2133
}
2134
else
2135
glyphs
[
index
]
=
{
2136
boundingbox
=
boundingbox
,
2137
width
=
width
,
2138
name
=
charset
and
charset
[
index
]
or
nil
,
2139
}
2140
end
2141 2142
if
trace_charstrings
then
2143
report
(
"
width : %s
"
,
tostring
(
width
)
)
2144
report
(
"
boundingbox: % t
"
,
boundingbox
)
2145
end
2146 2147
end
2148 2149
startparsing
=
function
(
fontdata
,
data
,
streams
)
2150
reginit
=
false
2151
axis
=
false
2152
regions
=
data
.
regions
2153
justpass
=
streams
=
=
true
2154
popped
=
3
2155
seacs
=
{
}
2156
if
regions
then
2157
regions
=
{
regions
}
-- needs checking
2158
axis
=
data
.
factors
or
false
2159
end
2160
end
2161 2162
stopparsing
=
function
(
fontdata
,
data
)
2163
stack
=
{
}
2164
glyphs
=
false
2165
result
=
{
}
2166
top
=
0
2167
locals
=
false
2168
globals
=
false
2169
strings
=
false
2170
popped
=
3
2171
seacs
=
{
}
2172
end
2173 2174
local
function
setwidths
(
private
)
2175
if
not
private
then
2176
return
0
,
0
2177
end
2178
local
privatedata
=
private
.
data
2179
if
not
privatedata
then
2180
return
0
,
0
2181
end
2182
return
privatedata
.
nominalwidthx
or
0
,
privatedata
.
defaultwidthx
or
0
2183
end
2184 2185
parsecharstrings
=
function
(
fontdata
,
data
,
glphs
,
doshapes
,
tversion
,
streams
,
nobias
)
2186 2187
local
dictionary
=
data
.
dictionaries
[
1
]
2188
local
charstrings
=
dictionary
.
charstrings
2189 2190
keepcurve
=
doshapes
2191
version
=
tversion
2192
strings
=
data
.
strings
2193
globals
=
data
.
routines
or
{
}
2194
locals
=
dictionary
.
subroutines
or
{
}
2195
charset
=
dictionary
.
charset
2196
vsindex
=
dictionary
.
vsindex
or
0
2197
glyphs
=
glphs
or
{
}
2198 2199
globalbias
,
localbias
=
setbias
(
globals
,
locals
,
nobias
)
2200
nominalwidth
,
defaultwidth
=
setwidths
(
dictionary
.
private
)
2201 2202
if
charstrings
then
2203
startparsing
(
fontdata
,
data
,
streams
)
2204
for
index
=
1
,
#
charstrings
do
2205
processshape
(
charstrings
[
index
]
,
index
-1
)
2206
end
2207
if
justpass
and
next
(
seacs
)
then
2208
-- old type 1 stuff ... seacs
2209
local
charset
=
data
.
dictionaries
[
1
]
.
charset
2210
if
charset
then
2211
local
lookup
=
table
.
swapped
(
charset
)
2212
for
index
,
v
in
next
,
seacs
do
2213
local
bindex
=
lookup
[
standardnames
[
v
.
base
]
]
2214
local
aindex
=
lookup
[
standardnames
[
v
.
accent
]
]
2215
local
bglyph
=
bindex
and
glyphs
[
bindex
]
2216
local
aglyph
=
aindex
and
glyphs
[
aindex
]
2217
if
bglyph
and
aglyph
then
2218
-- this is a real ugly hack but we seldom enter this branch (e.g. old lbr)
2219
local
jp
=
justpass
2220
justpass
=
false
2221
local
x
,
y
=
processshape
(
charstrings
[
bindex
+
1
]
,
bindex
,
true
)
2222
justpass
=
jp
2223
--
2224
local
base
=
bglyph
.
stream
2225
local
accent
=
aglyph
.
stream
2226
local
moveto
=
encode
[
-
x
-
v
.
asb
+
v
.
adx
]
.
.
chars
[
22
]
2227
.
.
encode
[
-
y
+
v
.
ady
]
.
.
chars
[
4
]
2228
-- prune an endchar
2229
base
=
sub
(
base
,
1
,
#
base
-1
)
2230
-- combine them
2231
glyphs
[
index
]
.
stream
=
base
.
.
moveto
.
.
accent
2232
end
2233
end
2234
end
2235
end
2236
stopparsing
(
fontdata
,
data
)
2237
else
2238
report
(
"
no charstrings
"
)
2239
end
2240
return
glyphs
2241
end
2242 2243
parsecharstring
=
function
(
fontdata
,
data
,
dictionary
,
tab
,
glphs
,
index
,
doshapes
,
tversion
,
streams
)
2244 2245
keepcurve
=
doshapes
2246
version
=
tversion
2247
strings
=
data
.
strings
2248
globals
=
data
.
routines
or
{
}
2249
locals
=
dictionary
.
subroutines
or
{
}
2250
charset
=
false
2251
vsindex
=
dictionary
.
vsindex
or
0
2252
glyphs
=
glphs
or
{
}
2253 2254
justpass
=
streams
=
=
true
2255
seacs
=
{
}
2256 2257
globalbias
,
localbias
=
setbias
(
globals
,
locals
,
nobias
)
2258
nominalwidth
,
defaultwidth
=
setwidths
(
dictionary
.
private
)
2259 2260
processshape
(
tab
,
index
-1
)
2261 2262
-- return glyphs[index]
2263
end
2264 2265
end
2266 2267
local
function
readglobals
(
f
,
data
)
2268
local
routines
=
readlengths
(
f
)
2269
for
i
=
1
,
#
routines
do
2270
routines
[
i
]
=
readbytetable
(
f
,
routines
[
i
]
)
2271
end
2272
data
.
routines
=
routines
2273
end
2274 2275
local
function
readencodings
(
f
,
data
)
2276
data
.
encodings
=
{
}
2277
end
2278 2279
local
function
readcharsets
(
f
,
data
,
dictionary
)
2280
local
header
=
data
.
header
2281
local
strings
=
data
.
strings
2282
local
nofglyphs
=
data
.
nofglyphs
2283
local
charsetoffset
=
dictionary
.
charset
2284
if
charsetoffset
and
charsetoffset
~
=
0
then
2285
setposition
(
f
,
header
.
offset
+
charsetoffset
)
2286
local
format
=
readbyte
(
f
)
2287
local
charset
=
{
[
0
]
=
"
.notdef
"
}
2288
dictionary
.
charset
=
charset
2289
if
format
=
=
0
then
2290
for
i
=
1
,
nofglyphs
do
2291
charset
[
i
]
=
strings
[
readushort
(
f
)
]
2292
end
2293
elseif
format
=
=
1
or
format
=
=
2
then
2294
local
readcount
=
format
=
=
1
and
readbyte
or
readushort
2295
local
i
=
1
2296
while
i
<
=
nofglyphs
do
2297
local
sid
=
readushort
(
f
)
2298
local
n
=
readcount
(
f
)
2299
for
s
=
sid
,
sid
+
n
do
2300
charset
[
i
]
=
strings
[
s
]
2301
i
=
i
+
1
2302
if
i
>
nofglyphs
then
2303
break
2304
end
2305
end
2306
end
2307
else
2308
report
(
"
cff parser: unsupported charset format %a
"
,
format
)
2309
end
2310
else
2311
dictionary
.
nocharset
=
true
2312
dictionary
.
charset
=
nil
2313
end
2314
end
2315 2316
local
function
readprivates
(
f
,
data
)
2317
local
header
=
data
.
header
2318
local
dictionaries
=
data
.
dictionaries
2319
local
private
=
dictionaries
[
1
]
.
private
2320
if
private
then
2321
setposition
(
f
,
header
.
offset
+
private
.
offset
)
2322
private
.
data
=
readstring
(
f
,
private
.
size
)
2323
end
2324
end
2325 2326
local
function
readlocals
(
f
,
data
,
dictionary
)
2327
local
header
=
data
.
header
2328
local
private
=
dictionary
.
private
2329
if
private
then
2330
local
subroutineoffset
=
private
.
data
.
subroutines
2331
if
subroutineoffset
~
=
0
then
2332
setposition
(
f
,
header
.
offset
+
private
.
offset
+
subroutineoffset
)
2333
local
subroutines
=
readlengths
(
f
)
2334
for
i
=
1
,
#
subroutines
do
2335
subroutines
[
i
]
=
readbytetable
(
f
,
subroutines
[
i
]
)
2336
end
2337
dictionary
.
subroutines
=
subroutines
2338
private
.
data
.
subroutines
=
nil
2339
else
2340
dictionary
.
subroutines
=
{
}
2341
end
2342
else
2343
dictionary
.
subroutines
=
{
}
2344
end
2345
end
2346 2347
-- These charstrings are little programs and described in: Technical Note #5177. A truetype
2348
-- font has only one dictionary.
2349 2350
local
function
readcharstrings
(
f
,
data
,
what
)
2351
local
header
=
data
.
header
2352
local
dictionaries
=
data
.
dictionaries
2353
local
dictionary
=
dictionaries
[
1
]
2354
local
stringtype
=
dictionary
.
charstringtype
2355
local
offset
=
dictionary
.
charstrings
2356
if
type
(
offset
)
~
=
"
number
"
then
2357
-- weird
2358
elseif
stringtype
=
=
2
then
2359
setposition
(
f
,
header
.
offset
+
offset
)
2360
-- could be a metatable .. delayed loading
2361
local
charstrings
=
readlengths
(
f
,
what
=
=
"
cff2
"
)
2362
local
nofglyphs
=
#
charstrings
2363
for
i
=
1
,
nofglyphs
do
2364
charstrings
[
i
]
=
readstring
(
f
,
charstrings
[
i
]
)
2365
end
2366
data
.
nofglyphs
=
nofglyphs
2367
dictionary
.
charstrings
=
charstrings
2368
else
2369
report
(
"
unsupported charstr type %i
"
,
stringtype
)
2370
data
.
nofglyphs
=
0
2371
dictionary
.
charstrings
=
{
}
2372
end
2373
end
2374 2375
-- cid (maybe do this stepwise so less mem) -- share with above
2376 2377
local
function
readcidprivates
(
f
,
data
)
2378
local
header
=
data
.
header
2379
local
dictionaries
=
data
.
dictionaries
[
1
]
.
cid
.
dictionaries
2380
for
i
=
1
,
#
dictionaries
do
2381
local
dictionary
=
dictionaries
[
i
]
2382
local
private
=
dictionary
.
private
2383
if
private
then
2384
setposition
(
f
,
header
.
offset
+
private
.
offset
)
2385
private
.
data
=
readstring
(
f
,
private
.
size
)
2386
end
2387
end
2388
parseprivates
(
data
,
dictionaries
)
2389
end
2390 2391
readers
.
parsecharstrings
=
parsecharstrings
-- used in font-onr.lua (type 1)
2392 2393
local
function
readnoselect
(
f
,
fontdata
,
data
,
glyphs
,
doshapes
,
version
,
streams
)
2394
local
dictionaries
=
data
.
dictionaries
2395
local
dictionary
=
dictionaries
[
1
]
2396
readglobals
(
f
,
data
)
2397
readcharstrings
(
f
,
data
,
version
)
2398
if
version
=
=
"
cff2
"
then
2399
dictionary
.
charset
=
nil
2400
else
2401
readencodings
(
f
,
data
)
2402
readcharsets
(
f
,
data
,
dictionary
)
2403
end
2404
readprivates
(
f
,
data
)
2405
parseprivates
(
data
,
data
.
dictionaries
)
2406
readlocals
(
f
,
data
,
dictionary
)
2407
startparsing
(
fontdata
,
data
,
streams
)
2408
parsecharstrings
(
fontdata
,
data
,
glyphs
,
doshapes
,
version
,
streams
)
2409
stopparsing
(
fontdata
,
data
)
2410
end
2411 2412
local
function
readfdselect
(
f
,
fontdata
,
data
,
glyphs
,
doshapes
,
version
,
streams
)
2413
local
header
=
data
.
header
2414
local
dictionaries
=
data
.
dictionaries
2415
local
dictionary
=
dictionaries
[
1
]
2416
local
cid
=
dictionary
.
cid
2417
local
cidselect
=
cid
and
cid
.
fdselect
2418
readglobals
(
f
,
data
)
2419
readcharstrings
(
f
,
data
,
version
)
2420
if
version
~
=
"
cff2
"
then
2421
readencodings
(
f
,
data
)
2422
end
2423
local
charstrings
=
dictionary
.
charstrings
2424
local
fdindex
=
{
}
2425
local
nofglyphs
=
data
.
nofglyphs
2426
local
maxindex
=
-1
2427
setposition
(
f
,
header
.
offset
+
cidselect
)
2428
local
format
=
readbyte
(
f
)
2429
if
format
=
=
1
then
2430
for
i
=
0
,
nofglyphs
do
-- notdef included (needs checking)
2431
local
index
=
readbyte
(
f
)
2432
fdindex
[
i
]
=
index
2433
if
index
>
maxindex
then
2434
maxindex
=
index
2435
end
2436
end
2437
elseif
format
=
=
3
then
2438
local
nofranges
=
readushort
(
f
)
2439
local
first
=
readushort
(
f
)
2440
local
index
=
readbyte
(
f
)
2441
while
true
do
2442
local
last
=
readushort
(
f
)
2443
if
index
>
maxindex
then
2444
maxindex
=
index
2445
end
2446
for
i
=
first
,
last
do
2447
fdindex
[
i
]
=
index
2448
end
2449
if
last
>
=
nofglyphs
then
2450
break
2451
else
2452
first
=
last
+
1
2453
index
=
readbyte
(
f
)
2454
end
2455
end
2456
else
2457
-- unsupported format
2458
end
2459
-- hm, always
2460
if
maxindex
>
=
0
then
2461
local
cidarray
=
cid
.
fdarray
2462
if
cidarray
then
2463
setposition
(
f
,
header
.
offset
+
cidarray
)
2464
local
dictionaries
=
readlengths
(
f
)
2465
for
i
=
1
,
#
dictionaries
do
2466
dictionaries
[
i
]
=
readstring
(
f
,
dictionaries
[
i
]
)
2467
end
2468
parsedictionaries
(
data
,
dictionaries
)
2469
cid
.
dictionaries
=
dictionaries
2470
readcidprivates
(
f
,
data
)
2471
for
i
=
1
,
#
dictionaries
do
2472
readlocals
(
f
,
data
,
dictionaries
[
i
]
)
2473
end
2474
startparsing
(
fontdata
,
data
,
streams
)
2475
for
i
=
1
,
#
charstrings
do
2476
parsecharstring
(
fontdata
,
data
,
dictionaries
[
fdindex
[
i
]
+
1
]
,
charstrings
[
i
]
,
glyphs
,
i
,
doshapes
,
version
,
streams
)
2477
-- charstrings[i] = nil
2478
end
2479
stopparsing
(
fontdata
,
data
)
2480
else
2481
report
(
"
no cid array
"
)
2482
end
2483
end
2484
end
2485 2486
local
gotodatatable
=
readers
.
helpers
.
gotodatatable
2487 2488
local
function
cleanup
(
data
,
dictionaries
)
2489
-- for i=1,#dictionaries do
2490
-- local d = dictionaries[i]
2491
-- d.subroutines = nil
2492
-- end
2493
-- data.strings = nil
2494
-- if data then
2495
-- data.charstrings = nil
2496
-- data.routines = nil
2497
-- end
2498
end
2499 2500
function
readers
.
cff
(
f
,
fontdata
,
specification
)
2501
local
tableoffset
=
gotodatatable
(
f
,
fontdata
,
"
cff
"
,
specification
.
details
or
specification
.
glyphs
)
2502
if
tableoffset
then
2503
local
header
=
readheader
(
f
)
2504
if
header
.
major
~
=
1
then
2505
report
(
"
only version %s is supported for table %a
"
,
1
,
"
cff
"
)
2506
return
2507
end
2508
local
glyphs
=
fontdata
.
glyphs
2509
local
names
=
readfontnames
(
f
)
2510
local
dictionaries
=
readtopdictionaries
(
f
)
2511
local
strings
=
readstrings
(
f
)
2512
local
data
=
{
2513
header
=
header
,
2514
names
=
names
,
2515
dictionaries
=
dictionaries
,
2516
strings
=
strings
,
2517
nofglyphs
=
fontdata
.
nofglyphs
,
2518
}
2519
--
2520
parsedictionaries
(
data
,
dictionaries
,
"
cff
"
)
2521
--
2522
local
dic
=
dictionaries
[
1
]
2523
local
cid
=
dic
.
cid
2524
--
2525
local
cffinfo
=
{
2526
familyname
=
dic
.
familyname
,
2527
fullname
=
dic
.
fullname
,
2528
boundingbox
=
dic
.
boundingbox
,
2529
weight
=
dic
.
weight
,
2530
italicangle
=
dic
.
italicangle
,
2531
underlineposition
=
dic
.
underlineposition
,
2532
underlinethickness
=
dic
.
underlinethickness
,
2533
defaultwidth
=
dic
.
defaultwidthx
,
2534
nominalwidth
=
dic
.
nominalwidthx
,
2535
monospaced
=
dic
.
monospaced
,
2536
}
2537
fontdata
.
cidinfo
=
cid
and
{
2538
registry
=
cid
.
registry
,
2539
ordering
=
cid
.
ordering
,
2540
supplement
=
cid
.
supplement
,
2541
}
2542
fontdata
.
cffinfo
=
cffinfo
2543
--
2544
local
all
=
specification
.
shapes
or
specification
.
streams
or
false
2545
if
specification
.
glyphs
or
all
then
2546
if
cid
and
cid
.
fdselect
then
2547
readfdselect
(
f
,
fontdata
,
data
,
glyphs
,
all
,
"
cff
"
,
specification
.
streams
)
2548
else
2549
readnoselect
(
f
,
fontdata
,
data
,
glyphs
,
all
,
"
cff
"
,
specification
.
streams
)
2550
end
2551
end
2552
local
private
=
dic
.
private
2553
if
private
then
2554
local
data
=
private
.
data
2555
if
type
(
data
)
=
=
"
table
"
then
2556
cffinfo
.
defaultwidth
=
data
.
defaultwidthx
or
cffinfo
.
defaultwidth
2557
cffinfo
.
nominalwidth
=
data
.
nominalwidthx
or
cffinfo
.
nominalwidth
2558
cffinfo
.
bluevalues
=
data
.
bluevalues
2559
cffinfo
.
otherblues
=
data
.
otherblues
2560
cffinfo
.
familyblues
=
data
.
familyblues
2561
cffinfo
.
familyotherblues
=
data
.
familyotherblues
2562
cffinfo
.
bluescale
=
data
.
bluescale
2563
cffinfo
.
blueshift
=
data
.
blueshift
2564
cffinfo
.
bluefuzz
=
data
.
bluefuzz
2565
cffinfo
.
stdhw
=
data
.
stdhw
2566
cffinfo
.
stdvw
=
data
.
stdvw
2567
end
2568
end
2569
cleanup
(
data
,
dictionaries
)
2570
end
2571
end
2572 2573
function
readers
.
cff2
(
f
,
fontdata
,
specification
)
2574
local
tableoffset
=
gotodatatable
(
f
,
fontdata
,
"
cff2
"
,
specification
.
glyphs
)
2575
if
tableoffset
then
2576
local
header
=
readheader
(
f
)
2577
if
header
.
major
~
=
2
then
2578
report
(
"
only version %s is supported for table %a
"
,
2
,
"
cff2
"
)
2579
return
2580
end
2581
local
glyphs
=
fontdata
.
glyphs
2582
local
dictionaries
=
{
readstring
(
f
,
header
.
dsize
)
}
2583
local
data
=
{
2584
header
=
header
,
2585
dictionaries
=
dictionaries
,
2586
nofglyphs
=
fontdata
.
nofglyphs
,
2587
}
2588
--
2589
parsedictionaries
(
data
,
dictionaries
,
"
cff2
"
)
2590
--
2591
local
offset
=
dictionaries
[
1
]
.
vstore
2592
if
offset
>
0
then
2593
local
storeoffset
=
dictionaries
[
1
]
.
vstore
+
data
.
header
.
offset
+
2
-- cff has a preceding size field
2594
local
regions
,
deltas
=
readers
.
helpers
.
readvariationdata
(
f
,
storeoffset
,
factors
)
2595
--
2596
data
.
regions
=
regions
2597
data
.
deltas
=
deltas
2598
else
2599
data
.
regions
=
{
}
2600
data
.
deltas
=
{
}
2601
end
2602
data
.
factors
=
specification
.
factors
2603
--
2604
local
cid
=
data
.
dictionaries
[
1
]
.
cid
2605
local
all
=
specification
.
shapes
or
specification
.
streams
or
false
2606
if
cid
and
cid
.
fdselect
then
2607
readfdselect
(
f
,
fontdata
,
data
,
glyphs
,
all
,
"
cff2
"
,
specification
.
streams
)
2608
else
2609
readnoselect
(
f
,
fontdata
,
data
,
glyphs
,
all
,
"
cff2
"
,
specification
.
streams
)
2610
end
2611
cleanup
(
data
,
dictionaries
)
2612
end
2613
end
2614 2615
-- temporary helper needed for checking backend patches
2616 2617
function
readers
.
cffcheck
(
filename
)
2618
local
f
=
io
.
open
(
filename
,
"
rb
"
)
2619
if
f
then
2620
local
fontdata
=
{
2621
glyphs
=
{
}
,
2622
}
2623
local
header
=
readheader
(
f
)
2624
if
header
.
major
~
=
1
then
2625
report
(
"
only version %s is supported for table %a
"
,
1
,
"
cff
"
)
2626
return
2627
end
2628
local
names
=
readfontnames
(
f
)
2629
local
dictionaries
=
readtopdictionaries
(
f
)
2630
local
strings
=
readstrings
(
f
)
2631
local
glyphs
=
{
}
2632
local
data
=
{
2633
header
=
header
,
2634
names
=
names
,
2635
dictionaries
=
dictionaries
,
2636
strings
=
strings
,
2637
glyphs
=
glyphs
,
2638
nofglyphs
=
0
,
2639
}
2640
--
2641
parsedictionaries
(
data
,
dictionaries
,
"
cff
"
)
2642
--
2643
local
cid
=
data
.
dictionaries
[
1
]
.
cid
2644
if
cid
and
cid
.
fdselect
then
2645
readfdselect
(
f
,
fontdata
,
data
,
glyphs
,
false
)
2646
else
2647
readnoselect
(
f
,
fontdata
,
data
,
glyphs
,
false
)
2648
end
2649
return
data
2650
end
2651
end
2652