1if not modules then modules = { } end modules ['anch-pgr'] = {
2 version = 1.001,
3 comment = "companion to anch-pgr.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
19local tonumber = tonumber
20local sort, concat = table.sort, table.concat
21local splitter = lpeg.splitat(":")
22local lpegmatch = lpeg.match
23
24local jobpositions = job.positions
25local formatters = string.formatters
26local setmetatableindex = table.setmetatableindex
27local settings_to_array = utilities.parsers.settings_to_array
28
29local enableaction = nodes.tasks.enableaction
30
31local context = context
32
33local ctx_doifelse = commands.doifelse
34
35local implement = interfaces.implement
36
37local texgetcount = tex.getcount
38local texiscount = tex.iscount
39
40local getmacro = tokens.getters.macro
41local expandasvalue = tex.expandasvalue
42local scanmpstring = mp.scan.string
43
44
45local string_value = tokens.values.string
46
47local report_graphics = logs.reporter("backgrounds")
48local report_shapes = logs.reporter("backgrounds","shapes")
49local report_free = logs.reporter("backgrounds","free")
50
51local trace_shapes = false trackers.register("backgrounds.shapes", function(v) trace_shapes = v end)
52local trace_ranges = false trackers.register("backgrounds.shapes.ranges",function(v) trace_ranges = v end)
53local trace_free = false trackers.register("backgrounds.shapes.free", function(v) trace_free = v end)
54
55local f_b_tag = formatters["b:%s"]
56local f_e_tag = formatters["e:%s"]
57local f_p_tag = formatters["p:%s"]
58
59local f_tag_two = formatters["%s:%s"]
60
61local f_point = formatters["%p"]
62local f_pair = formatters["(%p,%p)"]
63local f_path = formatters["%--t--cycle"]
64local f_pair_i = formatters["(%r,%r)"]
65
66local c_realpageno = texiscount("realpageno")
67
68graphics = graphics or { }
69local backgrounds = { }
70graphics.backgrounds = backgrounds
71
72
73
74backgrounds.point = f_point
75backgrounds.pair = f_pair
76backgrounds.path = f_path
77
78
79
80local texsetattribute = tex.setattribute
81
82local a_textbackground = attributes.private("textbackground")
83
84local nuts = nodes.nuts
85
86local new_latelua = nuts.pool.latelua
87local new_rule = nuts.pool.rule
88local new_kern = nuts.pool.kern
89local new_hlist = nuts.pool.hlist
90
91local getbox = nuts.getbox
92local getid = nuts.getid
93
94local setlink = nuts.setlink
95local getheight = nuts.getheight
96local getdepth = nuts.getdepth
97
98local nodecodes = nodes.nodecodes
99local par_code = nodecodes.par
100
101local startofpar = nuts.startofpar
102local insertbefore = nuts.insertbefore
103local insertafter = nuts.insertafter
104
105local processranges = nuts.processranges
106
107local unsetvalue = attributes.unsetvalue
108
109local jobpositions = job.positions
110local getpos = jobpositions.getpos
111local getfree = jobpositions.getfree
112
113
114local realpage = 1
115
116local enabled = false
117
118
119
120
121
122local function check(specification)
123
124 local a = specification.attribute
125 local index = specification.index
126 local depth = specification.depth
127 local d = specification.data
128 local where = specification.where
129 local ht = specification.ht
130 local dp = specification.dp
131
132 local w = d.shapes[realpage]
133 local x, y = getpos()
134 if trace_ranges then
135 report_shapes("attribute %i, index %i, depth %i, location %s, position (%p,%p)",
136 a,index,depth,where,x,y)
137 end
138 local n = #w
139 if d.index ~= index then
140 n = n + 1
141 d.index = index
142 d.depth = depth
143
144 w[n] = { y, ht, dp, x, x }
145 else
146 local wn = w[n]
147 local wh = wn[2]
148 local wd = wn[3]
149 if depth < d.depth then
150 local wy = wn[1]
151 wn[1] = y
152 d.depth = depth
153 local dy = wy - y
154 wh = wh - dy
155 wd = wd - dy
156 end
157 if where == "r" then
158 if x > wn[5] then
159 wn[5] = x
160 end
161 else
162 if x < wn[4] then
163 wn[4] = x
164 end
165 end
166 if ht > wh then
167 wn[2] = ht
168 end
169 if dp > wd then
170 wn[3] = dp
171 end
172 end
173
174end
175
176local index = 0
177
178local registervalue = attributes.registervalue
179local getvalue = attributes.getvalue
180
181local function flush(head,f,l,a,parent,depth)
182
183 local d = getvalue(a_textbackground,a)
184 if d then
185 local ix = index
186 local ht = getheight(parent)
187 local dp = getdepth(parent)
188 local ln = new_latelua { action = check, attribute = a, index = ix, depth = depth, data = d, where = "l", ht = ht, dp = dp }
189 local rn = new_latelua { action = check, attribute = a, index = ix, depth = depth, data = d, where = "r", ht = ht, dp = dp }
190 if trace_ranges then
191 ln = new_hlist(setlink(new_rule(65536,65536*4,0),new_kern(-65536),ln))
192 rn = new_hlist(setlink(new_rule(65536,0,65536*4),new_kern(-65536),rn))
193 end
194 if getid(f) == par_code and startofpar(f) then
195 insertafter(head,f,ln)
196 else
197 head, f = insertbefore(head,f,ln)
198 end
199 insertafter(head,l,rn)
200 end
201 return head, true
202end
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234local function registerbackground(name)
235 local b = jobpositions.tobesaved["b:"..name]
236 if b then
237 local n = registervalue(a_textbackground,t)
238 local s = setmetatableindex("table")
239 b.s = s
240 local t = {
241 bpos = b,
242 name = name,
243 n = n,
244 shapes = s,
245 count = 0,
246 sindex = 0,
247 }
248 texsetattribute(a_textbackground,n)
249 if not enabled then
250 enableaction("contributers", "nodes.handlers.textbackgrounds")
251 enabled = true
252 end
253 else
254 texsetattribute(a_textbackground,unsetvalue)
255 end
256end
257
258nodes.handlers.textbackgrounds = function(head,where,parent)
259
260 index = index + 1
261 realpage = texgetcount(c_realpageno)
262 return processranges(a_textbackground,flush,head,parent)
263end
264
265interfaces.implement {
266 name = "registerbackground",
267 actions = registerbackground,
268 arguments = "string",
269}
270
271
272
273
274local function topairs(t,n)
275 local r = { }
276 for i=1,n do
277 local ti = t[i]
278 r[i] = f_pair_i(ti[1]/65556,ti[2]/65536)
279 end
280 return concat(r," ")
281end
282
283local eps = 65536 / 4
284local pps = eps
285local nps = - pps
286
287local function unitvector(x,y)
288 if x < pps and x > nps then
289 x = 0
290 elseif x < 0 then
291 x = -1
292 else
293 x = 1
294 end
295 if y < pps and y > nps then
296 y = 0
297 elseif y < 0 then
298 y = -1
299 else
300 y = 1
301 end
302 return x, y
303end
304
305local function finish(t)
306 local tm = #t
307 if tm < 2 then
308 return
309 end
310 if trace_ranges then
311 report_shapes("initial list: %s",topairs(t,tm))
312 end
313
314 local n = 1
315 local tn = tm
316 local tf = t[1]
317 local tx = tf[1]
318 local ty = tf[2]
319 for i=2,#t do
320 local ti = t[i]
321 local ix = ti[1]
322 local iy = ti[2]
323 local dx = ix - tx
324 local dy = iy - ty
325 if dx > eps or dx < - eps or dy > eps or dy < - eps then
326 n = n + 1
327 t[n] = ti
328 tx = ix
329 ty = iy
330 end
331 end
332 if trace_shapes then
333 report_shapes("removing similar points: %s",topairs(t,n))
334 end
335 if n > 2 then
336
337 repeat
338 tn = n
339 n = 0
340 local tm = t[tn]
341 local tmx = tm[1]
342 local tmy = tm[2]
343 local tp = t[1]
344 local tpx = tp[1]
345 local tpy = tp[2]
346 for i=1,tn do
347 local ti = tp
348 local tix = tpx
349 local tiy = tpy
350 if i == tn then
351 tp = t[1]
352 else
353 tp = t[i+1]
354 end
355 tpx = tp[1]
356 tpy = tp[2]
357
358 local vx1, vx2 = unitvector(tix - tmx,tpx - tix)
359 if vx1 ~= vx2 then
360 n = n + 1
361 t[n] = ti
362 else
363 local vy1, vy2 = unitvector(tiy - tmy,tpy - tiy)
364 if vy1 ~= vy2 then
365 n = n + 1
366 t[n] = ti
367 end
368 end
369
370 tmx = tix
371 tmy = tiy
372 end
373 until n == tn or n <= 2
374 if trace_shapes then
375 report_shapes("removing redundant points: %s",topairs(t,n))
376 end
377
378 if n > 2 then
379 repeat
380 tn = n
381 n = 0
382 local tm = t[tn]
383 local tmx = tm[1]
384 local tmy = tm[2]
385 local tp = t[1]
386 local tpx = tp[1]
387 local tpy = tp[2]
388 for i=1,tn do
389 local ti = tp
390 local tix = tpx
391 local tiy = tpy
392 if i == tn then
393 tp = t[1]
394 else
395 tp = t[i+1]
396 end
397 tpx = tp[1]
398 tpy = tp[2]
399
400 local vx1, vx2 = unitvector(tix - tmx,tpx - tix)
401 if vx1 ~= - vx2 then
402 n = n + 1
403 t[n] = ti
404 else
405 local vy1, vy2 = unitvector(tiy - tmy,tpy - tiy)
406 if vy1 ~= - vy2 then
407 n = n + 1
408 t[n] = ti
409 end
410 end
411
412 tmx = tix
413 tmy = tiy
414 end
415 until n == tn or n <= 2
416 if trace_shapes then
417 report_shapes("removing spikes: %s",topairs(t,n))
418 end
419 end
420 end
421
422 if tm > n then
423 for i=tm,n+1,-1 do
424 t[i] = nil
425 end
426 end
427 if n > 1 then
428 local tf = t[1]
429 local tl = t[n]
430 local dx = tf[1] - tl[1]
431 local dy = tf[2] - tl[2]
432 if dx > eps or dx < - eps or dy > eps or dy < - eps then
433
434 else
435
436 t[n] = nil
437 n = n -1
438 end
439 if trace_shapes then
440 report_shapes("removing cyclic endpoints: %s",topairs(t,n))
441 end
442 end
443 return t
444end
445
446local eps = 65536
447
448
449
450
451local function shape(kind,b,p,realpage,xmin,xmax,ymin,ymax,fh,ld)
452 local s = b.s
453 if not s then
454 if trace_shapes then
455 report_shapes("calculating %s area, no shape",kind)
456 end
457 return
458 end
459 s = s[realpage]
460 if not s then
461 if trace_shapes then
462 report_shapes("calculating %s area, no shape for page %s",kind,realpage)
463 end
464 return
465 end
466 local ns = #s
467 if ns == 0 then
468 if trace_shapes then
469 report_shapes("calculating %s area, empty shape for page %s",kind,realpage)
470 end
471 return
472 end
473
474 if trace_shapes then
475 report_shapes("calculating %s area, using shape for page %s",kind,realpage)
476 end
477
478
479 local ph = p and p.h or 0
480 local pd = p and p.d or 0
481
482 xmax = xmax + eps
483 xmin = xmin - eps
484 ymax = ymax + eps
485 ymin = ymin - eps
486 local ls = { }
487 local rs = { }
488 local pl = nil
489 local pr = nil
490 local n = 0
491 local xl = nil
492 local xr = nil
493 local mh = ph
494 local md = pd
495 for i=1,ns do
496 local si = s[i]
497 local y = si[1]
498 local ll = si[4]
499 if ll then
500 xl = ll
501 local rr = si[5]
502 if rr then
503 xr = rr
504 end
505 end
506 if trace_ranges then
507 report_shapes("original : [%02i] xl=%p xr=%p y=%p",i,xl,xr,y)
508 end
509 if xl ~= xr then
510 local xm = xl + (xr - xl)/2
511 if xm >= xmin and xm <= xmax and y >= ymin and y <= ymax then
512 local ht = si[2]
513 if ht then
514 ph = ht
515 local dp = si[3]
516 if dp then
517 pd = dp
518 end
519 end
520 local h = y + (ph < mh and mh or ph)
521 local d = y - (pd < md and md or pd)
522 if pl then
523 n = n + 1
524 ls[n] = { pl, h }
525 rs[n] = { pr, h }
526 if trace_ranges then
527 report_shapes("paragraph : [%02i] xl=%p xr=%p y=%p",i,pl,pr,h)
528 end
529 end
530 n = n + 1
531 ls[n] = { xl, h }
532 rs[n] = { xr, h }
533 if trace_ranges then
534 report_shapes("height : [%02i] xl=%p xr=%p y=%p",i,xl,xr,h)
535 end
536 n = n + 1
537 ls[n] = { xl, d }
538 rs[n] = { xr, d }
539 if trace_ranges then
540 report_shapes("depth : [%02i] xl=%p xr=%p y=%p",i,xl,xr,d)
541 end
542 end
543 pl, pr = xl, xr
544 else
545 if trace_ranges then
546 report_shapes("ignored : [%02i] xl=%p xr=%p y=%p",i,xl,xr,y)
547 end
548 end
549 end
550
551 if true and n > 0 then
552
553
554 if fh then
555 local lsf = ls[1]
556 local rsf = rs[1]
557 if lsf[2] < fh then
558 lsf[2] = fh
559 end
560 if rsf[2] < fh then
561 rsf[2] = fh
562 end
563 end
564 if fd then
565 local lsl = ls[n]
566 local rsl = rs[n]
567 if lsl[2] > fd then
568 lsl[2] = fd
569 end
570 if rsl[2] > fd then
571 rsl[2] = fd
572 end
573 end
574 end
575
576 for i=n,1,-1 do
577 n = n + 1 rs[n] = ls[i]
578 end
579 return rs
580end
581
582local function singlepart(b,e,p,realpage,r,left,right)
583 local bx = b.x
584 local by = b.y
585 local ex = e.x
586 local ey = e.y
587 local rx = r.x
588 local ry = r.y
589 local bh = by + b.h
590 local bd = by - b.d
591 local eh = ey + e.h
592 local ed = ey - e.d
593 local rh = ry + r.h
594 local rd = ry - r.d
595 local rw = rx + r.w
596 if left then
597 rx = rx + left
598 rw = rw - right
599 end
600 if ex == rx then
601
602
603
604 ex = rw
605 end
606 local area
607 if by == ey then
608 if trace_shapes then
609 report_shapes("calculating single area, partial line")
610 end
611 area = {
612 { bx, bh },
613 { ex, eh },
614 { ex, ed },
615 { bx, bd },
616 }
617 elseif b.k == 2 then
618 area = {
619 { rx, bh },
620 { rw, bh },
621 { rw, ed },
622 { rx, ed },
623 }
624 else
625 area = shape("single",b,p,realpage,rx,rw,rd,rh,bh,ed)
626 end
627 if not area then
628 area = {
629 { bx, bh },
630 { rw, bh },
631 { rw, eh },
632 { ex, eh },
633 { ex, ed },
634 { rx, ed },
635 { rx, bd },
636 { bx, bd },
637 }
638 end
639 return {
640 location = "single",
641 region = r,
642 area = finish(area),
643 }
644end
645
646local function firstpart(b,e,p,realpage,r,left,right)
647 local bx = b.x
648 local by = b.y
649 local rx = r.x
650 local ry = r.y
651 local bh = by + b.h
652 local bd = by - b.d
653 local rh = ry + r.h
654 local rd = ry - r.d
655 local rw = rx + r.w
656 if left then
657 rx = rx + left
658 rw = rw - right
659 end
660 local area = shape("first",b,p,realpage,rx,rw,rd,rh,bh,false)
661 if not area then
662 if b.k == 2 then
663 area = {
664 { rx, bh },
665 { rw, bh },
666 { rw, rd },
667 { rx, rd },
668 }
669 else
670 area = {
671 { bx, bh },
672 { rw, bh },
673 { rw, rd },
674 { rx, rd },
675 { rx, bd },
676 { bx, bd },
677 }
678 end
679 end
680 return {
681 location = "first",
682 region = r,
683 area = finish(area),
684 }
685end
686
687local function middlepart(b,e,p,realpage,r,left,right)
688 local rx = r.x
689 local ry = r.y
690 local rh = ry + r.h
691 local rd = ry - r.d
692 local rw = rx + r.w
693 if left then
694 rx = rx + left
695 rw = rw - right
696 end
697 local area = shape("middle",b,p,realpage,rx,rw,rd,rh,false,false)
698 if not area then
699 area = {
700 { rw, rh },
701 { rw, rd },
702 { rx, rd },
703 { rx, rh },
704 }
705 end
706 return {
707 location = "middle",
708 region = r,
709 area = finish(area),
710 }
711end
712
713local function lastpart(b,e,p,realpage,r,left,right)
714 local ex = e.x
715 local ey = e.y
716 local rx = r.x
717 local ry = r.y
718 local eh = ey + e.h
719 local ed = ey - e.d
720 local rh = ry + r.h
721 local rd = ry - r.d
722 local rw = rx + r.w
723 if left then
724 rx = rx + left
725 rw = rw - right
726 end
727 local area = shape("last",b,p,realpage,rx,rw,rd,rh,false,ed)
728 if not area then
729 if b.k == 2 then
730 area = {
731 { rw, rh },
732 { rw, ed },
733 { rx, ed },
734 { rx, rh },
735 }
736 else
737 area = {
738 { rw, rh },
739 { rw, eh },
740 { ex, eh },
741 { ex, ed },
742 { rx, ed },
743 { rx, rh },
744 }
745 end
746 end
747 return {
748 location = "last",
749 region = r,
750 area = finish(area),
751 }
752end
753
754local function calculatemultipar(tag)
755 local collected = jobpositions.collected
756 local b = collected[f_b_tag(tag)]
757 local e = collected[f_e_tag(tag)]
758 if not b or not e then
759 report_shapes("invalid tag %a",tag)
760 return { }
761 end
762 local br = b.r
763 local er = e.r
764 if not br or not er then
765 report_shapes("invalid region for %a",tag)
766 return { }
767 end
768 local btag, bindex = lpegmatch(splitter,br)
769 local etag, eindex = lpegmatch(splitter,er)
770 if not bindex or not eindex or btag ~= etag then
771 report_shapes("invalid indices for %a",tag)
772 return { }
773 end
774 local bindex = tonumber(bindex)
775 local eindex = tonumber(eindex)
776
777
778
779
780
781 local left = 0
782 local right = 0
783 local bc = b.c
784 local rc = bc and collected[bc]
785 if rc then
786 local tb = collected[rc.r]
787 if tb then
788 left = -(tb.x - rc.x)
789 right = (tb.w - rc.w - left)
790 end
791 end
792
793
794 local bn = b.n
795 local p = bn and collected[f_p_tag(bn)]
796 if p then
797 left = left + (p.ls or 0)
798 right = right + (p.rs or 0)
799 end
800
801 local bp = b.p
802 if trace_shapes then
803 report_shapes("tag %a, left %p, right %p, par %s, page %s, column %s",
804 tag,left,right,bn or "-",bp or "-",bc or "-")
805 end
806
807 if bindex == eindex then
808 return {
809 list = { [bp] = { singlepart(b,e,p,bp,collected[br],left,right) } },
810 bpos = b,
811 epos = e,
812 }
813 else
814 local list = {
815 [bp] = { firstpart(b,e,p,bp,collected[br],left,right) },
816 }
817 for i=bindex+1,eindex-1 do
818 br = f_tag_two(btag,i)
819 local r = collected[br]
820 if r then
821 local rp = r.p
822 local pp = list[rp]
823 local mp = middlepart(b,e,p,rp,r,left,right)
824 if pp then
825 pp[#pp+1] = mp
826 else
827 list[rp] = { mp }
828 end
829 else
830 report_graphics("invalid middle for %a",br)
831 end
832 end
833 local ep = e.p
834 local pp = list[ep]
835 local lp = lastpart(b,e,p,ep,collected[er],left,right)
836 if pp then
837 pp[#pp+1] = lp
838 else
839 list[ep] = { lp }
840 end
841 return {
842 list = list,
843 bpos = b,
844 epos = e,
845 }
846 end
847end
848
849local pbg = { }
850
851local multilocs = {
852 single = 1,
853 first = 1,
854 middle = 2,
855 last = 3,
856}
857
858
859
860local f_template_a = formatters[ [[
861path multiregs[], multipars[], multibox ;
862string multikind[] ;
863numeric multilocs[], nofmultipars ;
864nofmultipars := %s ;
865multibox := unitsquare xyscaled (%p,%p) ;
866numeric par_strut_height, par_strut_depth, par_line_height ;
867par_strut_height := %p ;
868par_strut_depth := %p ;
869par_line_height := %p ;
870]] ]
871
872local f_template_b = formatters[ [[
873multilocs[%s] := %s ;
874multikind[%s] := "%s" ;
875multipars[%s] := (%--t--cycle) shifted - (%p,%p) ;
876]] ]
877
878
879
880local f_template_c = formatters[ [[
881setbounds currentpicture to multibox ;
882]] ]
883
884local function freemultipar(pagedata,frees)
885
886
887
888
889 if not frees then
890 return
891 end
892 local nfree = #frees
893 if nfree == 0 then
894 return
895 end
896 for i=1,#pagedata do
897 local data = pagedata[i]
898 local area = data.area
899
900 if area then
901
902 local region = data.region
903 local y = 0
904
905 local areas = { }
906 data.areas = areas
907
908 local f_1 = { }
909 local n_1 = 0
910 local f_2 = { }
911 local n_2 = 0
912 for i=1,#frees do
913 local f = frees[i]
914 local k = f.k
915 if k == 1 then
916 n_1 = n_1 + 1
917 f_1[n_1] = f
918 elseif k == 2 or k == 3 then
919 n_2 = n_2 + 1
920 f_2[n_2] = f
921 end
922 end
923
924 local lineheight = tex.dimen.lineheight
925
926
927
928 local function check_one(free1,free2)
929 local temp = { }
930 local some = false
931 local top = (free2 and (y + free2.y + free2.h + (free2.to or 0))) or false
932 local bot = (free1 and (y + free1.y - free1.d - (free1.bo or 0))) or false
933 for i=1,#area do
934 local a = area[i]
935 local x = a[1]
936 local y = a[2]
937 if free2 and y <= top then
938 y = top
939 end
940 if free1 and y >= bot then
941 y = bot
942 end
943 if not some then
944 some = y
945 elseif some == true then
946
947 elseif y ~= some then
948 some = true
949 end
950 temp[i] = { x, y }
951 end
952 if some == true then
953 areas[#areas+1] = temp
954 end
955 end
956
957 if n_1 > 0 then
958 check_one(false,f_1[1])
959 for i=2,n_1 do
960 check_one(f_1[i-1],f_1[i])
961 end
962 check_one(f_1[n_1],false)
963 end
964
965
966
967 if #areas == 0 then
968 areas[1] = area
969 end
970
971
972
973 local function check_two(area,frees)
974 local ul = area[1]
975 local ur = area[2]
976 local lr = area[3]
977 local ll = area[4]
978 local ulx = ul[1]
979 local uly = ul[2]
980 local urx = ur[1]
981 local ury = ur[2]
982 local lrx = lr[1]
983 local lry = lr[2]
984 local llx = ll[1]
985 local lly = ll[2]
986
987 local temp = { }
988 local n = 0
989 local done = false
990
991 for i=1,#frees do
992 local free = frees[i]
993 local fx = free.x
994 local fy = free.y
995 local ymax = y + fy + free.h + (free.to or 0)
996 local ymin = y + fy - free.d - (free.bo or 0)
997 local xmin = fx - (free.lo or 0)
998 local xmax = fx + free.w + (free.ro or 0)
999 if free.k == 3 then
1000 if uly <= ymax and uly >= ymin and lly <= ymin then
1001 if trace_free then
1002 report_free("case 1, top, right")
1003 end
1004 n = n + 1 temp[n] = { xmin, ury }
1005 n = n + 1 temp[n] = { xmin, ymin }
1006 n = n + 1 temp[n] = { lrx, ymin }
1007 n = n + 1 temp[n] = { lrx, lry }
1008 done = true
1009 elseif uly >= ymax and lly <= ymin then
1010 if trace_free then
1011 report_free("case 2, outside, right")
1012 end
1013 if uly - ymax < lineheight then
1014 n = n + 1 temp[n] = { xmin, ury }
1015 else
1016 n = n + 1 temp[n] = { urx, ury }
1017 n = n + 1 temp[n] = { urx, ymax }
1018 end
1019 n = n + 1 temp[n] = { xmin, ymax }
1020 n = n + 1 temp[n] = { xmin, ymin }
1021 n = n + 1 temp[n] = { lrx, ymin }
1022 n = n + 1 temp[n] = { lrx, lry }
1023 done = true
1024 elseif lly <= ymax and lly >= ymin and uly >= ymax then
1025 if trace_free then
1026 report_free("case 3, bottom, right")
1027 end
1028 if uly - ymax < lineheight then
1029 n = n + 1 temp[n] = { xmin, ury }
1030 else
1031 n = n + 1 temp[n] = { urx, ury }
1032 n = n + 1 temp[n] = { urx, ymax }
1033 end
1034 n = n + 1 temp[n] = { xmin, ymax }
1035 n = n + 1 temp[n] = { xmin, lry }
1036 done = true
1037 elseif uly <= ymax and lly >= ymin then
1038 if trace_free then
1039 report_free("case 4, inside, right")
1040 end
1041 n = n + 1 temp[n] = { xmin, uly }
1042 n = n + 1 temp[n] = { xmin, lly }
1043 done = true
1044 else
1045
1046 if trace_free then
1047 report_free("case 0, nothing")
1048 end
1049 end
1050 end
1051 end
1052
1053 if not done then
1054 if trace_free then
1055 report_free("no right shape")
1056 end
1057 n = n + 1 temp[n] = { urx, ury }
1058 n = n + 1 temp[n] = { lrx, lry }
1059 n = n + 1 temp[n] = { llx, lly }
1060 else
1061 done = false
1062 end
1063
1064 for i=#frees,1,-1 do
1065 local free = frees[i]
1066 local fx = free.x
1067 local fy = free.y
1068 local ymax = y + fy + free.h + (free.to or 0)
1069 local ymin = y + fy - free.d - (free.bo or 0)
1070 local xmin = fx - (free.lo or 0)
1071 local xmax = fx + free.w + (free.ro or 0)
1072 if free.k == 2 then
1073 if uly <= ymax and uly >= ymin and lly <= ymin then
1074 if trace_free then
1075 report_free("case 1, top, left")
1076 end
1077 n = n + 1 temp[n] = { ulx, ymin }
1078 n = n + 1 temp[n] = { xmax, ymin }
1079 n = n + 1 temp[n] = { xmax, uly }
1080 done = true
1081 elseif uly >= ymax and lly <= ymin then
1082 if trace_free then
1083 report_free("case 2, outside, left")
1084 end
1085 n = n + 1 temp[n] = { llx, lly }
1086 n = n + 1 temp[n] = { llx, ymin }
1087 n = n + 1 temp[n] = { xmax, ymin }
1088 n = n + 1 temp[n] = { xmax, ymax }
1089 if uly - ymax < lineheight then
1090 n = n + 1 temp[n] = { xmax, uly }
1091 else
1092 n = n + 1 temp[n] = { llx, ymax }
1093 n = n + 1 temp[n] = { llx, uly }
1094 end
1095 done = true
1096 elseif lly <= ymax and lly >= ymin and uly >= ymax then
1097 if trace_free then
1098 report_free("case 3, bottom, left")
1099 end
1100 n = n + 1 temp[n] = { xmax, lly }
1101 n = n + 1 temp[n] = { xmax, ymax }
1102 if uly - ymax < lineheight then
1103 n = n + 1 temp[n] = { xmax, uly }
1104 else
1105 n = n + 1 temp[n] = { llx, ymax }
1106 n = n + 1 temp[n] = { llx, uly }
1107 end
1108 done = true
1109 elseif uly <= ymax and lly >= ymin then
1110 if trace_free then
1111 report_free("case 4, inside, left")
1112 end
1113 n = n + 1 temp[n] = { xmax, lly }
1114 n = n + 1 temp[n] = { xmax, uly }
1115 done = true
1116 else
1117
1118 end
1119 end
1120 end
1121
1122 if not done then
1123 if trace_free then
1124 report_free("no left shape")
1125 end
1126 n = n + 1 temp[n] = { llx, lly }
1127 end
1128 n = n + 1 temp[n] = { ulx, uly }
1129
1130 return temp
1131 end
1132
1133 if n_2 > 0 then
1134 for i=1,#areas do
1135 local area = areas[i]
1136 if #area == 4 then
1137 areas[i] = check_two(area,f_2)
1138 else
1139
1140 end
1141 end
1142 end
1143
1144 for i=1,#areas do
1145 finish(areas[i])
1146 end
1147
1148 end
1149
1150 end
1151end
1152
1153local function fetchmultipar(n,anchor,page)
1154 local a = jobpositions.collected[anchor]
1155 if not a then
1156 report_graphics("missing anchor %a",anchor)
1157 else
1158 local data = pbg[n]
1159 if not data then
1160 data = calculatemultipar(n)
1161 pbg[n] = data
1162
1163 end
1164 local list = data and data.list
1165 if list then
1166 local pagedata = list[page]
1167 if pagedata then
1168 local k = data.bpos.k
1169 if k ~= 3 then
1170
1171 freemultipar(pagedata,getfree(page))
1172 end
1173 local nofmultipars = #pagedata
1174 if trace_shapes then
1175 report_graphics("fetching %a at page %s using anchor %a containing %s multipars",
1176 n,page,anchor,nofmultipars)
1177 end
1178 local x = a.x
1179 local y = a.y
1180 local w = a.w
1181 local h = a.h
1182 local d = a.d
1183 local bpos = data.bpos
1184 local bh = bpos.h
1185 local bd = bpos.d
1186 local result = { false }
1187 local n = 0
1188 for i=1,nofmultipars do
1189 local data = pagedata[i]
1190 local location = data.location
1191 local region = data.region
1192 local areas = data.areas
1193 if not areas then
1194 areas = { data.area }
1195 end
1196 for i=1,#areas do
1197 local area = areas[i]
1198 for i=1,#area do
1199 local a = area[i]
1200 area[i] = f_pair(a[1],a[2])
1201 end
1202 n = n + 1
1203 result[n+1] = f_template_b(n,multilocs[location],n,location,n,area,x,y)
1204 end
1205 end
1206 data[page] = nil
1207 result[1] = f_template_a(n,w,h+d,bh,bd,bh+bd)
1208 result[n+2] = f_template_c()
1209 return concat(result,"\n")
1210 end
1211 end
1212 end
1213 return f_template_a(0,0,0,0,0,0);
1214end
1215
1216backgrounds.fetchmultipar = fetchmultipar
1217
1218local function getwhatever(action)
1219 local tags = scanmpstring()
1220 local anchor = scanmpstring()
1221 local page = texgetcount(c_realpageno)
1222 if tags == "self" then
1223 tags = expandasvalue(string_value,"mpcategoryparameter",true,"self")
1224 elseif type(tags) == "string" then
1225 tags = settings_to_array(tags)
1226 for i=1,#tags do
1227 tags[i] = expandasvalue(string_value,"mpcategoryparameter",true,tags[i])
1228 end
1229 end
1230 if anchor == "anchor" then
1231 anchor = getmacro("MPanchorid")
1232 end
1233 if tags and anchor then
1234 return action(tags,anchor,page)
1235 end
1236end
1237
1238
1239
1240metapost.registerscript("getmultipars", function()
1241 return getwhatever(fetchmultipar)
1242end)
1243
1244
1245
1246implement {
1247 name = "fetchmultipar",
1248 actions = { fetchmultipar, context },
1249 arguments = { "string", "string", "integer" }
1250}
1251
1252
1253
1254do
1255
1256 local f_template_a = formatters[ [[
1257 path posboxes[], posregions[] ;
1258 numeric pospages[] ;
1259 numeric nofposboxes ;
1260 nofposboxes := %s ;
1261 %t
1262 ]] ]
1263
1264 local f_template_b = formatters[ [[
1265 pospages[%s] := %s ;
1266 posboxes[%s] := (%p,%p)--(%p,%p)--(%p,%p)--(%p,%p)--cycle ;
1267 posregions[%s] := (%p,%p)--(%p,%p)--(%p,%p)--(%p,%p)--cycle ;
1268 ]] ]
1269
1270 local function getposboxes(tags,anchor,page)
1271 local collected = jobpositions.collected
1272 if type(tags) == "string" then
1273 tags = settings_to_array(tags)
1274 end
1275 local list = { }
1276 local nofboxes = 0
1277 for i=1,#tags do
1278 local tag= tags[i]
1279 local c = collected[tag]
1280 if c then
1281 local r = c.r
1282 if anchor ~= r then
1283 r = anchor
1284 end
1285 if r then
1286 r = collected[r]
1287 if r then
1288 local rx = r.x
1289 local ry = r.y
1290 local rw = r.w
1291 local rh = r.h
1292 local rd = r.d
1293 local cx = c.x - rx
1294 local cy = c.y - ry
1295 local cw = cx + c.w
1296 local ch = cy + c.h
1297 local cd = cy - c.d
1298 nofboxes = nofboxes + 1
1299 list[nofboxes] = f_template_b(
1300 nofboxes,c.p,
1301 nofboxes,cx,ch,cw,ch,cw,cd,cx,cd,
1302 nofboxes,0,rh,rw,rh,rw,rd,0,rd
1303 )
1304 end
1305 end
1306 else
1307
1308 end
1309 end
1310 return f_template_a(nofboxes,list)
1311 end
1312
1313 metapost.registerscript("getposboxes", function()
1314 return getwhatever(getposboxes)
1315 end)
1316
1317 implement {
1318 name = "fetchposboxes",
1319 arguments = { "string", "string", "integer" },
1320 actions = { getposboxes, context },
1321 }
1322
1323end
1324
1325do
1326
1327 implement {
1328 name = "doifelserangeonpage",
1329 arguments = { "string", "string", "integer" },
1330 actions = function(first,last,page)
1331 local c = jobpositions.collected
1332 local f = c[first]
1333 if f then
1334 f = f.p
1335 if f and f ~= true and page >= f then
1336 local l = c[last]
1337 if l then
1338 l = l.p
1339 ctx_doifelse(l and l ~= true and page <= l)
1340 return
1341 end
1342 end
1343 end
1344 ctx_doifelse(false)
1345 end
1346 }
1347
1348end
1349 |