mp-core.mpiv /size: 56 Kb    last modification: 2020-07-01 14:35
1%D \module
2%D   [       file=mp-core.mpiv,
3%D        version=1999.08.01, % anchoring
4%D          title=\CONTEXT\ \METAPOST\ graphics,
5%D       subtitle=background macros,
6%D         author=Hans Hagen,
7%D           date=\currentdate,
8%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
9%C
10%C This module is part of the \CONTEXT\ macro||package and is
11%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
12%C details.
13
14if known context_core : endinput ; fi ;
15
16boolean context_core ; context_core := true ;
17
18%D Copied to here .. not used any more.
19
20if unknown NOfTextColumns : numeric NOfTextColumns ; NOfTextColumns := 1 ; fi ;
21if unknown NOfTextAreas   : numeric NOfTextAreas   ; NOfTextAreas   := 1 ; fi ;
22
23def SaveTextAreas =
24    path    SavedTextAreas  []  ;
25    path    SavedTextColumns[]  ;
26    numeric NOfSavedTextAreas   ;
27    numeric NOfSavedTextColumns ;
28    for i=1 upto NOfTextAreas :
29        SavedTextAreas[i] := TextAreas[i] ;
30    endfor ;
31    for i=1 upto NOfTextColumns :
32        SavedTextColumns[i] := TextColumns[i] ;
33    endfor ;
34    NOfSavedTextAreas   := NOfTextAreas ;
35    NOfSavedTextColumns := NOfTextColumns ;
36enddef ;
37
38def ResetTextAreas =
39    path TextAreas[], TextColumns[], PlainTextArea, RegionTextArea ;
40    numeric NOfTextAreas   ; NOfTextAreas   := 0 ;
41    numeric NOfTextColumns ; NOfTextColumns := 0 ;
42    numeric nofmultipars   ; nofmultipars   := 0 ;
43    TextAreas[0] := TextColumns[0] := origin -- cycle ;
44enddef ;
45
46ResetTextAreas ; SaveTextAreas ; ;
47
48def RegisterTextArea (expr x, y, w, h, d) =
49    begingroup ;
50    save p ; path p ;
51    p := unitsquare xyscaled(w,h+d) shifted (x,y-d) ;
52    if NOfTextAreas>0 :
53        % if needed, concatenate areas
54        if (round(llcorner TextAreas[NOfTextAreas]) = round(ulcorner p)) and
55           (round(lrcorner TextAreas[NOfTextAreas]) = round(urcorner p)) :
56            p :=
57                ulcorner TextAreas[NOfTextAreas] --
58                urcorner TextAreas[NOfTextAreas] --
59                lrcorner p                       --
60                llcorner p                       -- cycle ;
61        else :
62            NOfTextAreas := NOfTextAreas + 1 ;
63        fi ;
64    else :
65        NOfTextAreas := NOfTextAreas + 1 ;
66    fi ;
67    TextAreas[NOfTextAreas] := p ;
68    if NOfTextColumns>0 :
69        if (round(xpart llcorner TextColumns[NOfTextColumns]) = round(xpart ulcorner p)) and
70           (round(xpart lrcorner TextColumns[NOfTextColumns]) = round(xpart urcorner p)) :
71            p :=
72                ulcorner TextColumns[NOfTextColumns] --
73                urcorner TextColumns[NOfTextColumns] --
74                lrcorner p                           --
75                llcorner p                           -- cycle ;
76        else :
77            NOfTextColumns := NOfTextColumns + 1 ;
78        fi ;
79    else :
80        NOfTextColumns := NOfTextColumns + 1 ;
81    fi ;
82    TextColumns[NOfTextColumns] := p ;
83    endgroup ;
84enddef ;
85
86%D We store a local area in slot zero.
87
88def RegisterPlainTextArea(expr x,y,w,h,d) =
89    PlainTextArea := unitsquare xyscaled(w,h+d) shifted (x,y-d) ;
90enddef ;
91
92def RegisterRegionTextArea(expr x,y,w,h,d) =
93    RegionTextArea := unitsquare xyscaled(w,h+d) shifted (x,y-d) ;
94  % RegionTextArea := RegionTextArea enlarged 2mm ;
95enddef ;
96
97def RegisterLocalTextArea (expr x, y, w, h, d) =
98    TextAreas[0] := TextColumns[0] := unitsquare xyscaled(w,h+d) shifted (x,y-d) ;
99enddef ;
100
101def ResetLocalTextArea =
102    TextAreas[0] := TextColumns[0] := origin -- cycle ;
103enddef ;
104
105ResetLocalTextArea ;
106
107vardef InsideTextArea (expr _i_, _xy_) =
108    (round(xpart _xy_) >= round(xpart llcorner TextAreas[_i_])) and
109    (round(xpart _xy_) <= round(xpart lrcorner TextAreas[_i_])) and
110    (round(ypart _xy_) >= round(ypart llcorner TextAreas[_i_])) and
111    (round(ypart _xy_) <= round(ypart urcorner TextAreas[_i_]))
112enddef ;
113
114vardef InsideSavedTextArea (expr _i_, _xy_) =
115    (round(xpart _xy_) >= round(xpart llcorner SavedTextAreas[_i_])) and
116    (round(xpart _xy_) <= round(xpart lrcorner SavedTextAreas[_i_])) and
117    (round(ypart _xy_) >= round(ypart llcorner SavedTextAreas[_i_])) and
118    (round(ypart _xy_) <= round(ypart urcorner SavedTextAreas[_i_]))
119enddef ;
120
121vardef InsideSomeTextArea (expr _xy_) =
122    save ok ; boolean ok ; ok := false ;
123    for i := 1 upto NOfTextAreas :
124        if InsideTextArea(i,_xy_) :
125            ok := true ; % we can move the exit here
126        fi ;
127        exitif ok ;
128    endfor ;
129    ok
130enddef ;
131
132vardef InsideSomeSavedTextArea (expr _xy_) =
133    save ok ; boolean ok ; ok := false ;
134    for i := 1 upto NOfSavedTextAreas :
135        if InsideSavedTextArea(i,_xy_) :
136            ok := true ;
137        fi ;
138        exitif ok ;
139    endfor ;
140    ok
141enddef ;
142
143vardef TextAreaX (expr x) =
144    numeric _TextAreaX_ ; _TextAreaX_ := 0 ;
145    for i := 1 upto NOfTextAreas :
146        if (round(x) >= round(xpart llcorner TextAreas[i])) and
147           (round(x) <= round(xpart lrcorner TextAreas[i])) :
148            _TextAreaX_ := xpart llcorner TextAreas[i] ;
149        fi ;
150    endfor ;
151    _TextAreaX_
152enddef ;
153
154vardef TextAreaY (expr y) =
155    numeric _TextAreaY_ ; _TextAreaY_ := 0 ;
156    for i := 1 upto NOfTextAreas :
157        if (round(y) >= round(ypart llcorner TextAreas[NOfTextAreas])) and
158           (round(y) <= round(ypart ulcorner TextAreas[NOfTextAreas])) :
159            _TextAreaY_ := ypart llcorner TextAreas[NOfTextAreas] ;
160        fi ;
161    endfor ;
162    _TextAreaY_
163enddef ;
164
165vardef TextAreaXY (expr x, y) =
166    pair _TextAreaXY_ ; _TextAreaXY_ := origin ;
167    for i := 1 upto NOfTextAreas :
168        if (round(x) >= round(xpart llcorner TextAreas[i])) and
169           (round(x) <= round(xpart lrcorner TextAreas[i])) and
170           (round(y) >= round(ypart llcorner TextAreas[i])) and
171           (round(y) <= round(ypart ulcorner TextAreas[i])) :
172            _TextAreaXY_ := llconer TextAreas[i] ;
173        fi ;
174    endfor ;
175    _TextAreaXY_
176enddef ;
177
178vardef TextAreaW (expr x) =
179    numeric _TextAreaW_ ; _TextAreaW_ := 0 ;
180    for i := 1 upto NOfTextAreas :
181        if (round(x) >= round(xpart llcorner TextAreas[i])) and
182           (round(x) <= round(xpart lrcorner TextAreas[i])) :
183            _TextAreaW_ := bbwidth(TextAreas[i]) ;
184        fi ;
185    endfor ;
186    _TextAreaW_
187enddef ;
188
189vardef TextAreaH (expr y) =
190    numeric _TextAreaH_ ; _TextAreaH_ := 0 ;
191    for i := 1 upto NOfTextAreas :
192        if (round(y) >= round(ypart llcorner TextAreas[i])) and
193           (round(y) <= round(ypart ulcorner TextAreas[i])) :
194            _TextAreaH_ := bbheight(TextAreas[i]) ;
195        fi ;
196      endfor ;
197      _TextAreaH_
198enddef ;
199
200vardef TextAreaWH (expr x, y) =
201      pair _TextAreaWH_ ; _TextAreaWH_ := origin ;
202      for i := 1 upto NOfTextAreas :
203        if (round(x) >= round(xpart llcorner TextAreas[i])) and
204           (round(x) <= round(xpart lrcorner TextAreas[i])) and
205           (round(y) >= round(ypart llcorner TextAreas[i])) and
206           (round(y) <= round(ypart ulcorner TextAreas[i])) :
207            _TextAreaWH_ := (bbwidth(TextAreas[i]),bbheight(TextAreas[i])) ;
208        fi ;
209      endfor ;
210      _TextAreaWH_
211enddef ;
212
213%D Till here.
214
215pair    lxy[], rxy[], cxy[], llxy[], lrxy[], ulxy[], urxy[] ;
216path    pxy[] ;
217numeric hxy[], wxy[], dxy[], nxy[] ;
218
219def box_found (expr n,x,y,w,h,d) =
220    not ((x=0) and (y=0) and (w=0) and (h=0) and (d=0))
221enddef ;
222
223def initialize_box_pos (expr pos,n,x,y,w,h,d) =
224    pair lxy, rxy, cxy, llxy, lrxy, ulxy, urxy ;
225    path pxy ; numeric hxy, wxy, dxy, nxy;
226    lxy  := (x,y) ;
227    llxy := (x,y-d) ;
228    lrxy := (x+w,y-d) ;
229    urxy := (x+w,y+h) ;
230    ulxy := (x,y+h) ;
231    wxy  := w ;
232    hxy  := h ;
233    dxy  := d ;
234    rxy  := lxy shifted (wxy,0) ;
235    pxy  := llxy--lrxy--urxy--ulxy--cycle ;
236    cxy  := center pxy ;
237    nxy  := n ;
238    freeze_box(pos) ;
239enddef ;
240
241def freeze_box (expr pos) =
242    lxy[pos]  := lxy  ;
243    llxy[pos] := llxy ;
244    lrxy[pos] := lrxy ;
245    urxy[pos] := urxy ;
246    ulxy[pos] := ulxy ;
247    wxy[pos]  := wxy  ;
248    hxy[pos]  := hxy  ;
249    dxy[pos]  := dxy  ;
250    rxy[pos]  := rxy  ;
251    pxy[pos]  := pxy  ;
252    cxy[pos]  := cxy  ;
253    nxy[pos]  := nxy  ;
254enddef ;
255
256def initialize_box (expr n,x,y,w,h,d) =
257    numeric bpos ; bpos := 0 ; initialize_box_pos(bpos,n,x,y,w,h,d) ;
258enddef ;
259
260def initialize_area (expr fn,fx,fy,fw,fh,fd,
261                          tn,tx,ty,tw,th,td) =
262    numeric fpos ; fpos := 1 ; initialize_box_pos(fpos,fn,fx,fy,fw,fh,fd) ;
263    numeric tpos ; tpos := 2 ; initialize_box_pos(tpos,tn,tx,ty,tw,th,td) ;
264    do_initialize_area (fpos, tpos) ;
265enddef ;
266
267def do_initialize_area (expr fpos, tpos) =
268    lxy  := lxy[fpos] ;
269    llxy := (xpart llxy[fpos], ypart llxy[tpos]) ;
270    lrxy := lrxy[tpos] ;
271    urxy := (xpart urxy[tpos], ypart urxy[fpos]) ;
272    ulxy := ulxy[fpos] ;
273    wxy  := xpart lrxy - xpart llxy ;
274    hxy  := hxy[fpos] ;
275    dxy  := dxy[tpos] ;
276    rxy  := lxy shifted (wxy,0) ;
277    pxy  := llxy--lrxy--urxy--ulxy--cycle ;
278    cxy  := center pxy ;
279enddef ;
280
281def set_par_line_height (expr ph, pd) =
282    par_strut_height := if ph>0 : ph elseif StrutHeight>0 : StrutHeight else : 8pt fi ;
283    par_strut_depth  := if pd>0 : pd elseif StrutDepth >0 : StrutDepth  else : 3pt fi ;
284    par_line_height  := par_strut_height + par_strut_depth ;
285enddef ;
286
287def initialize_par (expr fn,fx,fy,fw,fh,fd,
288                         tn,tx,ty,tw,th,td,
289                         mn,mx,my,mw,mh,md,
290                         pn,px,py,pw,ph,pd,
291                         rw,rl,rr,rh,ra,ri) =
292
293    numeric fpos ; fpos := 1 ; initialize_box_pos(fpos,fn,fx,fy,fw,fh,fd) ;
294    numeric tpos ; tpos := 2 ; initialize_box_pos(tpos,tn,tx,ty,tw,th,td) ;
295    numeric mpos ; mpos := 3 ; initialize_box_pos(mpos,mn,mx,my,mw,mh,md) ;
296    numeric ppos ; ppos := 4 ; initialize_box_pos(ppos,pn,px,py,pw,ph,pd) ;
297
298    numeric par_strut_height, par_strut_depth, par_line_height ;
299
300    set_par_line_height (ph, pd) ;
301
302    do_initialize_area (fpos, tpos) ;
303    do_initialize_par  (fpos, tpos, mpos, ppos, rw,rl,rr,rh,ra,ri) ;
304
305enddef ;
306
307def initialize_area_par (expr fn,fx,fy,fw,fh,fd,
308                              tn,tx,ty,tw,th,td,
309                              wn,wx,wy,ww,wh,wd) =
310
311    numeric fpos ; fpos := 1 ; initialize_box_pos(fpos,fn,fx,fy,fw,fh,fd) ;
312    numeric tpos ; tpos := 2 ; initialize_box_pos(tpos,tn,tx,ty,tw,th,td) ;
313    numeric wpos ; wpos := 3 ; initialize_box_pos(wpos,wn,wx,wy,ww,wh,wd) ;
314
315    numeric par_strut_height, par_strut_depth, par_line_height ;
316
317    set_par_line_height (wh, wd) ;
318
319    numeric ffpos ; ffpos := 4 ; initialize_box_pos(ffpos,wn,wx,fy,0,wh,wd) ;
320    numeric ttpos ; ttpos := 5 ; initialize_box_pos(ttpos,wn,wx+ww,ty,0,wh,wd) ;
321
322    do_initialize_area (ffpos, ttpos) ;
323
324    numeric mpos ; mpos := 6 ; freeze_box(mpos) ;
325
326    do_initialize_par  (fpos, tpos, mpos, ffpos, 0,0,0,0,0,0) ;
327
328enddef ;
329
330def do_initialize_par (expr fpos, tpos, mpos, ppos, rw,rl,rr,rh,ra,ri) =
331
332    pair lref, rref, pref, lhref, rhref ;
333
334    % clip the page area to the left and right skips
335
336    llxy[mpos] := llxy[mpos] shifted (+rl,0) ;
337    lrxy[mpos] := lrxy[mpos] shifted (-rr,0) ;
338    urxy[mpos] := urxy[mpos] shifted (-rr,0) ;
339    ulxy[mpos] := ulxy[mpos] shifted (+rl,0) ;
340
341    % fixate the leftskip, rightskip and hanging indentation
342
343    lref := (xpart llxy[mpos],ypart ulxy[ppos]) ; lhref := lref shifted (rh,0) ;
344    rref := (xpart lrxy[mpos],ypart urxy[ppos]) ; rhref := rref shifted (rh,0) ;
345
346    pref := lxy[ppos] ;
347
348    if nxy[tpos] > nxy[fpos] :
349        if nxy[fpos] = nxy[mpos] :
350            % first of multiple pages
351            llxy[tpos] := llxy[mpos] ;
352            lrxy[tpos] := lrxy[mpos] ;
353            urxy[tpos] := lrxy[mpos] shifted (0,par_line_height) ;
354            ulxy[tpos] := llxy[mpos] shifted (0,par_line_height) ;
355            boxgriddirection := down ;
356        elseif nxy[tpos] = nxy[mpos] :
357            % last of multiple pages
358            llxy[fpos] := ulxy[mpos] shifted (0,-par_line_height) ;
359            lrxy[fpos] := urxy[mpos] shifted (0,-par_line_height) ;
360            urxy[fpos] := urxy[mpos] ;
361            ulxy[fpos] := ulxy[mpos] ;
362            boxgriddirection := up ;
363        else :
364            % middle of multiple pages
365            llxy[fpos] := ulxy[mpos] shifted (0,-par_line_height) ;
366            lrxy[fpos] := urxy[mpos] shifted (0,-par_line_height) ;
367            urxy[fpos] := urxy[mpos] ;
368            ulxy[fpos] := ulxy[mpos] ;
369            llxy[tpos] := llxy[mpos] ;
370            lrxy[tpos] := lrxy[mpos] ;
371            urxy[tpos] := lrxy[mpos] shifted (0,par_line_height) ;
372            ulxy[tpos] := llxy[mpos] shifted (0,par_line_height) ;
373            boxgriddirection := up ;
374        fi ;
375    else :
376        % just one page
377        boxgriddirection := up ;
378    fi ;
379
380    path txy, bxy, pxy, mxy ;
381
382    txy := originpath ; % top
383    bxy := originpath ; % bottom
384    pxy := originpath ; % composed
385
386    boolean lefthang, righthang, somehang ;
387
388    % we only hang on the first of a multiple page background
389
390    if nxy[mpos] > nxy[fpos] :
391        lefthang := righthang := somehang := false ;
392    else :
393        lefthang := (rh>0) ; righthang := (rh<0) ; somehang := false ;
394    fi ;
395
396    if lefthang :
397        mxy  := boundingbox (lref -- lref shifted (rh,ra*par_line_height)) ;
398    elseif righthang :
399        mxy  := boundingbox (rref -- rref shifted (rh,ra*par_line_height)) ;
400    else :
401        mxy  := originpath ;
402    fi ;
403
404    if round(ypart llxy[fpos]) = round(ypart llxy[tpos]) :
405
406        % We have a one-liner. Watch how er use the bottom pos for
407        % determining the height.
408
409        llxy[fpos] := (xpart llxy[fpos], ypart llxy[tpos]) ;
410        ulxy[fpos] := (xpart ulxy[fpos], ypart ulxy[tpos]) ;
411
412    else :
413
414        % We have a multi-liner. For convenience we now correct the
415        % begin and end points for indentation.
416
417        if lefthang and (round(ypart llxy[tpos]) >= round(ypart lrcorner mxy)) :
418            llxy[tpos] := (xpart lhref, ypart llxy[tpos]) ;
419            ulxy[tpos] := (xpart lhref, ypart ulxy[tpos]) ;
420        else :
421            llxy[tpos] := (xpart  lref, ypart llxy[tpos]) ;
422            ulxy[tpos] := (xpart  lref, ypart ulxy[tpos]) ;
423        fi ;
424
425        if righthang and (round(ypart lrxy[fpos]) >= round(ypart llcorner mxy)) :
426            lrxy[fpos] := (xpart rhref, ypart lrxy[fpos]) ;
427            urxy[fpos] := (xpart rhref, ypart urxy[fpos]) ;
428        else :
429            lrxy[fpos] := (xpart  rref, ypart lrxy[fpos]) ;
430            urxy[fpos] := (xpart  rref, ypart urxy[fpos]) ;
431        fi ;
432
433    fi ;
434
435    somehang := (ypart ulxy[fpos]>ypart llcorner mxy) and
436                (ypart llxy[tpos]<ypart llcorner mxy) ;
437
438    if round(ypart llxy[fpos]) = round(ypart llxy[tpos]) :
439
440        % A (short) one-liner goes into the top box.
441
442        txy := llxy[fpos] -- lrxy[tpos] -- urxy[tpos] -- ulxy[fpos] -- cycle ;
443
444    elseif (round(ypart llxy[fpos]) = round(ypart ulxy[tpos])) and
445           (round(xpart lrxy[tpos]) < round(xpart llxy[fpos])) :
446
447        % We have a sentence that spans two lines but with only end
448        % of line and begin of line segments. We need to take care of
449        % indentation.
450
451        txy := llxy[fpos] -- lrxy[fpos] -- urxy[fpos] -- ulxy[fpos] -- cycle ;
452        bxy := llxy[tpos] -- lrxy[tpos] -- urxy[tpos] -- ulxy[tpos] -- cycle ;
453
454    elseif (round(ypart llxy[fpos]) = round(ypart ulxy[tpos])) :
455
456        % We have a sentence that spans two lines but with overlap.
457
458        pxy :=
459            llxy[tpos] -- lrxy[tpos] -- urxy[tpos] -- lrxy[fpos] --
460            urxy[fpos] -- ulxy[fpos] -- llxy[fpos] -- ulxy[tpos] -- cycle ;
461
462    elseif lefthang and somehang :
463
464        % We have a sentence that spans more than two lines with
465        % left hanging indentation.
466
467        pxy :=
468            llxy[tpos] -- lrxy[tpos] -- urxy[tpos] --
469            (xpart urxy[fpos],ypart urxy[tpos]) --
470            urxy[fpos] -- ulxy[fpos] -- llxy[fpos] --
471            if round(ypart urxy[tpos]) < round(ypart llcorner mxy) :
472               (xpart lrcorner mxy,ypart llxy[fpos]) --
473               lrcorner mxy --
474               (xpart llxy[tpos],ypart llcorner mxy) --
475            else :
476               (xpart llxy[tpos],ypart llxy[fpos]) --
477            fi
478            cycle ;
479
480    elseif righthang and somehang :
481
482        % We have a sentence that spans more than two lines with
483        % right hanging indentation.
484
485        pxy :=
486            llxy[tpos] -- lrxy[tpos] -- urxy[tpos] --
487            if round(ypart urxy[tpos]) < round(ypart llcorner mxy) :
488                (xpart lrcorner mxy,ypart urxy[tpos]) --
489                lrcorner mxy -- llcorner mxy --
490            else :
491                (xpart urxy[fpos],ypart urxy[tpos]) --
492            fi
493            urxy[fpos] -- ulxy[fpos] -- llxy[fpos] --
494            (xpart llxy[tpos],ypart llxy[fpos]) --
495            cycle ;
496
497    else :
498
499        % We have a sentence that spans more than two lines with
500        % no hanging indentation.
501
502        pxy :=
503            llxy[tpos] -- lrxy[tpos] -- urxy[tpos] --
504            (xpart urxy[fpos],ypart urxy[tpos]) --
505            urxy[fpos] -- ulxy[fpos] -- llxy[fpos] --
506            (xpart llxy[tpos],ypart llxy[fpos]) --
507            cycle ;
508
509    fi ;
510
511    pxy := simplified pxy ;
512    pxy := unspiked   pxy ;
513
514enddef ;
515
516pair last_multi_par_shift ; last_multi_par_shift := origin ;
517
518def relocate_multipars (expr xy) =
519    last_multi_par_shift := xy ;
520    for i=1 upto nofmultipars :
521        multipars[i] := multipars[i] shifted last_multi_par_shift ;
522    endfor ;
523enddef ;
524
525boolean compensate_multi_par_topskip ;
526boolean span_multi_column_pars ;
527boolean auto_multi_par_hsize ;
528boolean enable_multi_par_fallback ;
529
530compensate_multi_par_topskip := true ;
531span_multi_column_pars       := false ;
532auto_multi_par_hsize         := false ; % true ;
533enable_multi_par_fallback    := true ;
534
535vardef multi_par_at_top (expr i) =
536  (round (ypart ulcorner multipars[i]) = round (ypart ulcorner (TextAreas[multirefs[i]] shifted last_multi_par_shift)))
537enddef ;
538
539numeric nofmultipars ; nofmultipars := 0 ;
540
541boolean obey_multi_par_hang    ; obey_multi_par_hang    := true  ;
542boolean obey_multi_par_more    ; obey_multi_par_more    := true  ;
543boolean snap_multi_par_tops    ; snap_multi_par_tops    := true  ;
544boolean local_multi_par_area   ; local_multi_par_area   := false ;
545boolean use_multi_par_region   ; use_multi_par_region   := false ;
546boolean ignore_multi_par_page  ; ignore_multi_par_page  := false ;
547boolean force_multi_par_chain  ; force_multi_par_chain  := true  ;
548boolean one_piece_multi_par    ; one_piece_multi_par    := false ;
549boolean check_multi_par_chain  ; check_multi_par_chain  := true  ; % extra page check
550
551boolean multi_column_first_page_hack; multi_column_first_page_hack := true ; % seems to work ok
552
553def simplify_multi_pars = % boundingbox ipv shape als optie
554    for i := 1 upto nofmultipars :
555        multipars[i] := boundingbox multipars[i] ;
556    endfor ;
557enddef ;
558
559def save_multipar (expr i, l, p) =
560    nofmultipars := nofmultipars + 1 ;
561    multirefs[nofmultipars] := i ;
562    multilocs[nofmultipars] := l ;
563    multipars[nofmultipars] := unspiked (simplified p) ;
564enddef ;
565
566def prepare_multi_pars (expr fn,fx,fy,fw,fh,fd,
567                             tn,tx,ty,tw,th,td,
568                             wn,wx,wy,ww,wh,wd,
569                             pn,px,py,pw,ph,pd,
570                             rw,rl,rr,rh,ra,ri) =
571
572% fill PlainTextArea withcolor red ;
573% fill RegionTextArea withcolor green;
574
575    if span_multi_column_pars :
576        begingroup ;
577        save TextAreas ; path TextAreas[] ;
578        save NOfTextAreas ; numeric NOfTextAreas ;
579        for i=1 upto NOfTextColumns :
580            TextAreas[i] := TextColumns[i] ;
581        endfor ;
582        NOfTextAreas := NOfTextColumns ;
583    fi ;
584
585    last_multi_par_shift := origin ;
586
587% save _tx_, _ty_, _fx_, _fy_ ;
588% if use_multi_par_region :
589%     _fx_ := fx ; %min(xpart ulcorner RegionTextArea,fx) ;
590%     _fy_ := fy ; %min(xpart ulcorner RegionTextArea,fy) ;
591%     _tx_ := min(xpart lrcorner RegionTextArea,tx) ;
592%     _ty_ := min(xpart lrcorner RegionTextArea,ty) ;
593% else :
594%     _fx_ := fx ;
595%     _fy_ := fy ;
596%     _tx_ := tx ;
597%     _ty_ := ty ;
598% fi ;
599
600%     numeric fpos ; fpos := 1 ; initialize_box_pos(fpos,fn,_fx_,_fy_,fw,fh,fd) ;
601%     numeric tpos ; tpos := 2 ; initialize_box_pos(tpos,tn,_tx_,_ty_,tw,th,td) ;
602    numeric fpos ; fpos := 1 ; initialize_box_pos(fpos,fn,fx,fy,fw,fh,fd) ;
603    numeric tpos ; tpos := 2 ; initialize_box_pos(tpos,tn,tx,ty,tw,th,td) ;
604    numeric wpos ; wpos := 3 ; initialize_box_pos(wpos,wn,wx,wy,ww,wh,wd) ;
605    numeric ppos ; ppos := 4 ; initialize_box_pos(ppos,pn,px,py,pw,ph,pd) ;
606
607    if local_multi_par_area :
608        RealPageNumber := fn ;
609        NOfTextAreas := 1 ;
610        NOfSavedTextAreas := 0 ;
611        TextAreas[1] := TextAreas[0] ;
612        TextColumns[1] := TextColumns[0] ;
613        nxy[fpos] := nxy[tpos] := nxy[wpos] := nxy[ppos] := RealPageNumber ;
614    elseif use_multi_par_region :
615        RealPageNumber := fn ;
616        NOfTextAreas := 1 ;
617        NOfSavedTextAreas := 0 ;
618        TextAreas[1] := RegionTextArea ;
619        TextColumns[1] := RegionTextArea ;
620        nxy[fpos] := nxy[tpos] := nxy[wpos] := nxy[ppos] := RealPageNumber ;
621    elseif ignore_multi_par_page :
622        RealPageNumber := fn ;
623        nxy[fpos] := nxy[tpos] := nxy[wpos] := nxy[ppos] := RealPageNumber ;
624    fi ;
625
626    numeric par_strut_height, par_strut_depth, par_line_height ;
627
628    set_par_line_height (ph, pd) ;
629
630    numeric par_hang_indent, par_hang_after, par_indent, par_left_skip, par_right_skip ;
631
632    par_hang_indent  := rh ;
633    par_hang_after   := ra ;
634    par_indent       := ri ;
635    par_left_skip    := rl ;
636    par_right_skip   := rr ;
637
638    pair par_start_pos ;
639    pair par_stop_pos ;
640
641    par_start_pos := llxy[fpos]
642        if par_indent   <0: shifted (-par_indent,   0) fi
643        if par_left_skip<0: shifted (-par_left_skip,0) fi ;
644
645    par_stop_pos := lrxy[tpos]
646        if par_right_skip<0: shifted (par_right_skip,0) fi ; % nasty as the endpos can be shifted by rightskip
647
648    if wxy[wpos]>0 :
649        left_skip  := rl + xpart llxy[wpos] - xpart llxy[ppos] ;
650        right_skip := rw - left_skip - ww ;
651    else :
652        left_skip  := rl ;
653        right_skip := rr ;
654    fi ;
655
656    path    multipar, multipars[] ;
657    numeric multiref, multirefs[] ;
658    numeric multiloc, multilocs[] ; % 1=begin 2=between 3=end
659
660    numeric multi_par_pages ; multi_par_pages := nxy[tpos]-nxy[fpos]+1 ;
661
662    % locals .. why can't i move these outside?
663
664    vardef _pmp_set_multipar_ (expr i) =
665        ( (TextAreas[i] leftenlarged -left_skip) rightenlarged (-right_skip
666        if auto_multi_par_hsize : + rw - bbwidth(TextAreas[i]) fi) )
667    enddef ;
668
669    vardef _pmp_snapped_multi_pos_ (expr p) =
670        if snap_multi_par_tops :
671            if abs(ypart p - ypart ulcorner multipar) < par_line_height :
672                (xpart p,ypart ulcorner multipar)
673            else :
674                p
675            fi
676        else :
677            p
678        fi
679    enddef ;
680
681    vardef _pmp_estimated_par_lines_ (expr h) =
682        round(h/par_line_height)
683    enddef ;
684
685    vardef _pmp_top_multi_par_(expr p) =
686        (round(_pmp_estimated_par_lines_(bbheight(p)*par_line_height))=round(bbheight(p)))
687    enddef ;
688
689    vardef _pmp_multi_par_tsc_(expr p) =
690        if _pmp_top_multi_par_(p) : TopSkipCorrection else : 0 fi
691    enddef ;
692
693    vardef _pmp_estimated_multi_par_height_ (expr n, t) =
694        if round(par_line_height)=0 :
695            0
696        else :
697            save ok, h ; boolean ok ;
698            numeric h ; h := 0 ;
699            ok := false ;
700            if (nxy[fpos]=RealPageNumber-1) :
701                for i := 1 upto NOfSavedTextAreas :
702                    if (InsideSavedTextArea(i,par_start_pos)) :
703                        ok := true ;
704                        h := h + _pmp_estimated_par_lines_(ypart ulxy[fpos] - ypart llcorner SavedTextAreas[i]) ;
705                    elseif ok :
706                        h := h + _pmp_estimated_par_lines_(bbheight(SavedTextAreas[i])) ;
707                    fi ;
708                endfor ;
709            fi ;
710            if ok :
711                for i := 1 upto n-1 :
712                    h := h + _pmp_estimated_par_lines_(bbheight(TextAreas[i])) ;
713                endfor ;
714            else :
715                % already: ok := false ;
716                for i := 1 upto n-1 :
717                    if (InsideTextArea(i,par_start_pos)) :
718                        ok := true ;
719                        h := h + _pmp_estimated_par_lines_(ypart ulxy[fpos] - ypart llcorner TextAreas[i]) ;
720                    elseif ok :
721                        h := h + _pmp_estimated_par_lines_(bbheight(TextAreas[i])) ;
722                    fi ;
723                endfor ;
724            fi ;
725            h
726        fi
727    enddef ;
728
729    vardef _pmp_left_top_hang_ (expr same_area) =
730
731        par_hang_after := ra + _pmp_estimated_par_lines_(py-fy) ;
732
733        if (par_hang_indent>0) and (par_hang_after<0) and obey_multi_par_hang :
734            pair _ul_ ; _ul_ := (xpart ulcorner multipar, ypart _pmp_snapped_multi_pos_(ulxy[fpos]));
735            pair _pa_ ; _pa_ := _ul_ shifted (0,par_hang_after*par_line_height) ;
736            _pa_ := (xpart _pa_,max(ypart _pa_ -TopSkipCorrection,ypart llcorner multipar)) ;
737            if same_area :
738                _pa_ := (xpart _pa_,max(ypart _pa_ -TopSkipCorrection,ypart llxy[tpos])) ;
739            fi ;
740            if obey_multi_par_more and (round(par_line_height)>0) :
741                par_hang_after := min(0,round(par_hang_after + (ypart urxy[fpos]-ypart _pa_)/par_line_height)) ;
742            fi ;
743            (xpart _ul_ + par_hang_indent, ypart lrxy[fpos]) --
744            (xpart _ul_ + par_hang_indent, ypart _pa_) --
745            (xpart ulcorner multipar, ypart _pa_)
746        else :
747            (xpart ulcorner multipar, ypart lrxy[fpos])
748        fi
749    enddef ;
750
751    vardef _pmp_right_top_hang_ (expr same_area) =
752
753        par_hang_after := ra + _pmp_estimated_par_lines_(py-fy) ;
754
755        if (par_hang_indent<0) and (par_hang_after<0) and obey_multi_par_hang :
756            pair _ur_ ; _ur_ := (xpart urcorner multipar, ypart _pmp_snapped_multi_pos_(urxy[fpos])) ;
757            pair _pa_ ; _pa_ := _ur_ shifted (0,par_hang_after*par_line_height) ;
758            _pa_ := (xpart _pa_,max(ypart _pa_ -TopSkipCorrection,ypart llcorner multipar)) ;
759            if same_area :
760                _pa_ := (xpart _pa_,max(ypart _pa_ -TopSkipCorrection,ypart _pmp_snapped_multi_pos_(ulxy[tpos]))) ;
761            fi ;
762            if obey_multi_par_more and (round(par_line_height)>0) :
763                par_hang_after := min(0,round(par_hang_after + (ypart urxy[fpos]-ypart _pa_)/par_line_height)) ;
764            fi ;
765            (xpart urcorner multipar, ypart _pa_) --
766            (xpart _ur_ + par_hang_indent, ypart _pa_) --
767            (xpart _ur_ + par_hang_indent, ypart _pmp_snapped_multi_pos_(urxy[fpos]))
768        else :
769            (xpart urcorner multipar, ypart _pmp_snapped_multi_pos_(urxy[fpos]))
770        fi
771    enddef ;
772
773    vardef _pmp_x_left_top_hang_ (expr i, t) =
774        par_hang_after := min(0,ra + _pmp_estimated_multi_par_height_(i,t)) ;
775        if (par_hang_indent>0) and (par_hang_after<0) :
776            pair _ul_ ; _ul_ := ulcorner multipar ;
777            pair _pa_ ; _pa_ := _ul_ shifted (0,par_hang_after*par_line_height) ;
778            _pa_ := (xpart _pa_,max(ypart _pa_,ypart llcorner multipar)) ;
779            if t :
780                _pa_ := (xpart _pa_,max(ypart _pa_,ypart llxy[tpos]));
781            fi ;
782            if abs(ypart _pa_-ypart llxy[tpos])<par_line_height :
783                _pa_ := (xpart _pa_,ypart llxy[tpos]);
784            fi ;
785            if abs(ypart _pa_-ypart llcorner multipar)<par_line_height :
786                _pa_ := (xpart _pa_,ypart llcorner multipar);
787            fi ;
788            (xpart _ul_, ypart _pa_) --
789            (xpart _ul_ + par_hang_indent, ypart _pa_) --
790            (xpart _ul_ + par_hang_indent, ypart _ul_)
791        else :
792            ulcorner multipar
793        fi
794    enddef ;
795
796    vardef _pmp_x_right_top_hang_ (expr i, t) =
797        par_hang_after := min(0,ra + _pmp_estimated_multi_par_height_(i,t)) ;
798        if (par_hang_indent<0) and (par_hang_after<0) :
799            pair _ur_ ; _ur_ := urcorner multipar ;
800            pair _pa_ ; _pa_ := _ur_ shifted (0,par_hang_after*par_line_height) ;
801            _pa_ := (xpart _pa_,max(ypart _pa_,ypart lrcorner multipar)) ;
802            if t :
803                _pa_ := (xpart _pa_,max(ypart _pa_,ypart _pmp_snapped_multi_pos_(urxy[tpos]))) ;
804            fi ;
805            (xpart _ur_ + par_hang_indent, ypart _ur_) --
806            (xpart _ur_ + par_hang_indent, ypart _pa_) --
807            (xpart _ur_, ypart _pa_)
808        else :
809            urcorner multipar
810        fi
811    enddef ;
812
813    vardef _pmp_left_bottom_hang_ (expr same_area) =
814        pair _ll_, _sa_, _pa_ ;
815        _sa_ := if same_area : llxy[tpos] else : lrcorner multipar fi ;
816        if (par_hang_indent>0) and (par_hang_after>0) and obey_multi_par_hang :
817            _ll_ := (xpart ulcorner multipar, ypart _pmp_snapped_multi_pos_(ulxy[fpos])) ;
818            _pa_ := _ll_ shifted (0,-par_hang_after*par_line_height) ;
819            _pa_ := (xpart _pa_,max(ypart _pa_,ypart llcorner multipar)) ;
820            if same_area :
821                _pa_ := (xpart _pa_,max(ypart _pa_,ypart _sa_)) ;
822            fi ;
823            if obey_multi_par_more and (round(par_line_height)>0) :
824                par_hang_after := max(0,round(par_hang_after - (ypart urxy[fpos]-ypart _pa_)/par_line_height)) ;
825            fi ;
826            _pa_ --
827            (xpart _pa_ + par_hang_indent,ypart _pa_) --
828            (xpart _pa_ + par_hang_indent,ypart _sa_)
829        else :
830            (xpart llcorner multipar, ypart _sa_)
831        fi
832    enddef ;
833
834    vardef _pmp_right_bottom_hang_ (expr same_area) =
835        pair _lr_, _sa_, _pa_ ;
836        _sa_ := if same_area : _pmp_snapped_multi_pos_(ulxy[tpos]) else : lrcorner multipar fi ;
837        if (par_hang_indent<0) and (par_hang_after>0) and obey_multi_par_hang :
838            _lr_ := (xpart urcorner multipar, ypart _pmp_snapped_multi_pos_(urxy[fpos])) ;
839            _pa_ := _lr_ shifted (0,-par_hang_after*par_line_height) ;
840            _pa_ := (xpart _pa_,max(ypart _pa_,ypart lrcorner multipar)) ;
841            if same_area :
842                _pa_ := (xpart _pa_,max(ypart _pa_,ypart _pmp_snapped_multi_pos_(ulxy[tpos]))) ;
843            fi ;
844            if obey_multi_par_more and (round(par_line_height)>0) :
845                par_hang_after := max(0,round(par_hang_after - (ypart urxy[fpos]-ypart _pa_)/par_line_height)) ;
846            fi ;
847            (xpart _pa_ + par_hang_indent,ypart _sa_) --
848            (xpart _pa_ + par_hang_indent,ypart _pa_) --
849            _pa_
850        else :
851        (xpart lrcorner multipar, ypart _sa_)
852        fi
853    enddef ;
854
855    vardef _pmp_x_left_bottom_hang_ (expr i, t) =
856        pair _ll_, _sa_, _pa_ ;
857        _sa_ := if t : llxy[tpos] else : llcorner multipar fi ;
858        if (par_hang_indent>0) and (ra>0) :
859            par_hang_after := max(0,ra - _pmp_estimated_multi_par_height_(i,t)) ;
860            _ll_ := ulcorner multipar ;
861            _pa_ := _ll_ shifted (0,-par_hang_after*par_line_height) ;
862            _pa_ := (xpart _pa_,max(ypart _pa_,ypart llcorner multipar)) ;
863            _pa_ := (xpart _pa_,max(ypart _pa_,ypart _sa_)) ;
864            % we need to compensate for topskip enlarged areas
865            if abs(ypart _pa_ - ypart _sa_) > par_line_height :
866                (xpart _pa_ + par_hang_indent,ypart _sa_) --
867                (xpart _pa_ + par_hang_indent,ypart _pa_) --
868            fi
869            _pa_
870        else :
871            (xpart llcorner multipar, ypart _sa_)
872        fi
873    enddef ;
874
875    vardef _pmp_x_right_bottom_hang_ (expr i, t) =
876        pair _lr_, _sa_, _pa_ ;
877        _sa_ := if t : _pmp_snapped_multi_pos_(ulxy[tpos]) else : llcorner multipar fi ;
878        if (par_hang_indent<0) and (ra>0) :
879            par_hang_after := max(0,ra - _pmp_estimated_multi_par_height_(i, t)) ;
880            _lr_ := urcorner multipar ;
881            _pa_ := _lr_ shifted (0,-par_hang_after*par_line_height) ;
882            _pa_ := (xpart _pa_,max(ypart _pa_,ypart lrcorner multipar)) ;
883            _pa_ := (xpart _pa_,max(ypart _pa_,ypart _sa_)) ;
884            % we need to compensate for topskip enlarged areas
885            _pa_
886            if abs(ypart _pa_ - ypart _sa_) > par_line_height :
887                -- (xpart _pa_ + par_hang_indent,ypart _pa_)
888                -- (xpart _pa_ + par_hang_indent,ypart _sa_)
889            fi
890        else :
891            (xpart lrcorner multipar, ypart _sa_)
892        fi
893    enddef ;
894
895    % def _pmp_test_multipar_ =
896    %     multipar := boundingbox multipar ;
897    % enddef ;
898
899    % first loop
900
901    ii := 0 ; nn := NOfTextAreas+1 ; nofmultipars := 0 ;
902
903    if enable_multi_par_fallback  and (nxy[fpos]=RealPageNumber)
904        and (nxy[tpos]=RealPageNumber) and not (InsideSomeTextArea(lxy[fpos]) and InsideSomeTextArea(rxy[tpos])) :
905
906        % fallback
907
908        % multipar :=
909        %     llxy[fpos] --
910        %     lrxy[tpos] --
911        %     urxy[tpos] --
912        %     ulxy[fpos] -- cycle ;
913        %
914        % save_multipar (1,1,multipar) ;
915
916        % we need to take the boundingbox because there can be
917        % more lines and we want a proper rectange
918
919        multipar :=
920            ulxy[fpos] --
921            urxy[tpos] --
922            lrxy[fpos] --
923            llxy[tpos] -- cycle ;
924
925        save_multipar (1,1,boundingbox(multipar)) ;
926
927    else :
928
929        % normal
930
931        for i=1 upto NOfTextAreas :
932
933            TopSkipCorrection := 0 ;
934
935            multipar := _pmp_set_multipar_(i) ;
936
937            % watch how we compensate for negative indentation
938
939            if (nxy[fpos]=RealPageNumber) and (InsideTextArea(i,par_start_pos)) :
940
941                % first one in chain
942
943                ii := i ;
944
945                if (nxy[tpos]=RealPageNumber) and (InsideTextArea(i,par_stop_pos)) :
946
947                    % in same area
948
949                    nn := i ;
950
951                    if compensate_multi_par_topskip and (round(LineHeight-ph-pd)=0) :
952
953                        TopSkipCorrection := TopSkip - StrutHeight ;
954
955                        if round(ypart ulxy[fpos] + TopSkipCorrection) = round(ypart ulcorner TextAreas[i]) :
956                            ulxy[fpos] := ulxy[fpos] shifted (0,TopSkipCorrection) ;
957                            urxy[fpos] := urxy[fpos] shifted (0,TopSkipCorrection) ;
958                        else :
959                            TopSkipCorrection := 0 ;
960                        fi ;
961
962                    fi ;
963
964                    if ypart llxy[fpos] = ypart llxy[tpos] :
965
966                        multipar :=
967                            llxy[fpos] --
968                            lrxy[tpos] --
969                            _pmp_snapped_multi_pos_(urxy[tpos]) --
970                            _pmp_snapped_multi_pos_(ulxy[fpos]) --
971                            cycle ;
972
973                        save_multipar (i,1,multipar) ;
974
975                    elseif (ypart llxy[fpos] = ypart ulxy[tpos]) and (xpart llxy[tpos] < xpart llxy[fpos]) :
976
977                        % two loners
978
979                        multipar := if obey_multi_par_hang :
980
981                            _pmp_right_bottom_hang_(true) --
982                            _pmp_right_top_hang_(true) --
983                            _pmp_snapped_multi_pos_(urxy[fpos]) --
984                            lrxy[fpos] --
985
986                        else :
987
988                            llxy[fpos] --
989                            (xpart urcorner multipar, ypart llxy[fpos]) --
990                            (xpart urcorner multipar, ypart ulxy[fpos]) --
991                            _pmp_snapped_multi_pos_(ulxy[fpos]) --
992
993                        fi cycle ;
994
995                        save_multipar (i,1,multipar) ;
996
997                        multipar := _pmp_set_multipar_(i) ;
998
999                        multipar := if obey_multi_par_hang :
1000
1001                            _pmp_left_bottom_hang_(true) --
1002                            llxy[tpos] --
1003                            _pmp_snapped_multi_pos_(ulxy[tpos]) --
1004                            _pmp_left_top_hang_(true) --
1005
1006                        else :
1007
1008                            (xpart llcorner multipar, ypart llxy[tpos]) --
1009                            llxy[tpos] --
1010                            _pmp_snapped_multi_pos_(ulxy[tpos]) --
1011                            (xpart llcorner multipar, ypart ulxy[tpos]) --
1012
1013                        fi cycle ;
1014
1015                        save_multipar (i,1,multipar) ;
1016
1017                    else :
1018
1019                        multipar := if obey_multi_par_hang :
1020
1021                            _pmp_left_bottom_hang_(true) --
1022                            llxy[tpos] --
1023                            _pmp_snapped_multi_pos_(ulxy[tpos]) --
1024                            _pmp_right_bottom_hang_(true) --
1025                            _pmp_right_top_hang_(true) --
1026                            _pmp_snapped_multi_pos_(urxy[fpos]) --
1027                            lrxy[fpos] --
1028                            _pmp_left_top_hang_(true) --
1029
1030                        else :
1031
1032                            (xpart llcorner multipar, ypart llxy[tpos]) --
1033                            llxy[tpos] --
1034                            _pmp_snapped_multi_pos_(ulxy[tpos]) --
1035                            (xpart lrcorner multipar, ypart ulxy[tpos]) --
1036                            (xpart urcorner multipar, ypart urxy[fpos]) --
1037                            _pmp_snapped_multi_pos_(urxy[fpos]) --
1038                            lrxy[fpos] --
1039                            (xpart ulcorner multipar, ypart lrxy[fpos]) --
1040
1041                        fi cycle  ;
1042
1043                        save_multipar (i,1,multipar) ;
1044
1045                    fi ;
1046
1047                else :
1048
1049                    multipar := if obey_multi_par_hang :
1050
1051                        _pmp_left_bottom_hang_(false) --
1052                        _pmp_right_bottom_hang_(false) --
1053                        _pmp_right_top_hang_(false) --
1054                        _pmp_snapped_multi_pos_(urxy[fpos]) --
1055                        lrxy[fpos] --
1056                        _pmp_left_top_hang_(false) --
1057
1058                    else :
1059
1060                        llcorner multipar --
1061                        lrcorner multipar --
1062                        (xpart urcorner multipar, ypart urxy[fpos]) --
1063                        _pmp_snapped_multi_pos_(urxy[fpos]) --
1064                        lrxy[fpos] --
1065                        (xpart ulcorner multipar, ypart lrxy[fpos]) --
1066
1067                    fi cycle ;
1068
1069                    save_multipar (i,1,multipar) ;
1070
1071                fi ;
1072
1073            elseif (nxy[tpos]=RealPageNumber) and (InsideTextArea(i,par_stop_pos)) :
1074
1075                % last one in chain
1076
1077                nn := i ;
1078
1079                if obey_multi_par_hang and obey_multi_par_more :
1080
1081                    multipar :=
1082                        _pmp_x_left_top_hang_(i,true) --
1083                        _pmp_x_right_top_hang_(i,true) --
1084                        _pmp_x_right_bottom_hang_(i,true) --
1085                        _pmp_snapped_multi_pos_(ulxy[tpos]) --
1086                        llxy[tpos] --
1087                        _pmp_x_left_bottom_hang_(i,true) --
1088                        cycle ;
1089
1090                else :
1091
1092                    multipar :=
1093                        ulcorner multipar --
1094                        urcorner multipar --
1095                        (xpart lrcorner multipar, ypart urxy[tpos]) --
1096                        _pmp_snapped_multi_pos_(ulxy[tpos]) --
1097                        llxy[tpos] --
1098                        (xpart llcorner multipar, ypart llxy[tpos]) --
1099                        cycle ;
1100
1101                fi ;
1102
1103                save_multipar (i,3,multipar) ;
1104
1105            elseif multi_column_first_page_hack and ((nxy[fpos]=RealPageNumber) and (nxy[tpos]>=RealPageNumber) and (NOfTextColumns>1)) :
1106
1107                save_multipar (i,2,multipar) ;
1108
1109            else :
1110                % handled later
1111            fi ;
1112
1113        endfor ;
1114
1115
1116        % second loop
1117
1118        if force_multi_par_chain or (ii > 1) :
1119
1120            for i=ii+1 upto nn-1 :
1121
1122                % rest of chain / todo : hang
1123
1124                % hm, the second+ column in column sets now gets lost in a NOfTextColumns
1125
1126                if (not check_multi_par_chain) or ((nxy[fpos]<RealPageNumber) and (nxy[tpos]>RealPageNumber)) :
1127
1128                    multipar := _pmp_set_multipar_(i) ;
1129
1130                    if obey_multi_par_hang and obey_multi_par_more :
1131
1132                        multipar :=
1133                            _pmp_x_left_top_hang_(i,false) --
1134                            _pmp_x_right_top_hang_(i,false) --
1135                            _pmp_x_right_bottom_hang_(i,false) --
1136                            _pmp_x_left_bottom_hang_(i,false) --
1137                            cycle ;
1138
1139                    fi ;
1140
1141                    save_multipar(i,2,multipar) ;
1142
1143                fi ;
1144
1145            endfor ;
1146
1147        fi ;
1148
1149        % end of normal/fallback
1150
1151    fi ;
1152
1153    if span_multi_column_pars :
1154        endgroup ;
1155    fi ;
1156
1157    % potential safeguard:
1158
1159    % for i=1 upto nofmultipars :
1160    %     if length p <= 4 :
1161    %         multipars[i] := boundingbox(multipars[i]) ;
1162    %     fi ;
1163    % end ;
1164
1165    % quick hack for gb:
1166
1167    one_piece_multi_par := (nofmultipars=1) and (pn=tn) ;
1168
1169enddef ;
1170
1171def boxgridoptions = withcolor .8red   enddef ;
1172def boxlineoptions = withcolor .8blue  enddef ;
1173def boxfilloptions = withcolor .8white enddef ;
1174
1175numeric boxgridtype      ; boxgridtype      := 0 ;
1176numeric boxlinetype      ; boxlinetype      := 1 ;
1177numeric boxfilltype      ; boxfilltype      := 1 ;
1178numeric boxdashtype      ; boxdashtype      := 0 ;
1179pair    boxgriddirection ; boxgriddirection := up ;
1180numeric boxgridwidth     ; boxgridwidth     := 1pt ;
1181numeric boxlinewidth     ; boxlinewidth     := 1pt ;
1182numeric boxlineradius    ; boxlineradius    := 0pt ;
1183numeric boxfilloffset    ; boxfilloffset    := 0pt ;
1184numeric boxgriddistance  ; boxgriddistance  := .5cm ;
1185numeric boxgridshift     ; boxgridshift     := 0pt ;
1186
1187% def draw_box =
1188%     draw pxy        boxlineoptions withpen pencircle scaled boxlinewidth ;
1189%     draw lxy -- rxy boxlineoptions withpen pencircle scaled boxgridwidth ;
1190% enddef ;
1191
1192def draw_par  = % 1 2 3 11 12
1193    do_draw_par(pxy) ; do_draw_par(txy) ; do_draw_par(bxy) ;
1194    for i = pxy, txy, bxy :
1195        if boxgridtype = 1 :
1196            boxgriddirection := origin ;
1197            draw baseline_grid (i,boxgriddirection,true ) boxgridoptions ;
1198        elseif boxgridtype = 2 :
1199            boxgriddirection := origin ;
1200            draw baseline_grid (i,boxgriddirection,false) boxgridoptions ;
1201        elseif boxgridtype = 3 :
1202            boxgriddirection := origin ;
1203            draw baseline_grid (i,boxgriddirection,true ) boxgridoptions ;
1204            draw baseline_grid (i,boxgriddirection,true ) shifted (0,ExHeight) boxgridoptions ;
1205        elseif boxgridtype = 4 :
1206            boxgriddirection := origin ;
1207            draw baseline_grid (i,boxgriddirection,true ) shifted (0,ExHeight/2) boxgridoptions ;
1208        elseif boxgridtype = 11 :
1209            draw graphic_grid(i,boxgriddistance,boxgriddistance,boxgriddistance/2,boxgriddistance/2) ;
1210        elseif boxgridtype = 12 :
1211            draw graphic_grid(i,boxgriddistance,boxgriddistance,0,0) ;
1212        fi ;
1213    endfor ;
1214enddef ;
1215
1216def do_show_par (expr p, r, c) =
1217    if length(p) > 2 :
1218        for i=0 upto length(p) :
1219            draw fullcircle scaled r shifted point i of p withpen pencircle scaled .5pt withcolor c ;
1220        endfor ;
1221    fi ;
1222    draw p withpen pencircle scaled .5pt withcolor c ;
1223enddef ;
1224
1225def show_par  =
1226    if length(mxy) > 2 :
1227        draw mxy dashed evenly withpen pencircle scaled .5pt withcolor .5white ;
1228    fi ;
1229    do_show_par(txy, 4pt, .5green) ;
1230    do_show_par(bxy, 6pt, .5blue ) ;
1231    do_show_par(pxy, 8pt, .5red  ) ;
1232    draw pref withpen pencircle scaled 2pt ;
1233enddef ;
1234
1235def sort_multi_pars =
1236    if nofmultipars>1 :
1237        begingroup ;
1238        save _p_, _n_ ; path _p_ ; numeric _n_ ;
1239        for i := 1 upto nofmultipars :
1240            if multilocs[i] = 3 :
1241                _p_ := multipars[nofmultipars] ;
1242                multipars[nofmultipars] := multipars[i] ;
1243                multipars[i] := _p_ ;
1244                _n_ := multirefs[nofmultipars] ;
1245                multirefs[nofmultipars] := multirefs[i] ;
1246                multirefs[i] := _n_ ;
1247                _n_ := multilocs[nofmultipars] ;
1248                multilocs[nofmultipars] := multilocs[i] ;
1249                multilocs[i] := _n_ ;
1250            fi ;
1251        endfor ;
1252        endgroup ;
1253    fi ;
1254enddef ;
1255
1256def collapse_multi_pars =
1257    if nofmultipars>1 :
1258        begingroup ;
1259        save _nofmultipars_ ; numeric _nofmultipars_ ;
1260        _nofmultipars_ := 1 ;
1261        sort_multi_pars ; % block not in order: 1, 3, 2....
1262        for i:=1 upto nofmultipars-1 :
1263            if (round(xpart(llcorner multipars[i]-llcorner multipars[i+1]))=0) and
1264               (round(xpart(lrcorner multipars[i]-lrcorner multipars[i+1]))=0) :
1265                multilocs[_nofmultipars_] := multilocs[i+1] ;
1266                multirefs[_nofmultipars_] := multirefs[i+1] ;
1267                multipars[_nofmultipars_] :=
1268                    ulcorner multipars[_nofmultipars_] --
1269                    urcorner multipars[_nofmultipars_] --
1270                    lrcorner multipars[i+1] --
1271                    llcorner multipars[i+1] -- cycle ;
1272            else :
1273                _nofmultipars_ := _nofmultipars_ + 1 ;
1274                multipars[_nofmultipars_] := multipars[i+1] ;
1275                multilocs[_nofmultipars_] := multilocs[i+1] ;
1276                multirefs[_nofmultipars_] := multirefs[i+1] ;
1277            fi  ;
1278        endfor ;
1279        nofmultipars := _nofmultipars_ ;
1280        endgroup ;
1281    fi ;
1282enddef ;
1283
1284def draw_multi_pars  =
1285    for i=1 upto nofmultipars :
1286        do_draw_par(multipars[i]) ;
1287        if boxgridtype= 1 :
1288            draw baseline_grid (multipars[i],if multilocs[i]=1: down else: up fi,true) ;
1289        elseif boxgridtype= 2 :
1290            draw baseline_grid (multipars[i],if multilocs[i]=1: down else: up fi,false) ;
1291        elseif boxgridtype= 3 :
1292            draw baseline_grid (multipars[i],if multilocs[i]=1: down else: up fi,true) ;
1293            draw baseline_grid (multipars[i],if multilocs[i]=1: down else: up fi,true) shifted (0,ExHeight) ;
1294        elseif boxgridtype= 4 :
1295            draw baseline_grid (multipars[i],if multilocs[i]=1: down else: up fi,true) shifted (0,ExHeight/2) ;
1296        elseif boxgridtype=11 :
1297            draw graphic_grid(multipars[i],boxgriddistance,boxgriddistance,boxgriddistance/2,boxgriddistance/2) ;
1298        elseif boxgridtype=12 :
1299            draw graphic_grid(multipars[i],boxgriddistance,boxgriddistance,0,0) ;
1300        fi ;
1301    endfor ;
1302enddef ;
1303
1304def show_multi_pars  =
1305    for i=1 upto nofmultipars :
1306        do_show_par(multipars[i], 6pt, .5blue) ;
1307    endfor ;
1308enddef ;
1309
1310vardef do_draw_par (expr p) =
1311    if (length p>2) and (bbwidth(p)>1) and (bbheight(p)>1) :
1312        save pp ; path pp ;
1313        if (boxlineradius>0) and (boxlinetype=2) :
1314            pp := p cornered boxlineradius ;
1315        else :
1316            pp := p ;
1317        fi ;
1318        if boxfilltype>0 :
1319            if boxfilloffset>0 :
1320                % temporary hack
1321                begingroup ;
1322                interim linejoin := mitered ;
1323                filldraw pp boxfilloptions withpen pencircle scaled (2*boxfilloffset) ;
1324                endgroup ;
1325            else :
1326                fill pp boxfilloptions ;
1327            fi ;
1328        fi ;
1329        if boxlinetype>0 :
1330            draw pp boxlineoptions withpen pencircle scaled boxlinewidth ;
1331        fi ;
1332    fi ;
1333enddef ;
1334
1335vardef baseline_grid (expr pxy, pdir, at_baseline) =
1336    save width ; width := bbwidth(pxy) ;
1337    save height ; height := bbheight(pxy) ;
1338    if (par_line_height>0) and (height>1) and (width>1) and (boxgridwidth>0) :
1339        save i, grid, bb ; picture grid ; pair start ; path bb ;
1340        def _do_ (expr start) =
1341            % 1 = normal, 2 = with background (i.e. no shine-through)
1342            if boxdashtype = 2 :
1343                draw start -- start shifted (width,0)
1344                    withpen pencircle scaled boxgridwidth
1345                    boxfilloptions ;
1346            fi ;
1347            draw start -- start shifted (width,0)
1348                if boxdashtype > 0 :
1349                    dashed evenly
1350                fi
1351                withpen pencircle scaled boxgridwidth
1352                boxgridoptions ;
1353        enddef ;
1354        grid := image ( % fails with inlinespace
1355            if pdir=up :
1356                for i = if at_baseline : par_strut_depth else : 0 fi step  par_line_height until max(height,par_line_height) :
1357                    _do_ (llcorner pxy shifted (0,+i)) ;
1358                endfor ;
1359            else :
1360                for i = if at_baseline : par_strut_height else : 0 fi step  par_line_height until height :
1361                    _do_ (ulcorner pxy shifted (0,-i)) ;
1362                endfor ;
1363            fi ;
1364        ) ;
1365        clip grid to pxy ;
1366        bb := boundingbox grid ;
1367        grid := grid shifted (0,boxgridshift) ;
1368        setbounds grid to bb ;
1369        grid
1370    else :
1371        nullpicture
1372    fi
1373enddef ;
1374
1375vardef graphic_grid (expr pxy, dx, dy, x, y) =
1376    if (bbheight(pxy)>dy) and (bbwidth(pxy)>dx) and (boxgridwidth>0) :
1377        save grid ; picture grid ;
1378        grid := image (
1379            for i = xpart llcorner pxy step dx until xpart lrcorner pxy :
1380                draw (i,ypart llcorner pxy) -- (i,ypart ulcorner pxy) withpen pencircle scaled boxgridwidth ;
1381            endfor ;
1382            for i = ypart llcorner pxy step dy until ypart ulcorner pxy :
1383                draw (xpart llcorner pxy,i) -- (xpart lrcorner pxy,i) withpen pencircle scaled boxgridwidth ;
1384            endfor
1385        ) shifted (x,y) ;
1386        clip grid to pxy ;
1387        grid
1388    else :
1389        nullpicture
1390    fi
1391enddef ;
1392
1393def anchor_box (expr n,x,y,w,h,d) =
1394    currentpicture := currentpicture shifted (-x,-y) ;
1395enddef ;
1396
1397let draw_area   = draw_box ;
1398let anchor_area = anchor_box ;
1399let anchor_par  = anchor_box ;
1400
1401numeric sync_n[], sync_p[][], sync_w[][], sync_h[][], sync_d[][], sync_t[][] ;
1402pair sync_xy[][] ; color sync_c[][] ;
1403
1404def ResetSyncTasks =
1405    path SyncPaths[] ; numeric SyncTasks[], NOfSyncPaths, CurrentSyncClass ;
1406    NOfSyncPaths := CurrentSyncClass := 0 ;
1407    if unknown SyncLeftOffset : numeric SyncLeftOffset ; SyncLeftOffset := 0          ; fi ;
1408    if unknown SyncWidth      : numeric SyncWidth      ; SyncWidth      := 0          ; fi ;
1409    if unknown SyncThreshold  : numeric SyncThreshold  ; SyncThreshold  := LineHeight ; fi ;
1410    if unknown SyncColor      : color   SyncColor      ; SyncColor      := .5white    ; fi ;
1411    if (SyncLeftOffset = 0) and (SyncWidth = 0) :
1412        SyncWidth := if known TextWidth : TextWidth else : -1cm fi ;
1413    fi ;
1414enddef ;
1415
1416ResetSyncTasks ;
1417
1418vardef SyncBox(expr n, i, leftoffset, width, topoffset, bottomoffset) =
1419    save o ; pair o ; o := (xpart llcorner PlainTextArea,ypart sync_xy[n][i]) ;
1420    o shifted (leftoffset,sync_h[n][i]+topoffset) --
1421    o shifted (width+leftoffset,sync_h[n][i]+topoffset) --
1422    o shifted (width+leftoffset,bottomoffset) --
1423    o shifted (leftoffset,bottomoffset) -- cycle
1424enddef ;
1425
1426def SetSyncColor(expr n, i, c) =
1427    sync_c[n][i] := c ;
1428enddef ;
1429
1430def SetSyncThreshold(expr n, i, th) =
1431    sync_th[n][i] := th ;
1432enddef ;
1433
1434vardef TheSyncColor(expr n, i) =
1435    if known sync_c[n][i] : sync_c[n][i] else : SyncColor fi
1436enddef ;
1437
1438vardef TheSyncThreshold(expr n, i) =
1439    if known sync_th[n][i] : sync_th[n][i] else : SyncThreshold fi
1440enddef ;
1441
1442vardef PrepareSyncTasks(expr n, collapse, extendtop, prestartnext) =
1443    ResetSyncTasks ;
1444    if known sync_n[n] :
1445        CurrentSyncClass := n ;
1446        save ok, l, d ; boolean ok ; ok := false ; NOfSyncPaths := l := 0 ;
1447        for i=1 upto sync_n[n] :
1448            if RealPageNumber > sync_p[n][i] :
1449                l := i ;
1450            elseif RealPageNumber = sync_p[n][i] :
1451                NOfSyncPaths := NOfSyncPaths + 1 ;
1452                if not ok :
1453                    if i>1 :
1454                        if sync_t[n][i-1] = sync_t[n][i] :
1455                            SyncPaths[NOfSyncPaths] := SyncBox(n, i, SyncLeftOffset, SyncWidth, PaperHeight, -PaperHeight) ;
1456                            SyncTasks[NOfSyncPaths] := i ;
1457                        else :
1458                            SyncPaths[NOfSyncPaths] := SyncBox(n, i-1, SyncLeftOffset, SyncWidth, PaperHeight, -PaperHeight) ;
1459                            SyncTasks[NOfSyncPaths] := i-1 ;
1460                            NOfSyncPaths := NOfSyncPaths + 1 ;
1461                            SyncPaths[NOfSyncPaths] := SyncBox(n, i, SyncLeftOffset, SyncWidth, 0, -PaperHeight) ;
1462                            SyncTasks[NOfSyncPaths] := i ;
1463                        fi ;
1464                    else :
1465                        SyncPaths[NOfSyncPaths] := SyncBox(n, i, SyncLeftOffset, SyncWidth, 0, -PaperHeight) ;
1466                        SyncTasks[NOfSyncPaths] := i ;
1467                    fi ;
1468                else :
1469                    SyncPaths[NOfSyncPaths] := SyncBox(n, i, SyncLeftOffset, SyncWidth, 0, -PaperHeight) ;
1470                    SyncTasks[NOfSyncPaths] := i ;
1471                fi ;
1472                ok := true ;
1473            fi ;
1474        endfor ;
1475        if (NOfSyncPaths = 0) and (l > 0) :
1476            NOfSyncPaths := 1 ;
1477            SyncPaths[NOfSyncPaths] := SyncBox(n, l, SyncLeftOffset, SyncWidth, PaperHeight, -PaperHeight) ;
1478            SyncTasks[NOfSyncPaths] := l ;
1479        fi ;
1480        if NOfSyncPaths > 0 :
1481            for i = 1 upto NOfSyncPaths-1 :
1482                SyncPaths[i] := topboundary SyncPaths[i] -- reverse topboundary SyncPaths[i+1] -- cycle ;
1483            endfor ;
1484            if unknown SyncThresholdMethod :
1485                numeric SyncThresholdMethod ; SyncThresholdMethod := 2 ;
1486            fi ;
1487            if extendtop :
1488                if SyncThresholdMethod = 1 :
1489                    if NOfSyncPaths>1 :
1490                        d := ypart (ulcorner PlainTextArea - sync_xy[n][SyncTasks[2]]) ;
1491                        if (SyncTasks[2]>1) and (d > 0pt) and (d <= TheSyncThreshold(n,sync_t[n][SyncTasks[2]])) and (sync_p[n][SyncTasks[2]] = RealPageNumber) :
1492                            SyncPaths[2] := SyncPaths[2] topenlarged PaperHeight ;
1493                        fi ;
1494                    fi ;
1495                else :
1496                    for i = 1 upto NOfSyncPaths :
1497                        d := ypart (ulcorner PlainTextArea - sync_xy[n][SyncTasks[i]]) ;
1498                        if (d > 0) and (d <= TheSyncThreshold(n,sync_t[n][SyncTasks[i]])) and (sync_p[n][SyncTasks[i]] = RealPageNumber) :
1499                            SyncPaths[i] := SyncPaths[i] topenlarged PaperHeight ;
1500                        fi ;
1501                    endfor ;
1502                fi ;
1503            fi ;
1504            if prestartnext :
1505                if NOfSyncPaths>1 :
1506                    if SyncTasks[NOfSyncPaths] < sync_n[n] : % there is a next one
1507                        d := ypart (ulcorner PlainTextArea - sync_xy[n][SyncTasks[NOfSyncPaths]+1]) ;
1508                        if (d > 0) and (d <= TheSyncThreshold(n, sync_t[n][SyncTasks[i]])) and (sync_p[n][SyncTasks[NOfSyncPaths]+1] = RealPageNumber+1) :
1509                            SyncPaths[NOfSyncPaths+1] :=
1510                                (xpart ulcorner SyncPaths[NOfSyncPaths],ypart llcorner PlainTextArea) --
1511                                (xpart urcorner SyncPaths[NOfSyncPaths],ypart llcorner PlainTextArea) --
1512                                lrcorner SyncPaths[NOfSyncPaths] --
1513                                llcorner SyncPaths[NOfSyncPaths] -- cycle ;
1514                            SyncTasks[NOfSyncPaths+1] := SyncTasks[NOfSyncPaths]+1 ;
1515                            NOfSyncPaths := NOfSyncPaths + 1 ;
1516                        fi ;
1517                    fi ;
1518                fi ;
1519            else :
1520                if NOfSyncPaths>1 :
1521                    d := ypart (sync_xy[n][SyncTasks[NOfSyncPaths]] - llcorner PlainTextArea) ;
1522                    if (d < TheSyncThreshold(n, SyncTasks[NOfSyncPaths])) :
1523                        NOfSyncPaths := NOfSyncPaths - 1 ;
1524                        SyncPaths[NOfSyncPaths] := SyncPaths[NOfSyncPaths] bottomenlarged PaperHeight ;
1525                    fi ;
1526                fi ;
1527            fi ;
1528            if (NOfSyncPaths>1) and collapse :
1529                save j ; numeric j ; j := 1 ;
1530                for i = 2 upto NOfSyncPaths :
1531                    if sync_t[n][SyncTasks[i]] = sync_t[n][SyncTasks[j]] :
1532                        SyncPaths[j] := boundingbox image (draw SyncPaths[i] ; draw SyncPaths[j] ; ) ;
1533                        SyncTasks[j] := SyncTasks[i] ;
1534                    else :
1535                        j := j + 1 ;
1536                        SyncPaths[j] := SyncPaths[i] ;
1537                        SyncTasks[j] := SyncTasks[i] ;
1538                    fi ;
1539                endfor ;
1540                NOfSyncPaths := j ;
1541            fi ;
1542        fi ;
1543    fi ;
1544enddef ;
1545
1546def SyncTask(expr n) =
1547    if known SyncTasks[n] : SyncTasks[n] else : 0 fi
1548enddef ;
1549
1550def FlushSyncTasks =
1551    for i = 1 upto NOfSyncPaths :
1552        ProcessSyncTask(SyncPaths[i], TheSyncColor(CurrentSyncClass,sync_t[CurrentSyncClass][SyncTasks[i]])) ;
1553    endfor ;
1554enddef ;
1555
1556def ProcessSyncTask(expr p, c) =
1557    fill p withcolor c ;
1558enddef ;
1559