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