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