mk-itworks.tex /size: 5241 b    last modification: 2023-12-21 09:43
1% language=us
2
3\environment mk-environment
4
5\startcomponent mk-itworks
6
7\chapter{It works!}
8
9One of the more powerful commands in \CONTEXT\ is \type {\framed}.
10You can pass quite some parameters that control the spacing,
11alignment, backgrounds and more. This command is used all over the
12place (although often hidden for the user) which means that it also has
13to be quite stable. However, there is one nasty bit of code that
14is hard to get right. Calculating the height of a box is not that
15complex: the height that \TEX\ reports is indeed the height.
16However, the width of box is determined by the value of \type
17{\hsize} at the time of typesetting. The actual content can be
18smaller. In the \type {\framed} macro by default the width is
19calculated automatically.
20
21\startbuffer
22\framed
23  [align=middle,width=fit]
24  {Out beyond the ethernet the spectrum spreads \unknown}
25\stopbuffer
26
27\typebuffer
28
29this shows up as:\footnote{Taken from \quote {Casino Nation} by Jackson Browne.}
30
31\startlinecorrection
32\getbuffer
33\stoplinecorrection
34
35Or take this quote:\footnote{Taken from \quote {A World Without Us} by Alan Weisman.}
36
37\startbuffer
38\hsize=.6\hsize \framed [align=middle,width=fit] {\input weisman }
39\stopbuffer
40
41\typebuffer
42
43This gives a multi|-|line paragraph:
44
45\startlinecorrection
46\getbuffer
47\stoplinecorrection
48
49Here the outer \type {\hsize} was made a bit smaller. As you can
50see the frame is determined by the widest line. Because it was one
51of the first features we needed, the code in \CONTEXT\ that is
52involved in determining the maximum natural width is pretty old.
53It boils down to unboxing a \type {\vbox} and stepwise grabbing
54the last box, penalty, kern and skip. You unwind the box
55backwards. However, you cannot grab everything or in \TEX\ speak:
56there is only a limited number of \type {\lastsomething} commands.
57Special nodes, like whatsits cannot be grabbed and they make the
58analyzer abort its analysis. There is no way that we can solve
59this in traditional \TEX\ and in \CONTEXT\ \MKII.
60
61So how about \LUATEX\ and \CONTEXT\ \MKIV ? The macro used in the
62\type {\framed} commands is:
63
64\starttyping
65\doreshapeframedbox{do something with \box\framebox}
66\stoptyping
67
68In \LUATEX\ we can manipulate box content at the \LUA\ level. Instead
69of providing a truckload of extra primitives (which would also introduce
70new data types at the \TEX\ end) we just delegate the job to \LUA.
71
72\starttyping
73\def\doreshapeframedbox
74  {\ctxlua{commands.doreshapeframedbox(\number\framebox)}}
75\stoptyping
76
77Here \type {\ctxlua} is our reserved instance and \type {commands}
78provides the namespace for commands that we delegate to \LUA\ (so,
79there are more of them). The amount of \LUA\ code is way less than
80the \TEX\ code which we will not show here; it's in \type
81{supp-box.tex} if you really want to see it.
82
83\starttyping
84function commands.doreshapeframedbox(n)
85    local box_n = tex.box[n]
86    if box_n.width ~= 0 then
87        local hpack = node.hpack
88        local free = node.free
89        local copy = node.copy_list
90        local noflines, lastlinelength, width = 0, 0, 0
91        local list = box_n.list
92        local done = false
93        for h in node.traverse_id('hlist',list) do
94            done = true
95            local p = hpack(copy(h.list))
96            lastlinelength = p.width
97            if lastlinelength > width then
98                width = lastlinelength
99            end
100            free(p)
101        end
102        if done then
103            if width ~= 0 then
104                for h in node.traverse_id('hlist',list) do
105                    if h.width ~= width then
106                        h.list = hpack(h.list,width,'exactly')
107                        h.width = width
108                    end
109                end
110            end
111            box_n.width = width
112        end
113        -- we can also do something with lastlinelength
114    end
115end
116\stoptyping
117
118In the first loop we inspect all lines (nodes with type \type
119{hlist}) and repack them to their natural width with \type
120{node.hpack}. In the process we keep track of the maximum natural
121width. In the second loop we repack the content again, but this
122time permanently. Now we use the maximum encountered width which
123is forced by the keyword \type {exactly}. Because all glue is
124still present we automatically get the desired alignment. We
125create local shortcuts to some node functions which makes it run
126faster; keep in mind that this is a core function called many
127times in a regular \CONTEXT\ job.
128
129In \CONTEXT\ \MKIV\ you will find quite some \LUA\ code and often
130it looks rather complex, especially if you have no clue why it's
131needed. Think of \OPENTYPE\ font handling which involves locating
132fonts, loading and caching them, storing features and later on
133applying them to node lists, etc. However, once we are beyond the
134stage of developing all the code that is needed to support the
135basics, we will start doing the things that more relate to the
136typesetting process itself, like the previous code. One of the
137candidates for a similar \LUA\ based solution is for instance
138column balancing. From the previous example code you can deduce
139that manipulating the node lists from \LUA\ can make that easier.
140Of course we're a few more years down the road then.
141
142\stopcomponent
143