summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/font-cff.lua
diff options
context:
space:
mode:
authorHans Hagen <pragma@wxs.nl>2017-03-01 13:51:17 +0100
committerContext Git Mirror Bot <phg42.2a@gmail.com>2017-03-01 13:51:17 +0100
commit0da55392b876cef55845157c4bfb8244d84c6450 (patch)
treea050eef10e2790e286b94dcfeae1aacc657b025b /tex/context/base/mkiv/font-cff.lua
parenta616b343d8dfe81008c9e8aee253cf31f088f35b (diff)
downloadcontext-0da55392b876cef55845157c4bfb8244d84c6450.tar.gz
2017-03-01 13:47:00
Diffstat (limited to 'tex/context/base/mkiv/font-cff.lua')
-rw-r--r--tex/context/base/mkiv/font-cff.lua370
1 files changed, 243 insertions, 127 deletions
diff --git a/tex/context/base/mkiv/font-cff.lua b/tex/context/base/mkiv/font-cff.lua
index 1c6bd56fd..e6f47e40b 100644
--- a/tex/context/base/mkiv/font-cff.lua
+++ b/tex/context/base/mkiv/font-cff.lua
@@ -23,7 +23,7 @@ if not modules then modules = { } end modules ['font-cff'] = {
local next, type, tonumber = next, type, tonumber
local byte = string.byte
local concat, remove = table.concat, table.remove
-local floor, abs, round, ceil = math.floor, math.abs, math.round, math.ceil
+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
local lpegmatch = lpeg.match
local formatters = string.formatters
@@ -31,14 +31,14 @@ local formatters = string.formatters
local readers = fonts.handlers.otf.readers
local streamreader = readers.streamreader
-local readbytes = streamreader.readbytes
local readstring = streamreader.readstring
local readbyte = streamreader.readcardinal1 -- 8-bit unsigned integer
local readushort = streamreader.readcardinal2 -- 16-bit unsigned integer
local readuint = streamreader.readcardinal3 -- 24-bit unsigned integer
-local readulong = streamreader.readcardinal4 -- 24-bit unsigned integer
+local readulong = streamreader.readcardinal4 -- 32-bit unsigned integer
local setposition = streamreader.setposition
local getposition = streamreader.getposition
+local readbytetable = streamreader.readbytetable
local setmetatableindex = table.setmetatableindex
@@ -611,16 +611,17 @@ do
-- All these indirect calls make this run slower but it's cleaner this way
-- and we cache the result. As we moved the boundingbox code inline we gain
- -- some back.
+ -- some back. I inlined some of then and a bit speed can be gained by more
+ -- inlining but not that much.
- local function moveto(x,y)
+ local function moveto()
if keepcurve then
r = r + 1
result[r] = { x, y, "m" }
end
if checked then
- if x < xmin then xmin = x elseif x > xmax then xmax = x end
- if y < ymin then ymin = y elseif y > ymax then ymax = y end
+ if x > xmax then xmax = x elseif x < xmin then xmin = x end
+ if y > ymax then ymax = y elseif y < ymin then ymin = y end
else
xmin = x
ymin = y
@@ -630,14 +631,50 @@ do
end
end
- local function lineto(x,y)
+ local function xmoveto() -- slight speedup
+ if keepcurve then
+ r = r + 1
+ result[r] = { x, y, "m" }
+ end
+ if not checked then
+ xmin = x
+ ymin = y
+ xmax = x
+ ymax = y
+ checked = true
+ elseif x > xmax then
+ xmax = x
+ elseif x < xmin then
+ xmin = x
+ end
+ end
+
+ local function ymoveto() -- slight speedup
+ if keepcurve then
+ r = r + 1
+ result[r] = { x, y, "m" }
+ end
+ if not checked then
+ xmin = x
+ ymin = y
+ xmax = x
+ ymax = y
+ checked = true
+ elseif y > ymax then
+ ymax = y
+ elseif y < ymin then
+ ymin = y
+ end
+ end
+
+ local function lineto() -- we could inline
if keepcurve then
r = r + 1
result[r] = { x, y, "l" }
end
if checked then
- if x < xmin then xmin = x elseif x > xmax then xmax = x end
- if y < ymin then ymin = y elseif y > ymax then ymax = y end
+ if x > xmax then xmax = x elseif x < xmin then xmin = x end
+ if y > ymax then ymax = y elseif y < ymin then ymin = y end
else
xmin = x
ymin = y
@@ -647,14 +684,50 @@ do
end
end
+ local function xlineto() -- slight speedup
+ if keepcurve then
+ r = r + 1
+ result[r] = { x, y, "l" }
+ end
+ if not checked then
+ xmin = x
+ ymin = y
+ xmax = x
+ ymax = y
+ checked = true
+ elseif x > xmax then
+ xmax = x
+ elseif x < xmin then
+ xmin = x
+ end
+ end
+
+ local function ylineto() -- slight speedup
+ if keepcurve then
+ r = r + 1
+ result[r] = { x, y, "l" }
+ end
+ if not checked then
+ xmin = x
+ ymin = y
+ xmax = x
+ ymax = y
+ checked = true
+ elseif y > ymax then
+ ymax = y
+ elseif y < ymin then
+ ymin = y
+ end
+ end
+
local function curveto(x1,y1,x2,y2,x3,y3)
if keepcurve then
r = r + 1
result[r] = { x1, y1, x2, y2, x3, y3, "c" }
end
if checked then
- if x1 < xmin then xmin = x1 elseif x1 > xmax then xmax = x1 end
- if y1 < ymin then ymin = y1 elseif y1 > ymax then ymax = y1 end
+ if x1 > xmax then xmax = x1 elseif x1 < xmin then xmin = x1 end
+ if y1 > ymax then ymax = y1 elseif y1 < ymin then ymin = y1 end
else
xmin = x1
ymin = y1
@@ -662,22 +735,22 @@ do
ymax = y1
checked = true
end
- if x2 < xmin then xmin = x2 elseif x2 > xmax then xmax = x2 end
- if y2 < ymin then ymin = y2 elseif y2 > ymax then ymax = y2 end
- if x3 < xmin then xmin = x3 elseif x3 > xmax then xmax = x3 end
- if y3 < ymin then ymin = y3 elseif y3 > ymax then ymax = y3 end
+ if x2 > xmax then xmax = x2 elseif x2 < xmin then xmin = x2 end
+ if y2 > ymax then ymax = y2 elseif y2 < ymin then ymin = y2 end
+ if x3 > xmax then xmax = x3 elseif x3 < xmin then xmin = x3 end
+ if y3 > ymax then ymax = y3 elseif y3 < ymin then ymin = y3 end
end
local function rmoveto()
- if top > 2 then
- if not width then
+ if not width then
+ if top > 2 then
width = stack[1]
if trace_charstrings then
showvalue("width",width)
end
+ else
+ width = true
end
- elseif not width then
- width = true
end
if trace_charstrings then
showstate("rmoveto")
@@ -685,45 +758,45 @@ do
x = x + stack[top-1] -- dx1
y = y + stack[top] -- dy1
top = 0
- moveto(x,y)
+ moveto()
end
local function hmoveto()
- if top > 1 then
- if not width then
+ if not width then
+ if top > 1 then
width = stack[1]
if trace_charstrings then
showvalue("width",width)
end
+ else
+ width = true
end
- elseif not width then
- width = true
end
if trace_charstrings then
showstate("hmoveto")
end
x = x + stack[top] -- dx1
top = 0
- moveto(x,y)
+ xmoveto()
end
local function vmoveto()
- if top > 1 then
- if not width then
+ if not width then
+ if top > 1 then
width = stack[1]
if trace_charstrings then
showvalue("width",width)
end
+ else
+ width = true
end
- elseif not width then
- width = true
end
if trace_charstrings then
showstate("vmoveto")
end
y = y + stack[top] -- dy1
top = 0
- moveto(x,y)
+ ymoveto()
end
local function rlineto()
@@ -733,21 +806,7 @@ do
for i=1,top,2 do
x = x + stack[i] -- dxa
y = y + stack[i+1] -- dya
- lineto(x,y)
- end
- top = 0
- end
-
- local function xlineto(swap) -- x (y,x)+ | (x,y)+
- for i=1,top do
- if swap then
- x = x + stack[i]
- swap = false
- else
- y = y + stack[i]
- swap = true
- end
- lineto(x,y)
+ lineto()
end
top = 0
end
@@ -756,14 +815,48 @@ do
if trace_charstrings then
showstate("hlineto")
end
- xlineto(true)
+ if top == 1 then
+ x = x + stack[1]
+ xlineto()
+ else
+ local swap = true
+ for i=1,top do
+ if swap then
+ x = x + stack[i]
+ xlineto()
+ swap = false
+ else
+ y = y + stack[i]
+ ylineto()
+ swap = true
+ end
+ end
+ end
+ top = 0
end
local function vlineto() -- y (x,y)+ | (y,x)+
if trace_charstrings then
showstate("vlineto")
end
- xlineto(false)
+ if top == 1 then
+ y = y + stack[1]
+ ylineto()
+ else
+ local swap = false
+ for i=1,top do
+ if swap then
+ x = x + stack[i]
+ xlineto()
+ swap = false
+ else
+ y = y + stack[i]
+ ylineto()
+ swap = true
+ end
+ end
+ end
+ top = 0
end
local function rrcurveto()
@@ -775,8 +868,8 @@ do
local ay = y + stack[i+1] -- dya
local bx = ax + stack[i+2] -- dxb
local by = ay + stack[i+3] -- dyb
- x = bx + stack[i+4] -- dxc
- y = by + stack[i+5] -- dyc
+ x = bx + stack[i+4] -- dxc
+ y = by + stack[i+5] -- dyc
curveto(ax,ay,bx,by,x,y)
end
top = 0
@@ -788,15 +881,15 @@ do
end
local s = 1
if top % 2 ~= 0 then
- y = y + stack[1] -- dy1
+ y = y + stack[1] -- dy1
s = 2
end
for i=s,top,4 do
- local ax = x + stack[i] -- dxa
+ local ax = x + stack[i] -- dxa
local ay = y
local bx = ax + stack[i+1] -- dxb
local by = ay + stack[i+2] -- dyb
- x = bx + stack[i+3] -- dxc
+ x = bx + stack[i+3] -- dxc
y = by
curveto(ax,ay,bx,by,x,y)
end
@@ -810,16 +903,16 @@ do
local s = 1
local d = 0
if top % 2 ~= 0 then
- d = stack[1] -- dx1
+ d = stack[1] -- dx1
s = 2
end
for i=s,top,4 do
local ax = x + d
- local ay = y + stack[i] -- dya
+ local ay = y + stack[i] -- dya
local bx = ax + stack[i+1] -- dxb
local by = ay + stack[i+2] -- dyb
x = bx
- y = by + stack[i+3] -- dyc
+ y = by + stack[i+3] -- dyc
curveto(ax,ay,bx,by,x,y)
d = 0
end
@@ -831,7 +924,6 @@ do
if last then
top = top - 1
end
- local sw = swap
for i=1,top,4 do
local ax, ay, bx, by
if swap then
@@ -893,7 +985,7 @@ do
end
x = x + stack[top-1] -- dxc
y = y + stack[top] -- dyc
- lineto(x,y)
+ lineto()
top = 0
end
@@ -905,7 +997,7 @@ do
for i=1,top-6,2 do
x = x + stack[i]
y = y + stack[i+1]
- lineto(x,y)
+ lineto()
end
end
local ax = x + stack[top-5]
@@ -945,7 +1037,7 @@ do
if trace_charstrings then
showstate("hflex")
end
- local ax = x + stack[1] -- dx1
+ local ax = x + stack[1] -- dx1
local ay = y
local bx = ax + stack[2] -- dx2
local by = ay + stack[3] -- dy2
@@ -956,7 +1048,7 @@ do
local dy = by
local ex = dx + stack[6] -- dx5
local ey = y
- x = ex + stack[7] -- dx6
+ x = ex + stack[7] -- dx6
curveto(dx,dy,ex,ey,x,y)
top = 0
end
@@ -976,7 +1068,7 @@ do
local dy = by
local ex = dx + stack[7] -- dx5
local ey = dy + stack[8] -- dy5
- x = ex + stack[9] -- dx6
+ x = ex + stack[9] -- dx6
curveto(dx,dy,ex,ey,x,y)
top = 0
end
@@ -1218,9 +1310,9 @@ do
[037] = flex1,
}
- local p_bytes = Ct((P(1)/byte)^0)
+ local process
- local function call(scope,list,bias,process)
+ local function call(scope,list,bias) -- ,process)
depth = depth + 1
if top == 0 then
showstate(formatters["unknown %s call"](scope))
@@ -1233,10 +1325,10 @@ do
end
local tab = list[index]
if tab then
- if type(tab) == "string" then
- tab = lpegmatch(p_bytes,tab)
- list[index] = tab
- end
+-- if type(tab) == "string" then
+-- tab = { byte(tab,1,#tab) }
+-- list[index] = tab
+-- end
process(tab)
else
showstate(formatters["unknown %s call %i"](scope,index))
@@ -1246,54 +1338,64 @@ do
depth = depth - 1
end
- local function process(tab)
+ -- precompiling and reuse is much slower than redoing the calls
+
+ process = function(tab)
local i = 1
local n = #tab
while i <= n do
local t = tab[i]
- if t >= 32 and t <= 246 then
- -- -107 .. +107
- top = top + 1
- stack[top] = t - 139
- i = i + 1
- elseif t >= 247 and t <= 250 then
- -- +108 .. +1131
- top = top + 1
- stack[top] = (t-247)*256 + tab[i+1] + 108
- i = i + 2
- elseif t >= 251 and t <= 254 then
- -- -1131 .. -108
- top = top + 1
- stack[top] = -(t-251)*256 - tab[i+1] - 108
- i = i + 2
+ if t >= 32 then
+ if t <= 246 then
+ -- -107 .. +107
+ top = top + 1
+ stack[top] = t - 139
+ i = i + 1
+ elseif t <= 250 then
+ -- +108 .. +1131
+ top = top + 1
+ -- stack[top] = (t-247)*256 + tab[i+1] + 108
+ -- stack[top] = t*256 - 247*256 + tab[i+1] + 108
+ stack[top] = t*256 - 63124 + tab[i+1]
+ i = i + 2
+ elseif t <= 254 then
+ -- -1131 .. -108
+ top = top + 1
+ -- stack[top] = -(t-251)*256 - tab[i+1] - 108
+ -- stack[top] = -t*256 + 251*256 - tab[i+1] - 108
+ stack[top] = -t*256 + 64148 - tab[i+1]
+ i = i + 2
+ else
+ local n = 0x100 * tab[i+1] + tab[i+2]
+ top = top + 1
+ if n >= 0x8000 then
+ -- stack[top] = n - 0xFFFF - 1 + (0x100 * tab[i+3] + tab[i+4])/0xFFFF
+ stack[top] = n - 0x10000 + (0x100 * tab[i+3] + tab[i+4])/0xFFFF
+ else
+ stack[top] = n + (0x100 * tab[i+3] + tab[i+4])/0xFFFF
+ end
+ i = i + 5
+ end
elseif t == 28 then
-- -32768 .. +32767 : b1<<8 | b2
top = top + 1
local n = 0x100 * tab[i+1] + tab[i+2]
if n >= 0x8000 then
- stack[top] = n - 0xFFFF - 1
+ -- stack[top] = n - 0xFFFF - 1
+ stack[top] = n - 0x10000
else
stack[top] = n
end
i = i + 3
- elseif t == 255 then
- local n = 0x100 * tab[i+1] + tab[i+2]
- top = top + 1
- if n >= 0x8000 then
- stack[top] = n - 0xFFFF - 1 + (0x100 * tab[i+3] + tab[i+4])/0xFFFF
- else
- stack[top] = n + (0x100 * tab[i+3] + tab[i+4])/0xFFFF
- end
- i = i + 5
- elseif t == 11 then
+ elseif t == 11 then
if trace_charstrings then
showstate("return")
end
return
elseif t == 10 then
- call("local",locals,localbias,process)
+ call("local",locals,localbias) -- ,process)
i = i + 1
- elseif t == 14 then -- endchar
+ elseif t == 14 then -- endchar
if width then
-- okay
elseif top > 0 then
@@ -1309,7 +1411,7 @@ do
end
return
elseif t == 29 then
- call("global",globals,globalbias,process)
+ call("global",globals,globalbias) -- ,process)
i = i + 1
elseif t == 12 then
i = i + 1
@@ -1356,7 +1458,7 @@ do
-- if y < ymin then ymin = y end
-- if y > ymax then ymax = y end
-- -- we now have a reasonable start so we could
- -- -- simplyfy the next checks
+ -- -- simplify the next checks
-- for i=1,nofsegments do
-- local s = segments[i]
-- local x = s[1]
@@ -1415,9 +1517,9 @@ do
for i=1,#charstrings do
local tab = charstrings[i]
- if type(tab) == "string" then
- tab = lpegmatch(p_bytes,tab)
- end
+-- if type(tab) == "string" then -- no real need as wel nil charstrings[i] at the end
+ tab = { byte(tab,1,#tab) }
+-- end
local index = i - 1
x = 0
y = 0
@@ -1425,7 +1527,7 @@ do
r = 0
top = 0
stems = 0
- result = { }
+ result = { } -- we could reuse it when only boundingbox calculations are needed
--
xmin = 0
xmax = 0
@@ -1450,15 +1552,7 @@ do
--
-- trace_charstrings = index == 3078 -- todo: make tracker
local glyph = glyphs[index] -- can be autodefined in otr
- if not glyph then
- glyphs[index] = {
- segments = doshapes ~= false and result or nil, -- optional
- boundingbox = boundingbox,
- width = width,
- name = charset[index],
- -- sidebearing = 0,
- }
- else
+ if glyph then
glyph.segments = doshapes ~= false and result or nil
glyph.boundingbox = boundingbox
if not glyph.width then
@@ -1468,12 +1562,26 @@ do
glyph.name = charset[index]
end
-- glyph.sidebearing = 0 -- todo
+ elseif doshapes then
+ glyphs[index] = {
+ segments = result,
+ boundingbox = boundingbox,
+ width = width,
+ name = charset[index],
+ -- sidebearing = 0,
+ }
+ else
+ glyphs[index] = {
+ boundingbox = boundingbox,
+ width = width,
+ name = charset[index],
+ }
end
if trace_charstrings then
report("width: %s",tostring(width))
report("boundingbox: % t",boundingbox)
end
- charstrings[i] = nil -- free memory
+ charstrings[i] = nil -- free memory (what if used more often?)
end
return glyphs
end
@@ -1491,9 +1599,10 @@ do
local nominalwidth = private and private.data.nominalwidthx or 0
local defaultwidth = private and private.data.defaultwidthx or 0
--
- if type(tab) == "string" then
- tab = lpegmatch(p_bytes,tab)
- end
+-- if type(tab) == "string" then
+ -- a helper is not much faster but might be nicer for the stack
+ tab = { byte(tab,1,#tab) }
+-- end
--
x = 0
y = 0
@@ -1527,15 +1636,7 @@ do
index = index - 1
--
local glyph = glyphs[index] -- can be autodefined in otr
- if not glyph then
- glyphs[index] = {
- segments = doshapes ~= false and result or nil, -- optional
- boundingbox = boundingbox,
- width = width,
- name = charset[index],
- -- sidebearing = 0,
- }
- else
+ if glyph then
glyph.segments = doshapes ~= false and result or nil
glyph.boundingbox = boundingbox
if not glyph.width then
@@ -1545,6 +1646,20 @@ do
glyph.name = charset[index]
end
-- glyph.sidebearing = 0 -- todo
+ elseif doshapes then
+ glyphs[index] = {
+ segments = result,
+ boundingbox = boundingbox,
+ width = width,
+ name = charset[index],
+ -- sidebearing = 0,
+ }
+ else
+ glyphs[index] = {
+ boundingbox = boundingbox,
+ width = width,
+ name = charset[index],
+ }
end
--
if trace_charstrings then
@@ -1564,7 +1679,7 @@ end
local function readglobals(f,data)
local routines = readlengths(f)
for i=1,#routines do
- routines[i] = readstring(f,routines[i])
+ routines[i] = readbytetable(f,routines[i])
end
data.routines = routines
end
@@ -1627,7 +1742,7 @@ local function readlocals(f,data,dictionary)
setposition(f,header.offset+private.offset+subroutineoffset)
local subroutines = readlengths(f)
for i=1,#subroutines do
- subroutines[i] = readstring(f,subroutines[i])
+ subroutines[i] = readbytetable(f,subroutines[i])
end
dictionary.subroutines = subroutines
private.data.subroutines = nil
@@ -1757,6 +1872,7 @@ local function readfdselect(f,data,glyphs,doshapes,version)
end
for i=1,#charstrings do
parsecharstring(data,dictionaries[fdindex[i]+1],charstrings[i],glyphs,i,doshapes,version)
+charstrings[i] = nil
end
resetcharstrings()
end