1if not modules then modules = { } end modules ['driv-shp'] = {
2 version = 1.001,
3 optimize = true,
4 comment = "companion to driv-ini.mkiv",
5 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
6 copyright = "PRAGMA ADE / ConTeXt Development Team",
7 license = "see context related readme files"
8}
9
10local type, next, rawget, rawset = type, next, rawget, rawset
11
12local setmetatableindex = table.setmetatableindex
13local formatters = string.formatters
14local concat = table.concat
15local keys = table.keys
16local insert = table.insert
17local sortedhash = table.sortedhash
18local find = string.find
19local stripstring = string.strip
20local sequenced = table.sequenced
21local round = math.round
22local nuts = nodes.nuts
23
24local tonut = nodes.tonut
25local tonode = nodes.tonode
26
27local getdirection = nuts.getdirection
28local getlist = nuts.getlist
29local getoffsets = nuts.getoffsets
30local getorientation = nuts.getorientation
31local getanchors = nuts.getanchors
32local getgeometry = nuts.getgeometry
33local getxyscales = nuts.getxyscales
34local getwhd = nuts.getwhd
35local getkern = nuts.getkern
36local getheight = nuts.getheight
37local getdepth = nuts.getdepth
38
39local getnext = nuts.getnext
40local getsubtype = nuts.getsubtype
41local getid = nuts.getid
42local getleader = nuts.getleader
43
44local getshift = nuts.getshift
45local getreplace = nuts.getreplace
46local setreplace = nuts.setreplace
47local getfont = nuts.getfont
48local getboth = nuts.getboth
49
50local getglyphdimensions = nuts.getglyphdimensions
51local getkerndimension = nuts.getkerndimension
52local getlistdimensions = nuts.getlistdimensions
53local getruledimensions = nuts.getruledimensions
54
55local setdirection = nuts.setdirection
56local setlink = nuts.setlink
57
58local isglyph = nuts.isglyph
59
60local nextnode = nuts.traversers.node
61
62local effectiveglue = nuts.effectiveglue
63local dirdimensions = nuts.dirdimensions
64
65local fonthashes = fonts.hashes
66local fontdata = fonthashes.identifiers
67local characters = fonthashes.characters
68local parameters = fonthashes.parameters
69
70local nodecodes = nodes.nodecodes
71local whatsitcodes = nodes.whatsitcodes
72local gluecodes = nodes.gluecodes
73local subtypes = nodes.subtypes
74
75local lefttoright_code <const> = tex.directioncodes.lefttoright
76local righttoleft_code <const> = tex.directioncodes.righttoleft
77
78local glyph_code <const> = nodecodes.glyph
79local kern_code <const> = nodecodes.kern
80local glue_code <const> = nodecodes.glue
81local hlist_code <const> = nodecodes.hlist
82local vlist_code <const> = nodecodes.vlist
83local dir_code <const> = nodecodes.dir
84local disc_code <const> = nodecodes.disc
85local math_code <const> = nodecodes.math
86local rule_code <const> = nodecodes.rule
87local whatsit_code <const> = nodecodes.whatsit
88
89local virtualrule_code <const> = nodes.rulecodes.virtual
90
91local leaders_code <const> = gluecodes.leaders
92local cleaders_code <const> = gluecodes.cleaders
93local xleaders_code <const> = gluecodes.xleaders
94local gleaders_code <const> = gluecodes.gleaders
95
96local spaceskip_code <const> = gluecodes.spaceskip
97local xspaceskip_code <const> = gluecodes.xspaceskip
98
99local getpagedimensions = layouts.getpagedimensions
100
101local drivers = drivers
102
103local report = logs.reporter("drivers")
104
105
106
107
108
109
110local lastfont = nil
111local fontcharacters = nil
112
113local maxdimen <const> = tex.magicconstants.maxdimen
114local runningrule <const> = tex.magicconstants.runningrule
115
116local pos_h = 0
117local pos_v = 0
118local pos_r = lefttoright_code
119local shippingmode = "none"
120
121local shipbox_h = 0
122local shipbox_v = 0
123local page_size_h = 0
124local page_size_v = 0
125
126local initialize
127local finalize
128local updatefontstate
129local pushorientation
130local poporientation
131local flushcharacter
132local flushfontchar
133local flushrule
134local flushliteral
135local flushwhatsit
136local flushspace
137
138
139
140function drivers.getpos () return round(pos_h), round(pos_v) end
141function drivers.getrpos() return round(pos_h), round(pos_v), pos_r end
142function drivers.gethpos() return round(pos_h) end
143function drivers.getvpos() return round(pos_v) end
144
145
146
147
148
149local tospace = false directives.register("backends.spaces", function(v) tospace = v end)
150
151local flush_character, flush_space do
152
153 local stack = setmetatableindex("table")
154 local level = 0
155 local nesting = 0
156 local main = 0
157
158
159
160 local default = 16384
161 local refactored = 1000000
162
163 local vfinjectors = fonts.helpers.vfinjectors
164
165
166
167
168
169 local function flush_vf_packet(current,pos_h,pos_v,pos_r,font,char,data,csx,csy,factor,sx,sy,slant,weight,vfcommands)
170 if nesting > 100 then
171 return
172 elseif nesting == 0 then
173 main = font
174
175
176
177
178
179
180 else
181
182
183
184
185
186
187 end
188
189 nesting = nesting + 1
190
191 local savedlevel = level
192
193 local function push()
194 level = level + 1
195 local s = stack[level]
196 s[1] = pos_h
197 s[2] = pos_v
198 s[3] = pos_r
199 end
200
201 local function pop()
202 if level > 0 then
203 local s = stack[level]
204 pos_h = s[1]
205 pos_v = s[2]
206 pos_r = s[3]
207 level = level - 1
208 end
209 end
210
211
212
213 local saved_h = pos_h
214 local saved_v = pos_v
215 local saved_r = pos_r
216
217 pos_r = lefttoright_code
218
219 local fdata = fontdata[font]
220 local fnt = font
221 local fonts = fdata.fonts
222 local siz = (fdata.parameters.factor or 1)/65536
223
224
225
226
227
228
229
230
231
232
233
234
235
236 local scale = data.scale
237 local xoffset = data.xoffset
238 local yoffset = data.yoffset
239
240 if scale then
241 sx = scale * sx
242 sy = scale * sy
243 end
244
245
246
247 if csx then
248 sx = sx * csx
249 csx = 1
250 end
251 if csy then
252 sy = sy * csy
253 csy = 1
254 end
255
256 if xoffset and xoffset ~= 0 then
257 if factor ~= 0 then
258 xoffset = xoffset + xoffset * factor / refactored
259 end
260 pos_h = pos_h + xoffset * sx
261 end
262
263 if yoffset and yoffset ~= 0 then
264 pos_v = pos_v + yoffset * sy
265 end
266
267
268
269 local function flushchar(fnt,chr,csx,csy,slnt)
270 if fnt then
271 local nest = char ~= chr or font ~= fnt
272 if fnt == 0 then
273 fnt = main
274 end
275 if csx then
276 csx = csx * sx
277 else
278 csx = sx
279 end
280 if csy then
281 csy = csy * sy
282 else
283 csy = sy
284 end
285
286
287 return flush_character(false,fnt,chr,factor,nest,pos_h,pos_v,pos_r,csx,csy,slnt or slant,weight)
288 else
289 return 0
290 end
291 end
292
293
294
295 for i=1,#vfcommands do
296 local packet = vfcommands[i]
297 if packet then
298 local command = packet[1]
299 if command == "char" then
300 local chr = packet[2]
301 local csx = packet[3]
302 local csy = packet[4] or csx
303 pos_h = pos_h + flushchar(fnt,chr,csx,csy) * sx
304 elseif command == "slot" then
305 local index = packet[2]
306 local chr = packet[3]
307 local csx = packet[4]
308 local csy = packet[5] or csx
309 if index == 0 then
310 pos_h = pos_h + flushchar(font,chr,csx,csy) * sx
311 else
312 local okay = fonts and fonts[index]
313 if okay then
314 local fnt = okay.id
315 if fnt then
316 if fnt == 0 then
317 fnt = font
318 end
319 pos_h = pos_h + flushchar(fnt,chr,csx,csy) * sx
320 end
321 else
322
323 pos_h = pos_h + flushchar(font,chr,csx,csy) * sx
324 end
325 end
326 elseif command == "use" then
327 local index = packet[2]
328 if index then
329 local fnt
330 if index == 0 then
331 fnt = font
332 else
333 local okay = fonts and fonts[index]
334 if okay then
335 fnt = okay.id
336 end
337 end
338 if fnt then
339
340 local d = characters[fnt]
341 if d then
342 for i=3,#packet do
343 local chr = packet[i]
344 local dat = d[chr]
345 if dat then
346 flushfontchar(fnt,chr,dat)
347 end
348 end
349 end
350 end
351 end
352 elseif command == "right" then
353 local h = packet[2]
354 if h ~= 0 then
355 if factor ~= 0 then
356 h = h + h * factor / refactored
357 end
358 pos_h = pos_h + h * sx
359 end
360 elseif command == "left" then
361 local h = packet[2]
362 if h ~= 0 then
363 if factor ~= 0 then
364 h = h + h * factor / refactored
365 end
366 pos_h = pos_h - h * sx
367 end
368 elseif command == "down" then
369 local v = packet[2]
370 if v and v ~= 0 then
371 pos_v = pos_v - v * sy
372 end
373 elseif command == "up" then
374 local v = packet[2]
375 if v and v ~= 0 then
376 pos_v = pos_v + v * sy
377 end
378 elseif command == "offset" then
379 local c = packet[4]
380 if c then
381 local ph = pos_h
382 local pv = pos_v
383 local csx = packet[5]
384 local csy = packet[6] or csx
385 local h = packet[2]
386 local v = packet[3]
387 local slnt = packet[7] or false
388 if h and h ~= 0 then
389 if factor ~= 0 then
390 h = h + h * factor / refactored
391 end
392 pos_h = pos_h + h * sx
393 end
394 if v and v ~= 0 then
395 pos_v = pos_v + v * sy
396 end
397 flushchar(fnt,c,csx,csy,slnt)
398 pos_h = ph
399 pos_v = pv
400 end
401 elseif command == "stay" then
402
403 push()
404 flushchar(font,packet[2],1,1)
405 pop()
406 elseif command == "compose" then
407 local ph = pos_h
408 local pv = pos_v
409 local h = packet[2] or 0
410 local v = packet[3] or 0
411 local c = packet[4]
412 if h ~= 0 then
413 if factor ~= 0 then
414 h = h + h * factor / refactored
415 end
416 pos_h = pos_h + h * sx
417 end
418 if v and v ~= 0 then
419 pos_v = pos_v + v * sy
420 end
421 if c then
422 flushchar(fnt,c)
423 pos_h = ph
424 pos_v = pv
425 end
426 elseif command == "push" then
427 push()
428 elseif command == "pop" then
429 pop()
430 elseif command == "frame" then
431
432 local width = packet[2]
433 local height = packet[3]
434 local depth = packet[4]
435 local wd, ht, dp
436 if not current then
437
438 elseif width == true or height == true or depth == true then
439 wd, ht, dp = getwhd(current,true)
440 end
441 if width == true then
442 width = wd or 0
443 elseif not width then
444 width = 0
445 end
446 if height == true then
447 height = ht or 0
448 elseif not height then
449 height = 0
450 end
451 if depth == true then
452 depth = dp or 0
453 elseif not depth then
454 depth = 0
455 end
456 local total = height + depth
457 if width > 0 and total > 0 then
458 if factor ~= 0 then
459 width = width + width * factor / refactored
460 end
461 if width > 0 then
462 local line = packet[5] or default
463 local outline = packet[6]
464 local advance = packet[7]
465 if outline == nil then
466 outline = true
467 end
468 if advance == nil then
469 advance = true
470 end
471 local baseline = outline and packet[8]
472 local color = packet[9]
473 if color then
474 vfinjectors.startcolor(pos_h,pos_v,color)
475 end
476 width = width * sx
477 height = height * sy
478 depth = depth * sy
479 flushspecialrule(pos_h,pos_v,pos_r,width,height,depth,line,outline,baseline)
480 if color then
481 vfinjectors.stopcolor()
482 end
483 if advance then
484 pos_h = pos_h + width
485 end
486 end
487 end
488 elseif command == "rule" then
489 local size_v = packet[2]
490 local size_h = packet[3]
491 if size_h > 0 and size_v > 0 then
492 if factor ~= 0 then
493 size_h = size_h + size_h * factor / refactored
494 end
495 if size_h > 0 then
496 size_h = size_h * sx
497 size_v = size_v * sy
498 flushsimplerule(pos_h,pos_v,pos_r,size_h,size_v)
499 pos_h = pos_h + size_h
500 end
501 end
502 elseif command == "line" then
503 local wd = packet[2] or 0
504 local ht = packet[3] or 0
505 local dp = packet[4] or 0
506 if wd > 0 and ht ~= 0 and dp ~= 0 then
507 if factor ~= 0 then
508 wd = wd + wd * factor / refactored
509 end
510 if wd > 0 then
511 wd = wd * sx
512 ht = ht * sy
513 dp = dp * sy
514 local color = packet[5]
515 if color then
516 vfinjectors.startcolor(pos_h,pos_v,color)
517 end
518 flushsimplerule(pos_h,pos_v-dp,pos_r,wd,ht+dp)
519 if color then
520 vfinjectors.stopcolor()
521 end
522 pos_h = pos_h + wd
523 end
524 end
525 elseif command == "font" then
526 local index = packet[2]
527 local okay = fonts and fonts[index]
528 if okay then
529 fnt = okay.id or fnt
530 end
531 elseif command == "lua" then
532 local code = packet[2]
533 local kind = type(code)
534 if kind ~= "function" then
535 code = loadstring(code)
536 kind = type(code)
537 end
538 if kind == "function" then
539 code(font,char,pos_h,pos_v,sx,sy)
540 end
541 elseif command == "node" then
542 local h = packet[2]
543 hlist_out(h,getlist(h))
544
545
546
547
548
549
550
551
552
553
554 elseif command == "inspect" then
555 inspect(vfcommands)
556 elseif command == "trace" then
557 report("virtual state: h=%p v=%p d=%i",pos_h,pos_v,pos_r)
558 else
559 local injector = vfinjectors[command]
560 if injector then
561 injector(pos_h,pos_v,packet)
562 end
563 end
564 end
565 end
566
567
568
569 pos_h = saved_h
570 pos_v = saved_v
571 pos_r = saved_r
572
573 if savedlevel ~= level then
574 report("")
575 report("virtual state: stack is corrupt")
576 report("")
577 end
578 level = savedlevel
579
580 nesting = nesting - 1
581
582 end
583
584 local onetimemessage
585
586 flush_character = function(current,font,char,factor,vfcommands,pos_h,pos_v,pos_r,csx,csy,slnt)
587
588 if font ~= lastfont then
589 lastfont = font
590 fontcharacters = characters[font]
591 updatefontstate(font)
592 end
593
594 local data = fontcharacters[char]
595 if not data then
596 if char > 0 then
597 if not onetimemessage then
598 onetimemessage = fonts.loggers.onetimemessage
599 end
600 onetimemessage(font,char,"missing")
601 end
602 return 0, 0, 0
603 end
604
605 if vfcommands then
606 vfcommands = data.commands
607 end
608 local width, height, depth, naturalwidth, sx, sy, slant, weight
609 if current then
610 width, height, depth, factor, sx, sy, slant, weight = getglyphdimensions(current)
611 else
612 width = data.width or 0
613 height = data.height or 0
614 depth = data.depth or 0
615 naturalwidth = width
616 if not factor then
617 factor = 0
618 end
619 sx = 1
620 sy = 1
621 slant = 0
622 weight = 0
623 end
624 if pos_r == righttoleft_code then
625 pos_h = pos_h - width
626 end
627 if vfcommands then
628 flush_vf_packet(current,pos_h,pos_v,pos_r,font,char,data,csx,csy,factor,sx,sy,slant,weight,vfcommands)
629 else
630 local orientation = data.orientation
631 if orientation and (orientation == 1 or orientation == 3) then
632
633 pushorientation(orientation,pos_h,pos_v)
634 flushcharacter(current,pos_h,pos_v,pos_r,font,char,data,csx,csy,factor,sx,sy,slnt or slant,weight)
635 poporientation(orientation,pos_h,pos_v)
636 else
637 flushcharacter(current,pos_h,pos_v,pos_r,font,char,data,csx,csy,factor,sx,sy,slnt or slant,weight)
638 end
639 end
640 return width, height, depth
641 end
642
643 flush_space = function(current,pos_h,pos_v,pos_r)
644 local font = getfont(current)
645 if font == lastfont then
646
647
648
649
650
651
652
653
654 flushspace(font)
655 end
656 end
657
658end
659
660
661
662local function reset_state()
663 pos_h = 0
664 pos_v = 0
665 pos_r = lefttoright_code
666 shipbox_h = 0
667 shipbox_v = 0
668 shippingmode = "none"
669 page_size_h = 0
670 page_size_v = 0
671end
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690local dirstack = { }
691local anchors = { }
692local befores = setmetatableindex("table")
693local afters = setmetatableindex("table")
694local stired = false
695
696local function reset_directions()
697 dirstack = { }
698end
699
700local function reset_anchors()
701 anchors = { }
702end
703
704local hlist_out, vlist_out do
705
706 local finalize = nodes.handlers.finalizelist
707 local flushnode = nuts.flushnode
708
709 interfaces.implement {
710 name = "registeranchorbox",
711 public = true,
712 protected = true,
713 arguments = { "integer", "integer", "box" },
714 actions = function(anchor,where,box)
715 box = tonut(box)
716 insert(where < 0 and befores[anchor] or afters[anchor],box)
717 finalize(box,false)
718 stored = true
719 end
720 }
721
722 local function flushstored(current,source,before)
723 local t = before and befores or afters
724 local s = rawget(t,source)
725 if s then
726 for i=1,#s do
727 local si = s[i]
728 if si then
729 local box = si
730
731
732 if getid(box) == vlist_code then
733 vlist_out(current,box)
734 else
735 hlist_out(current,box)
736 end
737 flushnode(box)
738 s[i] = false
739 end
740 end
741 rawset(t,source,nil)
742 end
743 end
744
745 local function applyorientation(orientation,x,y,width,height,depth,woffset,hoffset,doffset,xoffset,yoffset)
746 local ot = (orientation >> 0) & 0x0F
747 local ay = (orientation >> 4) & 0x0F
748 local ax = (orientation >> 8) & 0x0F
749 if ot == 4 then
750 ot, ay = 0, 1
751 elseif ot == 5 then
752 ot, ay = 0, 2
753 end
754 if ot == 0 or ot == 2 then
755 if ax == 1 then x = x - width
756 elseif ax == 2 then x = x + width
757 elseif ax == 3 then x = x - width/2
758 elseif ax == 4 then x = x + width/2
759 end
760 if ot == 2 then
761 doffset, hoffset = hoffset, doffset
762 end
763 if ay == 1 then y = y - doffset
764 elseif ay == 2 then y = y + hoffset
765 elseif ay == 3 then y = y + (doffset + hoffset)/2 - doffset
766 end
767 elseif ot == 1 or ot == 3 then
768 if ay == 1 then y = y - height
769 elseif ay == 2 then y = y + height
770 elseif ay == 3 then y = y - height/2
771 end
772 if ot == 1 then
773 doffset, hoffset = hoffset, doffset
774 end
775 if ax == 1 then x = x - width
776 elseif ax == 2 then x = x + width
777 elseif ax == 3 then x = x - width/2
778 elseif ax == 4 then x = x + width/2
779 elseif ax == 5 then x = x - hoffset
780 elseif ax == 6 then x = x + doffset
781 end
782 end
783 return ot, x + xoffset, y - yoffset
784 end
785
786 local function applyanchor(anchor,shift,anchor_h,anchor_v,width,height,depth)
787 local h = 0
788 local v = 0
789 local a = anchor & 0x00FF
790 local s = anchor & 0x0F00
791 if a == 0x02 then
792 v = height
793 elseif a == 0x03 then
794 v = - depth
795 elseif a == 0x04 then
796 h = width
797 elseif a == 0x05 then
798 h = width
799 v = height
800 elseif a == 0x06 then
801 h = width
802 v = - depth
803 elseif a == 0x07 then
804 h = width/2
805 elseif a == 0x08 then
806 h = width/2
807 v = height
808 elseif a == 0x09 then
809 h = width/2
810 v = - depth
811 elseif a == 0x0A then
812 h = width/2
813 v = height/2 - depth/2
814 elseif a == 0x0B then
815 h = width/2
816 v = height/2
817 elseif a == 0x0C then
818 h = width/2
819 v = - depth/2
820 elseif a == 0x0D then
821 v = height/2 - depth/2
822 elseif a == 0x0E then
823 h = width
824 v = height/2 - depth/2
825 end
826 if not shift then
827 h = -h
828 v = -v
829 end
830 if s == 0x100 then
831 h = -h
832 elseif s == 0x200 then
833 v = -v
834 elseif s == 0x300 then
835 h = -h
836 v = -v
837 else
838 end
839 anchor_h = anchor_h + h
840 anchor_v = anchor_v + v
841 return anchor_h, anchor_v
842 end
843
844 drivers.applyanchor = applyanchor
845 drivers.applyorientation = applyorientation
846
847
848
849
850
851 local eps <const> = 10
852
853 local function handle_except(except)
854 while except do
855 local h = pos_h
856 local v = pos_v
857 local r = pos_r
858 local id = getid(except)
859
860
861
862 hlist_out(except,except)
863
864 pos_h = h
865 pos_v = v
866 pos_r = r
867 except = getnext(except)
868 end
869 end
870
871 hlist_out = function(this_box,current)
872 local ref_h = pos_h
873 local ref_v = pos_v
874 local ref_r = pos_r
875 pos_r = getdirection(this_box)
876 local boxwidth,
877 boxheight,
878 boxdepth = getwhd(this_box)
879
880 local cur_h = 0
881
882
883
884
885
886
887
888
889 for current, id, subtype in nextnode, current do
890 if id == glyph_code then
891 local char, font = isglyph(current)
892 local x_offset, y_offset, left, right, raise = getoffsets(current)
893 if x_offset ~= 0 or y_offset ~= 0 then
894 if pos_r == righttoleft_code then
895 pos_h = ref_h - (cur_h + x_offset)
896 else
897 pos_h = ref_h + (cur_h + x_offset)
898 end
899
900 pos_v = ref_v + y_offset
901
902 end
903 pos_v = pos_v + raise
904 pos_h = pos_h - left
905 local wd = flush_character(current,font,char,false,true,pos_h,pos_v,pos_r)
906
907 cur_h = cur_h + wd
908 elseif id == glue_code then
909
910 local gluewidth = effectiveglue(current,this_box,true)
911 if gluewidth ~= 0 then
912 if subtype >= leaders_code then
913 local leader = getleader(current)
914 if leader then
915 local id = getid(leader)
916 if id == rule_code then
917 if gluewidth > 0 then
918 local width, height, depth = getwhd(leader)
919 local runningheight = height == runningrule
920 local runningdepth = depth == runningrule
921 if runningheight then
922 height = boxheight
923 end
924 if runningdepth then
925 depth = boxdepth
926 end
927 local total = height + depth
928 if total > 0 then
929 local xoffset, yoffset, top, bottom, on, off = getoffsets(leader)
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949 if pos_r == righttoleft_code then
950 pos_h = pos_h - gluewidth
951 end
952 pos_v = pos_v - depth
953 flushrule(leader,pos_h,pos_v,pos_r,gluewidth,total,getsubtype(leader),on,off,runningheight and runningdepth)
954 end
955 cur_h = cur_h + gluewidth
956 end
957 elseif gluewidth > 0 and (id == hlist_code or id == vlist_code or id == glyph_code) then
958 local width, height, depth = getwhd(leader)
959
960 if width > 0 then
961 gluewidth = gluewidth + eps
962 local edge = cur_h + gluewidth
963 local lx = 0
964 if subtype == gleaders_code then
965 local save_h = cur_h
966 if pos_r == righttoleft_code then
967 cur_h = ref_h - shipbox_h + cur_h
968 cur_h = width * (cur_h / width)
969 cur_h = ref_h - shipbox_h - cur_h
970 else
971 cur_h = ref_h - shipbox_h - cur_h
972 cur_h = width * (cur_h / width)
973 cur_h = ref_h - shipbox_h - cur_h
974 end
975 if cur_h < save_h then
976 cur_h = cur_h + width
977 end
978 local lr = gluewidth % width
979 cur_h = cur_h + lr / 2
980 elseif subtype == leaders_code then
981 local save_h = cur_h
982 cur_h = width * (cur_h / width)
983 if cur_h < save_h then
984 cur_h = cur_h + width
985 end
986 else
987 local lq = gluewidth / width
988 local lr = gluewidth % width
989 if subtype == cleaders_code then
990 cur_h = cur_h + lr / 2
991 else
992 lx = lr / (lq + 1)
993 cur_h = cur_h + (lr - (lq - 1) * lx) / 2
994 end
995 end
996 if id == glyph_code then
997 local char, font = isglyph(leader)
998 local x_offset, y_offset, left, right, raise = getoffsets(leader)
999 local h = ref_h
1000 local v = ref_v
1001 if x_offset ~= 0 or y_offset ~= 0 then
1002 if pos_r == righttoleft_code then
1003 h = h - x_offset
1004 else
1005 h = h + x_offset
1006 end
1007 v = v + y_offset
1008 end
1009 v = v + raise
1010 h = h - left
1011 local basepoint_h = 0
1012 if boxdir ~= pos_r then
1013 basepoint_h = boxwidth
1014 end
1015 if pos_r == righttoleft_code then
1016 pos_h = h - basepoint_h
1017 else
1018 pos_h = h + basepoint_h
1019 end
1020 while cur_h + width <= edge do
1021 if pos_r == righttoleft_code then
1022 pos_h = h - cur_h
1023 else
1024 pos_h = h + cur_h
1025 end
1026 pos_v = v
1027 flush_character(leader,font,char,false,true,pos_h,pos_v,pos_r)
1028 cur_h = cur_h + width + lx
1029 end
1030 else
1031 local shift = isglyph and 0 or getshift(leader)
1032 local boxdir = getdirection(leader) or lefttoright_code
1033 pushleaderlevel()
1034 while cur_h + width <= edge do
1035
1036 local basepoint_h = 0
1037
1038 if boxdir ~= pos_r then
1039 basepoint_h = boxwidth
1040 end
1041
1042 if pos_r == righttoleft_code then
1043 pos_h = ref_h - (cur_h + basepoint_h)
1044 else
1045 pos_h = ref_h + (cur_h + basepoint_h)
1046 end
1047 pos_v = ref_v - shift
1048
1049 if id == vlist_code then
1050 vlist_out(leader,getlist(leader))
1051 else
1052 hlist_out(leader,getlist(leader))
1053 end
1054 cur_h = cur_h + width + lx
1055 end
1056 popleaderlevel()
1057 end
1058 cur_h = edge - eps
1059 else
1060 cur_h = cur_h + gluewidth
1061 end
1062 else
1063
1064 cur_h = cur_h + gluewidth
1065 end
1066 else
1067 cur_h = cur_h + gluewidth
1068 end
1069 else
1070 if tospace and (subtype == spaceskip_code or subtype == xspaceskip_code) then
1071
1072 flush_space(current)
1073 end
1074 cur_h = cur_h + gluewidth
1075 end
1076 end
1077 elseif id == hlist_code or id == vlist_code then
1078 local width, height, depth, shift, list, except = getlistdimensions(current)
1079 if list then
1080 local geometry, hasoffset, hasorientation, hasanchor, boxdir = getgeometry(current,true)
1081 local anchor, source, target, targetdata, s_anchor, t_anchor
1082 local anc_h, anc_v
1083 local usedorientation = false
1084 if hasanchor then
1085 anchor, source, target, s_anchor, t_anchor = getanchors(current)
1086 end
1087 if hasorientation then
1088 local orientation, xoffset, yoffset, woffset, hoffset, doffset = getorientation(current)
1089 local orientation, basepoint_h, basepoint_v = applyorientation(orientation,0,shift,width,height,depth,woffset,hoffset,doffset,xoffset,yoffset)
1090 if orientation == 1 then
1091 basepoint_h = basepoint_h + doffset
1092 if boxdir == pos_r then
1093 basepoint_v = basepoint_v - height
1094 end
1095 usedorientation = orientation
1096 elseif orientation == 2 then
1097 if boxdir == pos_r then
1098 basepoint_h = basepoint_h + width
1099 end
1100 usedorientation = orientation
1101 elseif orientation == 3 then
1102 basepoint_h = basepoint_h + hoffset
1103 if boxdir ~= pos_r then
1104 basepoint_v = basepoint_v - height
1105 end
1106 usedorientation = orientation
1107 end
1108 if target then
1109 targetdata = anchors[target]
1110 if targetdata then
1111 anc_h = basepoint_h
1112 anc_v = - basepoint_v
1113 goto posdone
1114 end
1115 end
1116 if pos_r == righttoleft_code then
1117 pos_h = ref_h - (cur_h + basepoint_h)
1118 else
1119 pos_h = ref_h + (cur_h + basepoint_h)
1120 end
1121
1122 pos_v = ref_v - basepoint_v
1123 elseif hasoffset then
1124
1125 local xoffset, yoffset = getoffsets(current)
1126 local basepoint_h = boxdir ~= pos_r and width or 0
1127 local basepoint_v = shift
1128 if target then
1129 targetdata = anchors[target]
1130 if targetdata then
1131 anc_h = xoffset + basepoint_h
1132 anc_v = yoffset - basepoint_v
1133 goto posdone
1134 end
1135 end
1136 if pos_r == righttoleft_code then
1137 pos_h = ref_h - (cur_h + basepoint_h + xoffset)
1138 else
1139 pos_h = ref_h + (cur_h + basepoint_h + xoffset)
1140 end
1141 pos_v = ref_v - (basepoint_v - yoffset)
1142 elseif hasanchor then
1143 local basepoint_h = boxdir ~= pos_r and width or 0
1144 local basepoint_v = shift
1145 if target then
1146 targetdata = anchors[target]
1147 if targetdata then
1148 anc_h = basepoint_h
1149 anc_v = - basepoint_v
1150 goto posdone
1151 end
1152 end
1153 if pos_r == righttoleft_code then
1154 pos_h = ref_h - (cur_h + basepoint_h)
1155 else
1156 pos_h = ref_h + (cur_h + basepoint_h)
1157 end
1158 pos_v = ref_v - basepoint_v
1159 else
1160 local basepoint_h = boxdir ~= pos_r and width or 0
1161 local basepoint_v = shift
1162 if pos_r == righttoleft_code then
1163 pos_h = ref_h - (cur_h + basepoint_h)
1164 else
1165 pos_h = ref_h + (cur_h + basepoint_h)
1166 end
1167 pos_v = ref_v - basepoint_v
1168 end
1169 goto process
1170 ::posdone::
1171 if pos_r == righttoleft_code then
1172 pos_h = targetdata[1] - anc_h
1173 else
1174 pos_h = targetdata[1] + anc_h
1175 end
1176 pos_v = targetdata[2] + anc_v
1177 if anchor and anchor > 0 then
1178
1179
1180 pos_h, pos_v = applyanchor(t_anchor,true, pos_h,pos_v,targetdata[3],targetdata[4],targetdata[5])
1181 pos_h, pos_v = applyanchor(s_anchor,false,pos_h,pos_v,width,height,depth)
1182 end
1183 ::process::
1184 if source then
1185 local anchor_h = pos_h
1186 local anchor_v = pos_v
1187 if usedorientation then
1188 if usedorientation == 1 then
1189 anchor_v = anchor_v - (width - height)
1190 elseif usedorientation == 2 then
1191 anchor_v = anchor_v - (depth - height)
1192 elseif usedorientation == 3 then
1193 anchor_v = anchor_v + (height - width)
1194 end
1195 end
1196
1197 anchors[source] = { anchor_h, anchor_v, width, height, depth }
1198 end
1199 if usedorientation then
1200 pushorientation(usedorientation,pos_h,pos_v,pos_r)
1201 end
1202 if source and stored then
1203 flushstored(current,source,true)
1204 end
1205 if except then
1206 handle_except(except)
1207 end
1208 if id == vlist_code then
1209 vlist_out(current,list)
1210 else
1211 hlist_out(current,list)
1212 end
1213 if source and stored then
1214 flushstored(current,source,false)
1215 end
1216 if usedorientation then
1217 poporientation(usedorientation,pos_h,pos_v,pos_r)
1218 end
1219 end
1220 cur_h = cur_h + width
1221 elseif id == kern_code then
1222
1223
1224 local kern = getkerndimension(current)
1225 if kern ~= 0 then
1226 cur_h = cur_h + kern
1227 end
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238 elseif id == rule_code then
1239 local width, height, depth, virtual = getruledimensions(current)
1240 if width > 0 then
1241 local runningheight = height == runningrule
1242 local runningdepth = depth == runningrule
1243 if runningheight then
1244 height = boxheight
1245 end
1246 if runningdepth then
1247 depth = boxdepth
1248 end
1249 local total = height + depth
1250 if total > 0 then
1251 local xoffset, yoffset, top, bottom, on, off = getoffsets(current)
1252 if pos_r == righttoleft_code then
1253 pos_h = pos_h - width
1254 xoffset = - xoffset
1255 end
1256 if not virtual then
1257 if top ~= 0 then
1258
1259 total = total - top
1260 end
1261 if bottom ~= 0 then
1262 depth = depth - bottom
1263 total = total - bottom
1264 end
1265 end
1266 pos_v = pos_v - depth
1267 flushrule(current,pos_h + xoffset,pos_v + yoffset,pos_r,width,total,subtype,on,off,runningheight and runningdepth)
1268 end
1269 if not virtual then
1270 cur_h = cur_h + width
1271 end
1272 end
1273 elseif id == math_code then
1274
1275
1276
1277
1278 cur_h = cur_h + effectiveglue(current,this_box,true)
1279
1280 elseif id == dir_code then
1281
1282
1283
1284 local dir, cancel = getdirection(current)
1285 if cancel then
1286 local ds = dirstack[current]
1287 if ds then
1288 ref_h = ds.ref_h
1289 ref_v = ds.ref_v
1290 cur_h = ds.cur_h
1291
1292 else
1293
1294 end
1295 pos_r = dir
1296 else
1297 local width, enddir = dirdimensions(this_box,current)
1298 local new_h = cur_h + width
1299 if dir ~= pos_r then
1300 cur_h = new_h
1301 end
1302
1303 if enddir ~= current then
1304 dirstack[enddir] = {
1305 cur_h = new_h,
1306
1307 ref_h = ref_h,
1308 ref_v = ref_v,
1309 }
1310
1311 setdirection(enddir,pos_r)
1312 end
1313 if pos_r == righttoleft_code then
1314 pos_h = ref_h - cur_h
1315 else
1316 pos_h = ref_h + cur_h
1317 end
1318
1319 pos_v = ref_v
1320
1321 ref_h = pos_h
1322 ref_v = pos_v
1323 cur_h = 0
1324
1325 pos_r = dir
1326 goto synced
1327 end
1328 elseif id == whatsit_code then
1329 flushwhatsit[subtype](current,pos_h,pos_v)
1330 elseif id == disc_code then
1331 local replace, tail = getreplace(current)
1332
1333
1334 if replace then
1335 setlink(tail,getnext(current))
1336 setlink(current,replace)
1337 setreplace(current)
1338 end
1339
1340
1341
1342
1343
1344 else
1345
1346 goto synced
1347 end
1348
1349
1350 if pos_r == righttoleft_code then
1351 pos_h = ref_h - cur_h
1352 else
1353 pos_h = ref_h + cur_h
1354 end
1355
1356 pos_v = ref_v
1357 ::synced::
1358 end
1359 pos_h = ref_h
1360 pos_v = ref_v
1361 pos_r = ref_r
1362 end
1363
1364 vlist_out = function(this_box,current)
1365 local ref_h = pos_h
1366 local ref_v = pos_v
1367 local ref_r = pos_r
1368 pos_r = getdirection(this_box)
1369
1370 local boxwidth,
1371 boxheight,
1372 boxdepth = getwhd(this_box)
1373
1374 local cur_h = 0
1375 local cur_v = - boxheight
1376 local top_edge = cur_v
1377
1378
1379
1380
1381
1382
1383 pos_h = ref_h
1384 pos_v = ref_v - cur_v
1385
1386
1387
1388
1389
1390
1391
1392
1393 for current, id, subtype in nextnode, current do
1394 if id == glue_code then
1395 local glueheight = effectiveglue(current,this_box,true)
1396 if glueheight ~= 0 then
1397 if subtype >= leaders_code then
1398 local leader = getleader(current)
1399 if leader then
1400 local width, height, depth = getwhd(leader)
1401 local total = height + depth
1402 if getid(leader) == rule_code then
1403 depth = 0
1404 total = glueheight
1405 if total > 0 then
1406 local runningwidth = width == runningrule
1407 if runningwidth then
1408 width = boxwidth
1409 end
1410 if width > 0 then
1411 local xoffset, yoffset, left, right, on, off = getoffsets(leader)
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428 if pos_r == righttoleft_code then
1429 cur_h = cur_h - width
1430 end
1431 flushrule(leader,pos_h,pos_v - total,pos_r,width,total,getsubtype(leader),on,off,runningwidth)
1432 end
1433 cur_v = cur_v + total
1434 end
1435 elseif total > 0 and glueheight > 0 then
1436 glueheight = glueheight + 10
1437 local edge = cur_v + glueheight
1438 local ly = 0
1439 if subtype == gleaders_code then
1440 save_v = cur_v
1441 cur_v = ref_v - shipbox_v - cur_v
1442 cur_v = total * (cur_v / total)
1443 cur_v = ref_v - shipbox_v - cur_v
1444 if cur_v < save_v then
1445 cur_v = cur_v + total
1446 end
1447 local lr = glueheight % total
1448 cur_v = cur_v + lr / 2
1449 elseif subtype == leaders_code then
1450 save_v = cur_v
1451 cur_v = top_edge + total * ((cur_v - top_edge) // total)
1452 if cur_v < save_v then
1453 cur_v = cur_v + total
1454 end
1455 else
1456 local lq = glueheight / total
1457 local lr = glueheight % total
1458 if subtype == cleaders_code then
1459 cur_v = cur_v + lr / 2
1460 else
1461 ly = lr // (lq + 1)
1462 cur_v = cur_v + (lr - (lq - 1) * ly) / 2
1463 end
1464 end
1465 local shift = getshift(leader)
1466 pushleaderlevel()
1467 while cur_v + total <= edge do
1468
1469 if pos_r == righttoleft_code then
1470 pos_h = ref_h - shift
1471 else
1472 pos_h = ref_h + shift
1473 end
1474 pos_v = ref_v - (cur_v + height)
1475
1476 if getid(leader) == vlist_code then
1477 vlist_out(leader,getlist(leader))
1478 else
1479 hlist_out(leader,getlist(leader))
1480 end
1481 cur_v = cur_v + total + ly
1482 end
1483 popleaderlevel()
1484 cur_v = edge - 10
1485 else
1486 cur_v = cur_v + glueheight
1487 end
1488 end
1489 else
1490 cur_v = cur_v + glueheight
1491 end
1492 end
1493 elseif id == hlist_code or id == vlist_code then
1494 local width, height, depth, shift, list, except = getlistdimensions(current)
1495 if list then
1496 local geometry, hasoffset, hasorientation, hasanchor, boxdir = getgeometry(current,true)
1497 local anchor, source, target, targetdata, s_anchor, t_anchor
1498 local usedorientation = false
1499 if hasanchor then
1500 anchor, source, target, s_anchor, t_anchor = getanchors(current)
1501 end
1502 if hasorientation then
1503 local orientation, xoffset, yoffset, woffset, hoffset, doffset = getorientation(current)
1504 local orientation, basepoint_h, basepoint_v = applyorientation(orientation,shift,height,width,height,depth,woffset,hoffset,doffset,xoffset,yoffset)
1505 if orientation == 1 then
1506 basepoint_h = basepoint_h + width - height
1507 basepoint_v = basepoint_v - height
1508 usedorientation = orientation
1509 elseif orientation == 2 then
1510 basepoint_h = basepoint_h + width
1511 basepoint_v = basepoint_v + depth - height
1512 usedorientation = orientation
1513 elseif orientation == 3 then
1514 basepoint_h = basepoint_h + height
1515 usedorientation = orientation
1516 end
1517 if target then
1518 targetdata = anchors[target]
1519 if targetdata then
1520 if pos_r == righttoleft_code then
1521 pos_h = targetdata[1] - basepoint_h
1522 else
1523 pos_h = targetdata[1] + basepoint_h
1524 end
1525 pos_v = targetdata[2] - basepoint_v
1526 goto posdone
1527 end
1528 end
1529 if pos_r == righttoleft_code then
1530 pos_h = ref_h - basepoint_h
1531 else
1532 pos_h = ref_h + basepoint_h
1533 end
1534 pos_v = ref_v - (cur_v + basepoint_v)
1535 elseif hasoffset then
1536
1537 local xoffset, yoffset = getoffsets(current)
1538
1539
1540 if boxdir ~= pos_r then
1541 shift = shift + width
1542 end
1543 if target then
1544 targetdata = anchors[target]
1545 if targetdata then
1546 if pos_r == righttoleft_code then
1547 pos_h = targetdata[1] - (shift + xoffset)
1548 else
1549 pos_h = targetdata[1] + (shift + xoffset)
1550 end
1551 pos_v = targetdata[2] - (height - yoffset)
1552 goto posdone
1553 end
1554 end
1555 if pos_r == righttoleft_code then
1556 pos_h = ref_h - (shift + xoffset)
1557 else
1558 pos_h = ref_h + (shift + xoffset)
1559 end
1560 pos_v = ref_v - (cur_v + height - yoffset)
1561 elseif hasanchor then
1562
1563
1564 if boxdir ~= pos_r then
1565 shift = shift + width
1566 end
1567 if target then
1568 local a = anchors[target]
1569 if a then
1570 if pos_r == righttoleft_code then
1571 pos_h = targetdata[1] - shift
1572 else
1573 pos_h = targetdata[1] + shift
1574 end
1575 pos_v = targetdata[2] - height
1576 goto posdone
1577 end
1578 end
1579 if pos_r == righttoleft_code then
1580 pos_h = ref_h - shift
1581 else
1582 pos_h = ref_h + shift
1583 end
1584 pos_v = ref_v - (cur_v + height)
1585 else
1586
1587
1588 if boxdir ~= pos_r then
1589 shift = shift + width
1590 end
1591 if pos_r == righttoleft_code then
1592 pos_h = ref_h - shift
1593 else
1594 pos_h = ref_h + shift
1595 end
1596 pos_v = ref_v - (cur_v + height)
1597 end
1598 goto process
1599 ::posdone::
1600 if anchor and anchor > 0 then
1601 pos_h, pos_v = applyanchor(t_anchor,true, pos_h,pos_v,targetdata[3],targetdata[4],targetdata[5])
1602 pos_h, pos_v = applyanchor(s_anchor,false,pos_h,pos_v,width,height,depth)
1603 end
1604 ::process::
1605 if source then
1606
1607 local anchor_h = pos_h
1608 local anchor_v = pos_v
1609 if usedorientation then
1610 if usedorientation == 1 then
1611 anchor_v = anchor_v - (width - height)
1612 elseif usedorientation == 2 then
1613 anchor_v = anchor_v - (depth - height)
1614 elseif usedorientation == 3 then
1615 anchor_v = anchor_v + (height - width)
1616 end
1617 end
1618 anchors[source] = { anchor_h, anchor_v, width, height, depth }
1619 end
1620 if usedorientation then
1621 pushorientation(usedorientation,pos_h,pos_v,pos_r)
1622 end
1623 if source and stored then
1624 flushstored(current,source,true)
1625 end
1626 if except then
1627 handle_except(except)
1628 end
1629 if id == vlist_code then
1630 vlist_out(current,list)
1631 else
1632 hlist_out(current,list)
1633 end
1634 if source and stored then
1635 flushstored(current,source,false)
1636 end
1637 if usedorientation then
1638 poporientation(usedorientation,pos_h,pos_v,pos_r)
1639 end
1640 end
1641 cur_v = cur_v + height + depth
1642 elseif id == kern_code then
1643 cur_v = cur_v + getkern(current)
1644 elseif id == rule_code then
1645 local width, height, depth, virtual = getruledimensions(current)
1646 local total = height + depth
1647 if total > 0 then
1648 local runningwidth = width == runningrule
1649 if runningwidth then
1650 width = boxwidth
1651 end
1652 if width > 0 then
1653 local xoffset, yoffset, left, right, on, off = getoffsets(current)
1654 if not virtual then
1655 if left ~= 0 then
1656 width = width - left
1657 xoffset = left
1658 end
1659 if right ~= 0 then
1660 width = width - right
1661 end
1662 end
1663 if pos_r == righttoleft_code then
1664 xoffset = - xoffset - width
1665 end
1666 flushrule(current,pos_h + xoffset,pos_v - total - yoffset,pos_r,width,total,subtype,on,off,runningwidth)
1667 end
1668 if not virtual then
1669 cur_v = cur_v + total
1670 end
1671 end
1672 elseif id == whatsit_code then
1673 flushwhatsit[subtype](current,pos_h,pos_v)
1674 else
1675
1676 goto synced
1677 end
1678 if pos_r == righttoleft_code then
1679 pos_h = ref_h - cur_h
1680 else
1681 pos_h = ref_h + cur_h
1682 end
1683 pos_v = ref_v - cur_v
1684 ::synced::
1685 end
1686 pos_h = ref_h
1687 pos_v = ref_v
1688 pos_r = ref_r
1689 end
1690
1691end
1692
1693function drivers.converters.lmtx(driver,box,smode,objnum,specification)
1694
1695 if not driver then
1696 report("error in converter, no driver")
1697 return
1698 end
1699
1700 if box then
1701 box = tonut(box)
1702 else
1703 report("error in converter, no box")
1704 return
1705 end
1706
1707 local actions = driver.actions
1708 local flushers = driver.flushers
1709
1710 initialize = actions.initialize
1711 finalize = actions.finalize
1712
1713 updatefontstate = flushers.updatefontstate
1714
1715 pushorientation = flushers.pushorientation
1716 poporientation = flushers.poporientation
1717
1718 pushleaderlevel = flushers.pushleaderlevel
1719 popleaderlevel = flushers.popleaderlevel
1720
1721 flushcharacter = flushers.character
1722 flushfontchar = flushers.fontchar
1723 flushrule = flushers.rule
1724 flushsimplerule = flushers.simplerule
1725 flushspecialrule = flushers.specialrule
1726 flushliteral = flushers.literal
1727 flushwhatsit = flushers.whatsit
1728 flushspace = flushers.space
1729
1730 reset_directions()
1731 reset_anchors()
1732 reset_state()
1733
1734 shippingmode = smode
1735
1736 local details = nil
1737
1738 local width, height, depth = getwhd(box)
1739
1740 local total = height + depth
1741
1742 if height > maxdimen or depth > maxdimen or width > maxdimen or total > maxdimen then
1743 goto DONE
1744 end
1745
1746 if shippingmode == "page" then
1747
1748
1749
1750 local pagewidth, pageheight = getpagedimensions()
1751
1752 pos_r = lefttoright_code
1753
1754 if pagewidth > 0 then
1755 page_size_h = pagewidth
1756 else
1757 page_size_h = width
1758 end
1759
1760 if page_size_h == 0 then
1761 page_size_h = width
1762 end
1763
1764 if pageheight > 0 then
1765 page_size_v = pageheight
1766 else
1767 page_size_v = total
1768 end
1769
1770 if page_size_v == 0 then
1771 page_size_v = total
1772 end
1773
1774 local refpoint_h = 0
1775 local refpoint_v = page_size_v
1776
1777 pos_h = refpoint_h
1778 pos_v = refpoint_v - height
1779
1780 else
1781
1782 page_size_h = width
1783 page_size_v = total
1784 pos_r = getdirection(box)
1785 pos_v = depth
1786 pos_h = pos_r == righttoleft_code and width or 0
1787
1788 end
1789
1790 shipbox_ref_h = pos_h
1791 shipbox_ref_v = pos_v
1792
1793 details = {
1794 shippingmode = smode,
1795 boundingbox = { 0, 0, page_size_h, page_size_v },
1796 objectnumber = smode ~= "page" and objnum or nil,
1797 pagenumber = smode == "page" and objnum or nil,
1798 specification = specification,
1799 }
1800
1801 initialize(driver,details)
1802
1803 lastfont = nil
1804
1805 if getid(box) == vlist_code then
1806 vlist_out(box,getlist(box))
1807 else
1808 hlist_out(box,getlist(box))
1809 end
1810
1811 ::DONE::
1812
1813 finalize(driver,details)
1814
1815 shippingmode = "none"
1816end
1817
1818
1819
1820do
1821
1822
1823
1824
1825 local properties = nodes.properties.data
1826 local flush = texio.write
1827 local flushline = texio.writenl
1828
1829 local periods = utilities.strings.newrepeater(".")
1830
1831 local f_detail_0 = formatters["%s %s = %s"]
1832 local f_detail_1 = formatters["%i: %s %s = %s"]
1833 local f_detail_2 = formatters["%i:%i: %s %s = %s"]
1834
1835 local function showdetails(n,l,tlp,l1,l2)
1836 local p = properties[tonut(n)]
1837 if p then
1838 for k, v in sortedhash(p) do
1839 local t = type(v)
1840 local p = periods[l+1]
1841 if t == "string" then
1842 if find(v,"[\n\r]") then
1843 v = "\n" .. stripstring(v) .. "\n"
1844 end
1845 elseif t == "number" or t == "boolean" then
1846 v = tostring(v)
1847 elseif t == "table" then
1848 v = sequenced(v)
1849 else
1850 v = "<" .. tostring(v) .. ">"
1851 end
1852 if tlp == 3 then
1853 flushline(f_detail_2(l1,l2,p,k,v))
1854 elseif tlp == 2 then
1855 flushline(f_detail_1(l2,p,k,v))
1856 elseif tlp == 1 then
1857 flushline(f_detail_1(l1,p,k,v))
1858 else
1859 flushline(f_detail_0(p,k,v))
1860 end
1861 end
1862 end
1863 end
1864
1865 local whatsittracers = {
1866 latelua = showdetails,
1867 literal = showdetails,
1868 }
1869
1870 callbacks.register("show_whatsit",function(n,what,l,tlp,l1,l2)
1871 local s = nodes.whatsitcodes[n.subtype]
1872 if what == 1 then
1873 return s or "unknown"
1874
1875 else
1876 local w = whatsittracers[s]
1877 if w then
1878 w(n,l,tlp,l1,l2)
1879 end
1880 end
1881 end,"provide whatsit details")
1882
1883 local names = attributes.names
1884 local taglist = structures.tags.taglist
1885 local details = false
1886
1887 local a_tagged <const> = attributes.private('tagged')
1888
1889 trackers.register("attributes.tags",function(v) details = v end)
1890
1891 callbacks.register("get_attribute",function(k,v)
1892 local detail = nil
1893 if details and k == a_tagged then
1894 detail = taglist[v]
1895 if detail then
1896 detail = detail.taglist
1897 if detail then
1898 detail = detail[#detail]
1899 end
1900 end
1901 end
1902 return names[k], detail
1903 end,"provide verbose attribute name")
1904
1905end
1906 |