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