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