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