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