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 |