summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/lpdf-ano.lua
diff options
context:
space:
mode:
authorTaco Hoekwater <taco@elvenkind.com>2011-06-01 08:54:21 +0000
committerTaco Hoekwater <taco@elvenkind.com>2011-06-01 08:54:21 +0000
commitd7ccb42582f85acf30568913610ccf4d602023fb (patch)
tree7292e3545a420676878e7451b68892d360c62cb6 /Master/texmf-dist/tex/context/base/lpdf-ano.lua
parent2d62a6fe9b80def59c392268022f1f9a2d6e358f (diff)
commit context 2011.05.18
git-svn-id: svn://tug.org/texlive/trunk@22719 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/context/base/lpdf-ano.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/lpdf-ano.lua429
1 files changed, 269 insertions, 160 deletions
diff --git a/Master/texmf-dist/tex/context/base/lpdf-ano.lua b/Master/texmf-dist/tex/context/base/lpdf-ano.lua
index e9e67e16319..9f452c34d12 100644
--- a/Master/texmf-dist/tex/context/base/lpdf-ano.lua
+++ b/Master/texmf-dist/tex/context/base/lpdf-ano.lua
@@ -6,43 +6,59 @@ if not modules then modules = { } end modules ['lpdf-ano'] = {
license = "see context related readme files"
}
-local tostring, format, rep = tostring, string.rep, string.format
+local next, tostring = next, tostring
+local rep, format = string.rep, string.format
local texcount = tex.count
+local backends, lpdf = backends, lpdf
+
local trace_references = false trackers.register("references.references", function(v) trace_references = v end)
local trace_destinations = false trackers.register("references.destinations", function(v) trace_destinations = v end)
local trace_bookmarks = false trackers.register("references.bookmarks", function(v) trace_bookmarks = v end)
+local report_reference = logs.reporter("backend","references")
+local report_destination = logs.reporter("backend","destinations")
+local report_bookmark = logs.reporter("backend","bookmarks")
+
local variables = interfaces.variables
local constants = interfaces.constants
-local nodeinjections = backends.pdf.nodeinjections
-local codeinjections = backends.pdf.codeinjections
-local registrations = backends.pdf.registrations
-
-jobreferences = jobreferences or { }
-jobreferences.runners = jobreferences.runners or { }
-jobreferences.specials = jobreferences.specials or { }
-jobreferences.handlers = jobreferences.handlers or { }
-jobreferences.executers = jobreferences.executers or { }
-
-local runners = jobreferences.runners
-local specials = jobreferences.specials
-local handlers = jobreferences.handlers
-local executers = jobreferences.executers
-
-local pdfdictionary = lpdf.dictionary
-local pdfarray = lpdf.array
-local pdfreference = lpdf.reference
-local pdfunicode = lpdf.unicode
-local pdfconstant = lpdf.constant
-local pdfflushobject = lpdf.flushobject
-local pdfreserveobject = lpdf.reserveobject
-local pdfannotation = nodes.pdfannotation
-local pdfdestination = nodes.pdfdestination
-
-local pdfpagereference = tex.pdfpageref
+local settings_to_array = utilities.parsers.settings_to_array
+
+local nodeinjections = backends.pdf.nodeinjections
+local codeinjections = backends.pdf.codeinjections
+local registrations = backends.pdf.registrations
+
+local javascriptcode = interactions.javascripts.code
+
+local references = structures.references
+local bookmarks = structures.bookmarks
+
+local runners = references.runners
+local specials = references.specials
+local handlers = references.handlers
+local executers = references.executers
+local nodepool = nodes.pool
+
+local pdfannotation_node = nodepool.pdfannotation
+local pdfdestination_node = nodepool.pdfdestination
+local latelua_node = nodepool.latelua
+
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfreference = lpdf.reference
+local pdfunicode = lpdf.unicode
+local pdfconstant = lpdf.constant
+local pdfflushobject = lpdf.flushobject
+local pdfshareobjectreference = lpdf.shareobjectreference
+local pdfimmediateobject = lpdf.immediateobject
+local pdfreserveobject = lpdf.reserveobject
+local pdfpagereference = lpdf.pagereference
+local pdfdelayedobject = lpdf.delayedobject
+local pdfregisterannotation = lpdf.registerannotation
+
+local pdf_annot = pdfconstant("Annot")
local pdf_uri = pdfconstant("URI")
local pdf_gotor = pdfconstant("GoToR")
local pdf_goto = pdfconstant("GoTo")
@@ -51,26 +67,35 @@ local pdf_javascript = pdfconstant("JavaScript")
local pdf_link = pdfconstant("Link")
local pdf_n = pdfconstant("N")
local pdf_t = pdfconstant("T")
+local pdf_fit = pdfconstant("Fit")
+local pdf_named = pdfconstant("Named")
+
+-- todo: 3dview
+
local pdf_border = pdfarray { 0, 0, 0 }
+local getinnermethod = references.getinnermethod
+
local cache = { }
-local function pagedest(n)
- local pd = cache[n]
- if not pd then
- local a = pdfarray {
- pdfreference(pdfpagereference(n)),
- pdfconstant("Fit")
- }
- pd = pdfreference(pdfflushobject(a))
- cache[n] = pd
+local function pagedestination(n) -- only cache fit
+ if n > 0 then
+ local pd = cache[n]
+ if not pd then
+ local a = pdfarray {
+ pdfreference(pdfpagereference(n)),
+ pdf_fit,
+ }
+ pd = pdfshareobjectreference(a)
+ cache[n] = pd
+ end
+ return pd
end
- return pd
end
-lpdf.pagedest = pagedest
+lpdf.pagedestination = pagedestination
-local defaultdestination = pdfarray { 0, pdfconstant("Fit") }
+local defaultdestination = pdfarray { 0, pdf_fit }
local function link(url,filename,destination,page,actions)
if filename and filename ~= "" then
@@ -93,43 +118,36 @@ local function link(url,filename,destination,page,actions)
URI = url,
}
elseif filename and filename ~= "" then
+ -- no page ?
+ if destination == "" then
+ destination = nil
+ end
+ if not destination and page then
+ destination = pdfarray { page - 1, pdf_fit }
+ end
return pdfdictionary {
S = pdf_gotor, -- can also be pdf_launch
F = filename,
- D = (destination and destination ~= "" and destination), -- or defaultdestination,
+ D = destination or defaultdestination, -- D is mandate
NewWindow = (actions.newwindow and true) or nil,
}
elseif destination and destination ~= "" then
- local realpage, p = texcount.realpageno, tonumber(page)
- if not p then
- -- sorry
- elseif p > realpage then
- texcount.referencepagestate = 3
- elseif p < realpage then
- texcount.referencepagestate = 2
- else
- texcount.referencepagestate = 1
- end
- return pdfdictionary {
+ return pdfdictionary { -- can be cached
S = pdf_goto,
D = destination,
}
- elseif page and page ~= "" then
- local realpage, p = texcount.realpageno, tonumber(page)
- if p then
- if p > realpage then
- texcount.referencepagestate = 3
- elseif p < realpage then
- texcount.referencepagestate = 2
- else
- texcount.referencepagestate = 1
- end
- return pdfdictionary {
+ else
+ local p = tonumber(page)
+ if p and p > 0 then
+ return pdfdictionary { -- can be cached
S = pdf_goto,
- D = pagedest(p),
+ D = pdfarray {
+ pdfreference(pdfpagereference(p)),
+ pdf_fit,
+ }
}
else
- commands.writestatus("references","invalid page reference: %s",page or "?")
+ report_reference("invalid page reference: %s",tostring(page))
end
end
return false
@@ -152,7 +170,7 @@ function lpdf.launch(program,parameters)
end
function lpdf.javascript(name,arguments)
- local script = javascripts.code(name,arguments) -- make into object (hash)
+ local script = javascriptcode(name,arguments) -- make into object (hash)
if script then
return pdfdictionary {
S = pdf_javascript,
@@ -179,105 +197,158 @@ local function pdfaction(actions)
what = what(a,actions)
end
if what then
- action.next = what
+ action.Next = what
action = what
else
-- error
return nil
end
end
- return first
+ return first, actions.n
end
end
end
-lpdf.pdfaction = pdfaction
+lpdf.action = pdfaction
-function codeinjections.prerollreference(actions)
- local main = actions and pdfaction(actions)
- if main then
- main = pdfdictionary {
- Subtype = pdf_link,
- Border = pdf_border,
- H = (not actions.highlight and pdf_n) or nil,
- A = main,
- -- does not work at all in spite of specification
- -- OC = (actions.layer and lpdf.layerreferences[actions.layer]) or nil,
- -- OC = backends.pdf.layerreference(actions.layer),
- }
- return main("A") -- todo: cache this, maybe weak
+function codeinjections.prerollreference(actions) -- share can become option
+ if actions then
+ local main, n = pdfaction(actions)
+ if main then
+ main = pdfdictionary {
+ Subtype = pdf_link,
+ Border = pdf_border,
+ H = (not actions.highlight and pdf_n) or nil,
+ A = pdfshareobjectreference(main),
+ F = 4, -- print (mandate in pdf/a)
+ }
+ return main("A"), n
+ end
+ end
+end
+
+local function use_normal_annotations()
+
+ local function reference(width,height,depth,prerolled) -- keep this one
+ if prerolled then
+ if trace_references then
+ report_reference("w=%s, h=%s, d=%s, a=%s",width,height,depth,prerolled)
+ end
+ return pdfannotation_node(width,height,depth,prerolled)
+ end
+ end
+
+ local function finishreference()
end
+
+ return reference, finishreference
+
end
--- local cache = { } -- no real gain in thsi
---
--- function codeinjections.prerollreference(actions)
--- local main = actions and pdfaction(actions)
--- if main then
--- main = pdfdictionary {
--- Subtype = pdf_link,
--- Border = pdf_border,
--- H = (not actions.highlight and pdf_n) or nil,
--- A = main,
--- }
--- local cm = cache[main]
--- if not cm then
--- cm = "/A ".. tostring(pdfreference(pdfflushobject(main))
--- cache[main] = cm
--- end
--- return cm
--- end
--- end
-
-function nodeinjections.reference(width,height,depth,prerolled)
- if prerolled then
- if swapdir then
- width = - width
+-- evenrually we can do this for special refs only
+
+local hashed, nofunique, nofused = { }, 0, 0
+
+local function use_shared_annotations()
+
+ local factor = number.dimenfactors.bp
+
+ local function finishreference(width,height,depth,prerolled) -- %0.2f looks okay enough (no scaling anyway)
+ local h, v = pdf.h, pdf.v
+ local llx, lly = h*factor, (v - depth)*factor
+ local urx, ury = (h + width)*factor, (v + height)*factor
+ local annot = format("<< /Type /Annot %s /Rect [%0.2f %0.2f %0.2f %0.2f] >>",prerolled,llx,lly,urx,ury)
+ local n = hashed[annot]
+ if not n then
+ n = pdfdelayedobject(annot)
+ hashed[annot] = n
+ nofunique = nofunique + 1
end
- if trace_references then
- logs.report("references","w=%s, h=%s, d=%s, a=%s",width,height,depth,prerolled)
+ nofused = nofused + 1
+ pdfregisterannotation(n)
+ end
+
+ _bpnf_ = finishreference
+
+ local function reference(width,height,depth,prerolled)
+ if prerolled then
+ if trace_references then
+ report_reference("w=%s, h=%s, d=%s, a=%s",width,height,depth,prerolled)
+ end
+ local luacode = format("_bpnf_(%s,%s,%s,'%s')",width,height,depth,prerolled)
+ return latelua_node(luacode)
end
- return pdfannotation(width,height,depth,prerolled)
end
+
+ statistics.register("pdf annotations", function()
+ if nofused > 0 then
+ -- table.print(hashed,"hashed_annotations")
+ return string.format("%s embedded, %s unique",nofused,nofunique)
+ else
+ return nil
+ end
+ end)
+
+
+ return reference, finishreference
+
end
+local lln = latelua_node() if node.has_field(lln,'string') then
+
+ directives.register("refences.sharelinks", function(v)
+ if v then
+ nodeinjections.reference, codeinjections.finishreference = use_shared_annotations()
+ else
+ nodeinjections.reference, codeinjections.finishreference = use_normal_annotations()
+ end
+ end)
+
+ nodeinjections.reference, codeinjections.finishreference = use_shared_annotations()
+
+else
+
+ nodeinjections.reference, codeinjections.finishreference = use_normal_annotations()
+
+end node.free(lln)
+
+-- -- -- --
+-- -- -- --
+
function nodeinjections.destination(width,height,depth,name,view)
- if swapdir then
- width = - width
- end
if trace_destinations then
- logs.report("destinations","w=%s, h=%s, d=%s, n=%s, v=%s",width,height,depth,name,view or "no view")
+ report_destination("w=%s, h=%s, d=%s, n=%s, v=%s",width,height,depth,name,view or "no view")
end
- return pdfdestination(width,height,depth,name,view)
+ return pdfdestination_node(width,height,depth,name,view)
end
-- runners and specials
-local method = "internal"
-
runners["inner"] = function(var,actions)
- if method == "internal" then
+ if getinnermethod() == "names" then
local vir = var.i.references
local internal = vir and vir.internal
if internal then
- var.inner = "aut:"..internal
+ var.inner = "aut:" .. internal
end
+ else
+ var.inner = nil
end
return link(nil,nil,var.inner,var.r,actions)
end
runners["inner with arguments"] = function(var,actions)
- logs.report("references","todo: inner with arguments")
+ report_reference("todo: inner with arguments")
return false
end
runners["outer"] = function(var,actions)
- local file, url = jobreferences.checkedfileorurl(var.outer,var.outer)
+ local file, url = references.checkedfileorurl(var.outer,var.outer)
return link(url,file,var.arguments,nil,actions)
end
runners["outer with inner"] = function(var,actions)
- local file = jobreferences.checkedfile(var.f)
+ local file = references.checkedfile(var.f)
return link(nil,file,var.inner,var.r,actions)
end
@@ -287,7 +358,7 @@ runners["special outer with operation"] = function(var,actions)
end
runners["special outer"] = function(var,actions)
- logs.report("references","todo: special outer")
+ report_reference("todo: special outer")
return false
end
@@ -297,22 +368,22 @@ runners["special"] = function(var,actions)
end
runners["outer with inner with arguments"] = function(var,actions)
- logs.report("references","todo: outer with inner with arguments")
+ report_reference("todo: outer with inner with arguments")
return false
end
runners["outer with special and operation and arguments"] = function(var,actions)
- logs.report("references","todo: outer with special and operation and arguments")
+ report_reference("todo: outer with special and operation and arguments")
return false
end
runners["outer with special"] = function(var,actions)
- logs.report("references","todo: outer with special")
+ report_reference("todo: outer with special")
return false
end
runners["outer with special and operation"] = function(var,actions)
- logs.report("references","todo: outer with special and operation")
+ report_reference("todo: outer with special and operation")
return false
end
@@ -321,10 +392,11 @@ runners["special operation with arguments"] = runners["special"]
function specials.internal(var,actions) -- better resolve in strc-ref
local i = tonumber(var.operation)
- local v = jobreferences.internals[i]
+ local v = references.internals[i]
if not v then
-- error
- elseif method == "internal" then
+ report_reference("no internal reference '%s'",var.operation)
+ elseif getinnermethod() == "names" then
-- named
return link(nil,nil,"aut:"..i,v.references.realpage,actions)
else
@@ -333,27 +405,60 @@ function specials.internal(var,actions) -- better resolve in strc-ref
end
end
+-- realpage already resolved
+
specials.i = specials.internal
-function specials.page(var,actions) -- better resolve in strc-ref
+local pages = references.pages
+
+function specials.page(var,actions)
local file = var.f
if file then
- file = jobreferences.checkedfile(file)
- return link(nil,file,nil,p or var.operation,actions)
+ file = references.checkedfile(file)
+ return link(nil,file,nil,var.operation,actions)
else
- local p = jobreferences.pages[var.operation]
- if type(p) == "function" then
- p = p()
+ local p = var.r
+ if not p then -- todo: call special from reference code
+ p = pages[var.operation]
+ if type(p) == "function" then -- double
+ p = p()
+ else
+ p = tonumber(references.realpageofpage(tonumber(o)))
+ end
end
return link(nil,nil,nil,p or var.operation,actions)
end
end
+function specials.realpage(var,actions)
+ local file = var.f
+ if file then
+ file = references.checkedfile(file)
+ return link(nil,file,nil,var.operation,actions)
+ else
+ return link(nil,nil,nil,var.operation,actions)
+ end
+end
+
+function specials.userpage(var,actions)
+ local file = var.f
+ if file then
+ file = references.checkedfile(file)
+ return link(nil,file,nil,var.operation,actions)
+ else
+ local p = var.r
+ if not p then -- todo: call special from reference code
+ p = tonumber(references.realpageofpage(var.operation))
+ end
+ return link(nil,nil,nil,p,actions)
+ end
+end
+
-- todo, do this in references namespace ordered instead (this is an experiment)
local splitter = lpeg.splitat(":")
-function specials.order(var,actions) -- jobreferences.specials !
+function specials.order(var,actions) -- references.specials !
local operation = var.operation
if operation then
local kind, name, n = lpegmatch(splitter,operation)
@@ -369,22 +474,22 @@ function specials.order(var,actions) -- jobreferences.specials !
end
function specials.url(var,actions)
- local url = jobreferences.checkedurl(var.operation)
+ local url = references.checkedurl(var.operation)
return link(url,nil,var.arguments,nil,actions)
end
function specials.file(var,actions)
- local file = jobreferences.checkedfile(var.operation)
+ local file = references.checkedfile(var.operation)
return link(nil,file,var.arguments,nil,actions)
end
function specials.fileorurl(var,actions)
- local file, url = jobreferences.checkedfileorurl(var.operation,var.operation)
+ local file, url = references.checkedfileorurl(var.operation,var.operation)
return link(url,file,var.arguments,nil,actions)
end
function specials.program(var,content)
- local program = jobreferences.checkedprogram(var.operation)
+ local program = references.checkedprogram(var.operation)
return lpdf.launch(program,var.arguments)
end
@@ -394,8 +499,6 @@ end
specials.JS = specials.javascript
-local pdf_named = pdfconstant("Named")
-
executers.importform = pdfdictionary { S = pdf_named, N = pdfconstant("AcroForm:ImportFDF") }
executers.exportform = pdfdictionary { S = pdf_named, N = pdfconstant("AcroForm:ExportFDF") }
executers.first = pdfdictionary { S = pdf_named, N = pdfconstant("FirstPage") }
@@ -426,7 +529,7 @@ local function fieldset(arguments)
end
function executers.resetform(arguments)
- arguments = (type(arguments) == "table" and arguments) or aux.settings_to_array(arguments)
+ arguments = (type(arguments) == "table" and arguments) or settings_to_array(arguments)
return pdfdictionary {
S = pdfconstant("ResetForm"),
Field = fieldset(arguments[1])
@@ -448,7 +551,7 @@ local flags = {
}
function executers.submitform(arguments)
- arguments = (type(arguments) == "table" and arguments) or aux.settings_to_array(arguments)
+ arguments = (type(arguments) == "table" and arguments) or settings_to_array(arguments)
local flag = flags[formmethod] or flags.post
flag = (flag and (flag[formformat] or flag.xml)) or 32 -- default: post, xml
return pdfdictionary {
@@ -483,7 +586,7 @@ local pdf_resume = pdfconstant("Resume")
local pdf_pause = pdfconstant("Pause")
local function movie_or_sound(operation,arguments)
- arguments = (type(arguments) == "table" and arguments) or aux.settings_to_array(arguments)
+ arguments = (type(arguments) == "table" and arguments) or settings_to_array(arguments)
return pdfdictionary {
S = pdf_movie,
T = format("movie %s",arguments[1] or "noname"),
@@ -522,13 +625,15 @@ local function build(levels,start,parent,method)
local startlevel = levels[start][1]
local i, n = start, 0
local child, entry, m, prev, first, last, f, l
--- to be tested: i can be nil
while i and i <= #levels do
local li = levels[i]
local level, title, reference, open = li[1], li[2], li[3], li[4]
- if level == startlevel then
+ if level < startlevel then
+ pdfflushobject(child,entry)
+ return i, n, first, last
+ elseif level == startlevel then
if trace_bookmarks then
- logs.report("bookmark","%3i %s%s %s",reference.realpage,rep(" ",level-1),(open and "+") or "-",title)
+ report_bookmark("%3i %s%s %s",reference.realpage,rep(" ",level-1),(open and "+") or "-",title)
end
local prev = child
child = pdfreserveobject()
@@ -544,16 +649,13 @@ local function build(levels,start,parent,method)
if method == "internal" then
entry.Dest = "aut:" .. reference.internal
else -- if method == "page" then
- entry.Dest = pagedest(reference.realpage)
+ entry.Dest = pagedestination(reference.realpage)
end
if not first then first, last = child, child end
prev = child
last = prev
n = n + 1
i = i + 1
- elseif level < startlevel then
- pdfflushobject(child,entry)
- return i, n, first, last
elseif i < #levels and level > startlevel then
i, m, f, l = build(levels,i,pdfreference(child),method)
entry.Count = (open and m) or -m
@@ -576,14 +678,21 @@ local function build(levels,start,parent,method)
end
function codeinjections.addbookmarks(levels,method)
- local parent = pdfreserveobject()
- local _, m, first, last = build(levels,1,pdfreference(parent),method or "internal")
- local dict = pdfdictionary {
- Type = pdfconstant("Outlines"),
- First = pdfreference(first),
- Last = pdfreference(last),
- Count = m,
- }
- pdfflushobject(parent,dict)
- lpdf.addtocatalog("Outlines",lpdf.reference(parent))
+ if #levels > 0 then
+ structures.bookmarks.flatten(levels) -- dirty trick for lack of structure
+ local parent = pdfreserveobject()
+ local _, m, first, last = build(levels,1,pdfreference(parent),method or "internal")
+ local dict = pdfdictionary {
+ Type = pdfconstant("Outlines"),
+ First = pdfreference(first),
+ Last = pdfreference(last),
+ Count = m,
+ }
+ pdfflushobject(parent,dict)
+ lpdf.addtocatalog("Outlines",lpdf.reference(parent))
+ end
end
+
+-- this could also be hooked into the frontend finalizer
+
+lpdf.registerdocumentfinalizer(function() bookmarks.place() end,1,"bookmarks")