lpdf-ano.lua /size: 46 Kb    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
lpdf-ano
'
]
=
{
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
-- when using rotation: \disabledirectives[refences.sharelinks] (maybe flag links)
10 11
-- todo: /AA << WC << ... >> >> : WillClose actions etc
12 13
-- internal references are indicated by a number (and turned into <autoprefix><number>)
14
-- we only flush internal destinations that are referred
15 16
local
next
,
tostring
,
tonumber
,
rawget
,
type
=
next
,
tostring
,
tonumber
,
rawget
,
type
17
local
rep
,
format
,
find
=
string
.
rep
,
string
.
format
,
string
.
find
18
local
min
=
math
.
min
19
local
lpegmatch
=
lpeg
.
match
20
local
formatters
=
string
.
formatters
21
local
sortedkeys
,
concat
=
table
.
sortedkeys
,
table
.
concat
22 23
local
backends
,
lpdf
=
backends
,
lpdf
24 25
local
trace_references
=
false
trackers
.
register
(
"
references.references
"
,
function
(
v
)
trace_references
=
v
end
)
26
local
trace_destinations
=
false
trackers
.
register
(
"
references.destinations
"
,
function
(
v
)
trace_destinations
=
v
end
)
27
local
trace_bookmarks
=
false
trackers
.
register
(
"
references.bookmarks
"
,
function
(
v
)
trace_bookmarks
=
v
end
)
28 29
local
log_destinations
=
false
directives
.
register
(
"
destinations.log
"
,
function
(
v
)
log_destinations
=
v
end
)
30
local
untex_urls
=
true
directives
.
register
(
"
references.untexurls
"
,
function
(
v
)
untex_urls
=
v
end
)
31 32
local
report_references
=
logs
.
reporter
(
"
backend
"
,
"
references
"
)
33
local
report_destinations
=
logs
.
reporter
(
"
backend
"
,
"
destinations
"
)
34
local
report_bookmarks
=
logs
.
reporter
(
"
backend
"
,
"
bookmarks
"
)
35 36
local
variables
=
interfaces
.
variables
37
local
v_auto
=
variables
.
auto
38
local
v_page
=
variables
.
page
39
local
v_name
=
variables
.
name
40 41
local
factor
=
number
.
dimenfactors
.
bp
42 43
local
settings_to_array
=
utilities
.
parsers
.
settings_to_array
44 45
local
allocate
=
utilities
.
storage
.
allocate
46
local
setmetatableindex
=
table
.
setmetatableindex
47 48
local
nodeinjections
=
backends
.
pdf
.
nodeinjections
49
local
codeinjections
=
backends
.
pdf
.
codeinjections
50
local
registrations
=
backends
.
pdf
.
registrations
51 52
local
javascriptcode
=
interactions
.
javascripts
.
code
53 54
local
references
=
structures
.
references
55
local
bookmarks
=
structures
.
bookmarks
56 57
local
flaginternals
=
references
.
flaginternals
58
local
usedinternals
=
references
.
usedinternals
59
local
usedviews
=
references
.
usedviews
60 61
local
runners
=
references
.
runners
62
local
specials
=
references
.
specials
63
local
handlers
=
references
.
handlers
64
local
executers
=
references
.
executers
65 66
local
nodepool
=
nodes
.
pool
67 68
local
new_latelua
=
nodepool
.
latelua
69 70
local
texgetcount
=
tex
.
getcount
71 72
local
jobpositions
=
job
.
positions
73
local
getpos
=
jobpositions
.
getpos
74
local
gethpos
=
jobpositions
.
gethpos
75
local
getvpos
=
jobpositions
.
getvpos
76 77
local
pdfdictionary
=
lpdf
.
dictionary
78
local
pdfarray
=
lpdf
.
array
79
local
pdfreference
=
lpdf
.
reference
80
local
pdfunicode
=
lpdf
.
unicode
81
local
pdfconstant
=
lpdf
.
constant
82
local
pdfflushobject
=
lpdf
.
flushobject
83
local
pdfshareobjectreference
=
lpdf
.
shareobjectreference
84
local
pdfreserveobject
=
lpdf
.
reserveobject
85
local
pdfpagereference
=
lpdf
.
pagereference
86
local
pdfdelayedobject
=
lpdf
.
delayedobject
87
local
pdfregisterannotation
=
lpdf
.
registerannotation
-- forward definition (for the moment)
88
local
pdfnull
=
lpdf
.
null
89
local
pdfaddtocatalog
=
lpdf
.
addtocatalog
90
local
pdfaddtonames
=
lpdf
.
addtonames
91
local
pdfaddtopageattributes
=
lpdf
.
addtopageattributes
92
local
pdfrectangle
=
lpdf
.
rectangle
93 94
-- todo: 3dview
95 96
----- pdf_annot = pdfconstant("Annot")
97
local
pdf_uri
=
pdfconstant
(
"
URI
"
)
98
local
pdf_gotor
=
pdfconstant
(
"
GoToR
"
)
99
local
pdf_goto
=
pdfconstant
(
"
GoTo
"
)
100
local
pdf_launch
=
pdfconstant
(
"
Launch
"
)
101
local
pdf_javascript
=
pdfconstant
(
"
JavaScript
"
)
102
local
pdf_link
=
pdfconstant
(
"
Link
"
)
103
local
pdf_n
=
pdfconstant
(
"
N
"
)
104
local
pdf_t
=
pdfconstant
(
"
T
"
)
105
local
pdf_fit
=
pdfconstant
(
"
Fit
"
)
106
local
pdf_named
=
pdfconstant
(
"
Named
"
)
107 108
local
autoprefix
=
"
#
"
109
local
usedautoprefixes
=
{
}
110 111
local
function
registerautoprefix
(
name
)
112
local
internal
=
autoprefix
.
.
name
113
if
usedautoprefixes
[
internal
]
=
=
nil
then
114
usedautoprefixes
[
internal
]
=
false
115
end
116
return
internal
117
end
118 119
local
function
useautoprefix
(
name
)
120
local
internal
=
autoprefix
.
.
name
121
usedautoprefixes
[
internal
]
=
true
122
return
internal
123
end
124 125
local
function
checkautoprefixes
(
destinations
)
126
for
k
,
v
in
next
,
usedautoprefixes
do
127
if
not
v
then
128
if
trace_destinations
then
129
report_destinations
(
"
flushing unused autoprefix %a
"
,
k
)
130
end
131
destinations
[
k
]
=
nil
132
end
133
end
134
end
135 136
local
maxslice
=
32
-- could be made configureable ... 64 is also ok
137 138
local
function
pdfmakenametree
(
list
,
apply
)
139
if
not
next
(
list
)
then
140
return
141
end
142
local
slices
=
{
}
143
local
sorted
=
sortedkeys
(
list
)
144
local
size
=
#
sorted
145
local
maxslice
=
maxslice
146
if
size
<
=
1
.
5
*
maxslice
then
147
maxslice
=
size
148
end
149
for
i
=
1
,
size
,
maxslice
do
150
local
amount
=
min
(
i
+
maxslice
-1
,
size
)
151
local
names
=
pdfarray
{
}
152
local
n
=
0
153
for
j
=
i
,
amount
do
154
local
name
=
sorted
[
j
]
155
local
target
=
list
[
name
]
156
n
=
n
+
1
;
names
[
n
]
=
tostring
(
name
)
157
n
=
n
+
1
;
names
[
n
]
=
apply
and
apply
(
target
)
or
target
158
end
159
local
first
=
sorted
[
i
]
160
local
last
=
sorted
[
amount
]
161
local
limits
=
pdfarray
{
162
first
,
163
last
,
164
}
165
local
d
=
pdfdictionary
{
166
Names
=
names
,
167
Limits
=
limits
,
168
}
169
slices
[
#
slices
+
1
]
=
{
170
reference
=
pdfreference
(
pdfflushobject
(
d
)
)
,
171
limits
=
limits
,
172
}
173
end
174
local
function
collectkids
(
slices
,
first
,
last
)
175
local
f
=
slices
[
first
]
176
local
l
=
slices
[
last
]
177
if
f
and
l
then
178
local
k
=
pdfarray
(
)
179
local
n
=
0
180
local
d
=
pdfdictionary
{
181
Kids
=
k
,
182
Limits
=
pdfarray
{
183
f
.
limits
[
1
]
,
184
l
.
limits
[
2
]
,
185
}
,
186
}
187
for
i
=
first
,
last
do
188
n
=
n
+
1
;
k
[
n
]
=
slices
[
i
]
.
reference
189
end
190
return
d
191
end
192
end
193
if
#
slices
=
=
1
then
194
return
slices
[
1
]
.
reference
195
else
196
while
true
do
197
local
size
=
#
slices
198
if
size
>
maxslice
then
199
local
temp
=
{
}
200
local
n
=
0
201
for
i
=
1
,
size
,
maxslice
do
202
local
kids
=
collectkids
(
slices
,
i
,
min
(
i
+
maxslice
-1
,
size
)
)
203
if
kids
then
204
n
=
n
+
1
205
temp
[
n
]
=
{
206
reference
=
pdfreference
(
pdfflushobject
(
kids
)
)
,
207
limits
=
kids
.
Limits
,
208
}
209
else
210
-- error
211
end
212
end
213
slices
=
temp
214
else
215
local
kids
=
collectkids
(
slices
,
1
,
size
)
216
if
kids
then
217
return
pdfreference
(
pdfflushobject
(
kids
)
)
218
else
219
-- error
220
return
221
end
222
end
223
end
224
end
225
end
226 227
lpdf
.
makenametree
=
pdfmakenametree
228 229
-- Bah, I hate this kind of features .. anyway, as we have delayed resolving we
230
-- only support a document-wide setup and it has to be set before the first one
231
-- is used. Also, we default to a non-intrusive gray and the outline is kept
232
-- thin without dashing lines. This is as far as I'm prepared to go. This way
233
-- it can also be used as a debug feature.
234 235
local
pdf_border_style
=
pdfarray
{
0
,
0
,
0
}
-- radius radius linewidth
236
local
pdf_border_color
=
nil
237
local
set_border
=
false
238 239
local
function
pdfborder
(
)
240
set_border
=
true
241
return
pdf_border_style
,
pdf_border_color
242
end
243 244
lpdf
.
border
=
pdfborder
245 246
directives
.
register
(
"
references.border
"
,
function
(
v
)
247
if
v
and
not
set_border
then
248
if
type
(
v
)
=
=
"
string
"
then
249
local
m
=
attributes
.
list
[
attributes
.
private
(
'
color
'
)
]
or
{
}
250
local
c
=
m
and
m
[
v
]
251
local
v
=
c
and
attributes
.
colors
.
value
(
c
)
252
if
v
then
253
local
r
=
v
[
3
]
254
local
g
=
v
[
4
]
255
local
b
=
v
[
5
]
256
-- if r == g and g == b then
257
-- pdf_border_color = pdfarray { r } -- reduced, not not ... bugged viewers
258
-- else
259
pdf_border_color
=
pdfarray
{
r
,
g
,
b
}
-- always rgb
260
-- end
261
end
262
end
263
if
not
pdf_border_color
then
264
pdf_border_color
=
pdfarray
{
.
6
,
.
6
,
.
6
}
-- no reduce to { 0.6 } as there are buggy viewers out there
265
end
266
pdf_border_style
=
pdfarray
{
0
,
0
,
.
5
}
-- < 0.5 is not show by acrobat (at least not in my version)
267
end
268
end
)
269 270
-- the used and flag code here is somewhat messy in the sense
271
-- that it belongs in strc-ref but at the same time depends on
272
-- the backend so we keep it here
273 274
-- the caching is somewhat memory intense on the one hand but
275
-- it saves many small temporary tables so it might pay off
276 277
local
pagedestinations
=
setmetatableindex
(
function
(
t
,
k
)
278
k
=
tonumber
(
k
)
279
if
not
k
or
k
<
=
0
then
280
return
pdfnull
(
)
281
end
282
local
v
=
rawget
(
t
,
k
)
283
if
v
then
284
-- report_references("page number expected, got %s: %a",type(k),k)
285
return
v
286
end
287
local
v
=
k
>
0
and
pdfarray
{
288
pdfreference
(
pdfpagereference
(
k
)
)
,
289
pdf_fit
,
290
}
or
pdfnull
(
)
291
t
[
k
]
=
v
292
return
v
293
end
)
294 295
local
pagereferences
=
setmetatableindex
(
function
(
t
,
k
)
296
k
=
tonumber
(
k
)
297
if
not
k
or
k
<
=
0
then
298
return
nil
299
end
300
local
v
=
rawget
(
t
,
k
)
301
if
v
then
302
return
v
303
end
304
local
v
=
pdfdictionary
{
-- can be cached
305
S
=
pdf_goto
,
306
D
=
pagedestinations
[
k
]
,
307
}
308
t
[
k
]
=
v
309
return
v
310
end
)
311 312
local
defaultdestination
=
pdfarray
{
0
,
pdf_fit
}
313 314
-- fit is default (see lpdf-nod)
315 316
local
destinations
=
{
}
317
local
reported
=
setmetatableindex
(
"
table
"
)
318 319
local
function
pdfregisterdestination
(
name
,
reference
)
320
local
d
=
destinations
[
name
]
321
if
d
then
322
if
not
reported
[
name
]
[
reference
]
then
323
report_destinations
(
"
ignoring duplicate destination %a with reference %a
"
,
name
,
reference
)
324
reported
[
name
]
[
reference
]
=
true
325
end
326
else
327
destinations
[
name
]
=
reference
328
end
329
end
330 331
lpdf
.
registerdestination
=
pdfregisterdestination
332 333
logs
.
registerfinalactions
(
function
(
)
334
if
log_destinations
and
next
(
destinations
)
then
335
local
report
=
logs
.
startfilelogging
(
"
references
"
,
"
used destinations
"
)
336
local
n
=
0
337
for
destination
,
pagenumber
in
table
.
sortedhash
(
destinations
)
do
338
report
(
"
% 4i : %-5s : %s
"
,
pagenumber
,
usedviews
[
destination
]
or
defaultview
,
destination
)
339
n
=
n
+
1
340
end
341
logs
.
stopfilelogging
(
)
342
report_destinations
(
"
%s destinations saved in log file
"
,
n
)
343
end
344
end
)
345 346
local
function
pdfdestinationspecification
(
)
347
if
next
(
destinations
)
then
-- safeguard
348
checkautoprefixes
(
destinations
)
349
local
r
=
pdfmakenametree
(
destinations
,
pdfreference
)
350
if
r
then
351
pdfaddtonames
(
"
Dests
"
,
r
)
352
end
353
if
not
log_destinations
then
354
destinations
=
nil
355
end
356
end
357
end
358 359
lpdf
.
destinationspecification
=
pdfdestinationspecification
360 361
lpdf
.
registerdocumentfinalizer
(
pdfdestinationspecification
,
"
collect destinations
"
)
362 363
-- todo
364 365
local
destinations
=
{
}
366 367
local
f_xyz
=
formatters
[
"
<< /D [ %i 0 R /XYZ %.6N %.6N null ] >>
"
]
368
local
f_fit
=
formatters
[
"
<< /D [ %i 0 R /Fit ] >>
"
]
369
local
f_fitb
=
formatters
[
"
<< /D [ %i 0 R /FitB ] >>
"
]
370
local
f_fith
=
formatters
[
"
<< /D [ %i 0 R /FitH %.6N ] >>
"
]
371
local
f_fitv
=
formatters
[
"
<< /D [ %i 0 R /FitV %.6N ] >>
"
]
372
local
f_fitbh
=
formatters
[
"
<< /D [ %i 0 R /FitBH %.6N ] >>
"
]
373
local
f_fitbv
=
formatters
[
"
<< /D [ %i 0 R /FitBV %.6N ] >>
"
]
374
local
f_fitr
=
formatters
[
"
<< /D [ %i 0 R /FitR %.6N %.6N %.6N %.6N ] >>
"
]
375 376
local
v_standard
=
variables
.
standard
377
local
v_frame
=
variables
.
frame
378
local
v_width
=
variables
.
width
379
local
v_minwidth
=
variables
.
minwidth
380
local
v_height
=
variables
.
height
381
local
v_minheight
=
variables
.
minheight
382
local
v_fit
=
variables
.
fit
383
local
v_tight
=
variables
.
tight
384 385
-- nicer is to create dictionaries and set properties but it's a bit overkill
386 387
-- The problem with the following settings is that they are guesses: we never know
388
-- if a box is part of something larger that needs to be in view, or that we are
389
-- dealing with a vbox or vtop so the used h/d values cannot be trusted in a tight
390
-- view. Of course some decent additional offset would be nice so maybe i'll add
391
-- that some day. I never use anything else than 'fit' anyway as I think that the
392
-- document should fit the device (and vice versa). In fact, with todays swipe
393
-- and finger zooming this whole view is rather useless and as with any zooming
394
-- one looses the overview and keeps zooming.
395 396
-- todo: scaling
397 398
-- local destinationactions = {
399
-- [v_standard] = function(r,w,h,d) return f_xyz (r,gethpos()*factor,(getvpos()+h)*factor) end, -- local left,top with no zoom
400
-- [v_frame] = function(r,w,h,d) return f_fitr (r,pdfrectangle(w,h,d)) end, -- fit rectangle in window
401
-- [v_width] = function(r,w,h,d) return f_fith (r,(getvpos()+h)*factor) end, -- top coordinate, fit width of page in window
402
-- [v_minwidth] = function(r,w,h,d) return f_fitbh(r,(getvpos()+h)*factor) end, -- top coordinate, fit width of content in window
403
-- [v_height] = function(r,w,h,d) return f_fitv (r,gethpos()*factor) end, -- left coordinate, fit height of page in window
404
-- [v_minheight] = function(r,w,h,d) return f_fitbv(r,gethpos()*factor) end, -- left coordinate, fit height of content in window [v_fit] = f_fit, -- fit page in window
405
-- [v_tight] = f_fitb, -- fit content in window
406
-- [v_fit] = f_fit,
407
-- }
408 409
local
destinationactions
=
{
410
[
v_standard
]
=
function
(
r
,
w
,
h
,
d
,
o
)
-- local left,top with no zoom
411
local
tx
,
ty
=
getpos
(
)
412
return
f_xyz
(
r
,
tx
*
factor
,
(
ty
+
h
+
2
*
o
)
*
factor
)
-- we can assume margins
413
end
,
414
[
v_frame
]
=
function
(
r
,
w
,
h
,
d
,
o
)
-- fit rectangle in window
415
return
f_fitr
(
r
,
pdfrectangle
(
w
,
h
,
d
,
o
)
)
416
end
,
417
[
v_width
]
=
function
(
r
,
w
,
h
,
d
,
o
)
-- top coordinate, fit width of page in window
418
return
f_fith
(
r
,
(
getvpos
(
)
+
h
+
o
)
*
factor
)
419
end
,
420
[
v_minwidth
]
=
function
(
r
,
w
,
h
,
d
,
o
)
-- top coordinate, fit width of content in window
421
return
f_fitbh
(
r
,
(
getvpos
(
)
+
h
+
o
)
*
factor
)
422
end
,
423
[
v_height
]
=
function
(
r
,
w
,
h
,
d
,
o
)
-- left coordinate, fit height of page in window
424
return
f_fitv
(
r
,
(
gethpos
(
)
)
*
factor
)
425
end
,
426
[
v_minheight
]
=
function
(
r
,
w
,
h
,
d
,
o
)
-- left coordinate, fit height of content in window
427
return
f_fitbv
(
r
,
(
gethpos
(
)
)
*
factor
)
428
end
,
429
[
v_tight
]
=
f_fitb
,
-- fit content in window
430
[
v_fit
]
=
f_fit
,
-- fit content in window
431
}
432 433
local
mapping
=
{
434
[
v_standard
]
=
v_standard
,
xyz
=
v_standard
,
435
[
v_frame
]
=
v_frame
,
fitr
=
v_frame
,
436
[
v_width
]
=
v_width
,
fith
=
v_width
,
437
[
v_minwidth
]
=
v_minwidth
,
fitbh
=
v_minwidth
,
438
[
v_height
]
=
v_height
,
fitv
=
v_height
,
439
[
v_minheight
]
=
v_minheight
,
fitbv
=
v_minheight
,
440
[
v_fit
]
=
v_fit
,
fit
=
v_fit
,
441
[
v_tight
]
=
v_tight
,
fitb
=
v_tight
,
442
}
443 444
local
defaultview
=
v_fit
445
local
defaultaction
=
destinationactions
[
defaultview
]
446
local
offset
=
0
-- 65536*5
447 448
directives
.
register
(
"
destinations.offset
"
,
function
(
v
)
449
offset
=
string
.
todimen
(
v
)
or
0
450
end
)
451 452
-- A complication is that we need to use named destinations when we have views so we
453
-- end up with a mix. A previous versions just output multiple destinations but now
454
-- that we moved all to here we can be more sparse.
455 456
local
pagedestinations
=
setmetatableindex
(
function
(
t
,
k
)
-- not the same as the one above!
457
local
v
=
pdfdelayedobject
(
f_fit
(
k
)
)
458
t
[
k
]
=
v
459
return
v
460
end
)
461 462
local
function
flushdestination
(
specification
)
463
local
names
=
specification
.
names
464
local
view
=
specification
.
view
465
local
r
=
pdfpagereference
(
texgetcount
(
"
realpageno
"
)
)
466
if
(
references
.
innermethod
~
=
v_name
)
and
(
view
=
=
defaultview
or
not
view
or
view
=
=
"
"
)
then
467
r
=
pagedestinations
[
r
]
468
else
469
local
action
=
view
and
destinationactions
[
view
]
or
defaultaction
470
r
=
pdfdelayedobject
(
action
(
r
,
specification
.
width
,
specification
.
height
,
specification
.
depth
,
offset
)
)
471
end
472
for
n
=
1
,
#
names
do
473
local
name
=
names
[
n
]
474
if
name
then
475
pdfregisterdestination
(
name
,
r
)
476
end
477
end
478
end
479 480
function
nodeinjections
.
destination
(
width
,
height
,
depth
,
names
,
view
)
481
-- todo check if begin end node / was comment
482
view
=
view
and
mapping
[
view
]
or
defaultview
483
if
trace_destinations
then
484
report_destinations
(
"
width %p, height %p, depth %p, names %|t, view %a
"
,
width
,
height
,
depth
,
names
,
view
)
485
end
486
local
method
=
references
.
innermethod
487
local
noview
=
view
=
=
defaultview
488
local
doview
=
false
489
-- we could save some aut's by using a name when given but it doesn't pay off apart
490
-- from making the code messy and tracing hard .. we only save some destinations
491
-- which we already share anyway
492
if
method
=
=
v_page
then
493
for
n
=
1
,
#
names
do
494
local
name
=
names
[
n
]
495
local
used
=
usedviews
[
name
]
496
if
used
and
used
~
=
true
then
497
-- already done, maybe a warning
498
elseif
type
(
name
)
=
=
"
number
"
then
499
-- if noview then
500
-- usedviews[name] = view
501
-- names[n] = false
502
-- else
503
usedviews
[
name
]
=
view
504
names
[
n
]
=
false
505
-- end
506
else
507
usedviews
[
name
]
=
view
508
end
509
end
510
elseif
method
=
=
v_name
then
511
for
n
=
1
,
#
names
do
512
local
name
=
names
[
n
]
513
local
used
=
usedviews
[
name
]
514
if
used
and
used
~
=
true
then
515
-- already done, maybe a warning
516
elseif
type
(
name
)
=
=
"
number
"
then
517
local
used
=
usedinternals
[
name
]
518
usedviews
[
name
]
=
view
519
names
[
n
]
=
registerautoprefix
(
name
)
520
doview
=
true
521
else
522
usedviews
[
name
]
=
view
523
doview
=
true
524
end
525
end
526
else
527
for
n
=
1
,
#
names
do
528
local
name
=
names
[
n
]
529
if
usedviews
[
name
]
then
530
-- already done, maybe a warning
531
elseif
type
(
name
)
=
=
"
number
"
then
532
if
noview
then
533
usedviews
[
name
]
=
view
534
names
[
n
]
=
false
535
else
536
local
used
=
usedinternals
[
name
]
537
if
used
and
used
~
=
defaultview
then
538
usedviews
[
name
]
=
view
539
names
[
n
]
=
registerautoprefix
(
name
)
540
doview
=
true
541
else
542
names
[
n
]
=
false
543
end
544
end
545
else
546
usedviews
[
name
]
=
view
547
doview
=
true
548
end
549
end
550
end
551
if
doview
then
552
return
new_latelua
{
553
action
=
flushdestination
,
554
width
=
width
,
555
height
=
height
,
556
depth
=
depth
,
557
names
=
names
,
558
view
=
view
,
559
}
560
end
561
end
562 563
-- we could share dictionaries ... todo
564 565
local
function
pdflinkpage
(
page
)
566
return
pagereferences
[
page
]
567
end
568 569
local
function
pdflinkinternal
(
internal
,
page
)
570
-- local method = references.innermethod
571
if
internal
then
572
flaginternals
[
internal
]
=
true
-- for bookmarks and so
573
local
used
=
usedinternals
[
internal
]
574
if
used
=
=
defaultview
or
used
=
=
true
then
575
return
pagereferences
[
page
]
576
else
577
if
type
(
internal
)
~
=
"
string
"
then
578
internal
=
useautoprefix
(
internal
)
579
end
580
return
pdfdictionary
{
581
S
=
pdf_goto
,
582
D
=
internal
,
583
}
584
end
585
else
586
return
pagereferences
[
page
]
587
end
588
end
589 590
local
function
pdflinkname
(
destination
,
internal
,
page
)
591
local
method
=
references
.
innermethod
592
if
method
=
=
v_auto
then
593
local
used
=
defaultview
594
if
internal
then
595
flaginternals
[
internal
]
=
true
-- for bookmarks and so
596
used
=
usedinternals
[
internal
]
or
defaultview
597
end
598
if
used
=
=
defaultview
then
-- or used == true then
599
return
pagereferences
[
page
]
600
else
601
return
pdfdictionary
{
602
S
=
pdf_goto
,
603
D
=
destination
,
604
}
605
end
606
elseif
method
=
=
v_name
then
607
-- flaginternals[internal] = true -- for bookmarks and so
608
return
pdfdictionary
{
609
S
=
pdf_goto
,
610
D
=
destination
,
611
}
612
else
613
return
pagereferences
[
page
]
614
end
615
end
616 617
-- annotations
618 619
local
function
pdffilelink
(
filename
,
destination
,
page
,
actions
)
620
if
not
filename
or
filename
=
=
"
"
or
file
.
basename
(
filename
)
=
=
tex
.
jobname
then
621
return
false
622
end
623
filename
=
file
.
addsuffix
(
filename
,
"
pdf
"
)
624
if
(
not
destination
or
destination
=
=
"
"
)
or
(
references
.
outermethod
=
=
v_page
)
then
625
destination
=
pdfarray
{
(
page
or
1
)
-
1
,
pdf_fit
}
626
end
627
return
pdfdictionary
{
628
S
=
pdf_gotor
,
-- can also be pdf_launch
629
F
=
filename
,
630
D
=
destination
or
defaultdestination
,
631
NewWindow
=
actions
.
newwindow
and
true
or
nil
,
632
}
633
end
634 635
local
untex
=
references
.
urls
.
untex
636 637
local
function
pdfurllink
(
url
,
destination
,
page
)
638
if
not
url
or
url
=
=
"
"
then
639
return
false
640
end
641
if
untex_urls
then
642
url
=
untex
(
url
)
-- last minute cleanup of \* and spaces
643
end
644
if
destination
and
destination
~
=
"
"
then
645
url
=
url
.
.
"
#
"
.
.
destination
646
end
647
return
pdfdictionary
{
648
S
=
pdf_uri
,
649
URI
=
url
,
650
}
651
end
652 653
local
function
pdflaunch
(
program
,
parameters
)
654
if
not
program
or
program
=
=
"
"
then
655
return
false
656
end
657
return
pdfdictionary
{
658
S
=
pdf_launch
,
659
F
=
program
,
660
D
=
"
.
"
,
661
P
=
parameters
~
=
"
"
and
parameters
or
nil
662
}
663
end
664 665
local
function
pdfjavascript
(
name
,
arguments
)
666
local
script
=
javascriptcode
(
name
,
arguments
)
-- make into object (hash)
667
if
script
then
668
return
pdfdictionary
{
669
S
=
pdf_javascript
,
670
JS
=
script
,
671
}
672
end
673
end
674 675
local
function
pdfaction
(
actions
)
676
local
nofactions
=
#
actions
677
if
nofactions
>
0
then
678
local
a
=
actions
[
1
]
679
local
action
=
runners
[
a
.
kind
]
680
if
action
then
681
action
=
action
(
a
,
actions
)
682
end
683
if
action
then
684
local
first
=
action
685
for
i
=
2
,
nofactions
do
686
local
a
=
actions
[
i
]
687
local
what
=
runners
[
a
.
kind
]
688
if
what
then
689
what
=
what
(
a
,
actions
)
690
end
691
if
action
=
=
what
then
692
-- ignore this one, else we get a loop
693
elseif
what
then
694
action
.
Next
=
what
695
action
=
what
696
else
697
-- error
698
return
nil
699
end
700
end
701
return
first
,
actions
.
n
or
#
actions
702
end
703
end
704
end
705 706
lpdf
.
action
=
pdfaction
707 708
function
codeinjections
.
prerollreference
(
actions
)
-- share can become option
709
if
actions
then
710
local
main
,
n
=
pdfaction
(
actions
)
711
if
main
then
712
local
bs
,
bc
=
pdfborder
(
)
713
main
=
pdfdictionary
{
714
Subtype
=
pdf_link
,
715
Border
=
bs
,
716
C
=
bc
,
717
H
=
(
not
actions
.
highlight
and
pdf_n
)
or
nil
,
718
A
=
pdfshareobjectreference
(
main
)
,
719
F
=
4
,
-- print (mandate in pdf/a)
720
}
721
return
main
(
"
A
"
)
,
n
722
end
723
end
724
end
725 726
-- local function use_normal_annotations()
727
--
728
-- local function reference(width,height,depth,prerolled) -- keep this one
729
-- if prerolled then
730
-- if trace_references then
731
-- report_references("width %p, height %p, depth %p, prerolled %a",width,height,depth,prerolled)
732
-- end
733
-- return pdfannotation_node(width,height,depth,prerolled)
734
-- end
735
-- end
736
--
737
-- local function finishreference()
738
-- end
739
--
740
-- return reference, finishreference
741
--
742
-- end
743 744
-- eventually we can do this for special refs only
745 746
local
hashed
=
{
}
747
local
nofunique
=
0
748
local
nofused
=
0
749
local
nofspecial
=
0
750
local
share
=
true
751 752
local
f_annot
=
formatters
[
"
<< /Type /Annot %s /Rect [ %.6N %.6N %.6N %.6N ] >>
"
]
753
local
f_quadp
=
formatters
[
"
<< /Type /Annot %s /QuadPoints [ %s ] /Rect [ %.6N %.6N %.6N %.6N ] >>
"
]
754 755
directives
.
register
(
"
references.sharelinks
"
,
function
(
v
)
756
share
=
v
757
end
)
758 759
setmetatableindex
(
hashed
,
function
(
t
,
k
)
760
local
v
=
pdfdelayedobject
(
k
)
761
if
share
then
762
t
[
k
]
=
v
763
end
764
nofunique
=
nofunique
+
1
765
return
v
766
end
)
767 768
local
function
toquadpoints
(
paths
)
769
local
t
,
n
=
{
}
,
0
770
for
i
=
1
,
#
paths
do
771
local
path
=
paths
[
i
]
772
local
size
=
#
path
773
for
j
=
1
,
size
do
774
local
p
=
path
[
j
]
775
n
=
n
+
1
;
t
[
n
]
=
p
[
1
]
776
n
=
n
+
1
;
t
[
n
]
=
p
[
2
]
777
end
778
local
m
=
size
%
4
779
if
m
>
0
then
780
local
p
=
path
[
size
]
781
for
j
=
size
+
1
,
m
do
782
n
=
n
+
1
;
t
[
n
]
=
p
[
1
]
783
n
=
n
+
1
;
t
[
n
]
=
p
[
2
]
784
end
785
end
786
end
787
return
concat
(
t
,
"
"
)
788
end
789 790
local
function
finishreference
(
specification
)
791
local
prerolled
=
specification
.
prerolled
792
local
quadpoints
=
specification
.
mesh
793
local
llx
,
lly
,
794
urx
,
ury
=
pdfrectangle
(
specification
.
width
,
specification
.
height
,
specification
.
depth
)
795
local
specifier
=
nil
796
if
quadpoints
and
#
quadpoints
>
0
then
797
specifier
=
f_quadp
(
prerolled
,
toquadpoints
(
quadpoints
)
,
llx
,
lly
,
urx
,
ury
)
798
else
799
specifier
=
f_annot
(
prerolled
,
llx
,
lly
,
urx
,
ury
)
800
end
801
nofused
=
nofused
+
1
802
return
pdfregisterannotation
(
hashed
[
specifier
]
)
803
end
804 805
local
function
finishannotation
(
specification
)
806
local
prerolled
=
specification
.
prerolled
807
local
objref
=
specification
.
objref
808
if
type
(
prerolled
)
=
=
"
function
"
then
809
prerolled
=
prerolled
(
)
810
end
811
local
annot
=
f_annot
(
prerolled
,
pdfrectangle
(
specification
.
width
,
specification
.
height
,
specification
.
depth
)
)
812
if
objref
then
813
pdfdelayedobject
(
annot
,
objref
)
814
else
815
objref
=
pdfdelayedobject
(
annot
)
816
end
817
nofspecial
=
nofspecial
+
1
818
return
pdfregisterannotation
(
objref
)
819
end
820 821
function
nodeinjections
.
reference
(
width
,
height
,
depth
,
prerolled
,
mesh
)
822
if
prerolled
then
823
if
trace_references
then
824
report_references
(
"
link: width %p, height %p, depth %p, prerolled %a
"
,
width
,
height
,
depth
,
prerolled
)
825
end
826
return
new_latelua
{
827
action
=
finishreference
,
828
width
=
width
,
829
height
=
height
,
830
depth
=
depth
,
831
prerolled
=
prerolled
,
832
mesh
=
mesh
,
833
}
834
end
835
end
836 837
function
nodeinjections
.
annotation
(
width
,
height
,
depth
,
prerolled
,
objref
)
838
if
prerolled
then
839
if
trace_references
then
840
report_references
(
"
special: width %p, height %p, depth %p, prerolled %a
"
,
width
,
height
,
depth
,
841
type
(
prerolled
)
=
=
"
string
"
and
prerolled
or
"
-
"
)
842
end
843
return
new_latelua
{
844
action
=
finishannotation
,
845
width
=
width
,
846
height
=
height
,
847
depth
=
depth
,
848
prerolled
=
prerolled
,
849
objref
=
objref
or
false
,
850
}
851
end
852
end
853 854
-- beware, we register during a latelua sweep so we have to make sure that
855
-- we finalize after that (also in a latelua for the moment as we have no
856
-- callback yet)
857 858
local
annotations
=
nil
859 860
function
lpdf
.
registerannotation
(
n
)
861
if
annotations
then
862
annotations
[
#
annotations
+
1
]
=
pdfreference
(
n
)
863
else
864
annotations
=
pdfarray
{
pdfreference
(
n
)
}
-- no need to use lpdf.array cum suis
865
end
866
end
867 868
pdfregisterannotation
=
lpdf
.
registerannotation
869 870
function
lpdf
.
annotationspecification
(
)
871
if
annotations
then
872
local
r
=
pdfdelayedobject
(
tostring
(
annotations
)
)
-- delayed so okay in latelua
873
if
r
then
874
pdfaddtopageattributes
(
"
Annots
"
,
pdfreference
(
r
)
)
875
end
876
annotations
=
nil
877
end
878
end
879 880
lpdf
.
registerpagefinalizer
(
lpdf
.
annotationspecification
,
"
finalize annotations
"
)
881 882
statistics
.
register
(
"
pdf annotations
"
,
function
(
)
883
if
nofused
>
0
or
nofspecial
>
0
then
884
return
format
(
"
%s links (%s unique), %s special
"
,
nofused
,
nofunique
,
nofspecial
)
885
else
886
return
nil
887
end
888
end
)
889 890
-- runners and specials
891 892
local
splitter
=
lpeg
.
splitat
(
"
,
"
,
true
)
893 894
runners
[
"
inner
"
]
=
function
(
var
,
actions
)
895
local
internal
=
false
896
local
name
=
nil
897
local
method
=
references
.
innermethod
898
local
vi
=
var
.
i
899
local
page
=
var
.
r
900
if
vi
then
901
local
vir
=
vi
.
references
902
if
vir
then
903
-- todo: no need for it when we have a real reference ... although we need
904
-- this mess for prefixes anyway
905
local
reference
=
vir
.
reference
906
if
reference
and
reference
~
=
"
"
then
907
reference
=
lpegmatch
(
splitter
,
reference
)
or
reference
908
var
.
inner
=
reference
909
local
prefix
=
var
.
p
910
if
prefix
and
prefix
~
=
"
"
then
911
var
.
prefix
=
prefix
912
name
=
prefix
.
.
"
:
"
.
.
reference
913
else
914
name
=
reference
915
end
916
end
917
internal
=
vir
.
internal
918
if
internal
then
919
flaginternals
[
internal
]
=
true
920
end
921
end
922
end
923
if
name
then
924
return
pdflinkname
(
name
,
internal
,
page
)
925
elseif
internal
then
926
return
pdflinkinternal
(
internal
,
page
)
927
elseif
page
then
928
return
pdflinkpage
(
page
)
929
else
930
-- real bad
931
end
932
end
933 934
runners
[
"
inner with arguments
"
]
=
function
(
var
,
actions
)
935
report_references
(
"
todo: inner with arguments
"
)
936
return
false
937
end
938 939
runners
[
"
outer
"
]
=
function
(
var
,
actions
)
940
local
file
,
url
=
references
.
checkedfileorurl
(
var
.
outer
,
var
.
outer
)
941
if
file
then
942
return
pdffilelink
(
file
,
var
.
arguments
,
nil
,
actions
)
943
elseif
url
then
944
return
pdfurllink
(
url
,
var
.
arguments
,
nil
,
actions
)
945
end
946
end
947 948
runners
[
"
outer with inner
"
]
=
function
(
var
,
actions
)
949
return
pdffilelink
(
references
.
checkedfile
(
var
.
outer
)
,
var
.
inner
,
var
.
r
,
actions
)
950
end
951 952
runners
[
"
special outer with operation
"
]
=
function
(
var
,
actions
)
953
local
handler
=
specials
[
var
.
special
]
954
return
handler
and
handler
(
var
,
actions
)
955
end
956 957
runners
[
"
special outer
"
]
=
function
(
var
,
actions
)
958
report_references
(
"
todo: special outer
"
)
959
return
false
960
end
961 962
runners
[
"
special
"
]
=
function
(
var
,
actions
)
963
local
handler
=
specials
[
var
.
special
]
964
return
handler
and
handler
(
var
,
actions
)
965
end
966 967
runners
[
"
outer with inner with arguments
"
]
=
function
(
var
,
actions
)
968
report_references
(
"
todo: outer with inner with arguments
"
)
969
return
false
970
end
971 972
runners
[
"
outer with special and operation and arguments
"
]
=
function
(
var
,
actions
)
973
report_references
(
"
todo: outer with special and operation and arguments
"
)
974
return
false
975
end
976 977
runners
[
"
outer with special
"
]
=
function
(
var
,
actions
)
978
report_references
(
"
todo: outer with special
"
)
979
return
false
980
end
981 982
runners
[
"
outer with special and operation
"
]
=
function
(
var
,
actions
)
983
report_references
(
"
todo: outer with special and operation
"
)
984
return
false
985
end
986 987
runners
[
"
special operation
"
]
=
runners
[
"
special
"
]
988
runners
[
"
special operation with arguments
"
]
=
runners
[
"
special
"
]
989 990
local
reported
=
{
}
991 992
function
specials
.
internal
(
var
,
actions
)
-- better resolve in strc-ref
993
local
o
=
var
.
operation
994
local
i
=
o
and
tonumber
(
o
)
995
local
v
=
i
and
references
.
internals
[
i
]
996
if
v
then
997
flaginternals
[
i
]
=
true
-- also done in pdflinkinternal
998
return
pdflinkinternal
(
i
,
v
.
references
.
realpage
)
999
end
1000
local
v
=
i
or
o
or
"
<unset>
"
1001
if
not
reported
[
v
]
then
1002
report_references
(
"
no internal reference %a
"
,
v
)
1003
reported
[
v
]
=
true
1004
end
1005
end
1006 1007
-- realpage already resolved
1008 1009
specials
.
i
=
specials
.
internal
1010 1011
local
pages
=
references
.
pages
1012 1013
function
specials
.
page
(
var
,
actions
)
1014
local
file
=
var
.
f
1015
if
file
then
1016
return
pdffilelink
(
references
.
checkedfile
(
file
)
,
nil
,
var
.
operation
,
actions
)
1017
else
1018
local
p
=
var
.
r
1019
if
not
p
then
-- todo: call special from reference code
1020
p
=
pages
[
var
.
operation
]
1021
if
type
(
p
)
=
=
"
function
"
then
-- double
1022
p
=
p
(
)
1023
else
1024
p
=
references
.
realpageofpage
(
tonumber
(
p
)
)
1025
end
1026
end
1027
return
pdflinkpage
(
p
or
var
.
operation
)
1028
end
1029
end
1030 1031
function
specials
.
realpage
(
var
,
actions
)
1032
local
file
=
var
.
f
1033
if
file
then
1034
return
pdffilelink
(
references
.
checkedfile
(
file
)
,
nil
,
var
.
operation
,
actions
)
1035
else
1036
return
pdflinkpage
(
var
.
operation
)
1037
end
1038
end
1039 1040
function
specials
.
userpage
(
var
,
actions
)
1041
local
file
=
var
.
f
1042
if
file
then
1043
return
pdffilelink
(
references
.
checkedfile
(
file
)
,
nil
,
var
.
operation
,
actions
)
1044
else
1045
local
p
=
var
.
r
1046
if
not
p
then
-- todo: call special from reference code
1047
p
=
var
.
operation
1048
if
p
then
-- no function and special check here. only numbers
1049
p
=
references
.
realpageofpage
(
tonumber
(
p
)
)
1050
end
1051
-- if p then
1052
-- var.r = p
1053
-- end
1054
end
1055
return
pdflinkpage
(
p
or
var
.
operation
)
1056
end
1057
end
1058 1059
function
specials
.
deltapage
(
var
,
actions
)
1060
local
p
=
tonumber
(
var
.
operation
)
1061
if
p
then
1062
p
=
references
.
checkedrealpage
(
p
+
texgetcount
(
"
realpageno
"
)
)
1063
return
pdflinkpage
(
p
)
1064
end
1065
end
1066 1067
-- sections
1068 1069
function
specials
.
section
(
var
,
actions
)
1070
-- a bit duplicate
1071
local
sectionname
=
var
.
arguments
1072
local
destination
=
var
.
operation
1073
local
internal
=
structures
.
sections
.
internalreference
(
sectionname
,
destination
)
1074
if
internal
then
1075
var
.
special
=
"
internal
"
1076
var
.
operation
=
internal
1077
var
.
arguments
=
nil
1078
return
specials
.
internal
(
var
,
actions
)
1079
end
1080
end
1081 1082
-- todo, do this in references namespace ordered instead (this is an experiment)
1083 1084
local
splitter
=
lpeg
.
splitat
(
"
:
"
)
1085 1086
function
specials
.
order
(
var
,
actions
)
-- references.specials !
1087
local
operation
=
var
.
operation
1088
if
operation
then
1089
local
kind
,
name
,
n
=
lpegmatch
(
splitter
,
operation
)
1090
local
order
=
structures
.
lists
.
ordered
[
kind
]
1091
order
=
order
and
order
[
name
]
1092
local
v
=
order
[
tonumber
(
n
)
]
1093
local
r
=
v
and
v
.
references
.
realpage
1094
if
r
then
1095
var
.
operation
=
r
-- brrr, but test anyway
1096
return
specials
.
page
(
var
,
actions
)
1097
end
1098
end
1099
end
1100 1101
function
specials
.
url
(
var
,
actions
)
1102
return
pdfurllink
(
references
.
checkedurl
(
var
.
operation
)
,
var
.
arguments
,
nil
,
actions
)
1103
end
1104 1105
function
specials
.
file
(
var
,
actions
)
1106
return
pdffilelink
(
references
.
checkedfile
(
var
.
operation
)
,
var
.
arguments
,
nil
,
actions
)
1107
end
1108 1109
function
specials
.
fileorurl
(
var
,
actions
)
1110
local
file
,
url
=
references
.
checkedfileorurl
(
var
.
operation
,
var
.
operation
)
1111
if
file
then
1112
return
pdffilelink
(
file
,
var
.
arguments
,
nil
,
actions
)
1113
elseif
url
then
1114
return
pdfurllink
(
url
,
var
.
arguments
,
nil
,
actions
)
1115
end
1116
end
1117 1118
function
specials
.
program
(
var
,
content
)
1119
local
program
=
references
.
checkedprogram
(
var
.
operation
)
1120
return
pdflaunch
(
program
,
var
.
arguments
)
1121
end
1122 1123
function
specials
.
javascript
(
var
)
1124
return
pdfjavascript
(
var
.
operation
,
var
.
arguments
)
1125
end
1126 1127
specials
.
JS
=
specials
.
javascript
1128 1129
executers
.
importform
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
AcroForm:ImportFDF
"
)
}
1130
executers
.
exportform
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
AcroForm:ExportFDF
"
)
}
1131
executers
.
first
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
FirstPage
"
)
}
1132
executers
.
previous
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
PrevPage
"
)
}
1133
executers
.
next
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
NextPage
"
)
}
1134
executers
.
last
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
LastPage
"
)
}
1135
executers
.
backward
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
GoBack
"
)
}
1136
executers
.
forward
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
GoForward
"
)
}
1137
executers
.
print
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
Print
"
)
}
1138
executers
.
exit
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
Quit
"
)
}
1139
executers
.
close
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
Close
"
)
}
1140
executers
.
save
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
Save
"
)
}
1141
executers
.
savenamed
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
SaveAs
"
)
}
1142
executers
.
opennamed
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
Open
"
)
}
1143
executers
.
help
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
HelpUserGuide
"
)
}
1144
executers
.
toggle
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
FullScreen
"
)
}
1145
executers
.
search
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
Find
"
)
}
1146
executers
.
searchagain
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
FindAgain
"
)
}
1147
executers
.
gotopage
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
GoToPage
"
)
}
1148
executers
.
query
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
AcroSrch:Query
"
)
}
1149
executers
.
queryagain
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
AcroSrch:NextHit
"
)
}
1150
executers
.
fitwidth
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
FitWidth
"
)
}
1151
executers
.
fitheight
=
pdfdictionary
{
S
=
pdf_named
,
N
=
pdfconstant
(
"
FitHeight
"
)
}
1152 1153
local
function
fieldset
(
arguments
)
1154
-- [\dogetfieldset{#1}]
1155
return
nil
1156
end
1157 1158
function
executers
.
resetform
(
arguments
)
1159
arguments
=
(
type
(
arguments
)
=
=
"
table
"
and
arguments
)
or
settings_to_array
(
arguments
)
1160
return
pdfdictionary
{
1161
S
=
pdfconstant
(
"
ResetForm
"
)
,
1162
Field
=
fieldset
(
arguments
[
1
]
)
1163
}
1164
end
1165 1166
local
formmethod
=
"
post
"
-- "get" "post"
1167
local
formformat
=
"
xml
"
-- "xml" "html" "fdf"
1168 1169
-- bit 3 = html bit 6 = xml bit 4 = get
1170 1171
local
flags
=
{
1172
get
=
{
1173
html
=
12
,
fdf
=
8
,
xml
=
40
,
1174
}
,
1175
post
=
{
1176
html
=
4
,
fdf
=
0
,
xml
=
32
,
1177
}
1178
}
1179 1180
function
executers
.
submitform
(
arguments
)
1181
arguments
=
(
type
(
arguments
)
=
=
"
table
"
and
arguments
)
or
settings_to_array
(
arguments
)
1182
local
flag
=
flags
[
formmethod
]
or
flags
.
post
1183
flag
=
(
flag
and
(
flag
[
formformat
]
or
flag
.
xml
)
)
or
32
-- default: post, xml
1184
return
pdfdictionary
{
1185
S
=
pdfconstant
(
"
SubmitForm
"
)
,
1186
F
=
arguments
[
1
]
,
1187
Field
=
fieldset
(
arguments
[
2
]
)
,
1188
Flags
=
flag
,
1189
-- \PDFsubmitfiller
1190
}
1191
end
1192 1193
local
pdf_hide
=
pdfconstant
(
"
Hide
"
)
1194 1195
function
executers
.
hide
(
arguments
)
1196
return
pdfdictionary
{
1197
S
=
pdf_hide
,
1198
H
=
true
,
1199
T
=
arguments
,
1200
}
1201
end
1202 1203
function
executers
.
show
(
arguments
)
1204
return
pdfdictionary
{
1205
S
=
pdf_hide
,
1206
H
=
false
,
1207
T
=
arguments
,
1208
}
1209
end
1210 1211
local
pdf_movie
=
pdfconstant
(
"
Movie
"
)
1212
local
pdf_start
=
pdfconstant
(
"
Start
"
)
1213
local
pdf_stop
=
pdfconstant
(
"
Stop
"
)
1214
local
pdf_resume
=
pdfconstant
(
"
Resume
"
)
1215
local
pdf_pause
=
pdfconstant
(
"
Pause
"
)
1216 1217
local
function
movie_or_sound
(
operation
,
arguments
)
1218
arguments
=
(
type
(
arguments
)
=
=
"
table
"
and
arguments
)
or
settings_to_array
(
arguments
)
1219
return
pdfdictionary
{
1220
S
=
pdf_movie
,
1221
T
=
format
(
"
movie %s
"
,
arguments
[
1
]
or
"
noname
"
)
,
1222
Operation
=
operation
,
1223
}
1224
end
1225 1226
function
executers
.
startmovie
(
arguments
)
return
movie_or_sound
(
pdf_start
,
arguments
)
end
1227
function
executers
.
stopmovie
(
arguments
)
return
movie_or_sound
(
pdf_stop
,
arguments
)
end
1228
function
executers
.
resumemovie
(
arguments
)
return
movie_or_sound
(
pdf_resume
,
arguments
)
end
1229
function
executers
.
pausemovie
(
arguments
)
return
movie_or_sound
(
pdf_pause
,
arguments
)
end
1230 1231
function
executers
.
startsound
(
arguments
)
return
movie_or_sound
(
pdf_start
,
arguments
)
end
1232
function
executers
.
stopsound
(
arguments
)
return
movie_or_sound
(
pdf_stop
,
arguments
)
end
1233
function
executers
.
resumesound
(
arguments
)
return
movie_or_sound
(
pdf_resume
,
arguments
)
end
1234
function
executers
.
pausesound
(
arguments
)
return
movie_or_sound
(
pdf_pause
,
arguments
)
end
1235 1236
function
specials
.
action
(
var
)
1237
local
operation
=
var
.
operation
1238
if
var
.
operation
and
operation
~
=
"
"
then
1239
local
e
=
executers
[
operation
]
1240
if
type
(
e
)
=
=
"
table
"
then
1241
return
e
1242
elseif
type
(
e
)
=
=
"
function
"
then
1243
return
e
(
var
.
arguments
)
1244
end
1245
end
1246
end
1247 1248
local
function
build
(
levels
,
start
,
parent
,
method
,
nested
)
1249
local
startlevel
=
levels
[
start
]
.
level
1250
local
noflevels
=
#
levels
1251
local
i
=
start
1252
local
n
=
0
1253
local
child
,
entry
,
m
,
prev
,
first
,
last
,
f
,
l
1254
while
i
and
i
<
=
noflevels
do
1255
local
current
=
levels
[
i
]
1256
if
current
.
usedpage
=
=
false
then
1257
-- safeguard
1258
i
=
i
+
1
1259
else
1260
local
level
=
current
.
level
1261
local
title
=
current
.
title
1262
local
reference
=
current
.
reference
1263
local
opened
=
current
.
opened
1264
local
reftype
=
type
(
reference
)
1265
local
block
=
nil
1266
local
variant
=
"
unknown
"
1267
if
reftype
=
=
"
table
"
then
1268
-- we're okay
1269
variant
=
"
list
"
1270
block
=
reference
.
block
1271
realpage
=
reference
.
realpage
1272
elseif
reftype
=
=
"
string
"
then
1273
local
resolved
=
references
.
identify
(
"
"
,
reference
)
1274
realpage
=
resolved
and
structures
.
references
.
setreferencerealpage
(
resolved
)
or
0
1275
if
realpage
>
0
then
1276
variant
=
"
realpage
"
1277
realpage
=
realpage
1278
reference
=
structures
.
pages
.
collected
[
realpage
]
1279
block
=
reference
and
reference
.
block
1280
end
1281
elseif
reftype
=
=
"
number
"
then
1282
if
reference
>
0
then
1283
variant
=
"
realpage
"
1284
realpage
=
reference
1285
reference
=
structures
.
pages
.
collected
[
realpage
]
1286
block
=
reference
and
reference
.
block
1287
end
1288
else
1289
-- error
1290
end
1291
current
.
block
=
block
1292
if
variant
=
=
"
unknown
"
then
1293
-- error, ignore
1294
i
=
i
+
1
1295
-- elseif (level < startlevel) or (i > 1 and block ~= levels[i-1].reference.block) then
1296
elseif
(
level
<
startlevel
)
or
(
i
>
1
and
block
~
=
levels
[
i
-1
]
.
block
)
then
1297
if
nested
then
-- could be an option but otherwise we quit too soon
1298
if
entry
then
1299
pdfflushobject
(
child
,
entry
)
1300
else
1301
report_bookmarks
(
"
error 1
"
)
1302
end
1303
return
i
,
n
,
first
,
last
1304
else
1305
report_bookmarks
(
"
confusing level change at level %a around %a
"
,
level
,
title
)
1306
startlevel
=
level
1307
end
1308
end
1309
if
level
=
=
startlevel
then
1310
if
trace_bookmarks
then
1311
report_bookmarks
(
"
%3i %w%s %s
"
,
realpage
,
(
level
-1
)
*
2
,
(
opened
and
"
+
"
)
or
"
-
"
,
title
)
1312
end
1313
local
prev
=
child
1314
child
=
pdfreserveobject
(
)
1315
if
entry
then
1316
entry
.
Next
=
child
and
pdfreference
(
child
)
1317
pdfflushobject
(
prev
,
entry
)
1318
end
1319
local
action
=
nil
1320
if
variant
=
=
"
list
"
then
1321
action
=
pdflinkinternal
(
reference
.
internal
,
reference
.
realpage
)
1322
elseif
variant
=
=
"
realpage
"
then
1323
action
=
pagereferences
[
realpage
]
1324
else
1325
-- hm, what to do
1326
end
1327
entry
=
pdfdictionary
{
1328
Title
=
pdfunicode
(
title
)
,
1329
Parent
=
parent
,
1330
Prev
=
prev
and
pdfreference
(
prev
)
,
1331
A
=
action
,
1332
}
1333
-- entry.Dest = pdflinkinternal(reference.internal,reference.realpage)
1334
if
not
first
then
1335
first
,
last
=
child
,
child
1336
end
1337
prev
=
child
1338
last
=
prev
1339
n
=
n
+
1
1340
i
=
i
+
1
1341
elseif
i
<
noflevels
and
level
>
startlevel
then
1342
i
,
m
,
f
,
l
=
build
(
levels
,
i
,
pdfreference
(
child
)
,
method
,
true
)
1343
if
entry
then
1344
entry
.
Count
=
(
opened
and
m
)
or
-
m
1345
if
m
>
0
then
1346
entry
.
First
=
pdfreference
(
f
)
1347
entry
.
Last
=
pdfreference
(
l
)
1348
end
1349
else
1350
report_bookmarks
(
"
error 2
"
)
1351
end
1352
else
1353
-- missing intermediate level but ok
1354
i
,
m
,
f
,
l
=
build
(
levels
,
i
,
pdfreference
(
child
)
,
method
,
true
)
1355
if
entry
then
1356
entry
.
Count
=
(
opened
and
m
)
or
-
m
1357
if
m
>
0
then
1358
entry
.
First
=
pdfreference
(
f
)
1359
entry
.
Last
=
pdfreference
(
l
)
1360
end
1361
pdfflushobject
(
child
,
entry
)
1362
else
1363
report_bookmarks
(
"
error 3
"
)
1364
end
1365
return
i
,
n
,
first
,
last
1366
end
1367
end
1368
end
1369
pdfflushobject
(
child
,
entry
)
1370
return
nil
,
n
,
first
,
last
1371
end
1372 1373
function
codeinjections
.
addbookmarks
(
levels
,
method
)
1374
if
levels
and
#
levels
>
0
then
1375
local
parent
=
pdfreserveobject
(
)
1376
local
_
,
m
,
first
,
last
=
build
(
levels
,
1
,
pdfreference
(
parent
)
,
method
or
"
internal
"
,
false
)
1377
local
dict
=
pdfdictionary
{
1378
Type
=
pdfconstant
(
"
Outlines
"
)
,
1379
First
=
pdfreference
(
first
)
,
1380
Last
=
pdfreference
(
last
)
,
1381
Count
=
m
,
1382
}
1383
pdfflushobject
(
parent
,
dict
)
1384
pdfaddtocatalog
(
"
Outlines
"
,
lpdf
.
reference
(
parent
)
)
1385
end
1386
end
1387 1388
-- this could also be hooked into the frontend finalizer
1389 1390
lpdf
.
registerdocumentfinalizer
(
function
(
)
bookmarks
.
place
(
)
end
,
1
,
"
bookmarks
"
)
-- hm, why indirect call
1391