driv-shp.lmt /size: 75 Kb    last modification: 2025-02-21 11:03
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----- getwidth           = nuts.getwidth
39local getnext            = nuts.getnext
40local getsubtype         = nuts.getsubtype
41local getid              = nuts.getid
42local getleader          = nuts.getleader
43----- getglue            = nuts.getglue
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----- nextdir            = nuts.traversers.dir
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-- For the moment rules need at least some height but maybe some day we let user rules
107-- fall through or have some way to force a rule via some property.
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-- make local
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-- characters
146
147-- experiment (smaller page stream but might be fragile)
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    -- todo: cache streams
159
160    local default    =   16384 -- * number.dimenfactors.bp -- 65536 // 4
161    local refactored = 1000000 -- expansion related
162
163    local vfinjectors = fonts.helpers.vfinjectors
164
165    -- current can go
166
167 -- local alternative = false -- more local, can be an option: vf.commands.local
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         -- if alternative then
175         --     local s = stack[0]
176         --     s[1] = pos_h
177         --     s[2] = pos_v
178         --     s[3] = pos_r
179         -- end
180        else
181         -- if alternative then
182         --     local s = stack[0]
183         --     pos_h = s[1]
184         --     pos_v = s[2]
185         --     pos_r = s[3]
186         -- end
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     -- push() -- or:
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] -- offsets etc
220        local fnt     = font
221        local fonts   = fdata.fonts
222        local siz     = (fdata.parameters.factor or 1)/65536
223
224        -- An alternative where we (here) locally define handlers like this:
225        --
226        -- if not vfinjectors then
227        --     function vfinjectors.char(hpos,vpos,packet)
228        --         -- .... access: font, char, factor, sx, xy
229        --     end
230        -- end
231        --
232        -- doesn't work because accessing the parameters passed to the outer function doesn't
233        -- work as expected (so we end up in a nesting loop). I remember hitting this somewhat
234        -- unexpected feature before.
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     -- -- example of usage needed (nested vf)
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 -- expansion
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        -- we assume resolved fonts: id mandate but maybe also size
268
269        local function flushchar(fnt,chr,csx,csy,slnt) -- can't be moved out of the function due to binding locals
270            if fnt then                           -- to the function variables etc etc ... kind of messy
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                -- here no current!
286             -- return flushcharacter(false,pos_h,pos_v,pos_r,fnt,chr,nil,csx,csy,factor,sx,sy,slant,weight)
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        -- virtual t3 fonts have negative font index
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                            -- safeguard, we assume the font itself (often index 1)
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                            -- not efficient but ok for now as experiment
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] -- already scaled
354                    if h ~= 0 then
355                        if factor ~= 0 then
356                            h = h + h * factor / refactored -- expansion
357                        end
358                        pos_h = pos_h + h * sx
359                    end
360                elseif command == "left" then
361                    local h = packet[2] -- already scaled
362                    if h ~= 0 then
363                        if factor ~= 0 then
364                            h = h + h * factor / refactored -- expansion
365                        end
366                        pos_h = pos_h - h * sx
367                    end
368                elseif command == "down" then
369                    local v = packet[2] -- already scaled
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] -- already scaled
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 -- expansion
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                    -- we can do a fast one if needed, it's more an experiment
403                    push()
404                    flushchar(font,packet[2],1,1)
405                    pop()
406                elseif command == "compose" then -- for now idem
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 -- expansion
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                    -- d:width d:height d:depth d:rulethickness b:outline b:advance b:baseline s:color
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                        -- can be a space injected instead of glue
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] -- no longer needed probably
473                            if color then
474                                vfinjectors.startcolor(pos_h,pos_v,color) -- takes packet or string
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] -- no longer needed probably
515                            if color then
516                                vfinjectors.startcolor(pos_h,pos_v,color) -- takes packet or string
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 -- or maybe just return
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) -- maybe also packet
540                    end
541                elseif command == "node" then
542                    local h = packet[2]
543                    hlist_out(h,getlist(h))
544             -- elseif command == "pdf" then
545                    -- unsupported
546             -- elseif command == "pdfmode" then
547                    -- unsupported
548             -- elseif command == "special" then
549                    -- unsupported
550             -- elseif command == "nop"     then
551                    -- just ignored
552             -- elseif command == "image"   then
553                    -- unsupported, use "node"
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) -- maybe also sx, sy but then we need to check usage
562                    end
563                end
564            end
565        end
566
567     -- pop() -- or:
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 -- could be defined later (todo: make plug for this)
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) -- can move to lpdf-lmt, cleaner
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 -- here ?
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 -- 0 (none), 1, 2, 3 or 4 (none)
631            if orientation and (orientation == 1 or orientation == 3) then
632                -- we can get weird charactersbox tracing here
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         -- local char = 32
647         -- local data = fontcharacters[32]
648         -- if not data then
649         --     return
650         -- end
651         -- -- if pos_r == righttoleft_code then
652         -- --     pos_h = pos_h - (data.width or 0) -- here ?
653         -- -- end
654            flushspace(font)
655        end
656    end
657
658end
659
660-- end of characters
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-- local function dirstackentry(t,k)
674--     local v = {
675--         cur_h = 0,
676--         cur_v = 0,
677--         ref_h = 0,
678--         ref_v = 0,
679--     }
680--     t[k] = v
681--     return v
682-- end
683--
684-- local  dirstack = setmetatableindex(dirstackentry)
685--
686-- local function reset_directions()
687--     dirstack = setmetatableindex(dirstackentry)
688-- end
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 -- si[1]
730                    -- tagging needs it to be earlier
731                 -- finalize(box,false)
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 -- halfway_total_anchor
812            h = width/2
813            v = height/2 - depth/2
814        elseif a == 0x0B then -- halfway_height_anchor
815            h = width/2
816            v = height/2
817        elseif a == 0x0C then -- halfway_depth_anchor
818            h = width/2
819            v = - depth/2
820        elseif a == 0x0D then -- halfway_left_anchor
821            v = height/2 - depth/2
822        elseif a == 0x0E then -- halfway_right_anchor
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    -- to be checked: begin- or enddir kan nil zijn, weird
848
849    -- check frequencies of nodes
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         -- if id == vlist_code then
860         --     vlist_out(except,except)
861         -- elseif id == hlist_code then
862                hlist_out(except,except)
863         -- end
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     -- local cur_v = 0
882
883     -- if not current then
884     --     current = getlist(this_box)
885     -- end
886
887        -- we can encounter par, boundary and penalty nodes but a special
888        -- iterator over content nodes won't save much
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                 -- pos_v = ref_v - (cur_v - y_offset)
900                    pos_v = ref_v + y_offset
901                    -- synced
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             -- cur_h = cur_h + wd - right -- hm, no left here?
907                cur_h = cur_h + wd -- see new tabulate alignment code
908            elseif id == glue_code then
909             -- local gluewidth = effectiveglue(current,this_box)
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                                     -- -- only when we have a use case:
931                                     --
932                                     -- if pos_r == righttoleft_code then
933                                     --     pos_h   = pos_h - gluewidth
934                                     --     xoffset = - xoffset
935                                     -- end
936                                     -- if not virtual then
937                                     --     if top ~= 0 then
938                                     --      -- height = height - top
939                                     --         total  = total - top
940                                     --     end
941                                     --     if bottom ~= 0 then
942                                     --         depth = depth - bottom
943                                     --         total = total - bottom
944                                     --     end
945                                     -- end
946                                     -- pos_v = pos_v - depth
947                                     -- flushrule(leader,pos_h + xoffset,pos_v + yoffset,pos_r,gluewidth,total,getsubtype(leader))
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                                -- no need for //
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                                            -- todo: move some out of loop as above
1036                                            local basepoint_h = 0
1037                                         -- local basepoint_v = shift
1038                                            if boxdir ~= pos_r then
1039                                                basepoint_h = boxwidth
1040                                            end
1041                                            -- synch_pos_with_cur(ref_h,ref_v,cur_h + basepoint_h,shift)
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                                            -- synced
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                                -- maybe some day also glyphs
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                         -- kind of tricky because because we can have a different sx sy
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                     -- pos_v = ref_v - (cur_v + basepoint_v)
1122                        pos_v = ref_v - basepoint_v
1123                    elseif hasoffset then
1124--                         local orientation, xoffset, yoffset = getorientation(current)
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--                         pos_h, pos_v = applyanchor(anchor,true,t_anchor,pos_h,pos_v,targetdata[3],targetdata[4],targetdata[5])
1179--                         pos_h, pos_v = applyanchor(anchor,false,s_anchor,pos_h,pos_v,width,height,depth)
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 -- weird
1193                                anchor_v = anchor_v + (height - width)
1194                            end
1195                        end
1196-- anchor_v = anchor_v + shift
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                -- when we use getkerndimension we get rounded values
1223             -- if true then
1224                    local kern = getkerndimension(current)
1225                    if kern ~= 0 then
1226                        cur_h = cur_h + kern
1227                    end
1228             -- else
1229             --    local kern, factor = getkern(current,true)
1230             --    if kern ~= 0 then
1231             --        if factor ~= 0 then
1232             --            cur_h = cur_h + (1.0 + factor/1000000.0) * kern
1233             --        else
1234             --            cur_h = cur_h + kern
1235             --        end
1236             --    end
1237             -- end
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                             -- height = height - top
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             -- local kern = getkern(current)
1275             -- if kern ~= 0 then
1276             --     cur_h = cur_h + kern
1277             -- else
1278                    cur_h = cur_h + effectiveglue(current,this_box,true)
1279             -- end
1280            elseif id == dir_code then
1281             -- We normally have proper begin-end pairs. A begin without end is (silently) handled
1282             -- and an end without a begin will be (silently) skipped we only need to move forward
1283             -- so we then have a faster calculation.
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                     -- cur_v = ds.cur_v
1292                    else
1293                        -- pardir
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                    -- kind of weird but indeed we don't adapt here:  pos_r = dir
1303                    if enddir ~= current then
1304                        dirstack[enddir] = {
1305                            cur_h = new_h,
1306                         -- cur_v = cur_v,
1307                            ref_h = ref_h,
1308                            ref_v = ref_v,
1309                        }
1310                        -- kind of weird but indeed cheat here, so we basically have a bad one now
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                 -- pos_v = ref_v - cur_v
1319                    pos_v = ref_v
1320                    -- synced
1321                    ref_h = pos_h
1322                    ref_v = pos_v
1323                    cur_h = 0
1324                 -- cur_v = 0
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                -- actually, we no longer have these select discs in the packaged list ... it's about
1333                -- time to clean up the disc code a bit further
1334                if replace then -- and subtype ~= select_disc_code then
1335                    setlink(tail,getnext(current))
1336                    setlink(current,replace)
1337                    setreplace(current)
1338                end
1339         -- elseif id == par_code and startofpar(current) then
1340         --     local pardir = getdirection(current) or lefttoright_code
1341         --     if pardir == righttoleft_code then
1342         --     end
1343         -- end
1344            else
1345                -- penalty, boundary ... no dimensions
1346                goto synced
1347            end
1348            -- There is no gain in skipping over this when we have zero progression
1349            -- and such.
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         -- pos_v = ref_v - cur_v
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 -- needs checking .. needed ?
1375        local cur_v    = - boxheight
1376        local top_edge = cur_v
1377
1378     -- if pos_r == righttoleft_code then
1379     --     pos_h = ref_h - cur_h
1380     -- else
1381     --     pos_h = ref_h + cur_h
1382     -- end
1383        pos_h = ref_h
1384        pos_v = ref_v - cur_v
1385        -- synced
1386
1387     -- if not current then
1388     --     current = getlist(this_box)
1389     -- end
1390
1391     -- while current do
1392     --     local id = getid(current)
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 -- hm
1404                                total = glueheight -- forgotten ... needs testing
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                                     -- -- only when i have a use case:
1413                                     --
1414                                     -- if not virtual then
1415                                     --     if left ~= 0 then
1416                                     --         width = width - left
1417                                     --         xoffset = left
1418                                     --     end
1419                                     --     if right ~= 0 then
1420                                     --         width = width - right
1421                                     --     end
1422                                     -- end
1423                                     -- if pos_r == righttoleft_code then
1424                                     --     xoffset = - xoffset - width
1425                                     -- end
1426                                     -- flushrule(leader,pos_h + xoffset,pos_v - total - yoffset,pos_r,width,total,getsubtype(leader))
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 -- aleader
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 -- todo: <= edge - total
1468                                    -- synch_pos_with_cur(ref_h, ref_v, getshift(leader), cur_v + height)
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                                    -- synced
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 -- hm
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 -- weird
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                     -- local orientation, xoffset, yoffset = getorientation(current)
1537                        local xoffset, yoffset = getoffsets(current)
1538                     -- local basepoint_h = shift
1539                     -- local basepoint_v = height
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                     -- local basepoint_h = shift
1563                     -- local basepoint_v = height
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                     -- local basepoint_h = shift
1587                     -- local basepoint_v = height
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                        -- move this into apply_anchor
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 -- weird
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                -- penalty
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 -- must be outside labels
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        -- We have zero offsets in ConTeXt.
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, -- target
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 -- this forces a sync each page / object
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-- This will move to back-out.lua eventually.
1819
1820do
1821
1822    ----- sortedhash = table.sortedhash
1823
1824    ----- tonut      = nodes.tonut
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     -- elseif what == 2 then
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  -- we show the name and number
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