summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/lpdf-ano.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkiv/lpdf-ano.lua')
-rw-r--r--tex/context/base/mkiv/lpdf-ano.lua276
1 files changed, 188 insertions, 88 deletions
diff --git a/tex/context/base/mkiv/lpdf-ano.lua b/tex/context/base/mkiv/lpdf-ano.lua
index 01f015b72..49bf973c9 100644
--- a/tex/context/base/mkiv/lpdf-ano.lua
+++ b/tex/context/base/mkiv/lpdf-ano.lua
@@ -18,6 +18,7 @@ local rep, format, find = string.rep, string.format, string.find
local min = math.min
local lpegmatch = lpeg.match
local formatters = string.formatters
+local sortedkeys = table.sortedkeys
local backends, lpdf = backends, lpdf
@@ -48,10 +49,6 @@ local nodeinjections = backends.pdf.nodeinjections
local codeinjections = backends.pdf.codeinjections
local registrations = backends.pdf.registrations
-local getpos = codeinjections.getpos
-local gethpos = codeinjections.gethpos
-local getvpos = codeinjections.getvpos
-
local javascriptcode = interactions.javascripts.code
local references = structures.references
@@ -68,12 +65,15 @@ local executers = references.executers
local nodepool = nodes.pool
------ pdfannotation_node = nodepool.pdfannotation
------ pdfdestination_node = nodepool.pdfdestination
local new_latelua = nodepool.latelua
local texgetcount = tex.getcount
+local jobpositions = job.positions
+local getpos = jobpositions.getpos
+local gethpos = jobpositions.gethpos
+local getvpos = jobpositions.getvpos
+
local pdfdictionary = lpdf.dictionary
local pdfarray = lpdf.array
local pdfreference = lpdf.reference
@@ -106,6 +106,32 @@ local pdf_fit = pdfconstant("Fit")
local pdf_named = pdfconstant("Named")
local autoprefix = "#"
+local usedautoprefixes = { }
+
+local function registerautoprefix(name)
+ local internal = autoprefix .. name
+ if usedautoprefixes[internal] == nil then
+ usedautoprefixes[internal] = false
+ end
+ return internal
+end
+
+local function useautoprefix(name)
+ local internal = autoprefix .. name
+ usedautoprefixes[internal] = true
+ return internal
+end
+
+local function checkautoprefixes(destinations)
+ for k, v in next, usedautoprefixes do
+ if not v then
+ if trace_destinations then
+ report_destinations("flushing unused autoprefix %a",k)
+ end
+ destinations[k] = nil
+ end
+ end
+end
-- Bah, I hate this kind of features .. anyway, as we have delayed resolving we
-- only support a document-wide setup and it has to be set before the first one
@@ -113,9 +139,9 @@ local autoprefix = "#"
-- thin without dashing lines. This is as far as I'm prepared to go. This way
-- it can also be used as a debug feature.
-local pdf_border_style = pdfarray { 0, 0, 0 } -- radius radius linewidth
-local pdf_border_color = nil
-local set_border = false
+local pdf_border_style = pdfarray { 0, 0, 0 } -- radius radius linewidth
+local pdf_border_color = nil
+local set_border = false
local function pdfborder()
set_border = true
@@ -131,7 +157,9 @@ directives.register("references.border",function(v)
local c = m and m[v]
local v = c and attributes.colors.value(c)
if v then
- local r, g, b = v[3], v[4], v[5]
+ local r = v[3]
+ local g = v[4]
+ local b = v[5]
-- if r == g and g == b then
-- pdf_border_color = pdfarray { r } -- reduced, not not ... bugged viewers
-- else
@@ -192,12 +220,16 @@ local defaultdestination = pdfarray { 0, pdf_fit }
-- fit is default (see lpdf-nod)
-local destinations = { } -- to be used soon
+local destinations = { }
+local reported = setmetatableindex("table")
local function pdfregisterdestination(name,reference)
local d = destinations[name]
if d then
- report_destinations("ignoring duplicate destination %a with reference %a",name,reference)
+ if not reported[name][reference] then
+ report_destinations("ignoring duplicate destination %a with reference %a",name,reference)
+ reported[name][reference] = true
+ end
else
destinations[name] = reference
end
@@ -222,7 +254,11 @@ end)
local function pdfnametree(destinations)
local slices = { }
- local sorted = table.sortedkeys(destinations)
+ checkautoprefixes(destinations)
+ if not next(destinations) then
+ return
+ end
+ local sorted = sortedkeys(destinations)
local size = #sorted
if size <= 1.5*maxslice then
@@ -232,11 +268,12 @@ local function pdfnametree(destinations)
for i=1,size,maxslice do
local amount = min(i+maxslice-1,size)
local names = pdfarray { }
+ local n = 0
for j=i,amount do
local destination = sorted[j]
local pagenumber = destinations[destination]
- names[#names+1] = tostring(destination) -- tostring is a safeguard
- names[#names+1] = pdfreference(pagenumber)
+ n = n + 1 ; names[n] = tostring(destination) -- tostring is a safeguard
+ n = n + 1 ; names[n] = pdfreference(pagenumber)
end
local first = sorted[i]
local last = sorted[amount]
@@ -254,18 +291,23 @@ local function pdfnametree(destinations)
}
end
local function collectkids(slices,first,last)
- local k = pdfarray()
- local d = pdfdictionary {
- Kids = k,
- Limits = pdfarray {
- slices[first].limits[1],
- slices[last ].limits[2],
- },
- }
- for i=first,last do
- k[#k+1] = slices[i].reference
+ local f = slices[first]
+ local l = slices[last]
+ if f and l then
+ local k = pdfarray()
+ local n = 0
+ local d = pdfdictionary {
+ Kids = k,
+ Limits = pdfarray {
+ f.limits[1],
+ l.limits[2],
+ },
+ }
+ for i=first,last do
+ n = n + 1 ; k[n] = slices[i].reference
+ end
+ return d
end
- return d
end
if #slices == 1 then
return slices[1].reference
@@ -276,14 +318,24 @@ local function pdfnametree(destinations)
local size = #slices
for i=1,size,maxslice do
local kids = collectkids(slices,i,min(i+maxslice-1,size))
- temp[#temp+1] = {
- reference = pdfreference(pdfflushobject(kids)),
- limits = kids.Limits,
- }
+ if kids then
+ temp[#temp+1] = {
+ reference = pdfreference(pdfflushobject(kids)),
+ limits = kids.Limits,
+ }
+ else
+ -- error
+ end
end
slices = temp
else
- return pdfreference(pdfflushobject(collectkids(slices,1,#slices)))
+ local kids = collectkids(slices,1,#slices)
+ if kids then
+ return pdfreference(pdfflushobject(kids))
+ else
+ -- error
+ return
+ end
end
end
end
@@ -292,8 +344,9 @@ end
local function pdfdestinationspecification()
if next(destinations) then -- safeguard
local r = pdfnametree(destinations)
- -- pdfaddtocatalog("Dests",r)
- pdfaddtonames("Dests",r)
+ if r then
+ pdfaddtonames("Dests",r)
+ end
if not log_destinations then
destinations = nil
end
@@ -309,14 +362,25 @@ lpdf.registerdocumentfinalizer(pdfdestinationspecification,"collect destinations
local destinations = { }
-local f_xyz = formatters["<< /D [ %i 0 R /XYZ %0.3F %0.3F null ] >>"]
+local f_xyz = formatters["<< /D [ %i 0 R /XYZ %.6F %.6F null ] >>"]
local f_fit = formatters["<< /D [ %i 0 R /Fit ] >>"]
local f_fitb = formatters["<< /D [ %i 0 R /FitB ] >>"]
-local f_fith = formatters["<< /D [ %i 0 R /FitH %0.3F ] >>"]
-local f_fitv = formatters["<< /D [ %i 0 R /FitV %0.3F ] >>"]
-local f_fitbh = formatters["<< /D [ %i 0 R /FitBH %0.3F ] >>"]
-local f_fitbv = formatters["<< /D [ %i 0 R /FitBV %0.3F ] >>"]
-local f_fitr = formatters["<< /D [ %i 0 R /FitR %0.3F %0.3F %0.3F %0.3F ] >>"]
+local f_fith = formatters["<< /D [ %i 0 R /FitH %.6F ] >>"]
+local f_fitv = formatters["<< /D [ %i 0 R /FitV %.6F ] >>"]
+local f_fitbh = formatters["<< /D [ %i 0 R /FitBH %.6F ] >>"]
+local f_fitbv = formatters["<< /D [ %i 0 R /FitBV %.6F ] >>"]
+local f_fitr = formatters["<< /D [ %i 0 R /FitR %.6F %.6F %.6F %.6F ] >>"]
+
+directives.register("pdf.stripzeros",function()
+ f_xyz = formatters["<< /D [ %i 0 R /XYZ %.6N %.6N null ] >>"]
+ f_fit = formatters["<< /D [ %i 0 R /Fit ] >>"]
+ f_fitb = formatters["<< /D [ %i 0 R /FitB ] >>"]
+ f_fith = formatters["<< /D [ %i 0 R /FitH %.6N ] >>"]
+ f_fitv = formatters["<< /D [ %i 0 R /FitV %.6N ] >>"]
+ f_fitbh = formatters["<< /D [ %i 0 R /FitBH %.6N ] >>"]
+ f_fitbv = formatters["<< /D [ %i 0 R /FitBV %.6N ] >>"]
+ f_fitr = formatters["<< /D [ %i 0 R /FitR %.6N %.6N %.6N %.6N ] >>"]
+end)
local v_standard = variables.standard
local v_frame = variables.frame
@@ -404,13 +468,15 @@ local pagedestinations = setmetatableindex(function(t,k) -- not the same as the
return v
end)
-local function flushdestination(width,height,depth,names,view)
- local r = pdfpagereference(texgetcount("realpageno"))
+local function flushdestination(specification)
+ local names = specification.names
+ local view = specification.view
+ local r = pdfpagereference(texgetcount("realpageno"))
if (references.innermethod ~= v_name) and (view == defaultview or not view or view == "") then
r = pagedestinations[r]
else
local action = view and destinationactions[view] or defaultaction
- r = pdfdelayedobject(action(r,width,height,depth,offset))
+ r = pdfdelayedobject(action(r,specification.width,specification.height,specification.depth,offset))
end
for n=1,#names do
local name = names[n]
@@ -459,7 +525,7 @@ function nodeinjections.destination(width,height,depth,names,view)
elseif type(name) == "number" then
local used = usedinternals[name]
usedviews[name] = view
- names[n] = autoprefix .. name
+ names[n] = registerautoprefix(name)
doview = true
else
usedviews[name] = view
@@ -479,10 +545,9 @@ function nodeinjections.destination(width,height,depth,names,view)
local used = usedinternals[name]
if used and used ~= defaultview then
usedviews[name] = view
- names[n] = autoprefix .. name
+ names[n] = registerautoprefix(name)
doview = true
else
- -- names[n] = autoprefix .. name
names[n] = false
end
end
@@ -493,7 +558,14 @@ function nodeinjections.destination(width,height,depth,names,view)
end
end
if doview then
- return new_latelua(function() flushdestination(width,height,depth,names,view) end)
+ return new_latelua {
+ action = flushdestination,
+ width = width,
+ height = height,
+ depth = depth,
+ names = names,
+ view = view,
+ }
end
end
@@ -504,7 +576,7 @@ local function pdflinkpage(page)
end
local function pdflinkinternal(internal,page)
- local method = references.innermethod
+ -- local method = references.innermethod
if internal then
flaginternals[internal] = true -- for bookmarks and so
local used = usedinternals[internal]
@@ -512,7 +584,7 @@ local function pdflinkinternal(internal,page)
return pagereferences[page]
else
if type(internal) ~= "string" then
- internal = autoprefix .. internal
+ internal = useautoprefix(internal)
end
return pdfdictionary {
S = pdf_goto,
@@ -559,7 +631,7 @@ local function pdffilelink(filename,destination,page,actions)
end
filename = file.addsuffix(filename,"pdf")
if (not destination or destination == "") or (references.outermethod == v_page) then
- destination = pdfarray { (page or 0) - 1, pdf_fit }
+ destination = pdfarray { (page or 1) - 1, pdf_fit }
end
return pdfdictionary {
S = pdf_gotor, -- can also be pdf_launch
@@ -635,7 +707,7 @@ local function pdfaction(actions)
return nil
end
end
- return first, actions.n
+ return first, actions.n or #actions
end
end
end
@@ -686,9 +758,15 @@ local nofused = 0
local nofspecial = 0
local share = true
-local f_annot = formatters["<< /Type /Annot %s /Rect [ %0.3F %0.3F %0.3F %0.3F ] >>"]
+local f_annot = formatters["<< /Type /Annot %s /Rect [ %0.6F %0.6F %0.6F %0.6F ] >>"]
-directives.register("references.sharelinks", function(v) share = v end)
+directives.register("pdf.stripzeros",function()
+ f_annot = formatters["<< /Type /Annot %s /Rect [ %0.6N %0.6N %0.6N %0.6N ] >>"]
+end)
+
+directives.register("references.sharelinks", function(v)
+ share = v
+end)
setmetatableindex(hashed,function(t,k)
local v = pdfdelayedobject(k)
@@ -699,24 +777,26 @@ setmetatableindex(hashed,function(t,k)
return v
end)
-local function finishreference(width,height,depth,prerolled) -- %0.2f looks okay enough (no scaling anyway)
- local annot = hashed[f_annot(prerolled,pdfrectangle(width,height,depth))]
+local function finishreference(specification) -- %0.2f looks okay enough (no scaling anyway)
+ local annot = hashed[f_annot(specification.prerolled,pdfrectangle(specification.width,specification.height,specification.depth))]
nofused = nofused + 1
return pdfregisterannotation(annot)
end
-local function finishannotation(width,height,depth,prerolled,r)
+local function finishannotation(specification)
+ local prerolled = specification.prerolled
+ local objref = specification.objref
if type(prerolled) == "function" then
prerolled = prerolled()
end
- local annot = f_annot(prerolled,pdfrectangle(width,height,depth))
- if r then
- pdfdelayedobject(annot,r)
+ local annot = f_annot(prerolled,pdfrectangle(specification.width,specification.height,specification.depth))
+ if objref then
+ pdfdelayedobject(annot,objref)
else
- r = pdfdelayedobject(annot)
+ objref = pdfdelayedobject(annot)
end
nofspecial = nofspecial + 1
- return pdfregisterannotation(r)
+ return pdfregisterannotation(objref)
end
function nodeinjections.reference(width,height,depth,prerolled)
@@ -724,17 +804,30 @@ function nodeinjections.reference(width,height,depth,prerolled)
if trace_references then
report_references("link: width %p, height %p, depth %p, prerolled %a",width,height,depth,prerolled)
end
- return new_latelua(function() finishreference(width,height,depth,prerolled) end)
+ return new_latelua {
+ action = finishreference,
+ width = width,
+ height = height,
+ depth = depth,
+ prerolled = prerolled,
+ }
end
end
-function nodeinjections.annotation(width,height,depth,prerolled,r)
+function nodeinjections.annotation(width,height,depth,prerolled,objref)
if prerolled then
if trace_references then
report_references("special: width %p, height %p, depth %p, prerolled %a",width,height,depth,
type(prerolled) == "string" and prerolled or "-")
end
- return new_latelua(function() finishannotation(width,height,depth,prerolled,r or false) end)
+ return new_latelua {
+ action = finishannotation,
+ width = width,
+ height = height,
+ depth = depth,
+ prerolled = prerolled,
+ objref = objref or false,
+ }
end
end
@@ -757,7 +850,9 @@ pdfregisterannotation = lpdf.registerannotation
function lpdf.annotationspecification()
if annotations then
local r = pdfdelayedobject(tostring(annotations)) -- delayed so okay in latelua
- pdfaddtopageattributes("Annots",pdfreference(r))
+ if r then
+ pdfaddtopageattributes("Annots",pdfreference(r))
+ end
annotations = nil
end
end
@@ -872,16 +967,21 @@ end
runners["special operation"] = runners["special"]
runners["special operation with arguments"] = runners["special"]
+local reported = { }
+
function specials.internal(var,actions) -- better resolve in strc-ref
- local i = tonumber(var.operation)
+ local o = var.operation
+ local i = o and tonumber(o)
local v = i and references.internals[i]
- if not v then
- -- error
- report_references("no internal reference %a",i or "<unset>")
- else
- flaginternals[i] = true
+ if v then
+ flaginternals[i] = true -- also done in pdflinkinternal
return pdflinkinternal(i,v.references.realpage)
end
+ local v = i or o or "<unset>"
+ if not reported[v] then
+ report_references("no internal reference %a",v)
+ reported[v] = true
+ end
end
-- realpage already resolved
@@ -946,19 +1046,18 @@ end
-- sections
--- function specials.section(var,actions)
--- local sectionname = var.operation
--- local destination = var.arguments
--- local internal = structures.sections.internalreference(sectionname,destination)
--- if internal then
--- var.special = "internal"
--- var.operation = internal
--- var.arguments = nil
--- specials.internal(var,actions)
--- end
--- end
-
-specials.section = specials.internal -- specials.section just need to have a value as it's checked
+function specials.section(var,actions)
+ -- a bit duplicate
+ local sectionname = var.arguments
+ local destination = var.operation
+ local internal = structures.sections.internalreference(sectionname,destination)
+ if internal then
+ var.special = "internal"
+ var.operation = internal
+ var.arguments = nil
+ return specials.internal(var,actions)
+ end
+end
-- todo, do this in references namespace ordered instead (this is an experiment)
@@ -1129,7 +1228,8 @@ end
local function build(levels,start,parent,method,nested)
local startlevel = levels[start].level
local noflevels = #levels
- local i, n = start, 0
+ local i = start
+ local n = 0
local child, entry, m, prev, first, last, f, l
while i and i <= noflevels do
local current = levels[i]
@@ -1146,11 +1246,12 @@ local function build(levels,start,parent,method,nested)
local variant = "unknown"
if reftype == "table" then
-- we're okay
- variant = "list"
- block = reference.block
+ variant = "list"
+ block = reference.block
+ realpage = reference.realpage
elseif reftype == "string" then
local resolved = references.identify("",reference)
- local realpage = resolved and structures.references.setreferencerealpage(resolved) or 0
+ realpage = resolved and structures.references.setreferencerealpage(resolved) or 0
if realpage > 0 then
variant = "realpage"
realpage = realpage
@@ -1251,7 +1352,6 @@ end
function codeinjections.addbookmarks(levels,method)
if levels and #levels > 0 then
--- inspect(levels)
local parent = pdfreserveobject()
local _, m, first, last = build(levels,1,pdfreference(parent),method or "internal",false)
local dict = pdfdictionary {