followingup-directions.tex /size: 25 Kb    last modification: 2021-10-28 13:50
1% language=us runpath=texruns:manuals/followingup
2
3\startcomponent followingup-directions
4
5\environment followingup-style
6
7\startchapter[title={Directions}]
8
9\startsection[title={Introduction}]
10
11In \LUATEX\ the directional model taken from \OMEGA\ has been upgraded a bit. For
12instance in addition to the \type {\*dir} commands we have \type {\*direction}
13commands that take a number instead of a keyword. This is a bit more efficient and
14consistent as using these keywords was kind of un|-|\TEX. Internally direction
15related nodes (text directions) are not whatsits but first class nodes. We also
16use a subtype that indicates the push or pop state.
17
18The \LUATEX\ directional model provides four directions which is a subset of the
19many that \OMEGA\ provided, indicated by three letters, like \type {TRT} and
20\type {LTT}. In the beginning we had them all fixed\footnote {This was doen by
21Hartmut by rigorously checking all possible combinations} and thereby implemented
22but being in doubt about their usefulness we dropped most of them, just four were
23kept. However, in practice only right|-|to|-|left makes sense. Going from top to
24bottom in Japanese or Mongolian can also involve glyph rotation, which actually
25is not implemented in the engine at all. Spacing and inter|-|character breaks
26have to be implemented and in the end one has to combine the results into a
27page body. So, in practice you end up with juggling node list and macro magic in
28the page builder. The \type {LTL} (number~2) and \type {RTT} (number~3)
29directions are not used for serious work. Therefore, in \LUAMETATEX\ the model
30has been adapted. In the end, it was not entirely clear anyway what the three
31letters were indicating in each direction property (page, body, par, text, math)
32as most had no real meaning.
33
34As a side note: if you leave the (not really working well) vertical directions
35out of the picture, directional typesetting is not that hard to deal with and has
36hardly any consequences for the code. This is because horizontal dimensions are
37not affected by direction, only the final ship out is: when a run (wrapped in an
38hbox) goes the other way, the backend effectively has to skip the width and then
39with each component goes back. Not much more is involved. This means that a
40bidirectional engine is rather simple. The complications are more in the way a
41macro package deals with it, in relation to the input as well as the layout. The
42backend has to do the real work. \footnote {Of course when one hooks in \LUA\
43code taking care of direction can be needed!}
44
45\stopsection
46
47\startsection[title=Two directions]
48
49We now have only two directions left: the default left|-|to|-|right (l2r) and
50right|-|to|-|left (r2l). They work the same as before and in the backend we can
51get rid of the fuzzy parallel and rotation (which actually was just stacking
52nodes) heuristics.
53
54Reducing the lot to two directions simplifies some code in the engine. This is
55because when calculating dimensions a change in horizontal direction doesn't
56influence the width, height and depth in an orthogonal way. Because there are no
57longer top|-|down items we don't need to swap the height and or depth with the
58width. This also means that we don't need to keep much track of direction
59changes. Technically an hpack doesn't need to know its own direction and we can
60set it to any value afterwards if we want because the calculation are not
61influenced by it; so that also simplified matters.
62
63The \type {\bodydir} and \type {\pagedir} already didn't make much sense, and in
64\CONTEXT\ we actually intercepted them, so now they are removed. The body
65direction is always left|-|to|-|right and the page direction was only consulted
66in the backend code which we no longer have. Another side effect of going with
67only two directions is that rules no longer need to carry the direction property:
68there is no flipping of width with height and depth needed.
69
70\stopsection
71
72\startsection[title=Four orientations]
73
74Instead of the top|-|bottom variants we now have four orientations plus a bunch
75of anchoring options. Of course one could use the backend save, restore and
76matrix whatsits but a natural feature makes more sense. Let's start with what
77happens normally:
78
79\startbuffer[1]
80This is a \LUAMETATEX\ goodie.
81\stopbuffer
82
83\startbuffer[2]
84\hbox orientation 2{This is a \LUAMETATEX\ goodie.}
85\stopbuffer
86
87\startbuffer[3]
88This is a \hbox orientation 2{\LUAMETATEX} goodie.
89\stopbuffer
90
91\startbuffer[4]
92\hbox orientation 2{This is a \hbox orientation 002{\LUAMETATEX} goodie.}
93\stopbuffer
94
95\blank{\showstruts\strut}\quad\ruledhbox{\inlinebuffer[1]}\quad{\showstruts\strut}\blank
96
97This line has height and depth. We can rotate this sentence by 180 degrees around
98the baseline in which case the depth and height are flipped.
99
100\blank{\showstruts\strut}\quad\ruledhbox{\inlinebuffer[2]}\quad{\showstruts\strut}\blank
101
102or we flip part:
103
104\blank{\showstruts\strut}\quad\ruledhbox{\inlinebuffer[3]}\quad{\showstruts\strut}\blank
105
106or flip nested:
107
108\blank{\showstruts\strut}\quad\ruledhbox{\inlinebuffer[4]}\quad{\showstruts\strut}\blank
109
110but we're talking boxes, so the above examples are defined as:
111
112\typebuffer[1,2,3,4]
113
114The \type {orientation} keyword does the magic here. There are four such
115orientations with zero being the default. We saw that two rotates over 180
116degrees, so one and three are left for up and down.
117
118\startbuffer[5]
119\hbox orientation 0 {\TEX} and
120\hbox orientation 1 {\TEX} and
121\hbox orientation 2 {\TEX} and
122\hbox orientation 3 {\TEX}
123\stopbuffer
124
125\blank{\showstruts\strut}\quad\ruledhbox{\inlinebuffer[5]}\quad{\showstruts\strut}\blank
126
127This is codes as:
128
129\typebuffer[5]
130
131The landscape and seascape variants both sit on top of the baseline while the
132flipped variant has its depth swapped with the height. Although this would be
133enough a bit more control is possible. The number is actually a three byte hex
134number:
135
136\starttyping
1370x<X><Y><O>
138\stoptyping
139
140or in \TEX\ syntax
141
142\starttyping
143"<X><Y><O>
144\stoptyping
145
146We saw that the last byte regulates the orientation. The first and second one
147deal with anchoring horizontally and vertically. The vertical options of the
148horizontal variants anchor on the baseline, lower corner, upper corner or center.
149
150\startbuffer[6]
151\hbox orientation "002 {\TEX} and
152\hbox orientation "012 {\TEX} and
153\hbox orientation "022 {\TEX} and
154\hbox orientation "032 {\TEX}
155\stopbuffer
156
157\typebuffer[6]
158
159\blank{\showstruts\strut}\quad\ruledhbox{\inlinebuffer[6]}\quad{\showstruts\strut}\blank
160
161\startbuffer[7]
162\hbox orientation "002 {\TEX} and
163\hbox orientation "102 {\TEX} and
164\hbox orientation "202 {\TEX} and
165\hbox orientation "302 {\TEX} and
166\hbox orientation "402 {\TEX}
167\stopbuffer
168
169The horizontal options of the horizontal variants anchor in the center, left, right,
170halfway left and halfway right.
171
172\typebuffer[7]
173
174\blank{\showstruts\strut}\quad\ruledhbox{\inlinebuffer[7]}\quad{\showstruts\strut}\blank
175
176All combinations will be shown on the next pages, so we suffice with telling that
177for the vertical variants we can vertically anchor on the baseline, top, bottom
178or center, while horizontally we center, hang left or right, halfway left or
179right, and in addition align on the (rotated) baseline left or right.
180
181The orientation has consequences for the dimensions so they are dealt with in the
182expected way in constructing lines, paragraphs and pages, but the anchoring is
183virtual. As a bonus, we have two extra variants for orientation zero: on top of
184baseline or below, with dimensions taken into account.
185
186\startbuffer[8]
187\hbox orientation "000 {\TEX} and
188\hbox orientation "004 {\TEX} and
189\hbox orientation "005 {\TEX}
190\stopbuffer
191
192\typebuffer[8]
193
194\blank{\showstruts\strut}\quad\ruledhbox{\inlinebuffer[8]}\quad{\showstruts\strut}\blank
195
196\definecolor[brcolorh][r=1,t=.5,a=1]
197\definecolor[brcolord][b=1,t=.5,a=1]
198\definecolor[brcolorm][g=1,t=.5,a=1]
199
200\starttexdefinition ShowAnchor
201    \blackrule[width=2pt,height=1pt,depth=1pt,color=darkgray]
202\stoptexdefinition
203
204\starttexdefinition DemoRule#1#2#3
205    \ShowAnchor
206    \ruledhbox {
207        \hbox orientation "#1#2#3 {
208            \blackrule[height=6mm,depth=0mm,width=8mm,color=brcolorh]\kern-8mm\relax
209            \blackrule[height=0mm,depth=3mm,width=8mm,color=brcolord]\kern-8mm\relax
210            \blackrule[height=2mm,depth=-1mm,width=8mm,color=brcolorm]
211        }
212    }
213    \ShowAnchor
214\stoptexdefinition
215
216\starttexdefinition DemoText#1#2#3
217    \ShowAnchor
218    \ruledhbox{\hbox orientation "#1#2#3 {\red\TEX}}
219    \ShowAnchor
220\stoptexdefinition
221
222\starttexdefinition DemoSet #1#2
223    \startcombination[nx=4,ny=7,width=10cm]
224        {#200#1}{\ttxx 0x00#1} {#201#1}{\ttxx 0x01#1} {#202#1}{\ttxx 0x02#1} {#203#1}{\ttxx 0x03#1}
225        {#210#1}{\ttxx 0x10#1} {#211#1}{\ttxx 0x11#1} {#212#1}{\ttxx 0x12#1} {#213#1}{\ttxx 0x13#1}
226        {#220#1}{\ttxx 0x20#1} {#221#1}{\ttxx 0x21#1} {#222#1}{\ttxx 0x22#1} {#223#1}{\ttxx 0x23#1}
227        {#230#1}{\ttxx 0x30#1} {#231#1}{\ttxx 0x31#1} {#232#1}{\ttxx 0x32#1} {#233#1}{\ttxx 0x33#1}
228        {#240#1}{\ttxx 0x40#1} {#241#1}{\ttxx 0x41#1} {#242#1}{\ttxx 0x42#1} {#243#1}{\ttxx 0x43#1}
229        {#250#1}{\ttxx 0x50#1} {#251#1}{\ttxx 0x51#1} {#252#1}{\ttxx 0x52#1} {#253#1}{\ttxx 0x53#1}
230        {#260#1}{\ttxx 0x60#1} {#261#1}{\ttxx 0x61#1} {#262#1}{\ttxx 0x62#1} {#263#1}{\ttxx 0x63#1}
231    \stopcombination
232\stoptexdefinition
233
234\startplacefigure[title={orientation 0}]\scale[width=\textwidth]{\framed[offset=1cm]{\DemoSet0\DemoRule}}\stopplacefigure
235\startplacefigure[title={orientation 1}]\scale[width=\textwidth]{\framed[offset=1cm]{\DemoSet1\DemoRule}}\stopplacefigure
236\startplacefigure[title={orientation 2}]\scale[width=\textwidth]{\framed[offset=1cm]{\DemoSet2\DemoRule}}\stopplacefigure
237\startplacefigure[title={orientation 3}]\scale[width=\textwidth]{\framed[offset=1cm]{\DemoSet3\DemoRule}}\stopplacefigure
238
239\startplacefigure[title={orientation 0}]\scale[width=\textwidth]{\framed[offset=1cm]{\DemoSet0\DemoText}}\stopplacefigure
240\startplacefigure[title={orientation 1}]\scale[width=\textwidth]{\framed[offset=1cm]{\DemoSet1\DemoText}}\stopplacefigure
241\startplacefigure[title={orientation 2}]\scale[width=\textwidth]{\framed[offset=1cm]{\DemoSet2\DemoText}}\stopplacefigure
242\startplacefigure[title={orientation 3}]\scale[width=\textwidth]{\framed[offset=1cm]{\DemoSet3\DemoText}}\stopplacefigure
243
244% \page
245
246The anchoring can look somewhat confusing but you need to keep in mind that it is
247normally only used in very controlled circumstances and not in running text.
248Wrapped in macros users don't see the details. We're talking boxes here, so or
249instance:
250
251\startbuffer
252test\quad
253\hbox orientation 3 \bgroup
254    \strut test\hbox orientation "002 \bgroup\strut test\egroup test%
255\egroup \quad
256\hbox orientation 3 \bgroup
257    \strut test\hbox orientation "002 \bgroup\strut test\egroup test%
258\egroup \quad
259\hbox orientation 3 \bgroup
260    \strut test\hbox orientation "012 \bgroup\strut test\egroup test%
261\egroup \quad
262\hbox orientation 3 \bgroup
263    \strut test\hbox orientation "022 \bgroup\strut test\egroup test%
264\egroup \quad
265\hbox orientation 3 \bgroup
266    \strut test\hbox orientation "032 \bgroup\strut test\egroup test%
267\egroup \quad
268\hbox orientation 3 \bgroup
269    \strut test\hbox orientation "042 \bgroup\strut test\egroup test%
270\egroup
271\quad test
272\stopbuffer
273
274\typebuffer
275
276gives:
277
278\startlinecorrection[blank]
279\ruledhbox\bgroup \showcolorstruts \showboxes \inlinebuffer \egroup
280\stoplinecorrection
281
282\stopsection
283
284\startsection[title={Right|-|to|-|left typesetting}]
285
286Another aspect to keep in mind when we transform is the already mentioned
287right|-|to|-|left direction. We show some examples where we do things like this:
288
289\starttyping
290\hbox{\hbox
291    orientation #1
292    {\strut abcd}}
293\hbox{\hbox
294    orientation #1
295    to 15mm
296    {\strut abcd}}
297\hbox{\hbox
298    orientation #1
299    direction 1
300    {\righttoleft\strut abcd}}
301\hbox{\hbox
302    orientation #1
303    direction 1
304    to 15mm {\righttoleft\strut abcd}}
305\stoptyping
306
307\starttexdefinition TestH #1
308    \dontcomplain
309    \setbox\scratchbox\hbox{abcd}%
310    x\ruledhbox{\hbox orientation #1             to \wd\scratchbox  {\strut abcd}}x\quad
311    x\ruledhbox{\hbox orientation #1             to 15mm            {\strut abcd}}x\quad
312    x\ruledhbox{\hbox orientation #1 direction 1 to \wd\scratchbox  {\righttoleft\strut abcd}}x\quad
313    x\ruledhbox{\hbox orientation #1 direction 1 to 15mm            {\righttoleft\strut abcd}}x%
314\stoptexdefinition
315
316\starttexdefinition TestV #1
317    \dontcomplain
318    \setbox\scratchbox\hbox{abcd}%
319    x\ruledvbox{\vbox orientation #1             {\hsize \wd\scratchbox\strut abcd}}x\quad
320    x\ruledvbox{\vbox orientation #1             {\hsize           15mm\strut abcd}}x\quad
321    x\ruledvbox{\vbox orientation #1 {\righttoleft\hsize \wd\scratchbox\strut abcd}}x\quad
322    x\ruledvbox{\vbox orientation #1 {\righttoleft\hsize           15mm\strut abcd}}x%
323\stoptexdefinition
324
325\startplacefigure[title={Horizontal boxes.}]
326    \startcombination[nx=2,ny=2]
327        {\TestH 0} {orientation 0}
328        {\TestH 2} {orientation 2}
329        {\TestH 1} {orientation 1}
330        {\TestH 3} {orientation 3}
331    \stopcombination
332\stopplacefigure
333
334\startplacefigure[title={Vertical boxes.}]
335    \startcombination[nx=2,ny=2]
336        {\TestV 0} {orientation 0}
337        {\TestV 2} {orientation 2}
338        {\TestV 1} {orientation 1}
339        {\TestV 3} {orientation 3}
340    \stopcombination
341\stopplacefigure
342
343\stopsection
344
345\startsection[title={Vertical typesetting}]
346
347I'm no expert on vertical typesetting and have no application for it either. But
348from what I've seen vertically positioned glyphs are normally used in rather
349straightforward situations. Here I will just give some examples of how
350transformations can be used to achieve certain effects. It is no big deal to make
351macros or use \LUA\ to apply magic to node lists but it is beyond this description
352to discuss that.
353
354Before we fine tune this example we have to discuss another feature. When a \typ
355{orientation} keyword is given optionally \type {xoffset} and \type {yoffset} can
356be specified. These offsets are {\em not} taken into account when calculating
357dimensions. This is different from the offsets (at the \LUA\ end) used in glyphs
358because there the vertical offset is taken into account. Here are some examples
359of offsets in packaged lists:
360
361\startbuffer
362\hbox
363    {test 1}
364\hbox
365    orientation 0
366    yoffset  15pt
367    xoffset 150pt
368    {test}
369\vbox
370    orientation 0
371    {\hbox{test}}
372\vbox
373    orientation 0
374    yoffset  -5pt
375    xoffset 130pt
376    {\hbox{test}}
377\vbox
378    orientation 0
379    yoffset 2pt
380    {\hbox{test}}
381\stopbuffer
382
383\typebuffer
384
385\startlinecorrection[blank]
386    \start \showboxes \bfd \getbuffer \stop
387\stoplinecorrection
388
389In order to demonstrate some hacking, we first define a font that supports
390chinese glyphs:
391
392\startbuffer
393\definefont[NotoCJK][NotoSansCJKtc-Regular*default @ 24pt]
394\stopbuffer
395
396\typebuffer \getbuffer
397
398We put some text in a horizontal box; it doesn't show up in verbatim but you
399get the idea nevertheless:
400
401\startbuffer
402\hbox{\NotoCJK 通用规范汉字表}
403\stopbuffer
404
405\typebuffer
406
407\startlinecorrection[blank]
408    \start \showboxes \getbuffer \stop
409\stoplinecorrection
410
411Let's now rotate this line of text:
412
413\startbuffer[1]
414\hbox orientation 1 {\NotoCJK 通用规范汉字表}
415\stopbuffer
416
417\typebuffer[1]
418
419The result is shown in a while. Because we also need to rotate the glyphs we
420deconstruct the box.
421
422\startbuffer[2]
423\hbox orientation 1 \bgroup \NotoCJK %
424    \vbox {\hbox {}}%
425    \vbox {\hbox {}}%
426    \vbox {\hbox {}}%
427    \vbox {\hbox {test}}%
428    \vbox {\hbox {}}%
429    \vbox {\hbox {}}%
430    \vbox {\hbox {}}%
431    \vbox {\hbox {}}%
432\egroup
433\stopbuffer
434
435\typebuffer[2]
436
437Next we rotate the glyphs.
438
439\startbuffer[3]
440\hbox orientation 1 \bgroup \NotoCJK %
441    \vbox orientation 3 {\hbox {}}%
442    \vbox orientation 3 {\hbox {}}%
443    \vbox orientation 3 {\hbox {}}%
444    \vbox orientation 0 {\hbox {test}}%
445    \vbox orientation 3 {\hbox {}}%
446    \vbox orientation 3 {\hbox {}}%
447    \vbox orientation 3 {\hbox {}}%
448    \vbox orientation 3 {\hbox {}}%
449\egroup
450\stopbuffer
451
452\typebuffer[3]
453
454This still looks bad so we kick in some offsets and glue:
455
456\startbuffer[4]
457\dontleavehmode\hbox orientation 1 \bgroup \NotoCJK
458    \vbox
459        orientation 0 yoffset -.1ex
460        {\hbox orientation 3 {}}\hskip.2ex
461    \vbox
462        orientation 0 yoffset -.1ex
463        {\hbox orientation 3 {}}\hskip.2ex
464    \vbox
465        orientation 0 yoffset -.1ex
466        {\hbox orientation 3 {}}\hskip.6ex
467    \vbox
468        {\hbox             {test}}\hskip.2ex
469    \vbox
470        orientation 0 yoffset -.1ex
471        {\hbox orientation 3 {}}\hskip.2ex
472    \vbox
473        orientation 0 yoffset -.1ex
474        {\hbox orientation 3 {}}\hskip.2ex
475    \vbox
476        orientation 0 yoffset -.1ex
477        {\hbox orientation 3 {}}\hskip.2ex
478    \vbox
479        orientation 0 yoffset -.1ex
480        {\hbox orientation 3 {}}\hskip.2ex
481\egroup
482\stopbuffer
483
484\typebuffer[4]
485
486Now we're ready to compare the results
487
488\startlinecorrection[blank]
489    \startcombination[9*1]
490        {\showboxes \getbuffer[1]} {1}
491        {\showboxes \getbuffer[2]} {2}
492        {\showboxes \getbuffer[3]} {3}
493        {\showboxes \getbuffer[4]} {4}
494        {\quad}{}
495        {\getbuffer[1]} {1}
496        {\getbuffer[2]} {2}
497        {\getbuffer[3]} {3}
498        {\getbuffer[4]} {4}
499    \stopcombination
500\stoplinecorrection
501
502This could of course also be done with traditional kerns, raising and|/|or
503lowering and messing around with dimensions. It's just that when manipulating
504such rather complex constructs a little help (and efficiency) makes a difference,
505also at the \LUA\ end. Of course one can argue the result but all is
506programmable in the end.
507
508\stopsection
509
510\startsection[title={Considerations}]
511
512Just in case you wonder if using these offsets is better than using normal kerning
513and shifting, in practice offsets are not more efficient. Let's compare the
514alternatives. We go from most to least efficient.
515
516\starttyping
517\setbox\scratchbox\hpack{}
518\boxxoffset\scratchbox\scratchdimen
519\boxyoffset\scratchbox\scratchdimen
520\stoptyping
521
522This sets the offsets and by setting them we also trigger the transform. Scanning
523is fast and so is setting them. One million times expanding this takes (as
524reference) 0.73 seconds on my current machine.
525
526\starttyping
527\setbox\scratchbox\hpack
528  orientation \zerocount
529  xoffset     \scratchdimen
530  yoffset     \scratchdimen
531  {}
532\stoptyping
533
534This takes a bit more time, 1.11 seconds, because the keywords have to be scanned
535which happens on a token by token base.
536
537\starttyping
538\setbox\scratchbox\hpack{}
539\scratchheight\ht\scratchbox
540\scratchdepth\dp\scratchbox
541\setbox\scratchbox\hpack
542  {\kern\scratchdimen
543   \raise\scratchdimen\box\scratchbox
544   \kern\scratchdimen}
545\ht\scratchbox\scratchheight
546\dp\scratchbox\scratchdepth
547\stoptyping
548
549Now we're up to 1.69 seconds for the million expansions. Not only do we have some
550parsing going on, but we also have assignments and extra packing, which means
551calculations taking place.
552
553\starttyping
554\setbox\scratchbox\hpack{}
555\scratchwidth\wd\scratchbox
556\scratchheight\ht\scratchbox
557\scratchdepth\dp\scratchbox
558\setbox\scratchbox\hpack
559  {\kern\scratchdimen
560   \raise\scratchdimen\box\scratchbox}
561\wd\scratchbox\scratchwidth
562\ht\scratchbox\scratchheight
563\dp\scratchbox\scratchdepth
564\stoptyping
565
566This variant is about as fast, as I measured 1.72 seconds. So, compared to the
5670.73 seconds for the first variant, is this better? Does it help when we look at
568our existing macros and adapt them?
569
570Normally we don't have an empty box and normally we use \type {\hbox} because we
571want the content to be processed. And a million times building a list and
572processing content (which means runs over the list) will make the differences
573in timing become noise. Add to that garbage collection (in \LUA) and memory
574management (in \TEX) and it even becomes unpredictable. Seeing differences of
575a factor two in such timings is no exception.
576
577Another aspect is the parsing. When these commands are wrapped in macros we're
578talking expanding tokens which is pretty fast. When it comes from the input file
579a conversion to tokens has to happen too. And we will never see millions of such
580sequences in a source file.
581
582The backend also plays a role. Handling a kern or shift is more efficient than
583analyzing transforms (and offsets) especially in a \LUA\ variant. But on the
584other hand, we don't have an extra wrapping in a box so that actually saves work.
585
586So, before a \CONTEXT\ user thinks \quotation {Let's update macros and change
587policy.}, just consider staying with proven good old \TEX\ approaches. These
588features are mostly meant for efficient low level manipulations as discussed in
589relation to for instance handling scripts. In the rather large \CONTEXT\ code
590base there are really only a few places where it will make code look nicer, but
591there I don't expect an impact on performance.
592
593\stopsection
594
595\startsection[title={Integration}]
596
597How these mechanisms are used depends on ones needs and the macro package used.
598It makes no sense to cook up generic solutions because integration in a macro
599package is too different. But anyhow we'll give an example of some (definitely
600non optimized) \LUA\ magic.
601
602\startbuffer
603\startluacode
604local glyph_id = node.id("glyph")
605local fontdata = fonts.hashes.identifiers -- assumes generic font loader
606
607local function is_vertical(c)
608  -- more ranges matter but this will do here
609  return c >= 0x04E00 and c <= 0x09FFF
610end
611
612function document.go_vertical(boxnumber)
613  local box = tex.getbox(boxnumber)
614  local n   = box.list
615  while n do
616    if n.id == glyph_id and is_vertical(n.char) then
617      local o = .2 * fontdata[n.font].parameters.xheight
618      local prev, next = n.prev, n.next
619      n.next, n.prev = nil, nil
620      local l = nodes.new("hlist")
621      l.list = n
622      local w, h, d = n.width, n.height, n.depth
623      if prev then
624          prev.next, l.prev = l, prev
625      else
626          box.list = l
627      end
628      if next then
629          l.next, next.prev = next, l
630      end
631      l.width, l.height, l.depth  = h + d + o, w, 0
632      l.orientation = 0x003
633      l.xoffset, l.yoffset = o/2, -o/2
634      l.hoffset, l.doffset = h, d - o
635      n = next
636    else
637      n = n.next
638    end
639  end
640end
641\stopluacode
642\stopbuffer
643
644\typebuffer \getbuffer
645
646We will use some other magic that we won't discuss here which relates to handling
647scripts. For Hangul one needs to inject breakpoints and if needed also glue
648between characters. The script environment does this. We also need to bump the
649interline spacing. First we define a regular text helper and an auxiliary box.
650
651\startbuffer[1]
652\unexpanded\def\stripe#1%
653  {\hbox orientation 0 yoffset .2\exheight{\strut #1}}
654
655\newbox\MyVerticalBox
656\stopbuffer
657
658\typebuffer[1]
659
660Next we fill that box with some mix of text (I have no clue what, as I just
661copied it from some web page).
662
663\startbuffer[2a]
664\setbox\MyVerticalBox\hbox \bgroup
665    \NotoCJK
666    \startscript[hangul]%
667    \dorecurse{20}{通用规范汉字表 \stripe{test #1} }%
668    \unskip % remove last space
669    \stopscript
670\egroup
671\stopbuffer
672
673\typebuffer[2a]
674
675We then apply the \LUA\ magic to the result:
676
677\startbuffer[3a]
678\ctxlua{document.go_vertical(\number\MyVerticalBox)}
679\stopbuffer
680
681\typebuffer[3a]
682
683and finally assemble the result:
684
685\startbuffer[4a]
686\ruledvbox orientation 1 to \textwidth \bgroup
687    \setupinterlinespace[40pt]
688    \hsize .95\textheight
689    \unhbox\MyVerticalBox
690    \vfill
691\egroup
692\stopbuffer
693
694\typebuffer[4a]
695
696The result is shown in \in {figure} [fig:verticalmagic-1]. Of course this
697approach is not that user friendly but it just serves as example. In \CONTEXT\ we
698can follow a different route. First we define a new font feature. It is probably
699clear that we need some code elsewhere that does something useful with this
700information, but I will nos show this as it is rather \CONTEXT\ dependent.
701
702\startbuffer[2b]
703\definefontfeature
704  [vertical]
705  [vertical={%
706    orientation=3,%
707    down=.1,%
708    right=.1,%
709    ranges={%
710      cjkcompatibility,%
711      cjkcompatibilityforms,%
712      cjkcompatibilityideographs,%
713      cjkcompatibilityideographssupplement,%
714      cjkradicalssupplement,%
715    % cjkstrokes,%
716      cjksymbolsandpunctuation,%
717      cjkunifiedideographs,%
718      cjkunifiedideographsextensiona,%
719      cjkunifiedideographsextensionb,%
720      cjkunifiedideographsextensionc,%
721      cjkunifiedideographsextensiond,%
722      cjkunifiedideographsextensione,%
723      cjkunifiedideographsextensionf,%
724    }%
725  }]
726\stopbuffer
727
728\typebuffer[2b]
729
730We apply this feature to a font:
731
732\startbuffer[3b]
733\definefont
734  [NotoCJKvertical]
735  [NotoSansCJKtc-Regular*default,vertical @ 24pt]
736\stopbuffer
737
738\typebuffer[3b]
739
740\startbuffer[4b]
741\setbox\MyVerticalBox\hbox\bgroup
742    \NotoCJKvertical
743    \startscript[hangul]%
744    \dorecurse{20}{通用规范汉字表 \stripe{test #1} }%
745    \unskip
746    \stopscript
747\egroup
748\stopbuffer
749
750\typebuffer[4b]
751
752\startbuffer[5b]
753\ruledvbox orientation 1 to \textwidth \bgroup
754    \setupinterlinespace[40pt]
755    \hsize .95\textheight
756    \unhbox\MyVerticalBox
757    \vfill
758\egroup
759\stopbuffer
760
761\typebuffer[5b]
762
763The result is shown in \in {figure} [fig:verticalmagic-2]. Again this approach is
764not that user friendly but it already is a bit easier.
765
766\startplacefigure[reference=fig:verticalmagic-1,title={Some vertical magic using manipulations.}]
767    \getbuffer[1,2a,3a,4a]
768\stopplacefigure
769
770\startplacefigure[reference=fig:verticalmagic-2,title={Some vertical magic using fonts.}]
771    \getbuffer[1,2b,3b,4b,5b]
772\stopplacefigure
773
774\stopsection
775
776\stopchapter
777
778\stopcomponent
779