summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/lpdf-fld.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-fld.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-fld.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/lpdf-fld.lua899
1 files changed, 541 insertions, 358 deletions
diff --git a/Master/texmf-dist/tex/context/base/lpdf-fld.lua b/Master/texmf-dist/tex/context/base/lpdf-fld.lua
index c034aec6c91..590aee1abe5 100644
--- a/Master/texmf-dist/tex/context/base/lpdf-fld.lua
+++ b/Master/texmf-dist/tex/context/base/lpdf-fld.lua
@@ -6,38 +6,78 @@ if not modules then modules = { } end modules ['lpdf-fld'] = {
license = "see context related readme files"
}
--- cleaned up, e.g. no longer older viewers
--- always kids so no longer explicit main / clone / copy
--- some optimizations removed (will come bakc if needed)
+-- The problem with widgets is that so far each version of acrobat
+-- has some rendering problem. I tried to keep up with this but
+-- it makes no sense to do so as one cannot rely on the viewer
+-- not changing. Especially Btn fields are tricky as their appearences
+-- need to be synchronized in the case of children but e.g. acrobat
+-- 10 does not retain the state and forces a check symbol. If you
+-- make a file in acrobat then it has MK entries that seem to overload
+-- the already present appearance streams (they're probably only meant for
+-- printing) as it looks like the viewer has some fallback on (auto
+-- generated) MK behaviour built in. So ... hard to test. Unfortunately
+-- not even the default appearance is generated. This will probably be
+-- solved at some point.
local gmatch, lower, format = string.gmatch, string.lower, string.format
local lpegmatch = lpeg.match
+local utfchar = utf.char
+local bpfactor, todimen = number.dimenfactors.bp, string.todimen
-local trace_fields = false trackers.register("widgets.fields", function(v) trace_fields = v end)
+local trace_fields = false trackers.register("backends.fields", function(v) trace_fields = v end)
-local texsprint, ctxcatcodes = tex.sprint, tex.ctxcatcodes
+local report_fields = logs.reporter("backend","fields")
-local variables = interfaces.variables
+local backends, lpdf = backends, lpdf
-local nodeinjections = backends.pdf.nodeinjections
-local codeinjections = backends.pdf.codeinjections
-local registrations = backends.pdf.registrations
+local variables = interfaces.variables
+local context = context
-local registeredsymbol = codeinjections.registeredsymbol
+local references = structures.references
+local settings_to_array = utilities.parsers.settings_to_array
-local pdfstream = lpdf.stream
-local pdfdictionary = lpdf.dictionary
-local pdfarray = lpdf.array
-local pdfreference = lpdf.reference
-local pdfunicode = lpdf.unicode
-local pdfstring = lpdf.string
-local pdfconstant = lpdf.constant
-local pdftoeight = lpdf.toeight
-local pdfflushobject = lpdf.flushobject
-local pdfreserveobject = lpdf.reserveobject
-local pdfannotation = nodes.pdfannotation
+local pdfbackend = backends.pdf
-local submitoutputformat = 0 -- 0=unknown 1=HTML 2=FDF 3=XML => not yet used, needs to be checked
+local nodeinjections = pdfbackend.nodeinjections
+local codeinjections = pdfbackend.codeinjections
+local registrations = pdfbackend.registrations
+
+local registeredsymbol = codeinjections.registeredsymbol
+
+local pdfstream = lpdf.stream
+local pdfdictionary = lpdf.dictionary
+local pdfarray = lpdf.array
+local pdfreference = lpdf.reference
+local pdfunicode = lpdf.unicode
+local pdfstring = lpdf.string
+local pdfconstant = lpdf.constant
+local pdftoeight = lpdf.toeight
+local pdfflushobject = lpdf.flushobject
+local pdfimmediateobject = lpdf.immediateobject
+local pdfshareobjectreference = lpdf.shareobjectreference
+local pdfshareobject = lpdf.shareobject
+local pdfreserveobject = lpdf.reserveobject
+local pdfreserveannotation = lpdf.reserveannotation
+local pdfaction = lpdf.action
+
+local hpack_node = node.hpack
+
+local nodepool = nodes.pool
+
+local pdfannotation_node = nodepool.pdfannotation
+
+local submitoutputformat = 0 -- 0=unknown 1=HTML 2=FDF 3=XML => not yet used, needs to be checked
+
+local pdf_widget = pdfconstant("Widget")
+local pdf_tx = pdfconstant("Tx")
+local pdf_ch = pdfconstant("Ch")
+local pdf_btn = pdfconstant("Btn")
+local pdf_yes = pdfconstant("Yes")
+local pdf_off = pdfconstant("Off")
+local pdf_p = pdfconstant("P") -- None Invert Outline Push
+local pdf_n = pdfconstant("N") -- None Invert Outline Push
+--
+local pdf_no_rect = pdfarray { 0, 0, 0, 0 }
local splitter = lpeg.splitat("=>")
@@ -46,7 +86,7 @@ local formats = {
}
function codeinjections.setformsmethod(name)
- submitoutputformat = formats[lower(name)] or 3
+ submitoutputformat = formats[lower(name)] or formats.xml
end
local flag = {
@@ -94,7 +134,7 @@ plus.auto = plus.AutoView
-- some day .. lpeg with function or table
local function fieldflag(specification)
- local o, n = specification.options, 0
+ local o, n = specification.option, 0
if o and o ~= "" then
for f in gmatch(o,"[^, ]+") do
n = n + (flag[f] or 0)
@@ -104,7 +144,7 @@ local function fieldflag(specification)
end
local function fieldplus(specification)
- local o, n = specification.options, 0
+ local o, n = specification.option, 0
if o and o ~= "" then
for p in gmatch(o,"[^, ]+") do
n = n + (plus[p] or 0)
@@ -113,29 +153,30 @@ local function fieldplus(specification)
return n
end
-
local function checked(what)
- if what and what ~= "" then
- local set, bug = jobreferences.identify("",what)
- return not bug and #set > 0 and lpdf.pdfaction(set)
+ local set, bug = references.identify("",what)
+ if not bug and #set > 0 then
+ local r, n = pdfaction(set)
+ return pdfshareobjectreference(r)
end
end
local function fieldactions(specification) -- share actions
---~ print(table.serialize(specification))
local d, a = { }, nil
- a = specification.mousedown if a and a ~= "" then d.D = checked(a) end
- a = specification.mouseup if a and a ~= "" then d.U = checked(a) end
+ a = specification.mousedown
+ or specification.clickin if a and a ~= "" then d.D = checked(a) end
+ a = specification.mouseup
+ or specification.clickout if a and a ~= "" then d.U = checked(a) end
a = specification.regionin if a and a ~= "" then d.E = checked(a) end -- Enter
a = specification.regionout if a and a ~= "" then d.X = checked(a) end -- eXit
- a = specification.afterkeystroke if a and a ~= "" then d.K = checked(a) end
- a = specification.formatresult if a and a ~= "" then d.F = checked(a) end
- a = specification.validateresult if a and a ~= "" then d.V = checked(a) end
- a = specification.calculatewhatever if a and a ~= "" then d.C = checked(a) end
+ a = specification.afterkey if a and a ~= "" then d.K = checked(a) end
+ a = specification.format if a and a ~= "" then d.F = checked(a) end
+ a = specification.validate if a and a ~= "" then d.V = checked(a) end
+ a = specification.calculate if a and a ~= "" then d.C = checked(a) end
a = specification.focusin if a and a ~= "" then d.Fo = checked(a) end
a = specification.focusout if a and a ~= "" then d.Bl = checked(a) end
- -- a = specification.openpage if a and a ~= "" then d.PO = checked(a) end
- -- a = specification.closepage if a and a ~= "" then d.PC = checked(a) end
+ a = specification.openpage if a and a ~= "" then d.PO = checked(a) end
+ a = specification.closepage if a and a ~= "" then d.PC = checked(a) end
-- a = specification.visiblepage if a and a ~= "" then d.PV = checked(a) end
-- a = specification.invisiblepage if a and a ~= "" then d.PI = checked(a) end
return next(d) and pdfdictionary(d)
@@ -143,6 +184,26 @@ end
-- fonts and color
+local pdfdocencodingvector, pdfdocencodingcapsule
+
+-- The pdf doc encoding vector is needed in order to
+-- trigger propper unicode. Interesting is that when
+-- a glyph is not in the vector, it is still visible
+-- as it is taken from some other font. Messy.
+
+-- To be checked: only when text/line fields.
+
+local function checkpdfdocencoding()
+ report_fields("adding pdfdoc encoding vector")
+ local encoding = dofile(resolvers.findfile("lpdf-enc.lua")) -- no checking, fatal if not present
+ pdfdocencodingvector = pdfreference(pdfflushobject(encoding))
+ local capsule = pdfdictionary {
+ PDFDocEncoding = pdfdocencodingvector
+ }
+ pdfdocencodingcapsule = pdfreference(pdfflushobject(capsule))
+ checkpdfdocencoding = function() end
+end
+
local fontnames = {
rm = {
tf = "Times-Roman",
@@ -167,44 +228,59 @@ local fontnames = {
sl = "Courier-Oblique",
bi = "Courier-BoldOblique",
bs = "Courier-BoldOblique",
+ },
+ symbol = {
+ dingbats = "ZapfDingbats",
}
}
local usedfonts = { }
local function fieldsurrounding(specification)
- local size = specification.fontsize or "12pt"
- local style = specification.fontstyle or "rm"
- local alternative = specification.fontalternative or "tf"
- local s = fontnames[style]
+ local fontsize = specification.fontsize or "12pt"
+ local fontstyle = specification.fontstyle or "rm"
+ local fontalternative = specification.fontalternative or "tf"
+ local colorvalue = specification.colorvalue
+ local s = fontnames[fontstyle]
if not s then
- style, s = "rm", fontnames.rm
+ fontstyle, s = "rm", fontnames.rm
end
- local a = s[alternative]
+ local a = s[fontalternative]
if not a then
alternative, a = "tf", s.tf
end
- local tag = style .. alternative
- size = string.todimen(size)
+ local tag = fontstyle .. fontalternative
+ fontsize = todimen(fontsize)
+ fontsize = fontsize and (bpfactor * fontsize) or 12
+ fontraise = 0.1 * fontsize -- todo: figure out what the natural one is and compensate for strutdp
+ local fontcode = format("%0.4f Tf %0.4f Ts",fontsize,fontraise)
+ -- we could test for colorvalue being 1 (black) and omit it then
+ local colorcode = lpdf.color(3,colorvalue) -- we force an rgb color space
+ if trace_fields then
+ report_fields("fontcode : %s %s @ %s => %s => %s",fontstyle,fontalternative,fontsize,tag,fontcode)
+ report_fields("colorcode: %s => %s",colorvalue,colorcode)
+ end
local stream = pdfstream {
pdfconstant(tag),
- format("%0.4f Tf",(size and (number.dimenfactors.bp * size)) or 12),
+ format("%s %s",fontcode,colorcode)
}
usedfonts[tag] = a -- the name
- -- add color to stream: 0 g
-- move up with "x.y Ts"
return tostring(stream)
end
local function registerfonts()
if next(usedfonts) then
+ checkpdfdocencoding() -- already done
local d = pdfdictionary()
+ local pdffonttype, pdffontsubtype = pdfconstant("Font"), pdfconstant("Type1")
for tag, name in next, usedfonts do
local f = pdfdictionary {
- Type = pdfconstant("Font"),
- Subtype = pdfconstant("Type1"), -- todo
+ Type = pdffonttype,
+ Subtype = pdffontsubtype,
Name = pdfconstant(tag),
BaseFont = pdfconstant(name),
+ Encoding = pdfdocencodingvector,
}
d[tag] = pdfreference(pdfflushobject(f))
end
@@ -212,16 +288,6 @@ local function registerfonts()
end
end
--- cache
-
-local function fieldattributes(specification)
---~ return pdfarray {
---~ -- BG = -- backgroundcolor
---~ -- BC = -- framecolor
---~ }
- return nil
-end
-
-- symbols
local function fieldappearances(specification)
@@ -232,7 +298,7 @@ local function fieldappearances(specification)
-- error
return
end
- local v = aux.settings_to_array(values)
+ local v = settings_to_array(values)
local n, r, d
if #v == 1 then
n, r, d = v[1], v[1], v[1]
@@ -241,21 +307,23 @@ local function fieldappearances(specification)
else
n, r, d = v[1], v[2], v[3]
end
- local appearance = pdfdictionary { -- cache this one
+ local appearance = pdfdictionary {
N = registeredsymbol(n), R = registeredsymbol(r), D = registeredsymbol(d),
}
- return lpdf.sharedobj(tostring(appearance))
+ return pdfshareobjectreference(appearance)
end
+local YesorOn = "Yes" -- somehow On is not always working out well any longer (why o why this change)
+
local function fieldstates(specification,forceyes,values,default)
-- we don't use Opt here (too messy for radio buttons)
local values, default = values or specification.values, default or specification.default
- if not values then
+ if not values or values == "" then
-- error
return
end
- local v = aux.settings_to_array(values)
- local yes, off
+ local v = settings_to_array(values)
+ local yes, off, yesn, yesr, yesd, offn, offr, offd
if #v == 1 then
yes, off = v[1], v[1]
else
@@ -265,12 +333,12 @@ local function fieldstates(specification,forceyes,values,default)
if not (yesshown and yesvalue) then
yesshown = yes, yes
end
- yes = aux.settings_to_array(yesshown)
+ yes = settings_to_array(yesshown)
local offshown, offvalue = lpegmatch(splitter,off)
if not (offshown and offvalue) then
offshown = off, off
end
- off = aux.settings_to_array(offshown)
+ off = settings_to_array(offshown)
if #yes == 1 then
yesn, yesr, yesd = yes[1], yes[1], yes[1]
elseif #yes == 2 then
@@ -292,29 +360,42 @@ local function fieldstates(specification,forceyes,values,default)
offvalue = offn
end
if forceyes == true then
- forceyes = forceyes and "On" -- spec likes Yes more but we've used On for ages now
+ forceyes = forceyes and YesorOn -- spec likes Yes more but we've used On for ages now
else
-- false or string
end
if default == yesn then
default = pdfconstant(forceyes or yesn)
else
- default = pdfconstant("Off")
+ default = pdf_off
end
local appearance = pdfdictionary { -- maybe also cache components
N = pdfdictionary { [forceyes or yesn] = registeredsymbol(yesn), Off = registeredsymbol(offn) },
R = pdfdictionary { [forceyes or yesr] = registeredsymbol(yesr), Off = registeredsymbol(offr) },
D = pdfdictionary { [forceyes or yesd] = registeredsymbol(yesd), Off = registeredsymbol(offd) }
}
- local appearanceref = lpdf.sharedobj(tostring(appearance))
- return appearanceref, default
+ local appearanceref = pdfshareobjectreference(appearance)
+ return appearanceref, default, yesvalue
+end
+
+local function fielddefault(field)
+ local default = field.default
+ if not default or default == "" then
+ local values = settings_to_array(field.values)
+ default = values[1]
+ end
+ if not default or default == "" then
+ return pdf_off
+ else
+ return pdfconstant(default)
+ end
end
local function fieldoptions(specification)
local values = specification.values
local default = specification.default
if values then
- local v = aux.settings_to_array(values)
+ local v = settings_to_array(values)
for i=1,#v do
local vi = v[i]
local shown, value = lpegmatch(splitter,vi)
@@ -328,21 +409,32 @@ local function fieldoptions(specification)
end
end
-local function radiodefault(parent,field,forceyes)
- local default, values = parent.default, parent.values
- if not default or default == "" then
- values = aux.settings_to_array(values)
- default = values[1]
+local mapping = {
+ -- acrobat compliant (messy, probably some pdfdoc encoding interference here)
+ check = "4", -- 0x34
+ circle = "l", -- 0x6C
+ cross = "8", -- 0x38
+ diamond = "u", -- 0x75
+ square = "n", -- 0x6E
+ star = "H", -- 0x48
+}
+
+local function todingbat(n)
+ if n and n ~= "" then
+ return mapping[n] or ""
end
- local name = field.name
- local fieldvalues = aux.settings_to_array(field.values)
- local yes, off = fieldvalues[1], fieldvalues[2] or fieldvalues[1]
- if not default then
- return pdfconstant((forceyes and "On") or yes)
- elseif default == name then
- return pdfconstant((forceyes and "On") or default)
- else
- return pdfconstant("Off")
+end
+
+local function fieldrendering(specification)
+ local bvalue = tonumber(specification.backgroundcolorvalue)
+ local fvalue = tonumber(specification.framecolorvalue)
+ local svalue = specification.fontsymbol
+ if bvalue or fvalue or (svalue and svalue ~= "") then
+ return pdfdictionary {
+ BG = bvalue and pdfarray { lpdf.colorvalues(3,bvalue) } or nil,
+ BC = fvalue and pdfarray { lpdf.colorvalues(3,fvalue) } or nil,
+ CA = svalue and pdfstring (svalue) or nil,
+ }
end
end
@@ -350,7 +442,7 @@ end
local function fieldlayer(specification) -- we can move this in line
local layer = specification.layer
- return (layer and lpdf.layerreferences[layer]) or nil
+ return (layer and lpdf.layerreference(layer)) or nil
end
-- defining
@@ -388,7 +480,7 @@ end
local function predefinesymbols(specification)
local values = specification.values
if values then
- local symbols = aux.settings_to_array(values)
+ local symbols = settings_to_array(values)
for i=1,#symbols do
local symbol = symbols[i]
local a, b = lpegmatch(splitter,symbol)
@@ -403,16 +495,14 @@ function codeinjections.getdefaultfieldvalue(name)
local values = f.values
local default = f.default
if not default or default == "" then
- local symbols = aux.settings_to_array(values)
+ local symbols = settings_to_array(values)
local symbol = symbols[1]
if symbol then
local a, b = lpegmatch(splitter,symbol) -- splits at =>
default = a or symbol
end
end
- if default then
- tex.sprint(ctxcatcodes,default)
- end
+ return default
end
end
@@ -420,26 +510,26 @@ function codeinjections.definefield(specification)
local n = specification.name
local f = fields[n]
if not f then
- local kind = specification.kind
- if not kind then
+ local fieldtype = specification.type
+ if not fieldtype then
if trace_fields then
- logs.report("fields","invalid definition of '%s': unknown type",n)
+ report_fields("invalid definition of '%s': unknown type",n)
end
- elseif kind == "radio" then
+ elseif fieldtype == "radio" then
local values = specification.values
if values and values ~= "" then
- values = aux.settings_to_array(values)
+ values = settings_to_array(values)
for v=1,#values do
radios[values[v]] = { parent = n }
end
fields[n] = specification
if trace_fields then
- logs.report("fields","defining '%s' as radio",n or "?")
+ report_fields("defining '%s' as radio",n or "?")
end
elseif trace_fields then
- logs.report("fields","invalid definition of radio '%s': missing values",n)
+ report_fields("invalid definition of radio '%s': missing values",n)
end
- elseif kind == "sub" then
+ elseif fieldtype == "sub" then
-- not in main field list !
local radio = radios[n]
if radio then
@@ -449,16 +539,16 @@ function codeinjections.definefield(specification)
end
if trace_fields then
local p = radios[n] and radios[n].parent
- logs.report("fields","defining '%s' as sub of radio '%s'",n or "?",p or "?")
+ report_fields("defining '%s' as sub of radio '%s'",n or "?",p or "?")
end
elseif trace_fields then
- logs.report("fields","invalid definition of radio sub '%s': no parent",n)
+ report_fields("invalid definition of radio sub '%s': no parent",n)
end
predefinesymbols(specification)
- elseif kind == "text" or kind == "line" then
+ elseif fieldtype == "text" or fieldtype == "line" then
fields[n] = specification
if trace_fields then
- logs.report("fields","defining '%s' as %s",n,kind)
+ report_fields("defining '%s' as %s",n,fieldtype)
end
if specification.values ~= "" and specification.default == "" then
specification.default, specification.values = specification.values, nil
@@ -466,69 +556,76 @@ function codeinjections.definefield(specification)
else
fields[n] = specification
if trace_fields then
- logs.report("fields","defining '%s' as %s",n,kind)
+ report_fields("defining '%s' as %s",n,fieldtype)
end
predefinesymbols(specification)
end
elseif trace_fields then
- logs.report("fields","invalid definition of '%s': already defined",n)
+ report_fields("invalid definition of '%s': already defined",n)
end
end
-function codeinjections.clonefield(specification)
- local p, c, v = specification.parent, specification.children, specification.variant
+function codeinjections.clonefield(specification) -- obsolete
+ local p, c, v = specification.parent, specification.children, specification.alternative
if not p or not c then
if trace_fields then
- logs.report("fields","invalid clone: children: '%s', parent '%s', variant: '%s'",p or "?",c or "?", v or "?")
+ report_fields("invalid clone: children: '%s', parent '%s', alternative: '%s'",p or "?",c or "?", v or "?")
end
- else
- for n in gmatch(c,"[^, ]+") do
- local f, r, c, x = fields[n], radios[n], clones[n], fields[p]
- if f or r or c then
- if trace_fields then
- logs.report("fields","already cloned: child: '%s', parent '%s', variant: '%s'",p or "?",n or "?", v or "?")
- end
- elseif x then
- if trace_fields then
- logs.report("fields","invalid clone: child: '%s', variant: '%s', no parent",n or "?", v or "?")
- end
- else
- if trace_fields then
- logs.report("fields","cloning: child: '%s', parent '%s', variant: '%s'",p or "?",n or "?", v or "?")
- end
- clones[n] = specification
- predefinesymbols(specification)
+ return
+ end
+ local x = fields[p]
+ if not x then
+ if trace_fields then
+ report_fields("cloning: unknown parent '%s'",p)
+ end
+ return
+ end
+ for n in gmatch(c,"[^, ]+") do
+ local f, r, c = fields[n], radios[n], clones[n]
+ if f or r or c then
+ if trace_fields then
+ report_fields("already cloned: child: '%s', parent '%s', alternative: '%s'",p,n, v or "?")
end
+ else
+ if trace_fields then
+ report_fields("cloning: child: '%s', parent '%s', alternative: '%s'",p,n, v or "?")
+ end
+ clones[n] = specification
+ predefinesymbols(specification)
end
end
end
-function codeinjections.getfieldgroup(name)
+function codeinjections.getfieldcategory(name)
local f = fields[name] or radios[name] or clones[name]
- local g = f and f.group
- if not g or g == "" then
- local v, p, k = f.variant, f.parent, f.kind
- if v == "clone" or v == "copy" then
- f = fields[p] or radios[p]
- g = f and f.group
- elseif k == "sub" then
- f = fields[p]
- g = f and f.group
+ if f then
+ local g = f.category
+ if not g or g == "" then
+ local v, p, t = f.alternative, f.parent, f.type
+ if v == "clone" or v == "copy" then
+ f = fields[p] or radios[p]
+ g = f and f.category
+ elseif t == "sub" then
+ f = fields[p]
+ g = f and f.category
+ end
end
- end
- if g then
- texsprint(ctxcatcodes,g)
+ return g
end
end
--
-function codeinjections.doiffieldset(tag)
- commands.testcase(fieldsets[tag])
+function codeinjections.validfieldcategory(name)
+ return fields[name] or radios[name] or clones[name]
+end
+
+function codeinjections.validfieldset(name)
+ return fieldsets[tag]
end
-function codeinjections.doiffieldelse(name)
- commands.testcase(fields[name])
+function codeinjections.validfield(name)
+ return fields[name]
end
--
@@ -544,342 +641,428 @@ local function fieldalignment(specification)
end
local function enhance(specification,option)
- local so = specification.options
+ local so = specification.option
if so and so ~= "" then
- specification.options = so .. "," .. option
+ specification.option = so .. "," .. option
else
- specification.options = option
+ specification.option = option
end
return specification
end
-- finish
-local collected = pdfarray()
+local collected = pdfarray()
+local forceencoding = false
local function finishfields()
+ local sometext = forceencoding
for name, field in next, fields do
local kids = field.kids
if kids then
- pdfflushobject(field.kobj,kids)
+ pdfflushobject(field.kidsnum,kids)
+ end
+ local opt = field.opt
+ if opt then
+ pdfflushobject(field.optnum,opt)
+ end
+ local type = field.type
+ if not sometext and (type == "text" or type == "line") then
+ sometext = true
end
- local pobj = field.pobj
end
for name, field in next, radios do
local kids = field.kids
if kids then
- pdfflushobject(field.kobj,kids)
+ pdfflushobject(field.kidsnum,kids)
+ end
+ local opt = field.opt
+ if opt then
+ pdfflushobject(field.optnum,opt)
end
end
if #collected > 0 then
- usedfonts.tttf = fontnames.tt.tf
local acroform = pdfdictionary {
NeedAppearances = true,
- Fields = pdfreference(pdfflushobject(collected)),
- DR = pdfdictionary { Font = registerfonts() },
- CO = fieldsetlist(calculationset),
- DA = "/tttf 12 Tf 0 g",
+ Fields = pdfreference(pdfflushobject(collected)),
+ CO = fieldsetlist(calculationset),
}
+ if sometext then
+ checkpdfdocencoding()
+ usedfonts.tttf = fontnames.tt.tf
+ acroform.DA = "/tttf 12 Tf 0 g"
+ acroform.DR = pdfdictionary {
+ Font = registerfonts(),
+ Encoding = pdfdocencodingcapsule,
+ }
+ end
lpdf.addtocatalog("AcroForm",pdfreference(pdfflushobject(acroform)))
end
end
-lpdf.registerdocumentfinalizer(finishfields)
-
-local pdf_widget = pdfconstant("Widget")
-local pdf_tx = pdfconstant("Tx")
-local pdf_ch = pdfconstant("Ch")
-local pdf_btn = pdfconstant("Btn")
-local pdf_yes = pdfconstant("Yes")
-local pdf_p = pdfconstant("P") -- None Invert Outline Push
-local pdf_n = pdfconstant("N") -- None Invert Outline Push
---
-local pdf_no_rect = pdfarray { 0, 0, 0, 0 }
+lpdf.registerdocumentfinalizer(finishfields,"form fields")
local methods = { }
-function codeinjections.typesetfield(name,specification)
+function nodeinjections.typesetfield(name,specification)
local field = fields[name] or radios[name] or clones[name]
if not field then
- logs.report("fields", "unknown child '%s'",name)
+ report_fields( "unknown child '%s'",name)
-- unknown field
return
end
- local variant, parent = field.variant, field.parent
- if variant == "copy" or variant == "clone" then -- only in clones
+ local alternative, parent = field.alternative, field.parent
+ if alternative == "copy" or alternative == "clone" then -- only in clones
field = fields[parent] or radios[parent]
end
- local method = methods[field.kind]
+ local method = methods[field.type]
if method then
- method(name,specification,variant)
+ return method(name,specification,alternative)
else
- logs.report("fields", "unknown method '%s' for child '%s'",field.kind,name)
+ report_fields( "unknown method '%s' for child '%s'",field.type,name)
end
end
--- can be optional multipass optimization (share objects)
-
-local function save_parent(field,specification,d)
- local kn = pdfreserveobject()
- d.Kids = pdfreference(kn)
- field.kobj = kn
+local function save_parent(field,specification,d,hasopt)
+ local kidsnum = pdfreserveobject()
+ d.Kids = pdfreference(kidsnum)
+ field.kidsnum = kidsnum
field.kids = pdfarray()
- local pn = pdfflushobject(d)
- field.pobj = pn
- collected[#collected+1] = pdfreference(pn)
+ if hasopt then
+ local optnum = pdfreserveobject()
+ d.Opt = pdfreference(optnum)
+ field.optnum = optnum
+ field.opt = pdfarray()
+ end
+ local pnum = pdfflushobject(d)
+ field.pobj = pnum
+ collected[#collected+1] = pdfreference(pnum)
end
-local function save_kid(field,specification,d)
- local kn = pdfreserveobject()
+local function save_kid(field,specification,d,optname)
+ local kn = pdfreserveannotation()
field.kids[#field.kids+1] = pdfreference(kn)
- node.write(pdfannotation(specification.width,specification.height,0,d(),kn))
+ if optname then
+ field.opt[#field.opt+1] = optname
+ end
+ local width, height, depth = specification.width or 0, specification.height or 0, specification.depth
+ local box = hpack_node(pdfannotation_node(width,height,depth,d(),kn))
+ box.width, box.height, box.depth = width, height, depth -- redundant
+ return box
end
-function methods.line(name,specification,variant,extras)
- local field = fields[name]
- if variant == "copy" or variant == "clone" then
- logs.report("fields","todo: clones of text fields")
- end
- local kind = field.kind
- if not field.pobj then
- if trace_fields then
- logs.report("fields","using parent text '%s'",name)
+local function makelineparent(field,specification)
+ local text = pdfunicode(field.default)
+ local length = tonumber(specification.length or 0) or 0
+ local d = pdfdictionary {
+ Subtype = pdf_widget,
+ T = pdfunicode(specification.title),
+ F = fieldplus(specification),
+ Ff = fieldflag(specification),
+ OC = fieldlayer(specification),
+ DA = fieldsurrounding(specification),
+ AA = fieldactions(specification),
+ FT = pdf_tx,
+ Q = fieldalignment(specification),
+ MaxLen = length == 0 and 1000 or length,
+ DV = text,
+ V = text,
+ }
+ save_parent(field,specification,d)
+end
+
+local function makelinechild(name,specification)
+ local field, parent = clones[name], nil
+ if field then
+ parent = fields[field.parent]
+ if not parent.pobj then
+ if trace_fields then
+ report_fields("forcing parent text '%s'",parent.name)
+ end
+ makelineparent(parent,specification)
end
- if extras then
- enhance(specification,extras)
+ else
+ parent = fields[name]
+ field = parent
+ if not parent.pobj then
+ if trace_fields then
+ report_fields("using parent text '%s'",name)
+ end
+ makelineparent(parent,specification)
end
- local text = pdfunicode(field.default)
- local d = pdfdictionary {
- Subtype = pdf_widget,
- T = pdfunicode(specification.title),
- F = fieldplus(specification),
- Ff = fieldflag(specification),
- OC = fieldlayer(specification),
- MK = fieldsurrounding(specification), -- needed ?
- DA = fieldsurrounding(specification),
- AA = fieldactions(specification),
- FT = pdf_tx,
- Q = fieldalignment(specification),
- MaxLen = (specification.length == 0 and 1000) or specification.length,
- DV = text,
- V = text,
- }
- save_parent(field,specification,d)
- field.specification = specification
end
- specification = field.specification or { } -- todo: radio spec
if trace_fields then
- logs.report("fields","using child text '%s'",name)
+ report_fields("using child text '%s'",name)
end
local d = pdfdictionary {
Subtype = pdf_widget,
- Parent = pdfreference(field.pobj),
+ Parent = pdfreference(parent.pobj),
F = fieldplus(specification),
- DA = fieldattributes(specification),
OC = fieldlayer(specification),
- MK = fieldsurrounding(specification),
DA = fieldsurrounding(specification),
AA = fieldactions(specification),
+ MK = fieldrendering(specification),
Q = fieldalignment(specification),
}
- save_kid(field,specification,d)
+ return save_kid(parent,specification,d)
end
-function methods.text(name,specification,variant)
- methods.line(name,specification,variant,"MultiLine")
+function methods.line(name,specification)
+ return makelinechild(name,specification)
end
-function methods.choice(name,specification,variant,extras)
- local field = fields[name]
- if variant == "copy" or variant == "clone" then
- logs.report("fields","todo: clones of choice fields")
- end
- local kind = field.kind
- local d
- if not field.pobj then
- if trace_fields then
- logs.report("fields","using parent choice '%s'",name)
+function methods.text(name,specification)
+ return makelinechine(name,enhance(specification,"MultiLine"))
+end
+
+local function makechoiceparent(field,specification)
+ local d = pdfdictionary {
+ Subtype = pdf_widget,
+ T = pdfunicode(specification.title),
+ F = fieldplus(specification),
+ Ff = fieldflag(specification),
+ OC = fieldlayer(specification),
+ AA = fieldactions(specification),
+ FT = pdf_ch,
+ Opt = fieldoptions(field), -- todo
+ }
+ save_parent(field,specification,d)
+end
+
+local function makechoicechild(name,specification)
+ local field, parent = clones[name], nil
+ if field then
+ parent = fields[field.parent]
+ if not parent.pobj then
+ if trace_fields then
+ report_fields("forcing parent choice '%s'",parent.name)
+ end
+ makechoiceparent(parent,specification,extras)
end
- if extras then
- enhance(specification,extras)
+ else
+ parent = fields[name]
+ field = parent
+ if not parent.pobj then
+ if trace_fields then
+ report_fields("using parent choice '%s'",name)
+ end
+ makechoiceparent(parent,specification,extras)
end
- local d = pdfdictionary {
- Subtype = pdf_widget,
- T = pdfunicode(specification.title),
- F = fieldplus(specification),
- Ff = fieldflag(specification),
- OC = fieldlayer(specification),
- AA = fieldactions(specification),
- FT = pdf_ch,
- Opt = fieldoptions(field),
- }
- save_parent(field,specification,d)
- field.specification = specification
end
- specification = field.specification or { }
if trace_fields then
- logs.report("fields","using child choice '%s'",name)
+ report_fields("using child choice '%s'",name)
end
local d = pdfdictionary {
Subtype = pdf_widget,
- Parent = pdfreference(field.pobj),
+ Parent = pdfreference(parent.pobj),
F = fieldplus(specification),
- DA = fieldattributes(specification),
OC = fieldlayer(specification),
AA = fieldactions(specification),
}
- save_kid(field,specification,d)
+ return save_kid(parent,specification,d) -- do opt here
+end
+
+function methods.choice(name,specification)
+ return makechoicechild(name,specification)
end
-function methods.popup(name,specification,variant)
- methods.choice(name,specification,variant,"PopUp")
+function methods.popup(name,specification)
+ return makechoicechild(name,enhance(specification,"PopUp"))
end
-function methods.combo(name,specification,variant)
- methods.choice(name,specification,variant,"PopUp,Edit")
+
+function methods.combo(name,specification)
+ return makechoicechild(name,enhance(specification,"PopUp,Edit"))
end
--- Probably no default appearance needed for first kid and no javascripts for the
--- parent ... I will look into it when I have to make a complex document.
+local function makecheckparent(field,specification)
+ local d = pdfdictionary {
+ T = pdfunicode(specification.title),
+ F = fieldplus(specification),
+ Ff = fieldflag(specification),
+ OC = fieldlayer(specification),
+ AA = fieldactions(specification),
+ FT = pdf_btn,
+ V = fielddefault(field),
+ }
+ save_parent(field,specification,d,true)
+end
-function methods.check(name,specification,variant)
- -- no /Opt because (1) it's messy - see pdf spec, (2) it discouples kids and
- -- contrary to radio there is no way to associate then
- local field = fields[name]
- if variant == "copy" or variant == "clone" then
- logs.report("fields","todo: clones of check fields")
- end
- local kind = field.kind
- local appearance, default = fieldstates(field,true)
- if not field.pobj then
- if trace_fields then
- logs.report("fields","using parent check '%s'",name)
+local function makecheckchild(name,specification)
+ local field, parent = clones[name], nil
+ if field then
+ parent = fields[field.parent]
+ if not parent.pobj then
+ if trace_fields then
+ report_fields("forcing parent check '%s'",parent.name)
+ end
+ makecheckparent(parent,specification,extras)
+ end
+ else
+ parent = fields[name]
+ field = parent
+ if not parent.pobj then
+ if trace_fields then
+ report_fields("using parent check '%s'",name)
+ end
+ makecheckparent(parent,specification,extras)
end
- local d = pdfdictionary {
- Subtype = pdf_widget,
- T = pdfunicode(specification.title),
- F = fieldplus(specification),
- Ff = fieldflag(specification),
- OC = fieldlayer(specification),
- AA = fieldactions(specification),
- FT = pdf_btn,
- DV = default,
- V = default,
- AS = default,
- AP = appearance,
- H = pdf_n,
- }
- save_parent(field,specification,d)
- field.specification = specification
end
- specification = field.specification or { } -- todo: radio spec
if trace_fields then
- logs.report("fields","using child check '%s'",name)
+ report_fields("using child check '%s'",name)
end
local d = pdfdictionary {
Subtype = pdf_widget,
- Parent = pdfreference(field.pobj),
+ Parent = pdfreference(parent.pobj),
F = fieldplus(specification),
- DA = fieldattributes(specification),
OC = fieldlayer(specification),
AA = fieldactions(specification),
- DV = default,
- V = default,
- AS = default,
- AP = appearance,
H = pdf_n,
}
- save_kid(field,specification,d)
+ local fontsymbol = specification.fontsymbol
+ if fontsymbol and fontsymbol ~= "" then
+ specification.fontsymbol = todingbat(fontsymbol)
+ specification.fontstyle = "symbol"
+ specification.fontalternative = "dingbats"
+ d.DA = fieldsurrounding(specification)
+ d.MK = fieldrendering(specification)
+ return save_kid(parent,specification,d)
+ else
+ local appearance, default, value = fieldstates(field,true)
+ d.AS = default
+ d.AP = appearance
+ return save_kid(parent,specification,d,value)
+ end
end
-function methods.push(name,specification,variant)
- local field = fields[name]
- if variant == "copy" or variant == "clone" then
- logs.report("fields","todo: clones of push fields")
- end
- local kind = field.kind
- if not field.pobj then
- if trace_fields then
- logs.report("fields","using parent push '%s'",name)
+function methods.check(name,specification)
+ return makecheckchild(name,specification)
+end
+
+local function makepushparent(field,specification) -- check if we can share with the previous
+ local d = pdfdictionary {
+ Subtype = pdf_widget,
+ T = pdfunicode(specification.title),
+ F = fieldplus(specification),
+ Ff = fieldflag(specification),
+ OC = fieldlayer(specification),
+ AA = fieldactions(specification),
+ FT = pdf_btn,
+ AP = fieldappearances(field),
+ H = pdf_p,
+ }
+ save_parent(field,specification,d)
+end
+
+local function makepushchild(name,specification)
+ local field, parent = clones[name], nil
+ if field then
+ parent = fields[field.parent]
+ if not parent.pobj then
+ if trace_fields then
+ report_fields("forcing parent push '%s'",parent.name)
+ end
+ makepushparent(parent,specification)
+ end
+ else
+ parent = fields[name]
+ field = parent
+ if not parent.pobj then
+ if trace_fields then
+ report_fields("using parent push '%s'",name)
+ end
+ makepushparent(parent,specification)
end
- enhance(specification,"PushButton")
- local d = pdfdictionary {
- Subtype = pdf_widget,
- T = pdfunicode(specification.title),
- F = fieldplus(specification),
- Ff = fieldflag(specification),
- OC = fieldlayer(specification),
- AA = fieldactions(specification),
- FT = pdf_btn,
- AP = fieldappearances(field),
- H = pdf_p,
- }
- save_parent(field,specification,d)
- field.specification = specification
end
- specification = field.specification or { } -- todo: radio spec
if trace_fields then
- logs.report("fields","using child push '%s'",name)
+ report_fields("using child push '%s'",name)
end
+ local fontsymbol = specification.fontsymbol
local d = pdfdictionary {
Subtype = pdf_widget,
Parent = pdfreference(field.pobj),
F = fieldplus(specification),
- DA = fieldattributes(specification),
OC = fieldlayer(specification),
AA = fieldactions(specification),
- AP = fieldappearances(field),
H = pdf_p,
}
- save_kid(field,specification,d)
+ if fontsymbol and fontsymbol ~= "" then
+ specification.fontsymbol = todingbat(fontsymbol)
+ specification.fontstyle = "symbol"
+ specification.fontalternative = "dingbats"
+ d.DA = fieldsurrounding(specification)
+ d.MK = fieldrendering(specification)
+ else
+ d.AP = fieldappearances(field)
+ end
+ return save_kid(parent,specification,d)
+end
+
+function methods.push(name,specification)
+ return makepushchild(name,enhance(specification,"PushButton"))
+end
+
+local function makeradioparent(field,specification)
+ specification = enhance(specification,"Radio,RadiosInUnison")
+ local d = pdfdictionary {
+ T = field.name,
+ FT = pdf_btn,
+ F = fieldplus(specification),
+ Ff = fieldflag(specification),
+ H = pdf_n,
+ V = fielddefault(field),
+ }
+ save_parent(field,specification,d,true)
end
-function methods.sub(name,specification,variant)
- local field = radios[name] or fields[name] or clones[name] -- fields in case of a clone, maybe use dedicated clones
- local values
- if variant == "copy" or variant == "clone" then
- name = field.parent
- values = field.values -- clone only, copy has nil so same as parent
+local function makeradiochild(name,specification)
+ local field, parent = clones[name], nil
+ if field then
+ field = radios[field.parent]
+ parent = fields[field.parent]
+ if not parent.pobj then
+ if trace_fields then
+ report_fields("forcing parent radio '%s'",parent.name)
+ end
+ makeradioparent(parent,parent)
+ end
field = radios[name]
else
- values = field.values
- end
- local parent = fields[field.parent]
- if not parent then
- return
- end
- local appearance = fieldstates(field,name,values) -- we need to force the 'On' name
- local default = radiodefault(parent,field)
- if not parent.pobj then
- if trace_fields then
- logs.report("fields","using parent '%s' of radio '%s' with values '%s' and default '%s'",parent.name,name,parent.values or "?",parent.default or "?")
+ field = radios[name]
+ parent = fields[field.parent]
+ if not parent.pobj then
+ if trace_fields then
+ report_fields("using parent radio '%s'",name)
+ end
+ makeradioparent(parent,parent)
end
- local specification = parent.specification or { }
- -- enhance(specification,"Radio,RadiosInUnison")
- enhance(specification,"RadiosInUnison") -- maybe also PushButton as acrobat does
- local d = pdfdictionary {
- T = parent.name,
- FT = pdf_btn,
- Rect = pdf_no_rect,
- F = fieldplus(specification),
- Ff = fieldflag(specification),
- H = pdf_n,
- V = default,
- }
- save_parent(parent,specification,d)
end
if trace_fields then
- logs.report("fields","using child radio '%s' with values '%s'",name,values or "?")
+ report_fields("using child radio '%s' with values '%s' and default '%s'",name,field.values or "?",field.default or "?")
end
+ local fontsymbol = specification.fontsymbol
local d = pdfdictionary {
Subtype = pdf_widget,
Parent = pdfreference(parent.pobj),
F = fieldplus(specification),
- DA = fieldattributes(specification),
OC = fieldlayer(specification),
AA = fieldactions(specification),
- AS = default,
- AP = appearance,
H = pdf_n,
}
- save_kid(parent,specification,d)
+ if fontsymbol and fontsymbol ~= "" then
+ specification.fontsymbol = todingbat(fontsymbol)
+ specification.fontstyle = "symbol"
+ specification.fontalternative = "dingbats"
+ d.DA = fieldsurrounding(specification)
+ d.MK = fieldrendering(specification)
+ return save_kid(parent,specification,d)
+ else
+ local appearance, default, value = fieldstates(field,true) -- false is also ok
+ d.AS = default -- needed ?
+ d.AP = appearance
+ return save_kid(parent,specification,d,value)
+ end
+end
+
+function methods.sub(name,specification)
+ return makeradiochild(name,enhance(specification,"Radio,RadiosInUnison"))
end