summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/font-cff.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkiv/font-cff.lua')
-rw-r--r--tex/context/base/mkiv/font-cff.lua254
1 files changed, 200 insertions, 54 deletions
diff --git a/tex/context/base/mkiv/font-cff.lua b/tex/context/base/mkiv/font-cff.lua
index a19acc1a1..77b1c1888 100644
--- a/tex/context/base/mkiv/font-cff.lua
+++ b/tex/context/base/mkiv/font-cff.lua
@@ -27,7 +27,7 @@ if not modules then modules = { } end modules ['font-cff'] = {
-- the other hand, we can now feed back cff2 stuff.
local next, type, tonumber, rawget = next, type, tonumber, rawget
-local byte, char, gmatch = string.byte, string.char, string.gmatch
+local byte, char, gmatch, sub = string.byte, string.char, string.gmatch, string.sub
local concat, remove, unpack = table.concat, table.remove, table.unpack
local floor, abs, round, ceil, min, max = math.floor, math.abs, math.round, math.ceil, math.min, math.max
local P, C, R, S, C, Cs, Ct = lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg.Ct
@@ -145,6 +145,38 @@ local defaultstrings = { [0] = -- taken from ff
"Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold",
}
+local standardnames = { [0] = -- needed for seac
+ false, false, false, false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, false, false,
+ "space", "exclam", "quotedbl", "numbersign", "dollar", "percent",
+ "ampersand", "quoteright", "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", "quoteleft", "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", false, false, false,
+ false, false, false, false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false, false, false, false, "exclamdown",
+ "cent", "sterling", "fraction", "yen", "florin", "section", "currency",
+ "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft",
+ "guilsinglright", "fi", "fl", false, "endash", "dagger", "daggerdbl",
+ "periodcentered", false, "paragraph", "bullet", "quotesinglbase",
+ "quotedblbase", "quotedblright", "guillemotright", "ellipsis", "perthousand",
+ false, "questiondown", false, "grave", "acute", "circumflex", "tilde",
+ "macron", "breve", "dotaccent", "dieresis", false, "ring", "cedilla", false,
+ "hungarumlaut", "ogonek", "caron", "emdash", false, false, false, false,
+ false, false, false, false, false, false, false, false, false, false, false,
+ false, "AE", false, "ordfeminine", false, false, false, false, "Lslash",
+ "Oslash", "OE", "ordmasculine", false, false, false, false, false, "ae",
+ false, false, false, "dotlessi", false, false, "lslash", "oslash", "oe",
+ "germandbls", false, false, false, false
+}
+
local cffreaders = {
readbyte,
readushort,
@@ -655,6 +687,7 @@ do
local x = 0
local y = 0
local width = false
+ local lsb = 0
local r = 0
local stems = 0
local globalbias = 0
@@ -678,6 +711,9 @@ do
local factors = false
local axis = false
local vsindex = 0
+ local justpass = false
+ local seacs = { }
+ local procidx = nil
local function showstate(where)
report("%w%-10s : [%s] n=%i",depth*2,where,concat(stack," ",1,top),top)
@@ -1264,7 +1300,7 @@ do
end
local function divide()
- if version == 1 then
+ if version == "cff" then
local d = stack[top]
top = top - 1
stack[top] = stack[top] / d
@@ -1272,7 +1308,7 @@ do
end
local function closepath()
- if version == 1 then
+ if version == "cff" then
if trace_charstrings then
showstate("closepath")
end
@@ -1281,65 +1317,80 @@ do
end
local function hsbw()
- if version == 1 then
+ if version == "cff" then
if trace_charstrings then
showstate("hsbw")
end
- -- lsb = stack[top-1]
+ lsb = stack[top-1] or 0
width = stack[top]
end
top = 0
end
- local function seac()
- if version == 1 then
+ local function sbw()
+ if version == "cff" then
if trace_charstrings then
- showstate("seac")
+ showstate("sbw")
end
+ lsb = stack[top-3]
+ width = stack[top-1]
end
top = 0
end
- local function sbw()
- if version == 1 then
+ -- asb adx ady bchar achar seac (accented characters)
+
+ local function seac()
+ if version == "cff" then
if trace_charstrings then
- showstate("sbw")
+ showstate("seac")
end
- width = stack[top-1]
end
top = 0
end
- -- these are probably used for special cases i.e. call out to postscript
+ -- These are probably used for special cases i.e. call out to the
+ -- postscript interpreter (p 61 of the spec as well as chapter 8).
+
+ local popped = 3
+ local hints = 3
+
+ -- arg1 ... argn n othersubr# <callothersubr> (on postscript stack)
local function callothersubr()
- if version == 1 then
- -- we don't support this (ok, we could mimick these othersubs)
+ if version == "cff" then
if trace_charstrings then
- showstate("callothersubr (unsupported)")
+ showstate("callothersubr")
+ end
+ if stack[top] == hints then
+ popped = stack[top-2]
+ else
+ popped = 3
end
+ top = top - (stack[top-1] + 2)
+ else
+ top = 0
end
- top = 0
end
+ -- <pop> number (from postscript stack)
+
local function pop()
- if version == 1 then
- -- we don't support this
+ if version == "cff" then
if trace_charstrings then
- showstate("pop (unsupported)")
+ showstate("pop")
end
top = top + 1
- stack[top] = 0 -- a dummy
+ stack[top] = popped
else
top = 0
end
end
local function setcurrentpoint()
- if version == 1 then
- -- we don't support this
+ if version == "cff" then
if trace_charstrings then
- showstate("pop (unsupported)")
+ showstate("setcurrentpoint (unsupported)")
end
x = x + stack[top-1]
y = y + stack[top]
@@ -1489,6 +1540,41 @@ do
hvcurveto, -- 31
}
+ local reverse = { [0] =
+ "unsupported",
+ "getstem",
+ "unsupported",
+ "getstem",
+ "vmoveto",
+ "rlineto",
+ "hlineto",
+ "vlineto",
+ "rrcurveto",
+ "unsupported",
+ "unsupported",
+ "unsupported",
+ "unsupported",
+ "hsbw",
+ "unsupported",
+ "setvsindex",
+ "blend",
+ "unsupported",
+ "getstem",
+ "getmask",
+ "getmask",
+ "rmoveto",
+ "hmoveto",
+ "getstem",
+ "rcurveline",
+ "rlinecurve",
+ "vvcurveto",
+ "hhcurveto",
+ "unsupported",
+ "unsupported",
+ "vhcurveto",
+ "hvcurveto",
+ }
+
local subactions = {
-- cff 1
[000] = dotsection,
@@ -1540,6 +1626,7 @@ do
for i=1132,2048 do
t[i] = char(28,band(rshift(i,8),0xFF),band(i,0xFF))
end
+ -- we could inline some ...
setmetatableindex(encode,function(t,k)
-- 16.16-bit signed fixed value
local r = round(k)
@@ -1625,7 +1712,7 @@ do
local function call(scope,list,bias) -- ,process)
depth = depth + 1
if top == 0 then
- showstate(formatters["unknown %s call %s"](scope,"?"))
+ showstate(formatters["unknown %s call %s, case %s"](scope,"?",1))
top = 0
else
local index = stack[top] + bias
@@ -1637,7 +1724,7 @@ do
if tab then
process(tab)
else
- showstate(formatters["unknown %s call %s"](scope,index))
+ showstate(formatters["unknown %s call %s, case %s"](scope,index,2))
top = 0
end
end
@@ -1646,8 +1733,6 @@ do
-- precompiling and reuse is much slower than redoing the calls
- local justpass = false
-
-- local function decode(str)
-- local a, b, c, d, e = byte(str,1,5)
-- if a == 28 then
@@ -1765,6 +1850,17 @@ do
r = r + 1 ; result[r] = chars[12]
r = r + 1 ; result[r] = chars[t]
top = 0
+ elseif t == 6 then
+ seacs[procidx] = {
+ asb = stack[1],
+ adx = stack[2],
+ ady = stack[3],
+ base = stack[4],
+ accent = stack[5],
+ width = width,
+ lsb = lsb,
+ }
+ top = 0
else
local a = subactions[t]
if a then
@@ -1796,46 +1892,56 @@ do
-- cff 1: (when cff2 strip them)
elseif t == 1 or t == 3 or t == 18 or operation == 23 then
p_getstem() -- at the start
-if true then
- if top > 0 then
- for i=1,top do
- r = r + 1 ; result[r] = encode[stack[i]]
+ if true then
+ if top > 0 then
+ for i=1,top do
+ r = r + 1 ; result[r] = encode[stack[i]]
+ end
+ top = 0
end
+ r = r + 1 ; result[r] = chars[t]
+ else
top = 0
end
- r = r + 1 ; result[r] = chars[t]
-else
- top = 0
-end
i = i + 1
-- cff 1: (when cff2 strip them)
elseif t == 19 or t == 20 then
local s = p_getmask() or 0 -- after the stems
-if true then
- if top > 0 then
- for i=1,top do
- r = r + 1 ; result[r] = encode[stack[i]]
+ if true then
+ if top > 0 then
+ for i=1,top do
+ r = r + 1 ; result[r] = encode[stack[i]]
+ end
+ top = 0
+ end
+ r = r + 1 ; result[r] = chars[t]
+ for j=1,s do
+ i = i + 1
+ r = r + 1 ; result[r] = chars[tab[i]]
end
+ else
+ i = i + s
top = 0
end
- r = r + 1 ; result[r] = chars[t]
- for j=1,s do
- i = i + 1
- r = r + 1 ; result[r] = chars[tab[i]]
- end
-else
- i = i + s
- top = 0
-end
i = i + 1
-- cff 1: closepath
elseif t == 9 then
top = 0
i = i + 1
elseif t == 13 then
- local s = hsbw() or 0
- i = i + s + 1
+ hsbw()
+ if version == "cff" then
+ -- we do a moveto over lsb
+ r = r + 1 ; result[r] = encode[lsb]
+ r = r + 1 ; result[r] = chars[22]
+ else
+ -- lsb is supposed to be zero
+ end
+ i = i + 1
else
+ if trace_charstrings then
+ showstate(reverse[t] or "<action>")
+ end
if top > 0 then
for i=1,top do
r = r + 1 ; result[r] = encode[stack[i]]
@@ -1856,7 +1962,7 @@ end
end
else
if trace_charstrings then
- showvalue("<action>",t)
+ showstate(reverse[t] or "<action>")
end
top = 0
i = i + 1
@@ -1915,7 +2021,7 @@ end
end
end
- local function processshape(tab,index)
+ local function processshape(tab,index,hack)
if not tab then
glyphs[index] = {
@@ -1931,10 +2037,13 @@ end
x = 0
y = 0
width = false
+ lsb = 0
r = 0
top = 0
stems = 0
result = { } -- we could reuse it when only boundingbox calculations are needed
+ popped = 3
+ procidx = index
xmin = 0
xmax = 0
@@ -1952,6 +2061,10 @@ end
process(tab)
+ if hack then
+ return x, y
+ end
+
local boundingbox = {
round(xmin),
round(ymin),
@@ -2016,6 +2129,8 @@ end
axis = false
regions = data.regions
justpass = streams == true
+ popped = 3
+ seacs = { }
if regions then
regions = { regions } -- needs checking
axis = data.factors or false
@@ -2030,6 +2145,8 @@ end
locals = false
globals = false
strings = false
+ popped = 3
+ seacs = { }
end
local function setwidths(private)
@@ -2064,7 +2181,35 @@ end
startparsing(fontdata,data,streams)
for index=1,#charstrings do
processshape(charstrings[index],index-1)
--- charstrings[index] = nil -- free memory (what if used more often?)
+ end
+ if justpass and next(seacs) then
+ -- old type 1 stuff ... seacs
+ local charset = data.dictionaries[1].charset
+ if charset then
+ local lookup = table.swapped(charset)
+ for index, v in next, seacs do
+ local bindex = lookup[standardnames[v.base]]
+ local aindex = lookup[standardnames[v.accent]]
+ local bglyph = bindex and glyphs[bindex]
+ local aglyph = aindex and glyphs[aindex]
+ if bglyph and aglyph then
+ -- this is a real ugly hack but we seldom enter this branch (e.g. old lbr)
+ local jp = justpass
+ justpass = false
+ local x, y = processshape(charstrings[bindex+1],bindex,true)
+ justpass = jp
+ --
+ local base = bglyph.stream
+ local accent = aglyph.stream
+ local moveto = encode[-x-v.asb+v.adx] .. chars[22]
+ .. encode[-y +v.ady] .. chars[ 4]
+ -- prune an endchar
+ base = sub(base,1,#base-1)
+ -- combine them
+ glyphs[index].stream = base .. moveto .. accent
+ end
+ end
+ end
end
stopparsing(fontdata,data)
else
@@ -2085,6 +2230,7 @@ end
glyphs = glphs or { }
justpass = streams == true
+ seacs = { }
globalbias, localbias = setbias(globals,locals,nobias)
nominalwidth, defaultwidth = setwidths(dictionary.private)