lpdf-fld.lua /size: 50 Kb    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
lpdf-fld
'
]
=
{
2
version
=
1
.
001
,
3
comment
=
"
companion to lpdf-ini.mkiv
"
,
4
author
=
"
Hans Hagen, PRAGMA-ADE, Hasselt NL
"
,
5
copyright
=
"
PRAGMA ADE / ConTeXt Development Team
"
,
6
license
=
"
see context related readme files
"
7
}
8 9
-- TURN OFF: preferences -> forms -> highlight -> etc
10 11
-- The problem with widgets is that so far each version of acrobat has some
12
-- rendering problem. I tried to keep up with this but it makes no sense to do so as
13
-- one cannot rely on the viewer not changing. Especially Btn fields are tricky as
14
-- their appearences need to be synchronized in the case of children but e.g.
15
-- acrobat 10 does not retain the state and forces a check symbol. If you make a
16
-- file in acrobat then it has MK entries that seem to overload the already present
17
-- appearance streams (they're probably only meant for printing) as it looks like
18
-- the viewer has some fallback on (auto generated) MK behaviour built in. So ...
19
-- hard to test. Unfortunately not even the default appearance is generated. This
20
-- will probably be solved at some point.
21
--
22
-- Also, for some reason the viewer does not always show custom appearances when
23
-- fields are being rolled over or clicked upon, and circles or checks pop up when
24
-- you don't expect them. I fear that this kind of instability eventually will kill
25
-- pdf forms. After all, the manual says: "individual annotation handlers may ignore
26
-- this entry and provide their own appearances" and one might wonder what
27
-- 'individual' means here, but effectively this renders the whole concept of
28
-- appearances useless.
29
--
30
-- Okay, here is one observation. A pdf file contains objects and one might consider
31
-- each one to be a static entity when read in. However, acrobat starts rendering
32
-- and seems to manipulate (appearance streams) of objects in place (this is visible
33
-- when the file is saved again). And, combined with some other caching and hashing,
34
-- this might give side effects for shared objects. So, it seems that for some cases
35
-- one can best be not too clever and not share but duplicate information. Of course
36
-- this defeats the whole purpose of these objects. Of course I can be wrong.
37
--
38
-- A rarther weird side effect of the viewer is that the highlighting of fields
39
-- obscures values, unless you uses one of the BS variants, and this makes custum
40
-- appearances rather useless as there is no way to control this apart from changing
41
-- the viewer preferences. It could of course be a bug but it would be nice if the
42
-- highlighting was at least transparent. I have no clue why the built in shapes
43
-- work ok (some xform based appearances are generated) while equally valid other
44
-- xforms fail. It looks like acrobat appearances come on top (being refered to in
45
-- the MK) while custom ones are behind the highlight rectangle. One can disable the
46
-- "Show border hover color for fields" option in the preferences. If you load
47
-- java-imp-rhh this side effect gets disabled and you get what you expect (it took
48
-- me a while to figure out this hack).
49
--
50
-- When highlighting is enabled, those default symbols flash up, so it looks like we
51
-- have some inteference between this setting and custom appearances.
52
--
53
-- Anyhow, the NeedAppearances is really needed in order to get a rendering for
54
-- printing especially when highlighting (those colorfull foregrounds) is on.
55 56
local
tostring
,
tonumber
,
next
=
tostring
,
tonumber
,
next
57
local
gmatch
,
lower
,
format
,
formatters
=
string
.
gmatch
,
string
.
lower
,
string
.
format
,
string
.
formatters
58
local
lpegmatch
=
lpeg
.
match
59
local
bpfactor
,
todimen
=
number
.
dimenfactors
.
bp
,
string
.
todimen
60
local
sortedhash
=
table
.
sortedhash
61
local
trace_fields
=
false
trackers
.
register
(
"
backends.fields
"
,
function
(
v
)
trace_fields
=
v
end
)
62 63
local
report_fields
=
logs
.
reporter
(
"
backend
"
,
"
fields
"
)
64 65
local
backends
,
lpdf
=
backends
,
lpdf
66 67
local
variables
=
interfaces
.
variables
68
local
context
=
context
69 70
local
references
=
structures
.
references
71
local
settings_to_array
=
utilities
.
parsers
.
settings_to_array
72 73
local
pdfbackend
=
backends
.
pdf
74 75
local
nodeinjections
=
pdfbackend
.
nodeinjections
76
local
codeinjections
=
pdfbackend
.
codeinjections
77
local
registrations
=
pdfbackend
.
registrations
78 79
local
registeredsymbol
=
codeinjections
.
registeredsymbol
80 81
local
pdfstream
=
lpdf
.
stream
82
local
pdfdictionary
=
lpdf
.
dictionary
83
local
pdfarray
=
lpdf
.
array
84
local
pdfreference
=
lpdf
.
reference
85
local
pdfunicode
=
lpdf
.
unicode
86
local
pdfstring
=
lpdf
.
string
87
local
pdfconstant
=
lpdf
.
constant
88
local
pdfflushobject
=
lpdf
.
flushobject
89
local
pdfshareobjectreference
=
lpdf
.
shareobjectreference
90
local
pdfshareobject
=
lpdf
.
shareobject
91
local
pdfreserveobject
=
lpdf
.
reserveobject
92
local
pdfpagereference
=
lpdf
.
pagereference
93
local
pdfaction
=
lpdf
.
action
94
local
pdfmajorversion
=
lpdf
.
majorversion
95 96
local
pdfcolor
=
lpdf
.
color
97
local
pdfcolorvalues
=
lpdf
.
colorvalues
98
local
pdflayerreference
=
lpdf
.
layerreference
99 100
local
hpack_node
=
node
.
hpack
101 102
local
submitoutputformat
=
0
-- 0=unknown 1=HTML 2=FDF 3=XML => not yet used, needs to be checked
103 104
local
pdf_widget
=
pdfconstant
(
"
Widget
"
)
105
local
pdf_tx
=
pdfconstant
(
"
Tx
"
)
106
local
pdf_sig
=
pdfconstant
(
"
Sig
"
)
107
local
pdf_ch
=
pdfconstant
(
"
Ch
"
)
108
local
pdf_btn
=
pdfconstant
(
"
Btn
"
)
109
local
pdf_yes
=
pdfconstant
(
"
Yes
"
)
110
local
pdf_off
=
pdfconstant
(
"
Off
"
)
111
local
pdf_p
=
pdfconstant
(
"
P
"
)
-- None Invert Outline Push
112
local
pdf_n
=
pdfconstant
(
"
N
"
)
-- None Invert Outline Push
113
--
114
local
pdf_no_rect
=
pdfarray
{
0
,
0
,
0
,
0
}
115 116
local
splitter
=
lpeg
.
splitat
(
"
=>
"
)
117 118
local
formats
=
{
119
html
=
1
,
fdf
=
2
,
xml
=
3
,
120
}
121 122
function
codeinjections
.
setformsmethod
(
name
)
123
submitoutputformat
=
formats
[
lower
(
name
)
]
or
formats
.
xml
124
end
125 126
local
flag
=
{
-- /Ff
127
ReadOnly
=
0x00000001
,
-- 2^ 0
128
Required
=
0x00000002
,
-- 2^ 1
129
NoExport
=
0x00000004
,
-- 2^ 2
130
MultiLine
=
0x00001000
,
-- 2^12
131
Password
=
0x00002000
,
-- 2^13
132
NoToggleToOff
=
0x00004000
,
-- 2^14
133
Radio
=
0x00008000
,
-- 2^15
134
PushButton
=
0x00010000
,
-- 2^16
135
PopUp
=
0x00020000
,
-- 2^17
136
Edit
=
0x00040000
,
-- 2^18
137
Sort
=
0x00080000
,
-- 2^19
138
FileSelect
=
0x00100000
,
-- 2^20
139
DoNotSpellCheck
=
0x00400000
,
-- 2^22
140
DoNotScroll
=
0x00800000
,
-- 2^23
141
Comb
=
0x01000000
,
-- 2^24
142
RichText
=
0x02000000
,
-- 2^25
143
RadiosInUnison
=
0x02000000
,
-- 2^25
144
CommitOnSelChange
=
0x04000000
,
-- 2^26
145
}
146 147
local
plus
=
{
-- /F
148
Invisible
=
0x00000001
,
-- 2^0
149
Hidden
=
0x00000002
,
-- 2^1
150
Printable
=
0x00000004
,
-- 2^2
151
Print
=
0x00000004
,
-- 2^2
152
NoZoom
=
0x00000008
,
-- 2^3
153
NoRotate
=
0x00000010
,
-- 2^4
154
NoView
=
0x00000020
,
-- 2^5
155
ReadOnly
=
0x00000040
,
-- 2^6
156
Locked
=
0x00000080
,
-- 2^7
157
ToggleNoView
=
0x00000100
,
-- 2^8
158
LockedContents
=
0x00000200
,
-- 2^9
159
AutoView
=
0x00000100
,
-- 2^8
160
}
161 162
-- todo: check what is interfaced
163 164
flag
.
readonly
=
flag
.
ReadOnly
165
flag
.
required
=
flag
.
Required
166
flag
.
protected
=
flag
.
Password
167
flag
.
sorted
=
flag
.
Sort
168
flag
.
unavailable
=
flag
.
NoExport
169
flag
.
nocheck
=
flag
.
DoNotSpellCheck
170
flag
.
fixed
=
flag
.
DoNotScroll
171
flag
.
file
=
flag
.
FileSelect
172 173
plus
.
hidden
=
plus
.
Hidden
174
plus
.
printable
=
plus
.
Printable
175
plus
.
auto
=
plus
.
AutoView
176 177
lpdf
.
flags
.
widgets
=
flag
178
lpdf
.
flags
.
annotations
=
plus
179 180
-- some day .. lpeg with function or table
181 182
local
function
fieldflag
(
specification
)
-- /Ff
183
local
o
,
n
=
specification
.
option
,
0
184
if
o
and
o
~
=
"
"
then
185
for
f
in
gmatch
(
o
,
"
[^, ]+
"
)
do
186
n
=
n
+
(
flag
[
f
]
or
0
)
187
end
188
end
189
return
n
190
end
191 192
local
function
fieldplus
(
specification
)
-- /F
193
local
o
,
n
=
specification
.
option
,
0
194
if
o
and
o
~
=
"
"
then
195
for
p
in
gmatch
(
o
,
"
[^, ]+
"
)
do
196
n
=
n
+
(
plus
[
p
]
or
0
)
197
end
198
end
199
-- n = n + 4
200
return
n
201
end
202 203
-- keep:
204
--
205
-- local function checked(what)
206
-- local set, bug = references.identify("",what)
207
-- if not bug and #set > 0 then
208
-- local r, n = pdfaction(set)
209
-- return pdfshareobjectreference(r)
210
-- end
211
-- end
212
--
213
-- local function fieldactions(specification) -- share actions
214
-- local d, a = { }, nil
215
-- a = specification.mousedown
216
-- or specification.clickin if a and a ~= "" then d.D = checked(a) end
217
-- a = specification.mouseup
218
-- or specification.clickout if a and a ~= "" then d.U = checked(a) end
219
-- a = specification.regionin if a and a ~= "" then d.E = checked(a) end -- Enter
220
-- a = specification.regionout if a and a ~= "" then d.X = checked(a) end -- eXit
221
-- a = specification.afterkey if a and a ~= "" then d.K = checked(a) end
222
-- a = specification.format if a and a ~= "" then d.F = checked(a) end
223
-- a = specification.validate if a and a ~= "" then d.V = checked(a) end
224
-- a = specification.calculate if a and a ~= "" then d.C = checked(a) end
225
-- a = specification.focusin if a and a ~= "" then d.Fo = checked(a) end
226
-- a = specification.focusout if a and a ~= "" then d.Bl = checked(a) end
227
-- a = specification.openpage if a and a ~= "" then d.PO = checked(a) end
228
-- a = specification.closepage if a and a ~= "" then d.PC = checked(a) end
229
-- -- a = specification.visiblepage if a and a ~= "" then d.PV = checked(a) end
230
-- -- a = specification.invisiblepage if a and a ~= "" then d.PI = checked(a) end
231
-- return next(d) and pdfdictionary(d)
232
-- end
233 234
local
mapping
=
{
235
mousedown
=
"
D
"
,
clickin
=
"
D
"
,
236
mouseup
=
"
U
"
,
clickout
=
"
U
"
,
237
regionin
=
"
E
"
,
238
regionout
=
"
X
"
,
239
afterkey
=
"
K
"
,
240
format
=
"
F
"
,
241
validate
=
"
V
"
,
242
calculate
=
"
C
"
,
243
focusin
=
"
Fo
"
,
244
focusout
=
"
Bl
"
,
245
openpage
=
"
PO
"
,
246
closepage
=
"
PC
"
,
247
-- visiblepage = "PV",
248
-- invisiblepage = "PI",
249
}
250 251
local
function
fieldactions
(
specification
)
-- share actions
252
local
d
=
nil
253
for
key
,
target
in
sortedhash
(
mapping
)
do
-- sort so that we can compare pdf
254
local
code
=
specification
[
key
]
255
if
code
and
code
~
=
"
"
then
256
-- local a = checked(code)
257
local
set
,
bug
=
references
.
identify
(
"
"
,
code
)
258
if
not
bug
and
#
set
>
0
then
259
local
a
=
pdfaction
(
set
)
-- r, n
260
if
a
then
261
local
r
=
pdfshareobjectreference
(
a
)
262
if
d
then
263
d
[
target
]
=
r
264
else
265
d
=
pdfdictionary
{
[
target
]
=
r
}
266
end
267
else
268
report_fields
(
"
invalid field action %a, case %s
"
,
code
,
2
)
269
end
270
else
271
report_fields
(
"
invalid field action %a, case %s
"
,
code
,
1
)
272
end
273
end
274
end
275
-- if d then
276
-- d = pdfshareobjectreference(d) -- not much overlap or maybe only some patterns
277
-- end
278
return
d
279
end
280 281
-- fonts and color
282 283
local
pdfdocencodingvector
,
pdfdocencodingcapsule
284 285
-- The pdf doc encoding vector is needed in order to trigger propper unicode. Interesting is that when
286
-- a glyph is not in the vector, it is still visible as it is taken from some other font. Messy.
287 288
-- To be checked: only when text/line fields.
289 290
local
function
checkpdfdocencoding
(
)
291
report_fields
(
"
adding pdfdoc encoding vector
"
)
292
local
encoding
=
dofile
(
resolvers
.
findfile
(
"
lpdf-enc.lua
"
)
)
-- no checking, fatal if not present
293
pdfdocencodingvector
=
pdfreference
(
pdfflushobject
(
encoding
)
)
294
local
capsule
=
pdfdictionary
{
295
PDFDocEncoding
=
pdfdocencodingvector
296
}
297
pdfdocencodingcapsule
=
pdfreference
(
pdfflushobject
(
capsule
)
)
298
checkpdfdocencoding
=
function
(
)
end
299
end
300 301
local
fontnames
=
{
302
rm
=
{
303
tf
=
"
Times-Roman
"
,
304
bf
=
"
Times-Bold
"
,
305
it
=
"
Times-Italic
"
,
306
sl
=
"
Times-Italic
"
,
307
bi
=
"
Times-BoldItalic
"
,
308
bs
=
"
Times-BoldItalic
"
,
309
}
,
310
ss
=
{
311
tf
=
"
Helvetica
"
,
312
bf
=
"
Helvetica-Bold
"
,
313
it
=
"
Helvetica-Oblique
"
,
314
sl
=
"
Helvetica-Oblique
"
,
315
bi
=
"
Helvetica-BoldOblique
"
,
316
bs
=
"
Helvetica-BoldOblique
"
,
317
}
,
318
tt
=
{
319
tf
=
"
Courier
"
,
320
bf
=
"
Courier-Bold
"
,
321
it
=
"
Courier-Oblique
"
,
322
sl
=
"
Courier-Oblique
"
,
323
bi
=
"
Courier-BoldOblique
"
,
324
bs
=
"
Courier-BoldOblique
"
,
325
}
,
326
symbol
=
{
327
dingbats
=
"
ZapfDingbats
"
,
328
}
329
}
330 331
local
usedfonts
=
{
}
332 333
local
function
fieldsurrounding
(
specification
)
334
local
fontsize
=
specification
.
fontsize
or
"
12pt
"
335
local
fontstyle
=
specification
.
fontstyle
or
"
rm
"
336
local
fontalternative
=
specification
.
fontalternative
or
"
tf
"
337
local
colorvalue
=
tonumber
(
specification
.
colorvalue
)
338
local
s
=
fontnames
[
fontstyle
]
339
if
not
s
then
340
fontstyle
,
s
=
"
rm
"
,
fontnames
.
rm
341
end
342
local
a
=
s
[
fontalternative
]
343
if
not
a
then
344
alternative
,
a
=
"
tf
"
,
s
.
tf
345
end
346
local
tag
=
fontstyle
.
.
fontalternative
347
fontsize
=
todimen
(
fontsize
)
348
fontsize
=
fontsize
and
(
bpfactor
*
fontsize
)
or
12
349
fontraise
=
0
.
1
*
fontsize
-- todo: figure out what the natural one is and compensate for strutdp
350
local
fontcode
=
formatters
[
"
%0.4F Tf %0.4F Ts
"
]
(
fontsize
,
fontraise
)
351
-- we could test for colorvalue being 1 (black) and omit it then
352
local
colorcode
=
pdfcolor
(
3
,
colorvalue
)
-- we force an rgb color space
353
if
trace_fields
then
354
report_fields
(
"
using font, style %a, alternative %a, size %p, tag %a, code %a
"
,
fontstyle
,
fontalternative
,
fontsize
,
tag
,
fontcode
)
355
report_fields
(
"
using color, value %a, code %a
"
,
colorvalue
,
colorcode
)
356
end
357
local
stream
=
pdfstream
{
358
pdfconstant
(
tag
)
,
359
formatters
[
"
%s %s
"
]
(
fontcode
,
colorcode
)
360
}
361
usedfonts
[
tag
]
=
a
-- the name
362
-- move up with "x.y Ts"
363
return
tostring
(
stream
)
364
end
365 366
-- Can we use any font?
367 368
codeinjections
.
fieldsurrounding
=
fieldsurrounding
369 370
local
function
registerfonts
(
)
371
if
next
(
usedfonts
)
then
372
checkpdfdocencoding
(
)
-- already done
373
local
pdffontlist
=
pdfdictionary
(
)
374
local
pdffonttype
=
pdfconstant
(
"
Font
"
)
375
local
pdffontsubtype
=
pdfconstant
(
"
Type1
"
)
376
for
tag
,
name
in
sortedhash
(
usedfonts
)
do
377
local
f
=
pdfdictionary
{
378
Type
=
pdffonttype
,
379
Subtype
=
pdffontsubtype
,
380
Name
=
pdfconstant
(
tag
)
,
381
BaseFont
=
pdfconstant
(
name
)
,
382
Encoding
=
pdfdocencodingvector
,
383
}
384
pdffontlist
[
tag
]
=
pdfreference
(
pdfflushobject
(
f
)
)
385
end
386
return
pdffontlist
387
end
388
end
389 390
-- symbols
391 392
local
function
fieldappearances
(
specification
)
393
-- todo: caching
394
local
values
=
specification
.
values
395
local
default
=
specification
.
default
-- todo
396
if
not
values
then
397
-- error
398
return
399
end
400
local
v
=
settings_to_array
(
values
)
401
local
n
,
r
,
d
402
if
#
v
=
=
1
then
403
n
,
r
,
d
=
v
[
1
]
,
v
[
1
]
,
v
[
1
]
404
elseif
#
v
=
=
2
then
405
n
,
r
,
d
=
v
[
1
]
,
v
[
1
]
,
v
[
2
]
406
else
407
n
,
r
,
d
=
v
[
1
]
,
v
[
2
]
,
v
[
3
]
408
end
409
local
appearance
=
pdfdictionary
{
410
N
=
registeredsymbol
(
n
)
,
411
R
=
registeredsymbol
(
r
)
,
412
D
=
registeredsymbol
(
d
)
,
413
}
414
return
pdfshareobjectreference
(
appearance
)
415
-- return pdfreference(pdfflushobject(appearance))
416
end
417 418
-- The rendering part of form support has always been crappy and didn't really
419
-- improve over time. Did bugs become features? Who knows. Why provide for instance
420
-- control over appearance and then ignore it when the mouse clicks someplace else.
421
-- Strangely enough a lot of effort went into JavaScript support while basic
422
-- appearance control of checkboxes stayed poor. I found this link when googling for
423
-- conformation after the n^th time looking into this behaviour:
424
--
425
-- https://stackoverflow.com/questions/15479855/pdf-appearance-streams-checkbox-not-shown-correctly-after-focus-lost
426
--
427
-- ... "In particular check boxes, therefore, whenever not interacting with the user, shall
428
-- be displayed using their normal captions, not their appearances."
429
--
430
-- So: don't use check boxes. In fact, even radio buttons can have these funny "flash some
431
-- funny symbol" side effect when clocking on them. I tried all combinations if /H and /AP
432
-- and /AS and ... Because (afaiks) the acrobat interface assumes that one uses dingbats no
433
-- one really cared about getting custom appeances done well. This erratic behaviour might
434
-- as well be the reason why no open source viewer ever bothered implementing forms. It's
435
-- probably also why most forms out there look kind of bad.
436 437
local
function
fieldstates_precheck
(
specification
)
438
local
values
=
specification
.
values
439
local
default
=
specification
.
default
440
if
not
values
or
values
=
=
"
"
then
441
return
442
end
443
local
yes
=
settings_to_array
(
values
)
[
1
]
444
local
yesshown
,
yesvalue
=
lpegmatch
(
splitter
,
yes
)
445
if
not
(
yesshown
and
yesvalue
)
then
446
yesshown
=
yes
447
end
448
return
default
=
=
settings_to_array
(
yesshown
)
[
1
]
and
pdf_yes
or
pdf_off
449
end
450 451
local
function
fieldstates_check
(
specification
)
452
-- we don't use Opt here (too messy for radio buttons)
453
local
values
=
specification
.
values
454
local
default
=
specification
.
default
455
if
not
values
or
values
=
=
"
"
then
456
-- error
457
return
458
end
459
local
v
=
settings_to_array
(
values
)
460
local
yes
,
off
,
yesn
,
yesr
,
yesd
,
offn
,
offr
,
offd
461
if
#
v
=
=
1
then
462
yes
,
off
=
v
[
1
]
,
v
[
1
]
463
else
464
yes
,
off
=
v
[
1
]
,
v
[
2
]
465
end
466
local
yesshown
,
yesvalue
=
lpegmatch
(
splitter
,
yes
)
467
if
not
(
yesshown
and
yesvalue
)
then
468
yesshown
=
yes
,
yes
469
end
470
yes
=
settings_to_array
(
yesshown
)
471
local
offshown
,
offvalue
=
lpegmatch
(
splitter
,
off
)
472
if
not
(
offshown
and
offvalue
)
then
473
offshown
=
off
,
off
474
end
475
off
=
settings_to_array
(
offshown
)
476
if
#
yes
=
=
1
then
477
yesn
,
yesr
,
yesd
=
yes
[
1
]
,
yes
[
1
]
,
yes
[
1
]
478
elseif
#
yes
=
=
2
then
479
yesn
,
yesr
,
yesd
=
yes
[
1
]
,
yes
[
1
]
,
yes
[
2
]
480
else
481
yesn
,
yesr
,
yesd
=
yes
[
1
]
,
yes
[
2
]
,
yes
[
3
]
482
end
483
if
#
off
=
=
1
then
484
offn
,
offr
,
offd
=
off
[
1
]
,
off
[
1
]
,
off
[
1
]
485
elseif
#
off
=
=
2
then
486
offn
,
offr
,
offd
=
off
[
1
]
,
off
[
1
]
,
off
[
2
]
487
else
488
offn
,
offr
,
offd
=
off
[
1
]
,
off
[
2
]
,
off
[
3
]
489
end
490
if
not
yesvalue
then
491
yesvalue
=
yesdefault
or
yesn
492
end
493
if
not
offvalue
then
494
offvalue
=
offn
495
end
496
if
default
=
=
yesn
then
497
default
=
pdf_yes
498
yesvalue
=
yesvalue
=
=
yesn
and
"
Yes
"
or
"
Off
"
499
else
500
default
=
pdf_off
501
yesvalue
=
"
Off
"
502
end
503
local
appearance
504
-- if false then
505
if
true
then
506
-- needs testing
507
appearance
=
pdfdictionary
{
-- maybe also cache components
508
N
=
pdfshareobjectreference
(
pdfdictionary
{
Yes
=
registeredsymbol
(
yesn
)
,
Off
=
registeredsymbol
(
offn
)
}
)
,
509
R
=
pdfshareobjectreference
(
pdfdictionary
{
Yes
=
registeredsymbol
(
yesr
)
,
Off
=
registeredsymbol
(
offr
)
}
)
,
510
D
=
pdfshareobjectreference
(
pdfdictionary
{
Yes
=
registeredsymbol
(
yesd
)
,
Off
=
registeredsymbol
(
offd
)
}
)
,
511
}
512
else
513
appearance
=
pdfdictionary
{
-- maybe also cache components
514
N
=
pdfdictionary
{
Yes
=
registeredsymbol
(
yesn
)
,
Off
=
registeredsymbol
(
offn
)
}
,
515
R
=
pdfdictionary
{
Yes
=
registeredsymbol
(
yesr
)
,
Off
=
registeredsymbol
(
offr
)
}
,
516
D
=
pdfdictionary
{
Yes
=
registeredsymbol
(
yesd
)
,
Off
=
registeredsymbol
(
offd
)
}
517
}
518
end
519
local
appearanceref
=
pdfshareobjectreference
(
appearance
)
520
-- local appearanceref = pdfreference(pdfflushobject(appearance))
521
return
appearanceref
,
default
,
yesvalue
522
end
523 524
-- It looks like there is always a (MK related) symbol used and that the appearances
525
-- are only used as ornaments behind a symbol. So, contrary to what we did when
526
-- widgets showed up, we now limit ourself to more dumb definitions. Especially when
527
-- highlighting is enabled weird interferences happen. So, we play safe (some nice
528
-- code has been removed that worked well till recently).
529 530
local
function
fieldstates_radio
(
specification
,
name
,
parent
)
531
local
values
=
values
or
specification
.
values
532
local
default
=
default
or
parent
.
default
-- specification.default
533
if
not
values
or
values
=
=
"
"
then
534
-- error
535
return
536
end
537
local
v
=
settings_to_array
(
values
)
538
local
yes
,
off
,
yesn
,
yesr
,
yesd
,
offn
,
offr
,
offd
539
if
#
v
=
=
1
then
540
yes
,
off
=
v
[
1
]
,
v
[
1
]
541
else
542
yes
,
off
=
v
[
1
]
,
v
[
2
]
543
end
544
-- yes keys might be the same in the three appearances within a field
545
-- but can best be different among fields ... don't ask why
546
local
yessymbols
,
yesvalue
=
lpegmatch
(
splitter
,
yes
)
-- n,r,d=>x
547
if
not
(
yessymbols
and
yesvalue
)
then
548
yessymbols
=
yes
549
end
550
if
not
yesvalue
then
551
yesvalue
=
name
552
end
553
yessymbols
=
settings_to_array
(
yessymbols
)
554
if
#
yessymbols
=
=
1
then
555
yesn
=
yessymbols
[
1
]
556
yesr
=
yesn
557
yesd
=
yesr
558
elseif
#
yessymbols
=
=
2
then
559
yesn
=
yessymbols
[
1
]
560
yesr
=
yessymbols
[
2
]
561
yesd
=
yesr
562
else
563
yesn
=
yessymbols
[
1
]
564
yesr
=
yessymbols
[
2
]
565
yesd
=
yessymbols
[
3
]
566
end
567
-- we don't care about names, as all will be /Off
568
local
offsymbols
=
lpegmatch
(
splitter
,
off
)
or
off
569
offsymbols
=
settings_to_array
(
offsymbols
)
570
if
#
offsymbols
=
=
1
then
571
offn
=
offsymbols
[
1
]
572
offr
=
offn
573
offd
=
offr
574
elseif
#
offsymbols
=
=
2
then
575
offn
=
offsymbols
[
1
]
576
offr
=
offsymbols
[
2
]
577
offd
=
offr
578
else
579
offn
=
offsymbols
[
1
]
580
offr
=
offsymbols
[
2
]
581
offd
=
offsymbols
[
3
]
582
end
583
if
default
=
=
name
then
584
default
=
pdfconstant
(
name
)
585
else
586
default
=
pdf_off
587
end
588
--
589
local
appearance
590
if
false
then
-- needs testing
591
appearance
=
pdfdictionary
{
-- maybe also cache components
592
N
=
pdfshareobjectreference
(
pdfdictionary
{
[
name
]
=
registeredsymbol
(
yesn
)
,
Off
=
registeredsymbol
(
offn
)
}
)
,
593
R
=
pdfshareobjectreference
(
pdfdictionary
{
[
name
]
=
registeredsymbol
(
yesr
)
,
Off
=
registeredsymbol
(
offr
)
}
)
,
594
D
=
pdfshareobjectreference
(
pdfdictionary
{
[
name
]
=
registeredsymbol
(
yesd
)
,
Off
=
registeredsymbol
(
offd
)
}
)
,
595
}
596
else
597
appearance
=
pdfdictionary
{
-- maybe also cache components
598
N
=
pdfdictionary
{
[
name
]
=
registeredsymbol
(
yesn
)
,
Off
=
registeredsymbol
(
offn
)
}
,
599
R
=
pdfdictionary
{
[
name
]
=
registeredsymbol
(
yesr
)
,
Off
=
registeredsymbol
(
offr
)
}
,
600
D
=
pdfdictionary
{
[
name
]
=
registeredsymbol
(
yesd
)
,
Off
=
registeredsymbol
(
offd
)
}
601
}
602
end
603
local
appearanceref
=
pdfshareobjectreference
(
appearance
)
-- pdfreference(pdfflushobject(appearance))
604
return
appearanceref
,
default
,
yesvalue
605
end
606 607
local
function
fielddefault
(
field
,
pdf_yes
)
608
local
default
=
field
.
default
609
if
not
default
or
default
=
=
"
"
then
610
local
values
=
settings_to_array
(
field
.
values
)
611
default
=
values
[
1
]
612
end
613
if
not
default
or
default
=
=
"
"
then
614
return
pdf_off
615
else
616
return
pdf_yes
or
pdfconstant
(
default
)
617
end
618
end
619 620
local
function
fieldoptions
(
specification
)
621
local
values
=
specification
.
values
622
local
default
=
specification
.
default
623
if
values
then
624
local
v
=
settings_to_array
(
values
)
625
for
i
=
1
,
#
v
do
626
local
vi
=
v
[
i
]
627
local
shown
,
value
=
lpegmatch
(
splitter
,
vi
)
628
if
shown
and
value
then
629
v
[
i
]
=
pdfarray
{
pdfunicode
(
value
)
,
shown
}
630
else
631
v
[
i
]
=
pdfunicode
(
v
[
i
]
)
632
end
633
end
634
return
pdfarray
(
v
)
635
end
636
end
637 638
local
mapping
=
{
639
-- acrobat compliant (messy, probably some pdfdoc encoding interference here)
640
check
=
"
4
"
,
-- 0x34
641
circle
=
"
l
"
,
-- 0x6C
642
cross
=
"
8
"
,
-- 0x38
643
diamond
=
"
u
"
,
-- 0x75
644
square
=
"
n
"
,
-- 0x6E
645
star
=
"
H
"
,
-- 0x48
646
}
647 648
local
function
todingbat
(
n
)
649
if
n
and
n
~
=
"
"
then
650
return
mapping
[
n
]
or
"
"
651
end
652
end
653 654
local
function
fieldrendering
(
specification
)
655
local
bvalue
=
tonumber
(
specification
.
backgroundcolorvalue
)
656
local
fvalue
=
tonumber
(
specification
.
framecolorvalue
)
657
local
svalue
=
specification
.
fontsymbol
658
if
bvalue
or
fvalue
or
(
svalue
and
svalue
~
=
"
"
)
then
659
return
pdfdictionary
{
660
BG
=
bvalue
and
pdfarray
{
pdfcolorvalues
(
3
,
bvalue
)
}
or
nil
,
-- or zero_bg,
661
BC
=
fvalue
and
pdfarray
{
pdfcolorvalues
(
3
,
fvalue
)
}
or
nil
,
-- or zero_bc,
662
CA
=
svalue
and
pdfstring
(
svalue
)
or
nil
,
663
}
664
end
665
end
666 667
-- layers
668 669
local
function
fieldlayer
(
specification
)
-- we can move this in line
670
local
layer
=
specification
.
layer
671
return
(
layer
and
pdflayerreference
(
layer
)
)
or
nil
672
end
673 674
-- defining
675 676
local
fields
,
radios
,
clones
,
fieldsets
,
calculationset
=
{
}
,
{
}
,
{
}
,
{
}
,
nil
677 678
local
xfdftemplate
=
[[
679<?xml version='1.0' encoding='UTF-8'?> 680 681<xfdf xmlns='http://ns.adobe.com/xfdf/'> 682 <f href='%s.pdf'/> 683 <fields> 684%s 685 </fields> 686</xfdf> 687
]]
688 689
function
codeinjections
.
exportformdata
(
name
)
690
local
result
=
{
}
691
for
k
,
v
in
sortedhash
(
fields
)
do
692
result
[
#
result
+
1
]
=
formatters
[
"
<field name='%s'><value>%s</value></field>
"
]
(
v
.
name
or
k
,
v
.
default
or
"
"
)
693
end
694
local
base
=
file
.
basename
(
tex
.
jobname
)
695
local
xfdf
=
format
(
xfdftemplate
,
base
,
table
.
concat
(
result
,
"
\n
"
)
)
696
if
not
name
or
name
=
=
"
"
then
697
name
=
base
698
end
699
io
.
savedata
(
file
.
addsuffix
(
name
,
"
xfdf
"
)
,
xfdf
)
700
end
701 702
function
codeinjections
.
definefieldset
(
tag
,
list
)
703
fieldsets
[
tag
]
=
list
704
end
705 706
function
codeinjections
.
getfieldset
(
tag
)
707
return
fieldsets
[
tag
]
708
end
709 710
local
function
fieldsetlist
(
tag
)
711
if
tag
then
712
local
ft
=
fieldsets
[
tag
]
713
if
ft
then
714
local
a
=
pdfarray
(
)
715
for
name
in
gmatch
(
list
,
"
[^, ]+
"
)
do
716
local
f
=
field
[
name
]
717
if
f
and
f
.
pobj
then
718
a
[
#
a
+
1
]
=
pdfreference
(
f
.
pobj
)
719
end
720
end
721
return
a
722
end
723
end
724
end
725 726
function
codeinjections
.
setfieldcalculationset
(
tag
)
727
calculationset
=
tag
728
end
729 730
interfaces
.
implement
{
731
name
=
"
setfieldcalculationset
"
,
732
actions
=
codeinjections
.
setfieldcalculationset
,
733
arguments
=
"
string
"
,
734
}
735 736
local
function
predefinesymbols
(
specification
)
737
local
values
=
specification
.
values
738
if
values
then
739
local
symbols
=
settings_to_array
(
values
)
740
for
i
=
1
,
#
symbols
do
741
local
symbol
=
symbols
[
i
]
742
local
a
,
b
=
lpegmatch
(
splitter
,
symbol
)
743
codeinjections
.
presetsymbol
(
a
or
symbol
)
744
end
745
end
746
end
747 748
function
codeinjections
.
getdefaultfieldvalue
(
name
)
749
local
f
=
fields
[
name
]
750
if
f
then
751
local
values
=
f
.
values
752
local
default
=
f
.
default
753
if
not
default
or
default
=
=
"
"
then
754
local
symbols
=
settings_to_array
(
values
)
755
local
symbol
=
symbols
[
1
]
756
if
symbol
then
757
local
a
,
b
=
lpegmatch
(
splitter
,
symbol
)
-- splits at =>
758
default
=
a
or
symbol
759
end
760
end
761
return
default
762
end
763
end
764 765
function
codeinjections
.
definefield
(
specification
)
766
local
n
=
specification
.
name
767
local
f
=
fields
[
n
]
768
if
not
f
then
769
local
fieldtype
=
specification
.
type
770
if
not
fieldtype
then
771
if
trace_fields
then
772
report_fields
(
"
invalid definition for %a, unknown type
"
,
n
)
773
end
774
elseif
fieldtype
=
=
"
radio
"
then
775
local
values
=
specification
.
values
776
if
values
and
values
~
=
"
"
then
777
values
=
settings_to_array
(
values
)
778
for
v
=
1
,
#
values
do
779
radios
[
values
[
v
]
]
=
{
parent
=
n
}
780
end
781
fields
[
n
]
=
specification
782
if
trace_fields
then
783
report_fields
(
"
defining %a as type %a
"
,
n
,
"
radio
"
)
784
end
785
elseif
trace_fields
then
786
report_fields
(
"
invalid definition of radio %a, missing values
"
,
n
)
787
end
788
elseif
fieldtype
=
=
"
sub
"
then
789
-- not in main field list !
790
local
radio
=
radios
[
n
]
791
if
radio
then
792
-- merge specification
793
for
key
,
value
in
next
,
specification
do
794
radio
[
key
]
=
value
795
end
796
if
trace_fields
then
797
local
p
=
radios
[
n
]
and
radios
[
n
]
.
parent
798
report_fields
(
"
defining %a as type sub of radio %a
"
,
n
,
p
)
799
end
800
elseif
trace_fields
then
801
report_fields
(
"
invalid definition of radio sub %a, no parent given
"
,
n
)
802
end
803
predefinesymbols
(
specification
)
804
elseif
fieldtype
=
=
"
text
"
or
fieldtype
=
=
"
line
"
then
805
fields
[
n
]
=
specification
806
if
trace_fields
then
807
report_fields
(
"
defining %a as type %a
"
,
n
,
fieldtype
)
808
end
809
if
specification
.
values
~
=
"
"
and
specification
.
default
=
=
"
"
then
810
specification
.
default
,
specification
.
values
=
specification
.
values
,
nil
811
end
812
else
813
fields
[
n
]
=
specification
814
if
trace_fields
then
815
report_fields
(
"
defining %a as type %a
"
,
n
,
fieldtype
)
816
end
817
predefinesymbols
(
specification
)
818
end
819
elseif
trace_fields
then
820
report_fields
(
"
invalid definition for %a, already defined
"
,
n
)
821
end
822
end
823 824
function
codeinjections
.
clonefield
(
specification
)
-- obsolete
825
local
p
=
specification
.
parent
826
local
c
=
specification
.
children
827
local
v
=
specification
.
alternative
828
if
not
p
or
not
c
then
829
if
trace_fields
then
830
report_fields
(
"
invalid clone, children %a, parent %a, alternative %a
"
,
c
,
p
,
v
)
831
end
832
return
833
end
834
local
x
=
fields
[
p
]
or
radios
[
p
]
835
if
not
x
then
836
if
trace_fields
then
837
report_fields
(
"
invalid clone, unknown parent %a
"
,
p
)
838
end
839
return
840
end
841
for
n
in
gmatch
(
c
,
"
[^, ]+
"
)
do
842
local
f
,
r
,
c
=
fields
[
n
]
,
radios
[
n
]
,
clones
[
n
]
843
if
f
or
r
or
c
then
844
if
trace_fields
then
845
report_fields
(
"
already cloned, child %a, parent %a, alternative %a
"
,
n
,
p
,
v
)
846
end
847
else
848
if
trace_fields
then
849
report_fields
(
"
cloning, child %a, parent %a, alternative %a
"
,
n
,
p
,
v
)
850
end
851
clones
[
n
]
=
specification
852
predefinesymbols
(
specification
)
853
end
854
end
855
end
856 857
function
codeinjections
.
getfieldcategory
(
name
)
858
local
f
=
fields
[
name
]
or
radios
[
name
]
or
clones
[
name
]
859
if
f
then
860
local
g
=
f
.
category
861
if
not
g
or
g
=
=
"
"
then
862
local
v
,
p
,
t
=
f
.
alternative
,
f
.
parent
,
f
.
type
863
if
v
=
=
"
clone
"
or
v
=
=
"
copy
"
then
864
f
=
fields
[
p
]
or
radios
[
p
]
865
g
=
f
and
f
.
category
866
elseif
t
=
=
"
sub
"
then
867
f
=
fields
[
p
]
868
g
=
f
and
f
.
category
869
end
870
end
871
return
g
872
end
873
end
874 875
--
876 877
function
codeinjections
.
validfieldcategory
(
name
)
878
return
fields
[
name
]
or
radios
[
name
]
or
clones
[
name
]
879
end
880 881
function
codeinjections
.
validfieldset
(
name
)
882
return
fieldsets
[
tag
]
883
end
884 885
function
codeinjections
.
validfield
(
name
)
886
return
fields
[
name
]
887
end
888 889
--
890 891
local
alignments
=
{
892
flushleft
=
0
,
right
=
0
,
893
center
=
1
,
middle
=
1
,
894
flushright
=
2
,
left
=
2
,
895
}
896 897
local
function
fieldalignment
(
specification
)
898
return
alignments
[
specification
.
align
]
or
0
899
end
900 901
local
function
enhance
(
specification
,
option
)
902
local
so
=
specification
.
option
903
if
so
and
so
~
=
"
"
then
904
specification
.
option
=
so
.
.
"
,
"
.
.
option
905
else
906
specification
.
option
=
option
907
end
908
return
specification
909
end
910 911
-- finish (if we also collect parents we can inline the kids which is
912
-- more efficient ... but hardly anyone used widgets so ...)
913 914
local
collected
=
pdfarray
(
)
915
local
forceencoding
=
false
916 917
-- todo : check #opt
918 919
local
function
finishfields
(
)
920
local
sometext
=
forceencoding
921
local
somefont
=
next
(
usedfonts
)
922
for
name
,
field
in
sortedhash
(
fields
)
do
923
local
kids
=
field
.
kids
924
if
kids
then
925
pdfflushobject
(
field
.
kidsnum
,
kids
)
926
end
927
local
opt
=
field
.
opt
928
if
opt
then
929
pdfflushobject
(
field
.
optnum
,
opt
)
930
end
931
local
type
=
field
.
type
932
if
not
sometext
and
(
type
=
=
"
text
"
or
type
=
=
"
line
"
)
then
933
sometext
=
true
934
end
935
end
936
for
name
,
field
in
sortedhash
(
radios
)
do
937
local
kids
=
field
.
kids
938
if
kids
then
939
pdfflushobject
(
field
.
kidsnum
,
kids
)
940
end
941
local
opt
=
field
.
opt
942
if
opt
then
943
pdfflushobject
(
field
.
optnum
,
opt
)
944
end
945
end
946
if
#
collected
>
0
then
947
local
acroform
=
pdfdictionary
{
948
NeedAppearances
=
pdfmajorversion
(
)
=
=
1
or
nil
,
949
Fields
=
pdfreference
(
pdfflushobject
(
collected
)
)
,
950
CO
=
fieldsetlist
(
calculationset
)
,
951
}
952
if
sometext
or
somefont
then
953
checkpdfdocencoding
(
)
954
if
sometext
then
955
usedfonts
.
tttf
=
fontnames
.
tt
.
tf
956
acroform
.
DA
=
"
/tttf 12 Tf 0 g
"
957
end
958
acroform
.
DR
=
pdfdictionary
{
959
Font
=
registerfonts
(
)
,
960
Encoding
=
pdfdocencodingcapsule
,
961
}
962
end
963
-- maybe:
964
-- if sometext then
965
-- checkpdfdocencoding()
966
-- if sometext then
967
-- usedfonts.tttf = fontnames.tt.tf
968
-- acroform.DA = "/tttf 12 Tf 0 g"
969
-- end
970
-- acroform.DR = pdfdictionary {
971
-- Font = registerfonts(),
972
-- Encoding = pdfdocencodingcapsule,
973
-- }
974
-- elseif somefont then
975
-- acroform.DR = pdfdictionary {
976
-- Font = registerfonts(),
977
-- }
978
-- end
979
lpdf
.
addtocatalog
(
"
AcroForm
"
,
pdfreference
(
pdfflushobject
(
acroform
)
)
)
980
end
981
end
982 983
lpdf
.
registerdocumentfinalizer
(
finishfields
,
"
form fields
"
)
984 985
local
methods
=
{
}
986 987
function
nodeinjections
.
typesetfield
(
name
,
specification
)
988
local
field
=
fields
[
name
]
or
radios
[
name
]
or
clones
[
name
]
989
if
not
field
then
990
report_fields
(
"
unknown child %a
"
,
name
)
991
-- unknown field
992
return
993
end
994
local
alternative
,
parent
=
field
.
alternative
,
field
.
parent
995
if
alternative
=
=
"
copy
"
or
alternative
=
=
"
clone
"
then
-- only in clones
996
field
=
fields
[
parent
]
or
radios
[
parent
]
997
end
998
local
method
=
methods
[
field
.
type
]
999
if
method
then
1000
return
method
(
name
,
specification
,
alternative
)
1001
else
1002
report_fields
(
"
unknown method %a for child %a
"
,
field
.
type
,
name
)
1003
end
1004
end
1005 1006
local
function
save_parent
(
field
,
specification
,
d
)
1007
local
kidsnum
=
pdfreserveobject
(
)
1008
d
.
Kids
=
pdfreference
(
kidsnum
)
1009
field
.
kidsnum
=
kidsnum
1010
field
.
kids
=
pdfarray
(
)
1011
-- if d.Opt then
1012
-- local optnum = pdfreserveobject()
1013
-- d.Opt = pdfreference(optnum)
1014
-- field.optnum = optnum
1015
-- field.opt = pdfarray()
1016
-- end
1017
local
pnum
=
pdfflushobject
(
d
)
1018
field
.
pobj
=
pnum
1019
collected
[
#
collected
+
1
]
=
pdfreference
(
pnum
)
1020
end
1021 1022
local
function
save_kid
(
field
,
specification
,
d
,
optname
)
1023
local
kn
=
pdfreserveobject
(
)
1024
field
.
kids
[
#
field
.
kids
+
1
]
=
pdfreference
(
kn
)
1025
-- if optname then
1026
-- local opt = field.opt
1027
-- if opt then
1028
-- opt[#opt+1] = optname
1029
-- end
1030
-- end
1031
local
width
=
specification
.
width
or
0
1032
local
height
=
specification
.
height
or
0
1033
local
depth
=
specification
.
depth
or
0
1034
local
box
=
hpack_node
(
nodeinjections
.
annotation
(
width
,
height
,
depth
,
d
(
)
,
kn
)
)
1035
-- redundant
1036
box
.
width
=
width
1037
box
.
height
=
height
1038
box
.
depth
=
depth
1039
return
box
1040
end
1041 1042
local
function
makelineparent
(
field
,
specification
)
1043
local
text
=
pdfunicode
(
field
.
default
)
1044
local
length
=
tonumber
(
specification
.
length
or
0
)
or
0
1045
local
d
=
pdfdictionary
{
1046
Subtype
=
pdf_widget
,
1047
T
=
pdfunicode
(
specification
.
title
)
,
1048
F
=
fieldplus
(
specification
)
,
1049
Ff
=
fieldflag
(
specification
)
,
1050
OC
=
fieldlayer
(
specification
)
,
1051
DA
=
fieldsurrounding
(
specification
)
,
1052
AA
=
fieldactions
(
specification
)
,
1053
FT
=
pdf_tx
,
1054
Q
=
fieldalignment
(
specification
)
,
1055
MaxLen
=
length
=
=
0
and
1000
or
length
,
1056
DV
=
text
,
1057
V
=
text
,
1058
}
1059
save_parent
(
field
,
specification
,
d
)
1060
end
1061 1062
local
function
makelinechild
(
name
,
specification
)
1063
local
field
=
clones
[
name
]
1064
local
parent
=
nil
1065
if
field
then
1066
parent
=
fields
[
field
.
parent
]
1067
if
not
parent
.
pobj
then
1068
if
trace_fields
then
1069
report_fields
(
"
forcing parent text %a
"
,
parent
.
name
)
1070
end
1071
makelineparent
(
parent
,
specification
)
1072
end
1073
else
1074
parent
=
fields
[
name
]
1075
field
=
parent
1076
if
not
parent
.
pobj
then
1077
if
trace_fields
then
1078
report_fields
(
"
using parent text %a
"
,
name
)
1079
end
1080
makelineparent
(
parent
,
specification
)
1081
end
1082
end
1083
if
trace_fields
then
1084
report_fields
(
"
using child text %a
"
,
name
)
1085
end
1086
-- we could save a little by not setting some key/value when it's the
1087
-- same as parent but it would cost more memory to keep track of it
1088
local
d
=
pdfdictionary
{
1089
Subtype
=
pdf_widget
,
1090
Parent
=
pdfreference
(
parent
.
pobj
)
,
1091
F
=
fieldplus
(
specification
)
,
1092
OC
=
fieldlayer
(
specification
)
,
1093
DA
=
fieldsurrounding
(
specification
)
,
1094
AA
=
fieldactions
(
specification
)
,
1095
MK
=
fieldrendering
(
specification
)
,
1096
Q
=
fieldalignment
(
specification
)
,
1097
}
1098
return
save_kid
(
parent
,
specification
,
d
)
1099
end
1100 1101
function
methods
.
line
(
name
,
specification
)
1102
return
makelinechild
(
name
,
specification
)
1103
end
1104 1105
function
methods
.
text
(
name
,
specification
)
1106
return
makelinechild
(
name
,
enhance
(
specification
,
"
MultiLine
"
)
)
1107
end
1108 1109
-- copy of line ... probably also needs a /Lock
1110 1111
local
function
makesignatureparent
(
field
,
specification
)
1112
local
text
=
pdfunicode
(
field
.
default
)
1113
local
length
=
tonumber
(
specification
.
length
or
0
)
or
0
1114
local
d
=
pdfdictionary
{
1115
Subtype
=
pdf_widget
,
1116
T
=
pdfunicode
(
specification
.
title
)
,
1117
F
=
fieldplus
(
specification
)
,
1118
Ff
=
fieldflag
(
specification
)
,
1119
OC
=
fieldlayer
(
specification
)
,
1120
DA
=
fieldsurrounding
(
specification
)
,
1121
AA
=
fieldactions
(
specification
)
,
1122
FT
=
pdf_sig
,
1123
Q
=
fieldalignment
(
specification
)
,
1124
MaxLen
=
length
=
=
0
and
1000
or
length
,
1125
DV
=
text
,
1126
V
=
text
,
1127
}
1128
save_parent
(
field
,
specification
,
d
)
1129
end
1130 1131
local
function
makesignaturechild
(
name
,
specification
)
1132
local
field
=
clones
[
name
]
1133
local
parent
=
nil
1134
if
field
then
1135
parent
=
fields
[
field
.
parent
]
1136
if
not
parent
.
pobj
then
1137
if
trace_fields
then
1138
report_fields
(
"
forcing parent signature %a
"
,
parent
.
name
)
1139
end
1140
makesignatureparent
(
parent
,
specification
)
1141
end
1142
else
1143
parent
=
fields
[
name
]
1144
field
=
parent
1145
if
not
parent
.
pobj
then
1146
if
trace_fields
then
1147
report_fields
(
"
using parent text %a
"
,
name
)
1148
end
1149
makesignatureparent
(
parent
,
specification
)
1150
end
1151
end
1152
if
trace_fields
then
1153
report_fields
(
"
using child text %a
"
,
name
)
1154
end
1155
-- we could save a little by not setting some key/value when it's the
1156
-- same as parent but it would cost more memory to keep track of it
1157
local
d
=
pdfdictionary
{
1158
Subtype
=
pdf_widget
,
1159
Parent
=
pdfreference
(
parent
.
pobj
)
,
1160
F
=
fieldplus
(
specification
)
,
1161
OC
=
fieldlayer
(
specification
)
,
1162
DA
=
fieldsurrounding
(
specification
)
,
1163
AA
=
fieldactions
(
specification
)
,
1164
MK
=
fieldrendering
(
specification
)
,
1165
Q
=
fieldalignment
(
specification
)
,
1166
}
1167
return
save_kid
(
parent
,
specification
,
d
)
1168
end
1169 1170
function
methods
.
signature
(
name
,
specification
)
1171
return
makesignaturechild
(
name
,
specification
)
1172
end
1173
--
1174 1175
local
function
makechoiceparent
(
field
,
specification
)
1176
local
d
=
pdfdictionary
{
1177
Subtype
=
pdf_widget
,
1178
T
=
pdfunicode
(
specification
.
title
)
,
1179
F
=
fieldplus
(
specification
)
,
1180
Ff
=
fieldflag
(
specification
)
,
1181
OC
=
fieldlayer
(
specification
)
,
1182
AA
=
fieldactions
(
specification
)
,
1183
FT
=
pdf_ch
,
1184
Opt
=
fieldoptions
(
field
)
,
-- todo
1185
}
1186
save_parent
(
field
,
specification
,
d
)
1187
end
1188 1189
local
function
makechoicechild
(
name
,
specification
)
1190
local
field
=
clones
[
name
]
1191
local
parent
=
nil
1192
if
field
then
1193
parent
=
fields
[
field
.
parent
]
1194
if
not
parent
.
pobj
then
1195
if
trace_fields
then
1196
report_fields
(
"
forcing parent choice %a
"
,
parent
.
name
)
1197
end
1198
makechoiceparent
(
parent
,
specification
,
extras
)
1199
end
1200
else
1201
parent
=
fields
[
name
]
1202
field
=
parent
1203
if
not
parent
.
pobj
then
1204
if
trace_fields
then
1205
report_fields
(
"
using parent choice %a
"
,
name
)
1206
end
1207
makechoiceparent
(
parent
,
specification
,
extras
)
1208
end
1209
end
1210
if
trace_fields
then
1211
report_fields
(
"
using child choice %a
"
,
name
)
1212
end
1213
local
d
=
pdfdictionary
{
1214
Subtype
=
pdf_widget
,
1215
Parent
=
pdfreference
(
parent
.
pobj
)
,
1216
F
=
fieldplus
(
specification
)
,
1217
OC
=
fieldlayer
(
specification
)
,
1218
AA
=
fieldactions
(
specification
)
,
1219
}
1220
return
save_kid
(
parent
,
specification
,
d
)
-- do opt here
1221
end
1222 1223
function
methods
.
choice
(
name
,
specification
)
1224
return
makechoicechild
(
name
,
specification
)
1225
end
1226 1227
function
methods
.
popup
(
name
,
specification
)
1228
return
makechoicechild
(
name
,
enhance
(
specification
,
"
PopUp
"
)
)
1229
end
1230 1231
function
methods
.
combo
(
name
,
specification
)
1232
return
makechoicechild
(
name
,
enhance
(
specification
,
"
PopUp,Edit
"
)
)
1233
end
1234 1235
local
function
makecheckparent
(
field
,
specification
)
1236
local
default
=
fieldstates_precheck
(
field
)
1237
local
d
=
pdfdictionary
{
1238
T
=
pdfunicode
(
specification
.
title
)
,
-- todo: when tracing use a string
1239
F
=
fieldplus
(
specification
)
,
1240
Ff
=
fieldflag
(
specification
)
,
1241
OC
=
fieldlayer
(
specification
)
,
1242
AA
=
fieldactions
(
specification
)
,
-- can be shared
1243
FT
=
pdf_btn
,
1244
V
=
fielddefault
(
field
,
default
)
,
1245
}
1246
save_parent
(
field
,
specification
,
d
)
1247
end
1248 1249
local
function
makecheckchild
(
name
,
specification
)
1250
local
field
=
clones
[
name
]
1251
local
parent
=
nil
1252
if
field
then
1253
parent
=
fields
[
field
.
parent
]
1254
if
not
parent
.
pobj
then
1255
if
trace_fields
then
1256
report_fields
(
"
forcing parent check %a
"
,
parent
.
name
)
1257
end
1258
makecheckparent
(
parent
,
specification
,
extras
)
1259
end
1260
else
1261
parent
=
fields
[
name
]
1262
field
=
parent
1263
if
not
parent
.
pobj
then
1264
if
trace_fields
then
1265
report_fields
(
"
using parent check %a
"
,
name
)
1266
end
1267
makecheckparent
(
parent
,
specification
,
extras
)
1268
end
1269
end
1270
if
trace_fields
then
1271
report_fields
(
"
using child check %a
"
,
name
)
1272
end
1273
local
d
=
pdfdictionary
{
1274
Subtype
=
pdf_widget
,
1275
Parent
=
pdfreference
(
parent
.
pobj
)
,
1276
F
=
fieldplus
(
specification
)
,
1277
OC
=
fieldlayer
(
specification
)
,
1278
AA
=
fieldactions
(
specification
)
,
-- can be shared
1279
H
=
pdf_n
,
1280
}
1281
local
fontsymbol
=
specification
.
fontsymbol
1282
if
fontsymbol
and
fontsymbol
~
=
"
"
then
1283
specification
.
fontsymbol
=
todingbat
(
fontsymbol
)
1284
specification
.
fontstyle
=
"
symbol
"
1285
specification
.
fontalternative
=
"
dingbats
"
1286
d
.
DA
=
fieldsurrounding
(
specification
)
1287
d
.
MK
=
fieldrendering
(
specification
)
1288
return
save_kid
(
parent
,
specification
,
d
)
1289
else
1290
local
appearance
,
default
,
value
=
fieldstates_check
(
field
)
1291
d
.
AS
=
default
1292
d
.
AP
=
appearance
1293
return
save_kid
(
parent
,
specification
,
d
)
1294
end
1295
end
1296 1297
function
methods
.
check
(
name
,
specification
)
1298
return
makecheckchild
(
name
,
specification
)
1299
end
1300 1301
local
function
makepushparent
(
field
,
specification
)
-- check if we can share with the previous
1302
local
d
=
pdfdictionary
{
1303
Subtype
=
pdf_widget
,
1304
T
=
pdfunicode
(
specification
.
title
)
,
1305
F
=
fieldplus
(
specification
)
,
1306
Ff
=
fieldflag
(
specification
)
,
1307
OC
=
fieldlayer
(
specification
)
,
1308
AA
=
fieldactions
(
specification
)
,
-- can be shared
1309
FT
=
pdf_btn
,
1310
AP
=
fieldappearances
(
field
)
,
1311
H
=
pdf_p
,
1312
}
1313
save_parent
(
field
,
specification
,
d
)
1314
end
1315 1316
local
function
makepushchild
(
name
,
specification
)
1317
local
field
,
parent
=
clones
[
name
]
,
nil
1318
if
field
then
1319
parent
=
fields
[
field
.
parent
]
1320
if
not
parent
.
pobj
then
1321
if
trace_fields
then
1322
report_fields
(
"
forcing parent push %a
"
,
parent
.
name
)
1323
end
1324
makepushparent
(
parent
,
specification
)
1325
end
1326
else
1327
parent
=
fields
[
name
]
1328
field
=
parent
1329
if
not
parent
.
pobj
then
1330
if
trace_fields
then
1331
report_fields
(
"
using parent push %a
"
,
name
)
1332
end
1333
makepushparent
(
parent
,
specification
)
1334
end
1335
end
1336
if
trace_fields
then
1337
report_fields
(
"
using child push %a
"
,
name
)
1338
end
1339
local
fontsymbol
=
specification
.
fontsymbol
1340
local
d
=
pdfdictionary
{
1341
Subtype
=
pdf_widget
,
1342
Parent
=
pdfreference
(
field
.
pobj
)
,
1343
F
=
fieldplus
(
specification
)
,
1344
OC
=
fieldlayer
(
specification
)
,
1345
AA
=
fieldactions
(
specification
)
,
-- can be shared
1346
H
=
pdf_p
,
1347
}
1348
if
fontsymbol
and
fontsymbol
~
=
"
"
then
1349
specification
.
fontsymbol
=
todingbat
(
fontsymbol
)
1350
specification
.
fontstyle
=
"
symbol
"
1351
specification
.
fontalternative
=
"
dingbats
"
1352
d
.
DA
=
fieldsurrounding
(
specification
)
1353
d
.
MK
=
fieldrendering
(
specification
)
1354
else
1355
d
.
AP
=
fieldappearances
(
field
)
1356
end
1357
return
save_kid
(
parent
,
specification
,
d
)
1358
end
1359 1360
function
methods
.
push
(
name
,
specification
)
1361
return
makepushchild
(
name
,
enhance
(
specification
,
"
PushButton
"
)
)
1362
end
1363 1364
local
function
makeradioparent
(
field
,
specification
)
1365
specification
=
enhance
(
specification
,
"
Radio,RadiosInUnison,Print,NoToggleToOff
"
)
1366
local
d
=
pdfdictionary
{
1367
T
=
field
.
name
,
1368
FT
=
pdf_btn
,
1369
-- F = fieldplus(specification),
1370
Ff
=
fieldflag
(
specification
)
,
1371
-- H = pdf_n,
1372
V
=
fielddefault
(
field
)
,
1373
}
1374
save_parent
(
field
,
specification
,
d
)
1375
end
1376 1377
-- local function makeradiochild(name,specification)
1378
-- local field = clones[name]
1379
-- local parent = nil
1380
-- local pname = nil
1381
-- if field then
1382
-- pname = field.parent
1383
-- field = radios[pname]
1384
-- parent = fields[pname]
1385
-- if not parent.pobj then
1386
-- if trace_fields then
1387
-- report_fields("forcing parent radio %a",parent.name)
1388
-- end
1389
-- makeradioparent(parent,parent)
1390
-- end
1391
-- else
1392
-- field = radios[name]
1393
-- if not field then
1394
-- report_fields("there is some problem with field %a",name)
1395
-- return nil
1396
-- end
1397
-- pname = field.parent
1398
-- parent = fields[pname]
1399
-- if not parent.pobj then
1400
-- if trace_fields then
1401
-- report_fields("using parent radio %a",name)
1402
-- end
1403
-- makeradioparent(parent,parent)
1404
-- end
1405
-- end
1406
-- if trace_fields then
1407
-- report_fields("using child radio %a with values %a and default %a",name,field.values,field.default)
1408
-- end
1409
-- local fontsymbol = specification.fontsymbol
1410
-- -- fontsymbol = "circle"
1411
-- local d = pdfdictionary {
1412
-- Subtype = pdf_widget,
1413
-- Parent = pdfreference(parent.pobj),
1414
-- F = fieldplus(specification),
1415
-- OC = fieldlayer(specification),
1416
-- AA = fieldactions(specification),
1417
-- H = pdf_n,
1418
-- -- H = pdf_p,
1419
-- -- P = pdfpagereference(true),
1420
-- }
1421
-- if fontsymbol and fontsymbol ~= "" then
1422
-- specification.fontsymbol = todingbat(fontsymbol)
1423
-- specification.fontstyle = "symbol"
1424
-- specification.fontalternative = "dingbats"
1425
-- d.DA = fieldsurrounding(specification)
1426
-- d.MK = fieldrendering(specification)
1427
-- return save_kid(parent,specification,d) -- todo: what if no value
1428
-- else
1429
-- local appearance, default, value = fieldstates_radio(field,name,fields[pname])
1430
-- d.AP = appearance
1431
-- d.AS = default -- /Whatever
1432
-- return save_kid(parent,specification,d,value)
1433
-- end
1434
-- end
1435 1436
local
function
makeradiochild
(
name
,
specification
)
1437
local
field
,
parent
=
clones
[
name
]
,
nil
1438
if
field
then
1439
field
=
radios
[
field
.
parent
]
1440
parent
=
fields
[
field
.
parent
]
1441
if
not
parent
.
pobj
then
1442
if
trace_fields
then
1443
report_fields
(
"
forcing parent radio %a
"
,
parent
.
name
)
1444
end
1445
makeradioparent
(
parent
,
parent
)
1446
end
1447
else
1448
field
=
radios
[
name
]
1449
if
not
field
then
1450
report_fields
(
"
there is some problem with field %a
"
,
name
)
1451
return
nil
1452
end
1453
parent
=
fields
[
field
.
parent
]
1454
if
not
parent
.
pobj
then
1455
if
trace_fields
then
1456
report_fields
(
"
using parent radio %a
"
,
name
)
1457
end
1458
makeradioparent
(
parent
,
parent
)
1459
end
1460
end
1461
if
trace_fields
then
1462
report_fields
(
"
using child radio %a with values %a and default %a
"
,
name
,
field
.
values
,
field
.
default
)
1463
end
1464
local
fontsymbol
=
specification
.
fontsymbol
1465
-- fontsymbol = "circle"
1466
local
d
=
pdfdictionary
{
1467
Subtype
=
pdf_widget
,
1468
Parent
=
pdfreference
(
parent
.
pobj
)
,
1469
F
=
fieldplus
(
specification
)
,
1470
OC
=
fieldlayer
(
specification
)
,
1471
AA
=
fieldactions
(
specification
)
,
1472
H
=
pdf_n
,
1473
}
1474
if
fontsymbol
and
fontsymbol
~
=
"
"
then
1475
specification
.
fontsymbol
=
todingbat
(
fontsymbol
)
1476
specification
.
fontstyle
=
"
symbol
"
1477
specification
.
fontalternative
=
"
dingbats
"
1478
d
.
DA
=
fieldsurrounding
(
specification
)
1479
d
.
MK
=
fieldrendering
(
specification
)
1480
end
1481
local
appearance
,
default
,
value
=
fieldstates_radio
(
field
,
name
,
fields
[
field
.
parent
]
)
1482
d
.
AP
=
appearance
1483
d
.
AS
=
default
-- /Whatever
1484
-- d.MK = pdfdictionary { BC = pdfarray {0}, BG = pdfarray { 1 } }
1485
d
.
BS
=
pdfdictionary
{
S
=
pdfconstant
(
"
I
"
)
,
W
=
1
}
1486
return
save_kid
(
parent
,
specification
,
d
,
value
)
1487
end
1488 1489
function
methods
.
sub
(
name
,
specification
)
1490
return
makeradiochild
(
name
,
enhance
(
specification
,
"
Radio,RadiosInUnison
"
)
)
1491
end
1492