1if not modules then modules = { } end modules ['anch-pos'] = {
2 version = 1.001,
3 comment = "companion to anch-pos.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
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42local tostring, next, setmetatable, tonumber, rawget, rawset = tostring, next, setmetatable, tonumber, rawget, rawset
43local sort, sortedhash = table.sort, table.sortedhash
44local format, gmatch = string.format, string.gmatch
45local P, R, C, Cc, lpegmatch = lpeg.P, lpeg.R, lpeg.C, lpeg.Cc, lpeg.match
46local insert, remove = table.insert, table.remove
47local allocate = utilities.storage.allocate
48local setmetatableindex, setmetatablenewindex = table.setmetatableindex, table.setmetatablenewindex
49
50local report = logs.reporter("positions")
51
52local scanners = tokens.scanners
53local scanstring = scanners.string
54local scaninteger = scanners.integer
55local scandimen = scanners.dimen
56
57local implement = interfaces.implement
58
59local commands = commands
60local context = context
61
62local ctx_latelua = context.latelua
63
64local ctx_doif = commands.doif
65local ctx_doifelse = commands.doifelse
66
67local tex = tex
68local texgetdimen = tex.getdimen
69local texgetcount = tex.getcount
70local texgetinteger = tex.getintegervalue or tex.getcount
71local texiscount = tex.iscount
72local texisdimen = tex.isdimen
73local texsetcount = tex.setcount
74local texget = tex.get
75local texsp = tex.sp
76
77local texgetnest = tex.getnest
78local texgetparstate = tex.getparstate
79
80local nuts = nodes.nuts
81local tonut = nodes.tonut
82
83local setlink = nuts.setlink
84local getlist = nuts.getlist
85local setlist = nuts.setlist
86local getbox = nuts.getbox
87local getid = nuts.getid
88local getwhd = nuts.getwhd
89local setprop = nuts.setprop
90
91local getparstate = nuts.getparstate
92
93local hlist_code = nodes.nodecodes.hlist
94local par_code = nodes.nodecodes.par
95
96local find_tail = nuts.tail
97
98
99local new_latelua = nuts.pool.latelua
100
101local variables = interfaces.variables
102local v_text = variables.text
103local v_column = variables.column
104
105local pt = number.dimenfactors.pt
106local pts = number.pts
107local formatters = string.formatters
108
109local collected = allocate()
110local tobesaved = allocate()
111local positionsused = nil
112
113local jobpositions = {
114 collected = collected,
115 tobesaved = tobesaved,
116}
117
118job.positions = jobpositions
119
120local default = {
121 __index = {
122 x = 0,
123 y = 0,
124 w = 0,
125 h = 0,
126 d = 0,
127 p = 0,
128 n = 0,
129 ls = 0,
130 rs = 0,
131 hi = 0,
132 ha = 0,
133 hs = 0,
134 pi = 0,
135 ps = false,
136 dir = 0,
137 r2l = false,
138 }
139}
140
141local f_b_tag = formatters["b:%s"]
142local f_e_tag = formatters["e:%s"]
143local f_p_tag = formatters["p:%s"]
144
145
146local f_region = formatters["region:%s"]
147
148local f_tag_three = formatters["%s:%s:%s"]
149local f_tag_two = formatters["%s:%s"]
150
151local c_realpageno = texiscount("realpageno")
152local d_strutht = texisdimen("strutht")
153local d_strutdp = texisdimen("strutdp")
154
155
156
157
158local treemode = false
159local treemode = true
160
161local function checkshapes(s)
162 for p, data in next, s do
163 local n = #data
164 if n > 1 then
165 local d1 = data[1]
166 local ph = d1[2]
167 local pd = d1[3]
168 local xl = d1[4]
169 local xr = d1[5]
170 for i=2,n do
171 local di = data[i]
172 local h = di[2]
173 local d = di[3]
174 local l = di[4]
175 local r = di[5]
176 if r == xr then
177 di[5] = nil
178 if l == xl then
179 di[4] = nil
180 if d == pd then
181 di[3] = nil
182 if h == ph then
183 di[2] = nil
184 else
185 ph = h
186 end
187 else
188 pd, ph = d, h
189 end
190 else
191 ph, pd, xl = h, d, l
192 end
193 else
194 ph, pd, xl, xr = h, d, l, r
195 end
196 end
197 end
198 end
199end
200
201local columndata = { }
202local freedata = { }
203local syncdata = { }
204local columndone = false
205
206if treemode then
207
208
209
210
211
212
213
214
215
216
217
218
219 local prefix_number = { "text", "textarea", "page", "p", "free", "columnarea" }
220 local prefix_label_number = { "syncpos" }
221 local prefix_number_rest = { "region", "b", "e" }
222
223
224
225 local function splitter_pattern()
226 local p_number = R("09")^1/tonumber
227 local p_colon = P(":")
228 local p_label = C(P(1 - p_colon)^0)
229 local p_rest = C(P(1)^0)
230 return
231 C(lpeg.utfchartabletopattern(prefix_number )) * p_colon * p_number * P(-1)
232 + C(lpeg.utfchartabletopattern(prefix_label_number)) * p_colon * (p_number + p_label) * p_colon * p_number * P(-1)
233 + C(lpeg.utfchartabletopattern(prefix_number_rest )) * p_colon * (p_number + p_rest)
234 + Cc("user") * p_rest
235 end
236
237
238
239
240 columndata = { }
241 columndone = false
242
243 local deltapacking = true
244
245
246 local function checkcommondata(v,common)
247 if common then
248 local i = v.i
249 local t = common[i]
250 if t then
251v.i = nil
252 local m = t.mt
253 if not m then
254 setmetatable(t,default)
255 m = { __index = t }
256 t.mt = m
257 end
258 setmetatable(v,m)
259 return
260 end
261 end
262 setmetatable(v,default)
263 end
264
265 local function initializer()
266 tobesaved = jobpositions.tobesaved
267 collected = jobpositions.collected
268
269 local p_splitter = splitter_pattern()
270
271 local list = nil
272
273 local shared = setmetatableindex(rawget(collected,"shared"),"table")
274 local x_y_w_h_list = shared.x_y_w_h
275 local y_w_h_d_list = shared.y_w_h_d
276 local x_h_d_list = shared.x_h_d
277 local x_h_d_hs_list = shared.x_h_d_hs
278
279 columndata = setmetatableindex(function(t,k)
280 setmetatableindex(t,"table")
281 list = rawget(collected,"columnarea")
282 if list then
283
284 for i=1,#list do
285 local data = list[i]
286 columndata[data.p or 0][data.c or 0] = data
287 checkcommondata(data,y_w_h_d_list)
288 end
289 end
290 columndone = true
291 return t[k]
292 end)
293
294
295
296 setmetatableindex(collected,function(t,k)
297 if k ~= true then
298 local prefix, one, two = lpegmatch(p_splitter,k)
299 local list = rawget(t,prefix)
300 if list and type(list) == "table" then
301 local v = list[one] or false
302 if v then
303 if prefix == "p" then
304
305 if type(v) == "number" then
306 for i=one,1,-1 do
307 local l = list[i]
308 if type(l) ~= "number" then
309 if not getmetatable(l) then
310 checkcommondata(l,x_h_d_hs_list)
311 end
312 v = setmetatable({ y = v }, { __index = l })
313 list[one] = v
314 break
315 end
316 end
317 else
318 checkcommondata(v,x_h_d_hs_list)
319 end
320 elseif prefix == "text" or prefix == "textarea" then
321 if type(v) == "number" then
322 for i=one,1,-1 do
323 local l = list[i]
324 if type(l) ~= "number" then
325 if not getmetatable(l) then
326 checkcommondata(l,x_y_w_h_list)
327 end
328 v = setmetatable({ p = v }, { __index = l })
329 list[one] = v
330 break
331 end
332 end
333 else
334 checkcommondata(v,x_y_w_h_list)
335 end
336 elseif prefix == "columnarea" then
337 if not columndone then
338 checkcommondata(v,y_w_h_d_list)
339 end
340 elseif prefix == "syncpos" then
341
342 if two then
343
344 v = v[two] or { }
345 else
346 v = { }
347 end
348
349
350
351 elseif prefix == "free" then
352
353 elseif prefix == "page" then
354 checkcommondata(v)
355 else
356 checkcommondata(v)
357 end
358 else
359 if prefix == "page" then
360 for i=one,1,-1 do
361 local data = list[i]
362 if data then
363 v = setmetatableindex({ free = free or false, p = p },last)
364 list[one] = v
365 break
366 end
367 end
368 end
369 end
370 t[k] = v
371 return v
372 end
373 end
374 t[k] = false
375 return false
376 end)
377
378 setmetatableindex(tobesaved,function(t,k)
379 local prefix, one, two = lpegmatch(p_splitter,k)
380 local v = rawget(t,prefix)
381 if v and type(v) == "table" then
382 v = v[one]
383 if v and two then
384 v = v[two]
385 end
386 return v
387 else
388
389 end
390 end)
391
392 setmetatablenewindex(tobesaved,function(t,k,v)
393 local prefix, one, two = lpegmatch(p_splitter,k)
394 local p = rawget(t,prefix)
395 if not p then
396 p = { }
397 rawset(t,prefix,p)
398 end
399 if type(one) == "number" then
400 if #p < one then
401 for i=#p+1,one-1 do
402 p[i] = { }
403 end
404 end
405 end
406 if two then
407 local pone = p[one]
408 if not pone then
409 pone = { }
410 p[one] = pone
411 end
412 if type(two) == "number" then
413 if #pone < two then
414 for i=#pone+1,two-1 do
415 pone[i] = { }
416 end
417 end
418 end
419 pone[two] = v
420 else
421 p[one] = v
422 end
423 end)
424
425 syncdata = setmetatableindex(function(t,category)
426
427 local list = rawget(collected,"syncpos")
428 local tc = list and rawget(list,category)
429 if tc then
430 sort(tc,function(a,b)
431 local ap = a.p
432 local bp = b.p
433 if ap == bp then
434 return b.y < a.y
435 else
436 return ap < bp
437 end
438 end)
439 tc.start = 1
440 for i=1,#tc do
441 checkcommondata(tc[i],x_h_d_list)
442 end
443 else
444 tc = { }
445 end
446 t[category] = tc
447 return tc
448 end)
449 end
450
451 local function finalizer()
452
453
454
455
456
457 local nofpositions = 0
458 local nofpartials = 0
459 local nofdeltas = 0
460
461 local x_y_w_h_size = 0
462 local x_y_w_h_list = { }
463 local x_y_w_h_hash = setmetatableindex(function(t,x)
464 local y = setmetatableindex(function(t,y)
465 local w = setmetatableindex(function(t,w)
466 local h = setmetatableindex(function(t,h)
467 x_y_w_h_size = x_y_w_h_size + 1
468 t[h] = x_y_w_h_size
469 x_y_w_h_list[x_y_w_h_size] = { x = x, y = y, w = w, h = h }
470 return x_y_w_h_size
471 end)
472 t[w] = h
473 return h
474 end)
475 t[y] = w
476 return w
477 end)
478 t[x] = y
479 return y
480 end)
481
482 local y_w_h_d_size = 0
483 local y_w_h_d_list = { }
484 local y_w_h_d_hash = setmetatableindex(function(t,y)
485 local w = setmetatableindex(function(t,w)
486 local h = setmetatableindex(function(t,h)
487 local d = setmetatableindex(function(t,d)
488 y_w_h_d_size = y_w_h_d_size + 1
489 t[d] = y_w_h_d_size
490 y_w_h_d_list[y_w_h_d_size] = { y = y, w = w, h = h, d = d }
491 return y_w_h_d_size
492 end)
493 t[h] = d
494 return d
495 end)
496 t[w] = h
497 return h
498 end)
499 t[y] = w
500 return w
501 end)
502
503 local x_h_d_size = 0
504 local x_h_d_list = { }
505 local x_h_d_hash = setmetatableindex(function(t,x)
506 local h = setmetatableindex(function(t,h)
507 local d = setmetatableindex(function(t,d)
508 x_h_d_size = x_h_d_size + 1
509 t[d] = x_h_d_size
510 x_h_d_list[x_h_d_size] = { x = x, h = h, d = d }
511 return x_h_d_size
512 end)
513 t[h] = d
514 return d
515 end)
516 t[x] = h
517 return h
518 end)
519
520 local x_h_d_hs_size = 0
521 local x_h_d_hs_list = { }
522 local x_h_d_hs_hash = setmetatableindex(function(t,x)
523 local h = setmetatableindex(function(t,h)
524 local d = setmetatableindex(function(t,d)
525 local hs = setmetatableindex(function(t,hs)
526 x_h_d_hs_size = x_h_d_hs_size + 1
527 t[hs] = x_h_d_hs_size
528 x_h_d_hs_list[x_h_d_hs_size] = { x = x, h = h, d = d, hs = hs }
529 return x_h_d_hs_size
530 end)
531 t[d] = hs
532 return hs
533 end)
534 t[h] = d
535 return d
536 end)
537 t[x] = h
538 return h
539 end)
540
541 rawset(tobesaved,"shared", {
542 x_y_w_h = x_y_w_h_list,
543 y_w_h_d = y_w_h_d_list,
544 x_h_d = x_h_d_list,
545 x_h_d_hs = x_h_d_hs_list,
546 })
547
548
549
550
551
552
553 for k, v in sortedhash(tobesaved) do
554 if k == "p" then
555
556 local n = #v
557 for i=1,n do
558 local t = v[i]
559 local hsh = x_h_d_hs_hash[t.x or 0][t.h or 0][t.d or 0][t.hs or 0]
560 t.x = nil
561 t.h = nil
562 t.d = nil
563 t.hs = nil
564 t.i = hsh
565 local s = t.s
566 if s then
567 checkshapes(s)
568 end
569 end
570 if deltapacking then
571
572 local last
573 local current
574 for i=1,n do
575 current = v[i]
576 if last then
577 for k, v in next, last do
578 if k ~= "y" and v ~= current[k] then
579 goto DIFFERENT
580 end
581 end
582 for k, v in next, current do
583 if k ~= "y" and v ~= last[k] then
584 goto DIFFERENT
585 end
586 end
587 v[i] = current.y or 0
588 nofdeltas = nofdeltas + 1
589 goto CONTINUE
590 end
591 ::DIFFERENT::
592 last = current
593 ::CONTINUE::
594 end
595 end
596
597 nofpositions = nofpositions + n
598 nofpartials = nofpartials + n
599 elseif k == "syncpos" then
600
601 for k, t in next, v do
602
603 local n = #t
604 for j=1,n do
605 local t = t[j]
606 local hsh = x_h_d_hash[t.x or 0][t.h or 0][t.d or 0]
607 t.x = nil
608 t.h = nil
609 t.d = nil
610 t.i = hsh
611 end
612 nofpositions = nofpositions + n
613 nofpartials = nofpartials + n
614 end
615 elseif k == "text" or k == "textarea" then
616
617 local n = #v
618 for i=1,n do
619 local t = v[i]
620 local hsh = x_y_w_h_hash[t.x or 0][t.y or 0][t.w or 0][t.h or 0]
621 t.x = nil
622 t.y = nil
623 t.w = nil
624 t.h = nil
625 t.i = hsh
626 end
627 nofpositions = nofpositions + n
628 nofpartials = nofpartials + n
629 if deltapacking then
630
631 local last
632 local current
633 for i=1,n do
634 current = v[i]
635 if last then
636 for k, v in next, last do
637 if k ~= "p" and v ~= current[k] then
638 goto DIFFERENT
639 end
640 end
641 for k, v in next, current do
642 if k ~= "p" and v ~= last[k] then
643 goto DIFFERENT
644 end
645 end
646 v[i] = current.p or 0
647 nofdeltas = nofdeltas + 1
648 goto CONTINUE
649 end
650 ::DIFFERENT::
651 last = current
652 ::CONTINUE::
653 end
654 end
655 elseif k == "columnarea" then
656
657 local n = #v
658 for i=1,n do
659 local t = v[i]
660 local hsh = y_w_h_d_hash[t.y or 0][t.w or 0][t.h or 0][t.d or 0]
661 t.y = nil
662 t.w = nil
663 t.h = nil
664 t.d = nil
665 t.i = hsh
666 end
667 nofpositions = nofpositions + n
668 nofpartials = nofpartials + n
669 else
670 for k, t in next, v do
671 local s = t.s
672 if s then
673 checkshapes(s)
674 end
675 nofpositions = nofpositions + 1
676 end
677 end
678 end
679
680 statistics.register("positions", function()
681 if nofpositions > 0 then
682 return format("%s collected, %i deltas, %i shared partials, %i partial entries",
683 nofpositions, nofdeltas, nofpartials,
684 x_y_w_h_size + y_w_h_d_size + x_h_d_size + x_h_d_hs_size
685 )
686 else
687 return nil
688 end
689 end)
690
691 end
692
693 freedata = setmetatableindex(function(t,page)
694 local list = rawget(collected,"free")
695 local free = { }
696 if list then
697 local size = 0
698 for i=1,#list do
699 local l = list[i]
700 if l.p == page then
701 size = size + 1
702 free[size] = l
703 checkcommondata(l)
704 end
705 end
706 sort(free,function(a,b) return b.y < a.y end)
707 end
708 t[page] = free
709 return free
710 end)
711
712 job.register('job.positions.collected', tobesaved, initializer, finalizer)
713
714else
715
716 columndata = setmetatableindex("table")
717 freedata = setmetatableindex("table")
718
719 local function initializer()
720 tobesaved = jobpositions.tobesaved
721 collected = jobpositions.collected
722
723 local pagedata = { }
724 local p_splitter = lpeg.splitat(":",true)
725
726 for tag, data in next, collected do
727 local prefix, rest = lpegmatch(p_splitter,tag)
728 if prefix == "page" then
729 pagedata[tonumber(rest) or 0] = data
730 elseif prefix == "free" then
731 local t = freedata[data.p or 0]
732 t[#t+1] = data
733 elseif prefix == "columnarea" then
734 columndata[data.p or 0][data.c or 0] = data
735 end
736 setmetatable(data,default)
737 end
738 local pages = structures.pages.collected
739 if pages then
740 local last = nil
741 for p=1,#pages do
742 local region = "page:" .. p
743 local data = pagedata[p]
744 local free = freedata[p]
745 if free then
746 sort(free,function(a,b) return b.y < a.y end)
747 end
748 if data then
749 last = data
750 last.free = free
751 elseif last then
752 local t = setmetatableindex({ free = free, p = p },last)
753 if not collected[region] then
754 collected[region] = t
755 else
756
757 end
758 pagedata[p] = t
759 end
760 end
761 end
762 jobpositions.pagedata = pagedata
763
764 end
765
766 local function finalizer()
767
768
769
770
771
772 local nofpositions = 0
773
774 for k, v in next, tobesaved do
775 local s = v.s
776 if s then
777 checkshapes(s)
778 end
779 nofpositions = nofpositions + 1
780 end
781
782 statistics.register("positions", function()
783 if nofpositions > 0 then
784 return format("%s collected",nofpositions)
785 else
786 return nil
787 end
788 end)
789
790 end
791
792 local p_number = lpeg.patterns.cardinal/tonumber
793 local p_tag = P("syncpos:") * p_number * P(":") * p_number
794
795 syncdata = setmetatableindex(function(t,category)
796 setmetatable(t,nil)
797 for tag, pos in next, collected do
798 local c, n = lpegmatch(p_tag,tag)
799 if c then
800 local tc = t[c]
801 if tc then
802 tc[n] = pos
803 else
804 t[c] = { [n] = pos }
805 end
806 end
807 end
808 for k, list in next, t do
809 sort(list,function(a,b)
810 local ap = a.p
811 local bp = b.p
812 if ap == bp then
813 return b.y < a.y
814 else
815 return ap < bp
816 end
817 end)
818 list.start = 1
819 end
820 return t[category]
821 end)
822
823 job.register('job.positions.collected', tobesaved, initializer, finalizer)
824
825end
826
827function jobpositions.used()
828 if positionsused == nil then
829 positionsused = false
830 for k, v in next, collected do
831 if k ~= "shared" and type(v) == "table" and next(v) then
832 positionsused = true
833 break
834 end
835 end
836 end
837 return positionsused
838end
839
840function jobpositions.getfree(page)
841 return freedata[page]
842end
843
844function jobpositions.getsync(category)
845 return syncdata[category] or { }
846end
847
848local regions = { }
849local nofregions = 0
850local region = nil
851
852local columns = { }
853local nofcolumns = 0
854local column = nil
855
856local nofpages = nil
857
858
859
860local getpos, gethpos, getvpos, getrpos
861
862function jobpositions.registerhandlers(t)
863 getpos = t and t.getpos or function() return 0, 0 end
864 getrpos = t and t.getrpos or function() return 0, 0, 0 end
865 gethpos = t and t.gethpos or function() return 0 end
866 getvpos = t and t.getvpos or function() return 0 end
867end
868
869function jobpositions.getpos () return getpos () end
870function jobpositions.getrpos() return getrpos() end
871function jobpositions.gethpos() return gethpos() end
872function jobpositions.getvpos() return getvpos() end
873
874
875
876jobpositions.registerhandlers()
877
878local function setall(name,p,x,y,w,h,d,extra)
879 tobesaved[name] = {
880 p = p,
881 x = x ~= 0 and x or nil,
882 y = y ~= 0 and y or nil,
883 w = w ~= 0 and w or nil,
884 h = h ~= 0 and h or nil,
885 d = d ~= 0 and d or nil,
886 e = extra ~= "" and extra or nil,
887 r = region,
888 c = column,
889 r2l = texgetinteger("inlinelefttoright") == 1 and true or nil,
890 }
891end
892
893local function enhance(data)
894 if not data then
895 return nil
896 end
897 if data.r == true then
898 data.r = region
899 end
900 if data.x == true then
901 if data.y == true then
902 local x, y = getpos()
903 data.x = x ~= 0 and x or nil
904 data.y = y ~= 0 and y or nil
905 else
906 local x = gethpos()
907 data.x = x ~= 0 and x or nil
908 end
909 elseif data.y == true then
910 local y = getvpos()
911 data.y = y ~= 0 and y or nil
912 end
913 if data.p == true then
914 data.p = texgetcount(c_realpageno)
915 end
916 if data.c == true then
917 data.c = column
918 end
919 if data.w == 0 then
920 data.w = nil
921 end
922 if data.h == 0 then
923 data.h = nil
924 end
925 if data.d == 0 then
926 data.d = nil
927 end
928 return data
929end
930
931
932
933
934local function set(name,index,value)
935
936 local data = enhance(value or {})
937 if value then
938 container = tobesaved[name]
939 if not container then
940 tobesaved[name] = {
941 [index] = data
942 }
943 else
944 container[index] = data
945 end
946 else
947 tobesaved[name] = data
948 end
949end
950
951local function setspec(specification)
952 local name = specification.name
953 local index = specification.index
954 local value = specification.value
955 local data = enhance(value or {})
956 if value then
957 container = tobesaved[name]
958 if not container then
959 tobesaved[name] = {
960 [index] = data
961 }
962 else
963 container[index] = data
964 end
965 else
966 tobesaved[name] = data
967 end
968end
969
970local function get(id,index)
971 if index then
972 local container = collected[id]
973 return container and container[index]
974 else
975 return collected[id]
976 end
977end
978
979
980jobpositions.setall = setall
981jobpositions.set = set
982jobpositions.setspec = setspec
983jobpositions.get = get
984
985implement {
986 name = "dosaveposition",
987 public = true,
988 protected = true,
989 arguments = { "argument", "integerargument", "dimenargument", "dimenargument" },
990 actions = setall,
991}
992
993implement {
994 name = "dosavepositionwhd",
995 public = true,
996 protected = true,
997 arguments = { "argument", "integerargument", "dimenargument", "dimenargument", "dimenargument", "dimenargument", "dimenargument" },
998 actions = setall,
999}
1000
1001implement {
1002 name = "dosavepositionplus",
1003 public = true,
1004 protected = true,
1005 arguments = { "argument", "integerargument", "dimenargument", "dimenargument", "dimenargument", "dimenargument", "dimenargument", "argument" },
1006 actions = setall,
1007}
1008
1009
1010
1011
1012
1013
1014local function b_column(specification)
1015 local tag = specification.tag
1016 local x = gethpos()
1017 tobesaved[tag] = {
1018 r = true,
1019 x = x ~= 0 and x or nil,
1020
1021 }
1022 insert(columns,tag)
1023 column = tag
1024end
1025
1026local function e_column()
1027 local t = tobesaved[column]
1028 if not t then
1029
1030 else
1031 local x = gethpos() - t.x
1032 t.w = x ~= 0 and x or nil
1033 t.r = region
1034 end
1035 remove(columns)
1036 column = columns[#columns]
1037end
1038
1039jobpositions.b_column = b_column
1040jobpositions.e_column = e_column
1041
1042implement {
1043 name = "bposcolumn",
1044 arguments = "string",
1045 actions = function(tag)
1046 insert(columns,tag)
1047 column = tag
1048 end
1049}
1050
1051implement {
1052 name = "bposcolumnregistered",
1053 arguments = "string",
1054 actions = function(tag)
1055 insert(columns,tag)
1056 column = tag
1057 ctx_latelua { action = b_column, tag = tag }
1058 end
1059}
1060
1061implement {
1062 name = "eposcolumn",
1063 actions = function()
1064 remove(columns)
1065 column = columns[#columns]
1066 end
1067}
1068
1069implement {
1070 name = "eposcolumnregistered",
1071 actions = function()
1072 ctx_latelua { action = e_column }
1073 remove(columns)
1074 column = columns[#columns]
1075 end
1076}
1077
1078
1079
1080local function b_region(specification)
1081 local tag = specification.tag or specification
1082 local last = tobesaved[tag]
1083 if last then
1084 local x, y = getpos()
1085 last.x = x ~= 0 and x or nil
1086 last.y = y ~= 0 and y or nil
1087 last.p = texgetcount(c_realpageno)
1088 insert(regions,tag)
1089 region = tag
1090 end
1091end
1092
1093local function e_region(specification)
1094 local last = tobesaved[region]
1095 if last then
1096 local y = getvpos()
1097 if specification.correct then
1098 local h = (last.y or 0) - y
1099 last.h = h ~= 0 and h or nil
1100 end
1101 last.y = y ~= 0 and y or nil
1102 remove(regions)
1103 region = regions[#regions]
1104 end
1105end
1106
1107jobpositions.b_region = b_region
1108jobpositions.e_region = e_region
1109
1110local lastregion
1111
1112local function setregionbox(n,tag,index,k,lo,ro,to,bo,column)
1113 if not tag or tag == "" then
1114 nofregions = nofregions + 1
1115 tag = "region"
1116 index = nofregions
1117 elseif index ~= 0 then
1118
1119
1120 tag = tag .. ":" .. index
1121 end
1122 local box = getbox(n)
1123 local w, h, d = getwhd(box)
1124
1125
1126
1127
1128 tobesaved[tag] = {
1129
1130 x = 0,
1131 y = 0,
1132 w = w ~= 0 and w or nil,
1133 h = h ~= 0 and h or nil,
1134 d = d ~= 0 and d or nil,
1135 k = k ~= 0 and k or nil,
1136 lo = lo ~= 0 and lo or nil,
1137 ro = ro ~= 0 and ro or nil,
1138 to = to ~= 0 and to or nil,
1139 bo = bo ~= 0 and bo or nil,
1140 c = column or nil,
1141 }
1142 lastregion = tag
1143 return tag, box
1144end
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156local function markregionbox(n,tag,index,correct,...)
1157 local tag, box = setregionbox(n,tag,index,...)
1158
1159 local push = new_latelua { action = b_region, tag = tag }
1160 local pop = new_latelua { action = e_region, correct = correct }
1161
1162 local head = getlist(box)
1163
1164
1165
1166
1167
1168 if head then
1169 local tail = find_tail(head)
1170 setlink(push,head)
1171 setlink(tail,pop)
1172 else
1173 setlink(push,pop)
1174 end
1175 setlist(box,push)
1176end
1177
1178jobpositions.markregionbox = markregionbox
1179jobpositions.setregionbox = setregionbox
1180
1181function jobpositions.enhance(name)
1182 enhance(tobesaved[name])
1183end
1184
1185function jobpositions.gettobesaved(name,tag)
1186 local t = tobesaved[name]
1187 if t and tag then
1188 return t[tag]
1189 else
1190 return t
1191 end
1192end
1193
1194function jobpositions.settobesaved(name,tag,data)
1195 local t = tobesaved[name]
1196 if t and tag and data then
1197 t[tag] = data
1198 end
1199end
1200
1201do
1202
1203 local c_anch_positions_paragraph = texiscount("c_anch_positions_paragraph")
1204
1205 local nofparagraphs = 0
1206
1207 local function enhancepar_1(data)
1208 if data then
1209 local par = data.par
1210 local state = par and getparstate(data.par,true)
1211 if state then
1212 local x, y = getpos()
1213 if x ~= 0 then
1214 data.x = x
1215 end
1216 if y ~= 0 then
1217 data.y = y
1218 end
1219 data.p = texgetcount(c_realpageno)
1220 if column then
1221 data.c = column
1222 end
1223 if region then
1224 data.r = region
1225 end
1226
1227 data.par = nil
1228 local leftskip = state.leftskip
1229 local rightskip = state.rightskip
1230 local hangindent = state.hangindent
1231 local hangafter = state.hangafter
1232 local parindent = state.parindent
1233 local parshape = state.parshape
1234 if hangafter ~= 0 and hangafter ~= 1 then
1235 data.ha = hangafter
1236 end
1237 if hangindent ~= 0 then
1238 data.hi = hangindent
1239 end
1240 data.hs = state.hsize
1241 if leftskip ~= 0 then
1242 data.ls = leftskip
1243 end
1244 if parindent ~= 0 then
1245 data.pi = parindent
1246 end
1247 if rightskip ~= 0 then
1248 data.rs = rightskip
1249 end
1250 if parshape and #parshape > 0 then
1251 data.ps = parshape
1252 end
1253 end
1254 end
1255 return data
1256 end
1257
1258 local function enhancepar_2(data)
1259 if data then
1260 local x, y = getpos()
1261 if x ~= 0 then
1262 data.x = x
1263 end
1264 if y ~= 0 then
1265 data.y = y
1266 end
1267 data.p = texgetcount(c_realpageno)
1268 if column then
1269 data.c = column
1270 end
1271 if region then
1272 data.r = region
1273 end
1274 end
1275 return data
1276 end
1277
1278 implement {
1279 name = "parpos",
1280 actions = function()
1281 nofparagraphs = nofparagraphs + 1
1282 texsetcount("global",c_anch_positions_paragraph,nofparagraphs)
1283 local name = f_p_tag(nofparagraphs)
1284 local h = texgetdimen(d_strutht)
1285 local d = texgetdimen(d_strutdp)
1286
1287 local top = texgetnest("top","head")
1288 local nxt = top.next
1289 if nxt then
1290 nxt = tonut(nxt)
1291 end
1292 local data
1293 if nxt and getid(nxt) == par_code then
1294 local t = {
1295 h = h,
1296 d = d,
1297 par = nxt,
1298 }
1299 tobesaved[name] = t
1300 ctx_latelua { action = enhancepar_1, specification = t }
1301 else
1302
1303
1304 local state = texgetparstate()
1305 local leftskip = state.leftskip
1306 local rightskip = state.rightskip
1307 local hangindent = state.hangindent
1308 local hangafter = state.hangafter
1309 local parindent = state.parindent
1310 local parshape = state.parshape
1311 local t = {
1312 p = true,
1313 c = true,
1314 r = true,
1315 x = true,
1316 y = true,
1317 h = h,
1318 d = d,
1319 hs = state.hsize,
1320 }
1321 if leftskip ~= 0 then
1322 t.ls = leftskip
1323 end
1324 if rightskip ~= 0 then
1325 t.rs = rightskip
1326 end
1327 if hangindent ~= 0 then
1328 t.hi = hangindent
1329 end
1330 if hangafter ~= 1 and hangafter ~= 0 then
1331 t.ha = hangafter
1332 end
1333 if parindent ~= 0 then
1334 t.pi = parindent
1335 end
1336 if parshape and #parshape > 0 then
1337 t.ps = parshape
1338 end
1339 tobesaved[name] = t
1340 ctx_latelua { action = enhancepar_2, specification = t }
1341 end
1342 end
1343 }
1344
1345 implement {
1346 name = "dosetposition",
1347 arguments = "argument",
1348 public = true,
1349 protected = true,
1350 actions = function(name)
1351 local spec = {
1352 p = true,
1353 c = column,
1354 r = true,
1355 x = true,
1356 y = true,
1357 n = nofparagraphs > 0 and nofparagraphs or nil,
1358 r2l = texgetinteger("inlinelefttoright") == 1 or nil,
1359 }
1360 tobesaved[name] = spec
1361 ctx_latelua { action = enhance, specification = spec }
1362 end
1363 }
1364
1365 implement {
1366 name = "dosetpositionwhd",
1367 arguments = { "argument", "dimenargument", "dimenargument", "dimenargument" },
1368 public = true,
1369 protected = true,
1370 actions = function(name,w,h,d)
1371 local spec = {
1372 p = true,
1373 c = column,
1374 r = true,
1375 x = true,
1376 y = true,
1377 w = w ~= 0 and w or nil,
1378 h = h ~= 0 and h or nil,
1379 d = d ~= 0 and d or nil,
1380 n = nofparagraphs > 0 and nofparagraphs or nil,
1381 r2l = texgetinteger("inlinelefttoright") == 1 or nil,
1382 }
1383 tobesaved[name] = spec
1384 ctx_latelua { action = enhance, specification = spec }
1385 end
1386 }
1387
1388 implement {
1389 name = "dosetpositionbox",
1390 arguments = { "argument", "integerargument" },
1391 public = true,
1392 protected = true,
1393 actions = function(name,n)
1394 local box = getbox(n)
1395 local w, h, d = getwhd(box)
1396 local spec = {
1397 p = true,
1398 c = column,
1399 r = true,
1400 x = true,
1401 y = true,
1402 w = w ~= 0 and w or nil,
1403 h = h ~= 0 and h or nil,
1404 d = d ~= 0 and d or nil,
1405 n = nofparagraphs > 0 and nofparagraphs or nil,
1406 r2l = texgetinteger("inlinelefttoright") == 1 or nil,
1407 }
1408 tobesaved[name] = spec
1409 ctx_latelua { action = enhance, specification = spec }
1410 end
1411 }
1412
1413 implement {
1414 name = "dosetpositionplus",
1415 arguments = { "argument", "dimenargument", "dimenargument", "dimenargument" },
1416 public = true,
1417 protected = true,
1418 actions = function(name,w,h,d)
1419 local spec = {
1420 p = true,
1421 c = column,
1422 r = true,
1423 x = true,
1424 y = true,
1425 w = w ~= 0 and w or nil,
1426 h = h ~= 0 and h or nil,
1427 d = d ~= 0 and d or nil,
1428 n = nofparagraphs > 0 and nofparagraphs or nil,
1429 e = scanstring(),
1430 r2l = texgetinteger("inlinelefttoright") == 1 or nil,
1431 }
1432 tobesaved[name] = spec
1433 ctx_latelua { action = enhance, specification = spec }
1434 end
1435 }
1436
1437 implement {
1438 name = "dosetpositionstrut",
1439 arguments = "argument",
1440 public = true,
1441 protected = true,
1442 actions = function(name)
1443 local h = texgetdimen(d_strutht)
1444 local d = texgetdimen(d_strutdp)
1445 local spec = {
1446 p = true,
1447 c = column,
1448 r = true,
1449 x = true,
1450 y = true,
1451 h = h ~= 0 and h or nil,
1452 d = d ~= 0 and d or nil,
1453 n = nofparagraphs > 0 and nofparagraphs or nil,
1454 r2l = texgetinteger("inlinelefttoright") == 1 or nil,
1455 }
1456 tobesaved[name] = spec
1457 ctx_latelua { action = enhance, specification = spec }
1458 end
1459 }
1460
1461 implement {
1462 name = "dosetpositionstrutkind",
1463 arguments = { "argument", "integerargument" },
1464 public = true,
1465 protected = true,
1466 actions = function(name,kind)
1467 local h = texgetdimen(d_strutht)
1468 local d = texgetdimen(d_strutdp)
1469 local spec = {
1470 k = kind,
1471 p = true,
1472 c = column,
1473 r = true,
1474 x = true,
1475 y = true,
1476 h = h ~= 0 and h or nil,
1477 d = d ~= 0 and d or nil,
1478 n = nofparagraphs > 0 and nofparagraphs or nil,
1479 r2l = texgetinteger("inlinelefttoright") == 1 or nil,
1480 }
1481 tobesaved[name] = spec
1482 ctx_latelua { action = enhance, specification = spec }
1483 end
1484 }
1485
1486end
1487
1488function jobpositions.getreserved(tag,n)
1489 if tag == v_column then
1490 local fulltag = f_tag_three(tag,texgetcount(c_realpageno),n or 1)
1491 local data = collected[fulltag]
1492 if data then
1493 return data, fulltag
1494 end
1495 tag = v_text
1496 end
1497 if tag == v_text then
1498 local fulltag = f_tag_two(tag,texgetcount(c_realpageno))
1499 return collected[fulltag] or false, fulltag
1500 end
1501 return collected[tag] or false, tag
1502end
1503
1504function jobpositions.copy(target,source)
1505 collected[target] = collected[source]
1506end
1507
1508function jobpositions.replace(id,p,x,y,w,h,d)
1509 local c = collected[id]
1510 if c then
1511 c.p = p ; c.x = x ; c.y = y ; c.w = w ; c.h = h ; c.d = d ;
1512 else
1513 collected[i] = { p = p, x = x, y = y, w = w, h = h, d = d }
1514 end
1515end
1516
1517local function getpage(id)
1518 local jpi = collected[id]
1519 return jpi and jpi.p
1520end
1521
1522local function getcolumn(id)
1523 local jpi = collected[id]
1524 return jpi and jpi.c or false
1525end
1526
1527local function getparagraph(id)
1528 local jpi = collected[id]
1529 return jpi and jpi.n
1530end
1531
1532local function getregion(id)
1533 local jpi = collected[id]
1534 if jpi then
1535 local r = jpi.r
1536 if r then
1537 return r
1538 end
1539 local p = jpi.p
1540 if p then
1541 return "page:" .. p
1542 end
1543 end
1544 return false
1545end
1546
1547jobpositions.page = getpage
1548jobpositions.column = getcolumn
1549jobpositions.paragraph = getparagraph
1550jobpositions.region = getregion
1551
1552jobpositions.p = getpage
1553jobpositions.c = getcolumn
1554jobpositions.n = getparagraph
1555jobpositions.r = getregion
1556
1557function jobpositions.x(id)
1558 local jpi = collected[id]
1559 return jpi and jpi.x
1560end
1561
1562function jobpositions.y(id)
1563 local jpi = collected[id]
1564 return jpi and jpi.y
1565end
1566
1567function jobpositions.width(id)
1568 local jpi = collected[id]
1569 return jpi and jpi.w
1570end
1571
1572function jobpositions.height(id)
1573 local jpi = collected[id]
1574 return jpi and jpi.h
1575end
1576
1577function jobpositions.depth(id)
1578 local jpi = collected[id]
1579 return jpi and jpi.d
1580end
1581
1582function jobpositions.whd(id)
1583 local jpi = collected[id]
1584 if jpi then
1585 return jpi.h, jpi.h, jpi.d
1586 end
1587end
1588
1589function jobpositions.leftskip(id)
1590 local jpi = collected[id]
1591 return jpi and jpi.ls
1592end
1593
1594function jobpositions.rightskip(id)
1595 local jpi = collected[id]
1596 return jpi and jpi.rs
1597end
1598
1599function jobpositions.hsize(id)
1600 local jpi = collected[id]
1601 return jpi and jpi.hs
1602end
1603
1604function jobpositions.parindent(id)
1605 local jpi = collected[id]
1606 return jpi and jpi.pi
1607end
1608
1609function jobpositions.hangindent(id)
1610 local jpi = collected[id]
1611 return jpi and jpi.hi
1612end
1613
1614function jobpositions.hangafter(id)
1615 local jpi = collected[id]
1616 return jpi and jpi.ha or 1
1617end
1618
1619function jobpositions.xy(id)
1620 local jpi = collected[id]
1621 if jpi then
1622 return jpi.x, jpi.y
1623 else
1624 return 0, 0
1625 end
1626end
1627
1628function jobpositions.lowerleft(id)
1629 local jpi = collected[id]
1630 if jpi then
1631 return jpi.x, jpi.y - jpi.d
1632 else
1633 return 0, 0
1634 end
1635end
1636
1637function jobpositions.lowerright(id)
1638 local jpi = collected[id]
1639 if jpi then
1640 return jpi.x + jpi.w, jpi.y - jpi.d
1641 else
1642 return 0, 0
1643 end
1644end
1645
1646function jobpositions.upperright(id)
1647 local jpi = collected[id]
1648 if jpi then
1649 return jpi.x + jpi.w, jpi.y + jpi.h
1650 else
1651 return 0, 0
1652 end
1653end
1654
1655function jobpositions.upperleft(id)
1656 local jpi = collected[id]
1657 if jpi then
1658 return jpi.x, jpi.y + jpi.h
1659 else
1660 return 0, 0
1661 end
1662end
1663
1664function jobpositions.position(id)
1665 local jpi = collected[id]
1666 if jpi then
1667 return jpi.p, jpi.x, jpi.y, jpi.w, jpi.h, jpi.d
1668 else
1669 return 0, 0, 0, 0, 0, 0
1670 end
1671end
1672
1673local splitter = lpeg.splitat(",")
1674
1675function jobpositions.extra(id,n,default)
1676 local jpi = collected[id]
1677 if jpi then
1678 local e = jpi.e
1679 if e then
1680 local split = jpi.split
1681 if not split then
1682 split = lpegmatch(splitter,jpi.e)
1683 jpi.split = split
1684 end
1685 return texsp(split[n]) or default
1686 end
1687 end
1688 return default
1689end
1690
1691local function overlapping(one,two,overlappingmargin)
1692 one = collected[one]
1693 two = collected[two]
1694 if one and two and one.p == two.p then
1695 if not overlappingmargin then
1696 overlappingmargin = 2
1697 end
1698 local x_one = one.x
1699 local x_two = two.x
1700 local w_two = two.w
1701 local llx_one = x_one - overlappingmargin
1702 local urx_two = x_two + w_two + overlappingmargin
1703 if llx_one > urx_two then
1704 return false
1705 end
1706 local w_one = one.w
1707 local urx_one = x_one + w_one + overlappingmargin
1708 local llx_two = x_two - overlappingmargin
1709 if urx_one < llx_two then
1710 return false
1711 end
1712 local y_one = one.y
1713 local y_two = two.y
1714 local d_one = one.d
1715 local h_two = two.h
1716 local lly_one = y_one - d_one - overlappingmargin
1717 local ury_two = y_two + h_two + overlappingmargin
1718 if lly_one > ury_two then
1719 return false
1720 end
1721 local h_one = one.h
1722 local d_two = two.d
1723 local ury_one = y_one + h_one + overlappingmargin
1724 local lly_two = y_two - d_two - overlappingmargin
1725 if ury_one < lly_two then
1726 return false
1727 end
1728 return true
1729 end
1730end
1731
1732local function onsamepage(list,page)
1733 for id in gmatch(list,"([^,%s]+)") do
1734 local jpi = collected[id]
1735 if jpi then
1736 local p = jpi.p
1737 if not p then
1738 return false
1739 elseif not page then
1740 page = p
1741 elseif page ~= p then
1742 return false
1743 end
1744 end
1745 end
1746 return page
1747end
1748
1749local function columnofpos(realpage,xposition)
1750 local p = columndata[realpage]
1751 if p then
1752 for i=1,#p do
1753 local c = p[i]
1754 local x = c.x or 0
1755 local w = c.w or 0
1756 if xposition >= x and xposition <= (x + w) then
1757 return i
1758 end
1759 end
1760 end
1761 return 1
1762end
1763
1764local function getcolumndata(realpage,column)
1765 local p = columndata[realpage]
1766 if p then
1767 return p[column]
1768 end
1769end
1770
1771jobpositions.overlapping = overlapping
1772jobpositions.onsamepage = onsamepage
1773jobpositions.columnofpos = columnofpos
1774jobpositions.getcolumndata = getcolumndata
1775
1776
1777
1778implement {
1779 name = "replacepospxywhd",
1780 arguments = { "argument", "integerargument", "dimenargument", "dimenargument", "dimenargument", "dimenargument", "dimenargument" },
1781 public = true,
1782 protected = true,
1783 actions = function(name,page,x,y,w,h,d)
1784 local c = collected[name]
1785 if c then
1786 c.p = page ; c.x = x ; c.y = y ; c.w = w ; c.h = h ; c.d = d ;
1787 else
1788 collected[name] = { p = page, x = x, y = y, w = w, h = h, d = d }
1789 end
1790 end
1791}
1792
1793implement {
1794 name = "copyposition",
1795 arguments = "2 arguments",
1796 public = true,
1797 protected = true,
1798 actions = function(target,source)
1799 collected[target] = collected[source]
1800 end
1801}
1802
1803implement {
1804 name = "MPp",
1805 arguments = "argument",
1806 public = true,
1807 actions = function(name)
1808 local jpi = collected[name]
1809 if jpi then
1810 local p = jpi.p
1811 if p and p ~= true then
1812 context(p)
1813 return
1814 end
1815 end
1816 context('0')
1817 end
1818}
1819
1820implement {
1821 name = "MPx",
1822 arguments = "argument",
1823 public = true,
1824 actions = function(name)
1825 local jpi = collected[name]
1826 if jpi then
1827 local x = jpi.x
1828 if x and x ~= true and x ~= 0 then
1829 context("%.5Fpt",x*pt)
1830 return
1831 end
1832 end
1833 context('0pt')
1834 end
1835}
1836
1837implement {
1838 name = "MPy",
1839 arguments = "argument",
1840 public = true,
1841 actions = function(name)
1842 local jpi = collected[name]
1843 if jpi then
1844 local y = jpi.y
1845 if y and y ~= true and y ~= 0 then
1846 context("%.5Fpt",y*pt)
1847 return
1848 end
1849 end
1850 context('0pt')
1851 end
1852}
1853
1854implement {
1855 name = "MPw",
1856 arguments = "argument",
1857 public = true,
1858 actions = function(name)
1859 local jpi = collected[name]
1860 if jpi then
1861 local w = jpi.w
1862 if w and w ~= 0 then
1863 context("%.5Fpt",w*pt)
1864 return
1865 end
1866 end
1867 context('0pt')
1868 end
1869}
1870
1871implement {
1872 name = "MPh",
1873 arguments = "argument",
1874 public = true,
1875 actions = function(name)
1876 local jpi = collected[name]
1877 if jpi then
1878 local h = jpi.h
1879 if h and h ~= 0 then
1880 context("%.5Fpt",h*pt)
1881 return
1882 end
1883 end
1884 context('0pt')
1885 end
1886}
1887
1888implement {
1889 name = "MPd",
1890 arguments = "argument",
1891 public = true,
1892 actions = function(name)
1893 local jpi = collected[name]
1894 if jpi then
1895 local d = jpi.d
1896 if d and d ~= 0 then
1897 context("%.5Fpt",d*pt)
1898 return
1899 end
1900 end
1901 context('0pt')
1902 end
1903}
1904
1905implement {
1906 name = "MPxy",
1907 arguments = "argument",
1908 public = true,
1909 actions = function(name)
1910 local jpi = collected[name]
1911 if jpi then
1912 context('(%.5Fpt,%.5Fpt)',
1913 jpi.x*pt,
1914 jpi.y*pt
1915 )
1916 else
1917 context('(0,0)')
1918 end
1919 end
1920}
1921
1922implement {
1923 name = "MPwhd",
1924 arguments = "argument",
1925 public = true,
1926 actions = function(name)
1927 local jpi = collected[name]
1928 if jpi then
1929 local w = jpi.w or 0
1930 local h = jpi.h or 0
1931 local d = jpi.d or 0
1932 if w ~= 0 or h ~= 0 or d ~= 0 then
1933 context("%.5Fpt,%.5Fpt,%.5Fpt",w*pt,h*pt,d*pt)
1934 return
1935 end
1936 end
1937 context('0pt,0pt,0pt')
1938 end
1939}
1940
1941implement {
1942 name = "MPll",
1943 arguments = "argument",
1944 public = true,
1945 actions = function(name)
1946 local jpi = collected[name]
1947 if jpi then
1948 context('(%.5Fpt,%.5Fpt)',
1949 jpi.x *pt,
1950 (jpi.y-jpi.d)*pt
1951 )
1952 else
1953 context('(0,0)')
1954 end
1955 end
1956}
1957
1958implement {
1959 name = "MPlr",
1960 arguments = "argument",
1961 public = true,
1962 actions = function(name)
1963 local jpi = collected[name]
1964 if jpi then
1965 context('(%.5Fpt,%.5Fpt)',
1966 (jpi.x + jpi.w)*pt,
1967 (jpi.y - jpi.d)*pt
1968 )
1969 else
1970 context('(0,0)')
1971 end
1972 end
1973}
1974
1975implement {
1976 name = "MPur",
1977 arguments = "argument",
1978 public = true,
1979 actions = function(name)
1980 local jpi = collected[name]
1981 if jpi then
1982 context('(%.5Fpt,%.5Fpt)',
1983 (jpi.x + jpi.w)*pt,
1984 (jpi.y + jpi.h)*pt
1985 )
1986 else
1987 context('(0,0)')
1988 end
1989 end
1990}
1991
1992implement {
1993 name = "MPul",
1994 arguments = "argument",
1995 public = true,
1996 actions = function(name)
1997 local jpi = collected[name]
1998 if jpi then
1999 context('(%.5Fpt,%.5Fpt)',
2000 jpi.x *pt,
2001 (jpi.y + jpi.h)*pt
2002 )
2003 else
2004 context('(0,0)')
2005 end
2006 end
2007}
2008
2009local function MPpos(id)
2010 local jpi = collected[id]
2011 if jpi then
2012 local p = jpi.p
2013 if p then
2014 context("%s,%.5Fpt,%.5Fpt,%.5Fpt,%.5Fpt,%.5Fpt",
2015 p,
2016 jpi.x*pt,
2017 jpi.y*pt,
2018 jpi.w*pt,
2019 jpi.h*pt,
2020 jpi.d*pt
2021 )
2022 return
2023 end
2024 end
2025 context('0,0,0,0,0,0')
2026end
2027
2028implement {
2029 name = "MPpos",
2030 arguments = "argument",
2031 public = true,
2032 actions = MPpos
2033}
2034
2035implement {
2036 name = "MPn",
2037 arguments = "argument",
2038 public = true,
2039 actions = function(name)
2040 local jpi = collected[name]
2041 if jpi then
2042 local n = jpi.n
2043 if n then
2044 context(n)
2045 return
2046 end
2047 end
2048 context(0)
2049 end
2050}
2051
2052implement {
2053 name = "MPc",
2054 arguments = "argument",
2055 public = true,
2056 actions = function(name)
2057 local jpi = collected[name]
2058 if jpi then
2059 local c = jpi.c
2060 if c and c ~= true then
2061 context(c)
2062 return
2063 end
2064 end
2065 context('0')
2066 end
2067}
2068
2069implement {
2070 name = "MPr",
2071 arguments = "argument",
2072 public = true,
2073 actions = function(name)
2074 local jpi = collected[name]
2075 if jpi then
2076 local r = jpi.r
2077 if r and r ~= true then
2078 context(r)
2079 return
2080 end
2081 local p = jpi.p
2082 if p and p ~= true then
2083 context("page:" .. p)
2084 end
2085 end
2086 end
2087}
2088
2089local function MPpardata(id)
2090 local t = collected[id]
2091 if not t then
2092 local tag = f_p_tag(id)
2093 t = collected[tag]
2094 end
2095 if t then
2096 context("%.5Fpt,%.5Fpt,%.5Fpt,%.5Fpt,%s,%.5Fpt",
2097 t.hs*pt,
2098 t.ls*pt,
2099 t.rs*pt,
2100 t.hi*pt,
2101 t.ha,
2102 t.pi*pt
2103 )
2104 else
2105 context("0,0,0,0,0,0")
2106 end
2107end
2108
2109implement {
2110 name = "MPpardata",
2111 arguments = "argument",
2112 public = true,
2113 actions = MPpardata
2114}
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129implement {
2130 name = "MPls",
2131 arguments = "argument",
2132 public = true,
2133 actions = function(name)
2134 local jpi = collected[name]
2135 if jpi then
2136 context("%.5Fpt",jpi.ls*pt)
2137 else
2138 context("0pt")
2139 end
2140 end
2141}
2142
2143implement {
2144 name = "MPrs",
2145 arguments = "argument",
2146 public = true,
2147 actions = function(name)
2148 local jpi = collected[name]
2149 if jpi then
2150 context("%.5Fpt",jpi.rs*pt)
2151 else
2152 context("0pt")
2153 end
2154 end
2155}
2156
2157local splitter = lpeg.tsplitat(",")
2158
2159implement {
2160 name = "MPplus",
2161 arguments = { "argument", "integerargument", "argument" },
2162 public = true,
2163 actions = function(name,n,default)
2164 local jpi = collected[name]
2165 if jpi then
2166 local e = jpi.e
2167 if e then
2168 local split = jpi.split
2169 if not split then
2170 split = lpegmatch(splitter,jpi.e)
2171 jpi.split = split
2172 end
2173 context(split[n] or default)
2174 return
2175 end
2176 end
2177 context(default)
2178 end
2179}
2180
2181implement {
2182 name = "MPrest",
2183 arguments = "2 arguments",
2184 public = true,
2185 actions = function(name,default)
2186 local jpi = collected[name]
2187 context(jpi and jpi.e or default)
2188 end
2189}
2190
2191implement {
2192 name = "MPxywhd",
2193 arguments = "argument",
2194 public = true,
2195 actions = function(name)
2196 local jpi = collected[name]
2197 if jpi then
2198 context("%.5Fpt,%.5Fpt,%.5Fpt,%.5Fpt,%.5Fpt",
2199 jpi.x*pt,
2200 jpi.y*pt,
2201 jpi.w*pt,
2202 jpi.h*pt,
2203 jpi.d*pt
2204 )
2205 else
2206 context("0,0,0,0,0")
2207 end
2208 end
2209}
2210
2211implement {
2212 name = "doifelseposition",
2213 arguments = "argument",
2214 public = true,
2215 protected = true,
2216 actions = function(name)
2217 ctx_doifelse(collected[name])
2218 end
2219}
2220
2221implement {
2222 name = "doifposition",
2223 arguments = "argument",
2224 public = true,
2225 protected = true,
2226 actions = function(name)
2227 ctx_doif(collected[name])
2228 end
2229}
2230
2231implement {
2232 name = "doifelsepositiononpage",
2233 arguments = { "string", "integerargument" },
2234 public = true,
2235 protected = true,
2236 actions = function(name,p)
2237 local c = collected[name]
2238 ctx_doifelse(c and c.p == p)
2239 end
2240}
2241
2242implement {
2243 name = "doifelseoverlapping",
2244 arguments = "2 arguments",
2245 public = true,
2246 protected = true,
2247 actions = function(one,two)
2248 ctx_doifelse(overlapping(one,two))
2249 end
2250}
2251
2252implement {
2253 name = "doifelsepositionsonsamepage",
2254 arguments = "argument",
2255 public = true,
2256 protected = true,
2257 actions = function(list)
2258 ctx_doifelse(onsamepage(list))
2259 end
2260}
2261
2262implement {
2263 name = "doifelsepositionsonthispage",
2264 arguments = "argument",
2265 public = true,
2266 protected = true,
2267 actions = function(list)
2268 ctx_doifelse(onsamepage(list,tostring(texgetcount(c_realpageno))))
2269 end
2270}
2271
2272implement {
2273 name = "doifelsepositionsused",
2274 public = true,
2275 protected = true,
2276 actions = function()
2277 ctx_doifelse(jobpositions.used())
2278 end
2279}
2280
2281implement {
2282 name = "markregionbox",
2283 arguments = "2 integers",
2284 actions = markregionbox
2285}
2286
2287implement {
2288 name = "setregionbox",
2289 arguments = "2 integers",
2290 actions = setregionbox
2291}
2292
2293implement {
2294 name = "markregionboxtagged",
2295 arguments = { "integer", "string", "integer" },
2296 actions = markregionbox
2297}
2298
2299implement {
2300 name = "markregionboxtaggedn",
2301 arguments = { "integer", "string", "integer", "integer" },
2302 actions = function(box,tag,index,n)
2303 markregionbox(box,tag,index,nil,nil,nil,nil,nil,nil,n)
2304 end
2305}
2306
2307implement {
2308 name = "setregionboxtagged",
2309 arguments = { "integer", "string", "integer" },
2310 actions = setregionbox
2311}
2312
2313implement {
2314 name = "markregionboxcorrected",
2315 arguments = { "integer", "string", "integer", true },
2316 actions = markregionbox
2317}
2318
2319implement {
2320 name = "markregionboxtaggedkind",
2321 arguments = { "integer", "string", "integer", "integer", "dimen", "dimen", "dimen", "dimen" },
2322 actions = function(box,tag,index,n,d1,d2,d3,d4)
2323 markregionbox(box,tag,index,nil,n,d1,d2,d3,d4)
2324 end
2325}
2326
2327implement {
2328 name = "reservedautoregiontag",
2329 public = true,
2330 actions = function()
2331 nofregions = nofregions + 1
2332 context(f_region(nofregions))
2333 end
2334}
2335
2336
2337
2338local newsavepos = nodes.pool.savepos
2339
2340jobpositions.lastx = 0
2341jobpositions.lasty = 0
2342
2343implement { name = "savepos", actions = function() context(newsavepos()) end }
2344implement { name = "lastxpos", actions = function() context(jobpositions.lastx) end }
2345implement { name = "lastypos", actions = function() context(jobpositions.lasty) end }
2346 |