1if not modules then modules = { } end modules [ ' typo-mar ' ] = {
2 version = 1 . 001 ,
3 comment = " companion to typo-mar.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
14local format , validstring = string . format , string . valid
15local insert , remove , sortedkeys , fastcopy = table . insert , table . remove , table . sortedkeys , table . fastcopy
16local setmetatable , next , tonumber = setmetatable , next , tonumber
17local formatters = string . formatters
18local toboolean = toboolean
19local settings_to_hash = utilities . parsers . settings_to_hash
20
21local attributes = attributes
22local nodes = nodes
23local variables = variables
24local context = context
25
26local trace_margindata = false trackers . register ( " typesetters.margindata " , function ( v ) trace_margindata = v end )
27local trace_marginstack = false trackers . register ( " typesetters.margindata.stack " , function ( v ) trace_marginstack = v end )
28local trace_margingroup = false trackers . register ( " typesetters.margindata.group " , function ( v ) trace_margingroup = v end )
29
30local report_margindata = logs . reporter ( " margindata " )
31
32local tasks = nodes . tasks
33local prependaction = tasks . prependaction
34local disableaction = tasks . disableaction
35local enableaction = tasks . enableaction
36
37local variables = interfaces . variables
38
39local conditionals = tex . conditionals
40local systemmodes = tex . systemmodes
41
42local v_top = variables . top
43local v_depth = variables . depth
44local v_local = variables [ " local " ]
45local v_global = variables [ " global " ]
46local v_left = variables . left
47local v_right = variables . right
48local v_inner = variables . inner
49local v_outer = variables . outer
50local v_margin = variables . margin
51local v_edge = variables . edge
52local v_default = variables . default
53local v_normal = variables . normal
54local v_yes = variables . yes
55local v_continue = variables . continue
56local v_first = variables . first
57local v_text = variables . text
58local v_paragraph = variables . paragraph
59local v_line = variables . line
60
61local nuts = nodes . nuts
62local tonode = nuts . tonode
63
64local hpacknodes = nuts . hpack
65local traverseid = nuts . traverseid
66local flushnodelist = nuts . flushlist
67
68local getnext = nuts . getnext
69local getprev = nuts . getprev
70local getid = nuts . getid
71local getattr = nuts . getattr
72local setattr = nuts . setattr
73local getsubtype = nuts . getsubtype
74local getlist = nuts . getlist
75local getwhd = nuts . getwhd
76local setlist = nuts . setlist
77local setlink = nuts . setlink
78local getshift = nuts . getshift
79local setshift = nuts . setshift
80local getwidth = nuts . getwidth
81local setwidth = nuts . setwidth
82local getheight = nuts . getheight
83
84local setattrlist = nuts . setattrlist
85
86local getbox = nuts . getbox
87local takebox = nuts . takebox
88
89local setprop = nuts . setprop
90local getprop = nuts . getprop
91
92local nodecodes = nodes . nodecodes
93local listcodes = nodes . listcodes
94local whatsitcodes = nodes . whatsitcodes
95
96local hlist_code = nodecodes . hlist
97local vlist_code = nodecodes . vlist
98local whatsit_code = nodecodes . whatsit
99local userdefined_code = whatsitcodes . userdefined
100
101local nodepool = nuts . pool
102
103local new_hlist = nodepool . hlist
104local new_usernode = nodepool . usernode
105local latelua = nodepool . latelua
106
107local texgetdimen = tex . getdimen
108local texgetcount = tex . getcount
109local texget = tex . get
110
111local isleftpage = layouts . status . isleftpage
112local registertogether = builders . paragraphs . registertogether
113
114local paragraphs = typesetters . paragraphs
115local addtoline = paragraphs . addtoline
116local moveinline = paragraphs . moveinline
117local calculatedelta = paragraphs . calculatedelta
118
119local a_linenumber = attributes . private ( ' linenumber ' )
120
121local inline_mark = nodepool . userids [ " margins.inline " ]
122
123local jobpositions = job . positions
124local getposition = jobpositions . get
125local setposition = jobpositions . set
126local getreserved = jobpositions . getreserved
127
128local margins = { }
129typesetters . margins = margins
130
131local locations = { v_left , v_right , v_inner , v_outer }
132local categories = { }
133local displaystore = { }
134local inlinestore = { }
135local nofsaved = 0
136local nofstored = 0
137local nofinlined = 0
138local nofdelayed = 0
139local nofinjected = 0
140local h_anchors = 0
141local v_anchors = 0
142
143local mt1 = {
144 __index = function ( t , location )
145 local v = { [ v_local ] = { } , [ v_global ] = { } }
146 t [ location ] = v
147 return v
148 end
149}
150
151local mt2 = {
152 __index = function ( stores , category )
153 categories [ # categories + 1 ] = category
154 local v = { }
155 setmetatable ( v , mt1 )
156 stores [ category ] = v
157 return v
158 end
159}
160
161setmetatable ( displaystore , mt2 )
162
163local defaults = {
164 __index = {
165 location = v_left ,
166 align = v_normal ,
167 method = " " ,
168 name = " " ,
169 threshold = 0 ,
170 margin = v_normal ,
171 scope = v_global ,
172 distance = 0 ,
173 hoffset = 0 ,
174 voffset = 0 ,
175 category = v_default ,
176 line = 0 ,
177 vstack = 0 ,
178 dy = 0 ,
179 baseline = false ,
180 inline = false ,
181 leftskip = 0 ,
182 rightskip = 0 ,
183 option = { }
184 }
185}
186
187local enablelocal , enableglobal
188
189local function showstore ( store , banner , location )
190 if next ( store ) then
191 for i , si in table . sortedpairs ( store ) do
192 local si = store [ i ]
193 report_margindata ( " %s: stored in %a at %s: %a => %s " , banner , location , i , validstring ( si . name , " no name " ) , nodes . toutf ( getlist ( si . box ) ) )
194 end
195 else
196 report_margindata ( " %s: nothing stored in location %a " , banner , location )
197 end
198end
199
200function margins . save ( t )
201 setmetatable ( t , defaults )
202 local content = takebox ( t . number )
203 local location = t . location
204 local category = t . category
205 local inline = t . inline
206 local scope = t . scope
207 local name = t . name
208 local option = t . option
209 local stack = t . stack
210 if option then
211 option = settings_to_hash ( option )
212 t . option = option
213 end
214 if not content then
215 report_margindata ( " ignoring empty margin data %a " , location or " unknown " )
216 return
217 end
218 setprop ( content , " specialcontent " , " margindata " )
219 local store
220 if inline then
221 store = inlinestore
222 else
223 store = displaystore [ category ] [ location ]
224 if not store then
225 report_margindata ( " invalid location %a " , location )
226 return
227 end
228 store = store [ scope ]
229 end
230 if not store then
231 report_margindata ( " invalid scope %a " , scope )
232 return
233 end
234 if enablelocal and scope = = v_local then
235 enablelocal ( )
236 if enableglobal then
237 enableglobal ( )
238 end
239 elseif enableglobal and scope = = v_global then
240 enableglobal ( )
241 end
242 nofsaved = nofsaved + 1
243 nofstored = nofstored + 1
244 if trace_marginstack then
245 showstore ( store , " before " , location )
246 end
247 if name and name ~ = " " then
248
249 if inlinestore then
250 local t = sortedkeys ( store ) for j = # t , 1 , -1 do local i = t [ j ]
251 local si = store [ i ]
252 if si . name = = name then
253 local s = remove ( store , i )
254 flushnodelist ( s . box )
255 end
256 end
257 else
258 for i = # store , 1 , -1 do
259 local si = store [ i ]
260 if si . name = = name then
261 local s = remove ( store , i )
262 flushnodelist ( s . box )
263 end
264 end
265 end
266 if trace_marginstack then
267 showstore ( store , " between " , location )
268 end
269 end
270 if t . number then
271 local leftmargindistance = texgetdimen ( " naturalleftmargindistance " )
272 local rightmargindistance = texgetdimen ( " naturalrightmargindistance " )
273 local strutbox = getbox ( " strutbox " )
274 local _ , strutht , strutdp = getwhd ( strutbox )
275
276 t . box = content
277 t . n = nofsaved
278
279
280 t . strutheight = strutht
281 t . strutdepth = strutdp
282
283 t . leftskip = texget ( " leftskip " , false )
284 t . rightskip = texget ( " rightskip " , false )
285
286 t . leftmargindistance = leftmargindistance
287 t . rightmargindistance = rightmargindistance
288 t . leftedgedistance = texgetdimen ( " naturalleftedgedistance " )
289 + texgetdimen ( " leftmarginwidth " )
290 + leftmargindistance
291 t . rightedgedistance = texgetdimen ( " naturalrightedgedistance " )
292 + texgetdimen ( " rightmarginwidth " )
293 + rightmargindistance
294 t . lineheight = texgetdimen ( " lineheight " )
295
296
297 if inline then
298 local n = new_usernode ( inline_mark , nofsaved )
299 setattrlist ( n , true )
300 context ( tonode ( n ) )
301 store [ nofsaved ] = t
302 nofinlined = nofinlined + 1
303 else
304 insert ( store , t )
305 end
306 end
307 if trace_marginstack then
308 showstore ( store , " after " , location )
309 end
310 if trace_margindata then
311 report_margindata ( " saved %a, location %a, scope %a, inline %a " , nofsaved , location , scope , inline )
312 end
313end
314
315
316
317
318
319
320
321
322
323local function realign ( current , candidate )
324 local location = candidate . location
325 local margin = candidate . margin
326 local hoffset = candidate . hoffset
327 local distance = candidate . distance
328 local hsize = candidate . hsize
329 local width = candidate . width
330 local align = candidate . align
331 local inline = candidate . inline
332 local anchor = candidate . anchor
333 local hook = candidate . hook
334 local scope = candidate . scope
335 local option = candidate . option
336 local reverse = hook . reverse
337 local atleft = true
338 local hmove = 0
339 local delta = 0
340 local leftpage = isleftpage ( )
341 local leftdelta = 0
342 local rightdelta = 0
343 local leftdistance = distance
344 local rightdistance = distance
345
346 if not anchor or anchor = = " " then
347 anchor = v_text
348 end
349 if margin = = v_normal then
350
351 elseif margin = = v_local then
352 leftdelta = - candidate . leftskip
353 rightdelta = candidate . rightskip
354 elseif margin = = v_margin then
355 leftdistance = candidate . leftmargindistance
356 rightdistance = candidate . rightmargindistance
357 elseif margin = = v_edge then
358 leftdistance = candidate . leftedgedistance
359 rightdistance = candidate . rightedgedistance
360 end
361 if leftpage then
362 leftdistance , rightdistance = rightdistance , leftdistance
363 end
364 if location = = v_right then
365 atleft = false
366 elseif location = = v_inner then
367 if leftpage then
368 atleft = false
369 end
370 elseif location = = v_outer then
371 if not leftpage then
372 atleft = false
373 end
374 else
375
376 end
377
378 local islocal = scope = = v_local
379 local area = ( not islocal or option [ v_text ] ) and anchor or nil
380
381 if atleft then
382 delta = hoffset + leftdelta + leftdistance
383 else
384 delta = hoffset + rightdelta + rightdistance
385 end
386
387 local delta , hmove = calculatedelta (
388 hook ,
389 width ,
390 delta ,
391 atleft ,
392 islocal ,
393 option [ v_paragraph ] ,
394 area
395 )
396
397 if hmove ~ = 0 then
398 delta = delta + hmove
399 if trace_margindata then
400 report_margindata ( " realigned %a, location %a, margin %a, move %p " , candidate . n , location , margin , hmove )
401 end
402 else
403 if trace_margindata then
404 report_margindata ( " realigned %a, location %a, margin %a " , candidate . n , location , margin )
405 end
406 end
407 moveinline ( hook , candidate . node , delta )
408end
409
410local function realigned ( current , candidate )
411 realign ( current , candidate )
412 nofdelayed = nofdelayed - 1
413 setprop ( current , " margindata " , false )
414 return true
415end
416
417
418
419
420
421
422
423
424
425
426
427local validstacknames = {
428 [ v_left ] = v_left ,
429 [ v_right ] = v_right ,
430 [ v_inner ] = v_inner ,
431 [ v_outer ] = v_outer ,
432}
433
434local cache = { }
435local stacked = { [ v_yes ] = { } , [ v_continue ] = { } }
436local anchors = { [ v_yes ] = { } , [ v_continue ] = { } }
437
438local function resetstacked ( all )
439 stacked [ v_yes ] = { }
440 anchors [ v_yes ] = { }
441 if all then
442 stacked [ v_continue ] = { }
443 anchors [ v_continue ] = { }
444 end
445end
446
447
448
449local function sa ( specification )
450 local tag = specification . tag
451 local p = cache [ tag ]
452 if p then
453 if trace_marginstack then
454 report_margindata ( " updating anchor %a " , tag )
455 end
456 p . p = true
457 p . y = true
458
459 setposition ( " md:v " , tag , p )
460 cache [ tag ] = nil
461 end
462end
463
464local function setanchor ( v_anchor )
465 return latelua { action = sa , tag = v_anchor }
466end
467
468local function aa ( specification )
469 local tag = specification . tag
470 local n = specification . n
471 local p = jobpositions . gettobesaved ( ' md:v ' , tag )
472 if p then
473 if trace_marginstack then
474 report_margindata ( " updating injected %a " , tag )
475 end
476 local pages = p . pages
477 if not pages then
478 pages = { }
479 p . pages = pages
480 end
481 pages [ n ] = texgetcount ( " realpageno " )
482 elseif trace_marginstack then
483 report_margindata ( " not updating injected %a " , tag )
484 end
485end
486
487local function addtoanchor ( v_anchor , n )
488 return latelua { action = aa , tag = v_anchor , n = n }
489end
490
491local function markovershoot ( current )
492 v_anchors = v_anchors + 1
493 cache [ v_anchors ] = fastcopy ( stacked )
494 local anchor = setanchor ( v_anchors )
495
496
497 local list = hpacknodes ( setlink ( anchor , getlist ( current ) ) , getwidth ( current ) , " exactly " )
498 if trace_marginstack then
499 report_margindata ( " marking anchor %a " , v_anchors )
500 end
501 setlist ( current , list )
502end
503
504local function inject ( parent , head , candidate )
505 local box = candidate . box
506 if not box then
507 return head , nil , false
508 end
509 local width , height , depth
510 = getwhd ( box )
511 local shift = getshift ( box )
512 local stack = candidate . stack
513 local stackname = candidate . stackname
514 local location = candidate . location
515 local method = candidate . method
516 local voffset = candidate . voffset
517 local line = candidate . line
518 local baseline = candidate . baseline
519 local strutheight = candidate . strutheight
520 local strutdepth = candidate . strutdepth
521 local inline = candidate . inline
522 local psubtype = getsubtype ( parent )
523
524
525
526 if not stackname or stackname = = " " then
527 stackname = location
528 else
529 stackname = validstacknames [ stackname ] or location
530 end
531 local isstacked = stack = = v_continue or stack = = v_yes
532 local offset = isstacked and stacked [ stack ] [ stackname ]
533 local firstonstack = offset = = false or offset = = nil
534 nofinjected = nofinjected + 1
535 nofdelayed = nofdelayed + 1
536
537 baseline = tonumber ( baseline )
538 if not baseline then
539 baseline = toboolean ( baseline )
540 end
541
542 if baseline = = true then
543 baseline = false
544 else
545 baseline = tonumber ( baseline )
546 if not baseline or baseline < = 0 then
547
548 baseline = false
549 end
550 end
551 candidate . width = width
552 candidate . hsize = getwidth ( parent )
553 candidate . psubtype = psubtype
554 candidate . stackname = stackname
555 if trace_margindata then
556 report_margindata ( " processing, index %s, height %p, depth %p, parent %a, method %a " , candidate . n , height , depth , listcodes [ psubtype ] , method )
557 end
558
559
560
561
562
563 if isstacked then
564 firstonstack = true
565 local anchor = getposition ( " md:v " )
566 if anchor and ( location = = v_inner or location = = v_outer ) then
567 local pages = anchor . pages
568 if pages then
569 local page = pages [ nofinjected ]
570 if page then
571 if isleftpage ( page ) then
572 stackname = location = = v_inner and v_right or v_left
573 else
574 stackname = location = = v_inner and v_left or v_right
575 end
576 candidate . stackname = stackname
577 offset = stack and stack ~ = " " and stacked [ stack ] [ stackname ]
578 end
579 end
580 end
581 local current = v_anchors + 1
582 local previous = anchors [ stack ] [ stackname ]
583 if trace_margindata then
584 report_margindata ( " anchor %i, offset so far %p " , current , offset or 0 )
585 end
586 local ap = anchor and anchor [ previous ]
587 local ac = anchor and anchor [ current ]
588 if not previous then
589 elseif previous = = current then
590 firstonstack = false
591 elseif ap and ac and ap . p = = ac . p then
592 local distance = ( ap . y or 0 ) - ( ac . y or 0 )
593 if trace_margindata then
594 report_margindata ( " distance %p " , distance )
595 end
596 if offset > distance then
597
598 offset = offset - distance
599 firstonstack = false
600 else
601 offset = 0
602 end
603 else
604
605 end
606 anchors [ v_yes ] [ stackname ] = current
607 anchors [ v_continue ] [ stackname ] = current
608 if firstonstack then
609 offset = 0
610 end
611 offset = offset + candidate . dy
612 shift = shift + offset
613 else
614 if firstonstack then
615 offset = 0
616 end
617 offset = offset + candidate . dy
618 shift = shift + offset
619 end
620
621
622
623
624 if method = = v_top then
625 local delta = height - getheight ( parent )
626 if trace_margindata then
627 report_margindata ( " top aligned by %p " , delta )
628 end
629 if delta < candidate . threshold then
630 shift = shift + voffset + delta
631 end
632 elseif method = = v_line then
633 local _ , ph , pd = getwhd ( parent )
634 if pd = = 0 then
635 local delta = height - ph
636 if trace_margindata then
637 report_margindata ( " top aligned by %p (no depth) " , delta )
638 end
639 if delta < candidate . threshold then
640 shift = shift + voffset + delta
641 end
642 end
643 elseif method = = v_first then
644 if baseline then
645 shift = shift + voffset + height - baseline
646 else
647 shift = shift + voffset
648 end
649 if trace_margindata then
650 report_margindata ( " first aligned " )
651 end
652 elseif method = = v_depth then
653 local delta = strutdepth
654 if trace_margindata then
655 report_margindata ( " depth aligned by %p " , delta )
656 end
657 shift = shift + voffset + delta
658 elseif method = = v_height then
659 local delta = - strutheight
660 if trace_margindata then
661 report_margindata ( " height aligned by %p " , delta )
662 end
663 shift = shift + voffset + delta
664 elseif voffset ~ = 0 then
665 if trace_margindata then
666 report_margindata ( " voffset %p applied " , voffset )
667 end
668 shift = shift + voffset
669 end
670
671 if line ~ = 0 then
672 local delta = line * candidate . lineheight
673 if trace_margindata then
674 report_margindata ( " offset %p applied to line %s " , delta , line )
675 end
676 shift = shift + delta
677 offset = offset + delta
678 end
679 setshift ( box , shift )
680 setwidth ( box , 0 )
681
682 if isstacked then
683 setlink ( box , addtoanchor ( v_anchors , nofinjected ) )
684 box = new_hlist ( box )
685
686 end
687
688 candidate . hook , candidate . node = addtoline ( parent , box )
689
690 setprop ( box , " margindata " , candidate )
691 if trace_margindata then
692 report_margindata ( " injected, location %a, stack %a, shift %p " , location , stackname , shift )
693 end
694
695 offset = offset + depth
696 local room = {
697 height = height ,
698 depth = offset ,
699 slack = candidate . bottomspace ,
700 lineheight = candidate . lineheight ,
701 stacked = inline and isstacked ,
702 }
703 offset = offset + height
704
705 stacked [ v_yes ] [ stackname ] = offset
706 stacked [ v_continue ] [ stackname ] = offset
707
708 if trace_margindata then
709 report_margindata ( " status, offset %s " , offset )
710 end
711 return getlist ( parent ) , room , inline and isstacked or ( stack = = v_continue )
712end
713
714local function flushinline ( parent , head )
715 local current = head
716 local done = false
717 local continue = false
718 local room , don , con , list
719 while current and nofinlined > 0 do
720 local id = getid ( current )
721 if id = = whatsit_code then
722 if getsubtype ( current ) = = userdefined_code and getprop ( current , " id " ) = = inline_mark then
723 local n = getprop ( current , " data " )
724 local candidate = inlinestore [ n ]
725 if candidate then
726 inlinestore [ n ] = nil
727 nofinlined = nofinlined - 1
728 head , room , con = inject ( parent , head , candidate )
729 done = true
730 continue = continue or con
731 nofstored = nofstored - 1
732 if room and room . stacked then
733
734
735
736 registertogether ( parent , room )
737 end
738 end
739 end
740 elseif id = = hlist_code or id = = vlist_code then
741
742 list , don , con = flushinline ( current , getlist ( current ) )
743 setlist ( current , list )
744 continue = continue or con
745 done = done or don
746 end
747 current = getnext ( current )
748 end
749 return head , done , continue
750end
751
752local function flushed ( scope , parent )
753 local head = getlist ( parent )
754 local done = false
755 local continue = false
756 local room , con , don
757 for c = 1 , # categories do
758 local category = categories [ c ]
759 for l = 1 , # locations do
760 local location = locations [ l ]
761 local store = displaystore [ category ] [ location ] [ scope ]
762 if store then
763 while true do
764 local candidate = remove ( store , 1 )
765 if candidate then
766 head , room , con = inject ( parent , head , candidate )
767 done = true
768 continue = continue or con
769 nofstored = nofstored - 1
770 if room then
771 registertogether ( parent , room )
772 end
773 else
774 break
775 end
776 end
777 else
778
779 end
780 end
781 end
782 if nofinlined > 0 then
783 if done then
784 setlist ( parent , head )
785 end
786 head , don , con = flushinline ( parent , head )
787 continue = continue or con
788 done = done or don
789 end
790 if done then
791 local a = getattr ( head , a_linenumber )
792 if false then
793 local l = hpacknodes ( head , getwidth ( parent ) , " exactly " )
794 setlist ( parent , l )
795 if a then
796 setattr ( l , a_linenumber , a )
797 end
798 else
799
800 setlist ( parent , head )
801 if a then
802 setattr ( parent , a_linenumber , a )
803 end
804 end
805 end
806 return done , continue
807end
808
809
810
811
812local function handler ( scope , head , group )
813 if nofstored > 0 then
814 if trace_margindata then
815 report_margindata ( " flushing stage one, stored %s, scope %s, delayed %s, group %a " , nofstored , scope , nofdelayed , group )
816 end
817 local current = head
818 local done = false
819 while current do
820 local id = getid ( current )
821 if ( id = = vlist_code or id = = hlist_code ) and getprop ( current , " margindata " ) = = nil then
822 local don , continue = flushed ( scope , current )
823 if don then
824 done = true
825 setprop ( current , " margindata " , false )
826 if continue then
827 markovershoot ( current )
828 end
829 if nofstored < = 0 then
830 break
831 end
832 end
833 end
834 current = getnext ( current )
835 end
836 if trace_margindata then
837 if done then
838 report_margindata ( " flushing stage one, done, %s left " , nofstored )
839 else
840 report_margindata ( " flushing stage one, nothing done, %s left " , nofstored )
841 end
842 end
843 resetstacked ( )
844 end
845 return head
846end
847
848local trialtypesetting = context . trialtypesetting
849
850
851
852
853function margins . localhandler ( head , group )
854
855 if trialtypesetting ( ) then
856 return head
857 end
858
859 local inhibit = conditionals . inhibitmargindata
860 if inhibit then
861 if trace_margingroup then
862 report_margindata ( " ignored 3, group %a, stored %s, inhibit %a " , group , nofstored , inhibit )
863 end
864 return head
865 end
866 if nofstored > 0 then
867 return handler ( v_local , head , group )
868 end
869 if trace_margingroup then
870 report_margindata ( " ignored 4, group %a, stored %s, inhibit %a " , group , nofstored , inhibit )
871 end
872 return head
873end
874
875function margins . globalhandler ( head , group )
876
877 if trialtypesetting ( ) then
878 return head , false
879 end
880
881 local inhibit = conditionals . inhibitmargindata
882 if inhibit or nofstored = = 0 then
883 if trace_margingroup then
884 report_margindata ( " ignored 1, group %a, stored %s, inhibit %a " , group , nofstored , inhibit )
885 end
886 return head
887 elseif group = = " hmode_par " then
888 return handler ( v_global , head , group )
889 elseif group = = " vmode_par " then
890 return handler ( v_global , head , group )
891
892
893 elseif group = = " box " then
894 return handler ( v_global , head , group )
895 elseif group = = " alignment " then
896 return handler ( v_global , head , group )
897 else
898 if trace_margingroup then
899 report_margindata ( " ignored 2, group %a, stored %s, inhibit %a " , group , nofstored , inhibit )
900 end
901 return head
902 end
903end
904
905local function finalhandler ( head )
906 if nofdelayed > 0 then
907 local current = head
908 while current and nofdelayed > 0 do
909 local id = getid ( current )
910 if id = = hlist_code then
911 local a = getprop ( current , " margindata " )
912 if not a then
913 finalhandler ( getlist ( current ) )
914 elseif realigned ( current , a ) then
915 if nofdelayed = = 0 then
916 return head , true
917 end
918 end
919 elseif id = = vlist_code then
920 finalhandler ( getlist ( current ) )
921 end
922 current = getnext ( current )
923 end
924 end
925 return head
926end
927
928function margins . finalhandler ( head )
929 if nofdelayed > 0 then
930 if trace_margindata then
931 report_margindata ( " flushing stage two, instore: %s, delayed: %s " , nofstored , nofdelayed )
932 end
933 head = finalhandler ( head )
934 resetstacked ( nofdelayed = = 0 )
935 else
936 resetstacked ( )
937 end
938 return head
939end
940
941
942
943
944enablelocal = function ( )
945 enableaction ( " finalizers " , " typesetters.margins.localhandler " )
946 enableaction ( " shipouts " , " typesetters.margins.finalhandler " )
947 enablelocal = nil
948end
949
950enableglobal = function ( )
951 enableaction ( " mvlbuilders " , " typesetters.margins.globalhandler " )
952 enableaction ( " shipouts " , " typesetters.margins.finalhandler " )
953 enableglobal = nil
954end
955
956statistics . register ( " margin data " , function ( )
957 if nofsaved > 0 then
958 return format ( " %s entries, %s pending " , nofsaved , nofdelayed )
959 else
960 return nil
961 end
962end )
963
964interfaces . implement {
965 name = " savemargindata " ,
966 actions = margins . save ,
967 arguments = {
968 {
969 { " location " } ,
970 { " method " } ,
971 { " category " } ,
972 { " name " } ,
973 { " scope " } ,
974 { " number " , " integer " } ,
975 { " margin " } ,
976 { " distance " , " dimen " } ,
977 { " hoffset " , " dimen " } ,
978 { " voffset " , " dimen " } ,
979 { " dy " , " dimen " } ,
980 { " bottomspace " , " dimen " } ,
981 { " baseline " } ,
982 { " threshold " , " dimen " } ,
983 { " inline " , " boolean " } ,
984 { " anchor " } ,
985
986
987 { " align " } ,
988 { " option " } ,
989 { " line " , " integer " } ,
990 { " index " , " integer " } ,
991 { " stackname " } ,
992 { " stack " } ,
993 }
994 }
995}
996 |