summaryrefslogtreecommitdiff
path: root/doc/context/sources/general/manuals/followingup/followingup-directions.tex
blob: 244baff90ded04b0f06aff82e690ca0347567d82 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
% language=us

\startcomponent followingup-directions

\environment followingup-style

\startchapter[title={Directions}]

\startsection[title={Introduction}]

In \LUATEX\ the directional model taken from \OMEGA\ has been upgraded a bit. For
instance in addition to the \type {\*dir} commands we have \type {\*direction}
commands that take a number instead of a keyword. This is a bit more efficient and
consistent as using these keywords was kind of un|-|\TEX. Internally direction
related nodes (text directions) are not whatsits but first class nodes. We also
use a subtype that indicates the push or pop state.

The \LUATEX\ directional model provides four directions which is a subset of the
many that \OMEGA\ provided, indicated by three letters, like \type {TRT} and
\type {LTT}. In the beginning we had them all fixed\footnote {This was doen by
Hartmut by rigorously checking all possible combinations} and thereby implemented
but being in doubt about their usefulness we dropped most of them, just four were
kept. However, in practice only right|-|to|-|left makes sense. Going from top to
bottom in Japanese or Mongolian can also involve glyph rotation, which actually
is not implemented in the engine at all. Spacing and inter|-|character breaks
have to be implemented and in the end one has to combine the results into a
page body. So, in practice you end up with juggling node list and macro magic in
the page builder. The \type {LTL} (number~2) and \type {RTT} (number~3)
directions are not used for serious work. Therefore, in \LUAMETATEX\ the model
has been adapted. In the end, it was not entirely clear anyway what the three
letters were indicating in each direction property (page, body, par, text, math)
as most had no real meaning.

As a side note: if you leave the (not really working well) vertical directions
out of the picture, directional typesetting is not that hard to deal with and has
hardly any consequences for the code. This is because horizontal dimensions are
not affected by direction, only the final ship out is: when a run (wrapped in an
hbox) goes the other way, the backend effectively has to skip the width and then
with each component goes back. Not much more is involved. This means that a
bidirectional engine is rather simple. The complications are more in the way a
macro package deals with it, in relation to the input as well as the layout. The
backend has to do the real work. \footnote {Of course when one hooks in \LUA\
code taking care of direction can be needed!}

\stopsection

\startsection[title=Two directions]

We now have only two directions left: the default left|-|to|-|right (l2r) and
right|-|to|-|left (r2l). They work the same as before and in the backend we can
get rid of the fuzzy parallel and rotation (which actually was just stacking
nodes) heuristics.

Reducing the lot to two directions simplifies some code in the engine. This is
because when calculating dimensions a change in horizontal direction doesn't
influence the width, height and depth in an orthogonal way. Because there are no
longer top|-|down items we don't need to swap the height and or depth with the
width. This also means that we don't need to keep much track of direction
changes. Technically an hpack doesn't need to know its own direction and we can
set it to any value afterwards if we want because the calculation are not
influenced by it; so that also simplified matters.

The \type {\bodydir} and \type {\pagedir} already didn't make much sense, and in
\CONTEXT\ we actually intercepted them, so now they are removed. The body
direction is always left|-|to|-|right and the page direction was only consulted
in the backend code which we no longer have. Another side effect of going with
only two directions is that rules no longer need to carry the direction property:
there is no flipping of width with height and depth needed.

\stopsection

\startsection[title=Four orientations]

Instead of the top|-|bottom variants we now have four orientations plus a bunch
of anchoring options. Of course one could use the backend save, restore and
matrix whatsits but a natural feature makes more sense. Let's start with what
happens normally:

\startbuffer[1]
This is a \LUAMETATEX\ goodie.
\stopbuffer

\startbuffer[2]
\hbox orientation 2{This is a \LUAMETATEX\ goodie.}
\stopbuffer

\startbuffer[3]
This is a \hbox orientation 2{\LUAMETATEX} goodie.
\stopbuffer

\startbuffer[4]
\hbox orientation 2{This is a \hbox orientation 002{\LUAMETATEX} goodie.}
\stopbuffer

\blank{\showstruts\strut}\quad\ruledhbox{\inlinebuffer[1]}\quad{\showstruts\strut}\blank

This line has height and depth. We can rotate this sentence by 180 degrees around
the baseline in which case the depth and height are flipped.

\blank{\showstruts\strut}\quad\ruledhbox{\inlinebuffer[2]}\quad{\showstruts\strut}\blank

or we flip part:

\blank{\showstruts\strut}\quad\ruledhbox{\inlinebuffer[3]}\quad{\showstruts\strut}\blank

or flip nested:

\blank{\showstruts\strut}\quad\ruledhbox{\inlinebuffer[4]}\quad{\showstruts\strut}\blank

but we're talking boxes, so the above examples are defined as:

\typebuffer[1,2,3,4]

The \type {orientation} keyword does the magic here. There are four such
orientations with zero being the default. We saw that two rotates over 180
degrees, so one and three are left for up and down.

\startbuffer[5]
\hbox orientation 0 {\TEX} and
\hbox orientation 1 {\TEX} and
\hbox orientation 2 {\TEX} and
\hbox orientation 3 {\TEX}
\stopbuffer

\blank{\showstruts\strut}\quad\ruledhbox{\inlinebuffer[5]}\quad{\showstruts\strut}\blank

This is codes as:

\typebuffer[5]

The landscape and seascape variants both sit on top of the baseline while the
flipped variant has its depth swapped with the height. Although this would be
enough a bit more control is possible. The number is actually a three byte hex
number:

\starttyping
0x<X><Y><O>
\stoptyping

or in \TEX\ syntax

\starttyping
"<X><Y><O>
\stoptyping

We saw that the last byte regulates the orientation. The first and second one
deal with anchoring horizontally and vertically. The vertical options of the
horizontal variants anchor on the baseline, lower corner, upper corner or center.

\startbuffer[6]
\hbox orientation "002 {\TEX} and
\hbox orientation "012 {\TEX} and
\hbox orientation "022 {\TEX} and
\hbox orientation "032 {\TEX}
\stopbuffer

\typebuffer[6]

\blank{\showstruts\strut}\quad\ruledhbox{\inlinebuffer[6]}\quad{\showstruts\strut}\blank

\startbuffer[7]
\hbox orientation "002 {\TEX} and
\hbox orientation "102 {\TEX} and
\hbox orientation "202 {\TEX} and
\hbox orientation "302 {\TEX} and
\hbox orientation "402 {\TEX}
\stopbuffer

The horizontal options of the horizontal variants anchor in the center, left, right,
halfway left and halfway right.

\typebuffer[7]

\blank{\showstruts\strut}\quad\ruledhbox{\inlinebuffer[7]}\quad{\showstruts\strut}\blank

All combinations will be shown on the next pages, so we suffice with telling that
for the vertical variants we can vertically anchor on the baseline, top, bottom
or center, while horizontally we center, hang left or right, halfway left or
right, and in addition align on the (rotated) baseline left or right.

The orientation has consequences for the dimensions so they are dealt with in the
expected way in constructing lines, paragraphs and pages, but the anchoring is
virtual. As a bonus, we have two extra variants for orientation zero: on top of
baseline or below, with dimensions taken into account.

\startbuffer[8]
\hbox orientation "000 {\TEX} and
\hbox orientation "004 {\TEX} and
\hbox orientation "005 {\TEX}
\stopbuffer

\typebuffer[8]

\blank{\showstruts\strut}\quad\ruledhbox{\inlinebuffer[8]}\quad{\showstruts\strut}\blank

\definecolor[brcolorh][r=1,t=.5,a=1]
\definecolor[brcolord][b=1,t=.5,a=1]
\definecolor[brcolorm][g=1,t=.5,a=1]

\starttexdefinition ShowAnchor
    \blackrule[width=2pt,height=1pt,depth=1pt,color=darkgray]
\stoptexdefinition

\starttexdefinition DemoRule#1#2#3
    \ShowAnchor
    \ruledhbox {
        \hbox orientation "#1#2#3 {
            \blackrule[height=6mm,depth=0mm,width=8mm,color=brcolorh]\kern-8mm\relax
            \blackrule[height=0mm,depth=3mm,width=8mm,color=brcolord]\kern-8mm\relax
            \blackrule[height=2mm,depth=-1mm,width=8mm,color=brcolorm]
        }
    }
    \ShowAnchor
\stoptexdefinition

\starttexdefinition DemoText#1#2#3
    \ShowAnchor
    \ruledhbox{\hbox orientation "#1#2#3 {\red\TEX}}
    \ShowAnchor
\stoptexdefinition

\starttexdefinition DemoSet #1#2
    \startcombination[nx=4,ny=7,width=10cm]
        {#200#1}{\ttxx 0x00#1} {#201#1}{\ttxx 0x01#1} {#202#1}{\ttxx 0x02#1} {#203#1}{\ttxx 0x03#1}
        {#210#1}{\ttxx 0x10#1} {#211#1}{\ttxx 0x11#1} {#212#1}{\ttxx 0x12#1} {#213#1}{\ttxx 0x13#1}
        {#220#1}{\ttxx 0x20#1} {#221#1}{\ttxx 0x21#1} {#222#1}{\ttxx 0x22#1} {#223#1}{\ttxx 0x23#1}
        {#230#1}{\ttxx 0x30#1} {#231#1}{\ttxx 0x31#1} {#232#1}{\ttxx 0x32#1} {#233#1}{\ttxx 0x33#1}
        {#240#1}{\ttxx 0x40#1} {#241#1}{\ttxx 0x41#1} {#242#1}{\ttxx 0x42#1} {#243#1}{\ttxx 0x43#1}
        {#250#1}{\ttxx 0x50#1} {#251#1}{\ttxx 0x51#1} {#252#1}{\ttxx 0x52#1} {#253#1}{\ttxx 0x53#1}
        {#260#1}{\ttxx 0x60#1} {#261#1}{\ttxx 0x61#1} {#262#1}{\ttxx 0x62#1} {#263#1}{\ttxx 0x63#1}
    \stopcombination
\stoptexdefinition

\startplacefigure[title={orientation 0}]\scale[width=\textwidth]{\framed[offset=1cm]{\DemoSet0\DemoRule}}\stopplacefigure
\startplacefigure[title={orientation 1}]\scale[width=\textwidth]{\framed[offset=1cm]{\DemoSet1\DemoRule}}\stopplacefigure
\startplacefigure[title={orientation 2}]\scale[width=\textwidth]{\framed[offset=1cm]{\DemoSet2\DemoRule}}\stopplacefigure
\startplacefigure[title={orientation 3}]\scale[width=\textwidth]{\framed[offset=1cm]{\DemoSet3\DemoRule}}\stopplacefigure

\startplacefigure[title={orientation 0}]\scale[width=\textwidth]{\framed[offset=1cm]{\DemoSet0\DemoText}}\stopplacefigure
\startplacefigure[title={orientation 1}]\scale[width=\textwidth]{\framed[offset=1cm]{\DemoSet1\DemoText}}\stopplacefigure
\startplacefigure[title={orientation 2}]\scale[width=\textwidth]{\framed[offset=1cm]{\DemoSet2\DemoText}}\stopplacefigure
\startplacefigure[title={orientation 3}]\scale[width=\textwidth]{\framed[offset=1cm]{\DemoSet3\DemoText}}\stopplacefigure

% \page

The anchoring can look somewhat confusing but you need to keep in mind that it is
normally only used in very controlled circumstances and not in running text.
Wrapped in macros users don't see the details. We're talking boxes here, so or
instance:

\startbuffer
test\quad
\hbox orientation 3 \bgroup
    \strut test\hbox orientation "002 \bgroup\strut test\egroup test%
\egroup \quad
\hbox orientation 3 \bgroup
    \strut test\hbox orientation "002 \bgroup\strut test\egroup test%
\egroup \quad
\hbox orientation 3 \bgroup
    \strut test\hbox orientation "012 \bgroup\strut test\egroup test%
\egroup \quad
\hbox orientation 3 \bgroup
    \strut test\hbox orientation "022 \bgroup\strut test\egroup test%
\egroup \quad
\hbox orientation 3 \bgroup
    \strut test\hbox orientation "032 \bgroup\strut test\egroup test%
\egroup \quad
\hbox orientation 3 \bgroup
    \strut test\hbox orientation "042 \bgroup\strut test\egroup test%
\egroup
\quad test
\stopbuffer

\typebuffer

gives:

\startlinecorrection[blank]
\ruledhbox\bgroup \showcolorstruts \showboxes \inlinebuffer \egroup
\stoplinecorrection

\stopsection

\startsection[title={Right|-|to|-|left typesetting}]

Another aspect to keep in mind when we transform is the already mentioned
right|-|to|-|left direction. We show some examples where we do things like this:

\starttyping
\hbox{\hbox
    orientation #1
    {\strut abcd}}
\hbox{\hbox
    orientation #1
    to 15mm
    {\strut abcd}}
\hbox{\hbox
    orientation #1
    direction 1
    {\righttoleft\strut abcd}}
\hbox{\hbox
    orientation #1
    direction 1
    to 15mm {\righttoleft\strut abcd}}
\stoptyping

\starttexdefinition TestH #1
    \dontcomplain
    \setbox\scratchbox\hbox{abcd}%
    x\ruledhbox{\hbox orientation #1             to \wd\scratchbox  {\strut abcd}}x\quad
    x\ruledhbox{\hbox orientation #1             to 15mm            {\strut abcd}}x\quad
    x\ruledhbox{\hbox orientation #1 direction 1 to \wd\scratchbox  {\righttoleft\strut abcd}}x\quad
    x\ruledhbox{\hbox orientation #1 direction 1 to 15mm            {\righttoleft\strut abcd}}x%
\stoptexdefinition

\starttexdefinition TestV #1
    \dontcomplain
    \setbox\scratchbox\hbox{abcd}%
    x\ruledvbox{\vbox orientation #1             {\hsize \wd\scratchbox\strut abcd}}x\quad
    x\ruledvbox{\vbox orientation #1             {\hsize           15mm\strut abcd}}x\quad
    x\ruledvbox{\vbox orientation #1 {\righttoleft\hsize \wd\scratchbox\strut abcd}}x\quad
    x\ruledvbox{\vbox orientation #1 {\righttoleft\hsize           15mm\strut abcd}}x%
\stoptexdefinition

\startplacefigure[title={Horizontal boxes.}]
    \startcombination[nx=2,ny=2]
        {\TestH 0} {orientation 0}
        {\TestH 2} {orientation 2}
        {\TestH 1} {orientation 1}
        {\TestH 3} {orientation 3}
    \stopcombination
\stopplacefigure

\startplacefigure[title={Vertical boxes.}]
    \startcombination[nx=2,ny=2]
        {\TestV 0} {orientation 0}
        {\TestV 2} {orientation 2}
        {\TestV 1} {orientation 1}
        {\TestV 3} {orientation 3}
    \stopcombination
\stopplacefigure

\stopsection

\startsection[title={Vertical typesetting}]

I'm no expert on vertical typesetting and have no application for it either. But
from what I've seen vertically positioned glyphs are normally used in rather
straightforward situations. Here I will just give some examples of how
transformations can be used to achieve certain effects. It is no big deal to make
macros or use \LUA\ to apply magic to node lists but it is beyond this description
to discuss that.

Before we fine tune this example we have to discuss another feature. When a \typ
{orientation} keyword is given optionally \type {xoffset} and \type {yoffset} can
be specified. These offsets are {\em not} taken into account when calculating
dimensions. This is different from the offsets (at the \LUA\ end) used in glyphs
because there the vertical offset is taken into account. Here are some examples
of offsets in packaged lists:

\startbuffer
\hbox
    {test 1}
\hbox
    orientation 0
    yoffset  15pt
    xoffset 150pt
    {test}
\vbox
    orientation 0
    {\hbox{test}}
\vbox
    orientation 0
    yoffset  -5pt
    xoffset 130pt
    {\hbox{test}}
\vbox
    orientation 0
    yoffset 2pt
    {\hbox{test}}
\stopbuffer

\typebuffer

\startlinecorrection[blank]
    \start \showboxes \bfd \getbuffer \stop
\stoplinecorrection

In order to demonstrate some hacking, we first define a font that supports
chinese glyphs:

\startbuffer
\definefont[NotoCJK][NotoSansCJKtc-Regular*default @ 24pt]
\stopbuffer

\typebuffer \getbuffer

We put some text in a horizontal box; it doesn't show up in verbatim but you
get the idea nevertheless:

\startbuffer
\hbox{\NotoCJK 通用规范汉字表}
\stopbuffer

\typebuffer

\startlinecorrection[blank]
    \start \showboxes \getbuffer \stop
\stoplinecorrection

Let's now rotate this line of text:

\startbuffer[1]
\hbox orientation 1 {\NotoCJK 通用规范汉字表}
\stopbuffer

\typebuffer[1]

The result is shown in a while. Because we also need to rotate the glyphs we
deconstruct the box.

\startbuffer[2]
\hbox orientation 1 \bgroup \NotoCJK %
    \vbox {\hbox {通}}%
    \vbox {\hbox {用}}%
    \vbox {\hbox {规}}%
    \vbox {\hbox {test}}%
    \vbox {\hbox {范}}%
    \vbox {\hbox {汉}}%
    \vbox {\hbox {字}}%
    \vbox {\hbox {表}}%
\egroup
\stopbuffer

\typebuffer[2]

Next we rotate the glyphs.

\startbuffer[3]
\hbox orientation 1 \bgroup \NotoCJK %
    \vbox orientation 3 {\hbox {通}}%
    \vbox orientation 3 {\hbox {用}}%
    \vbox orientation 3 {\hbox {规}}%
    \vbox orientation 0 {\hbox {test}}%
    \vbox orientation 3 {\hbox {范}}%
    \vbox orientation 3 {\hbox {汉}}%
    \vbox orientation 3 {\hbox {字}}%
    \vbox orientation 3 {\hbox {表}}%
\egroup
\stopbuffer

\typebuffer[3]

This still looks bad so we kick in some offsets and glue:

\startbuffer[4]
\dontleavehmode\hbox orientation 1 \bgroup \NotoCJK
    \vbox
        orientation 0 yoffset -.1ex
        {\hbox orientation 3 {通}}\hskip.2ex
    \vbox
        orientation 0 yoffset -.1ex
        {\hbox orientation 3 {用}}\hskip.2ex
    \vbox
        orientation 0 yoffset -.1ex
        {\hbox orientation 3 {规}}\hskip.6ex
    \vbox
        {\hbox             {test}}\hskip.2ex
    \vbox
        orientation 0 yoffset -.1ex
        {\hbox orientation 3 {范}}\hskip.2ex
    \vbox
        orientation 0 yoffset -.1ex
        {\hbox orientation 3 {汉}}\hskip.2ex
    \vbox
        orientation 0 yoffset -.1ex
        {\hbox orientation 3 {字}}\hskip.2ex
    \vbox
        orientation 0 yoffset -.1ex
        {\hbox orientation 3 {表}}\hskip.2ex
\egroup
\stopbuffer

\typebuffer[4]

Now we're ready to compare the results

\startlinecorrection[blank]
    \startcombination[9*1]
        {\showboxes \getbuffer[1]} {1}
        {\showboxes \getbuffer[2]} {2}
        {\showboxes \getbuffer[3]} {3}
        {\showboxes \getbuffer[4]} {4}
        {\quad}{}
        {\getbuffer[1]} {1}
        {\getbuffer[2]} {2}
        {\getbuffer[3]} {3}
        {\getbuffer[4]} {4}
    \stopcombination
\stoplinecorrection

This could of course also be done with traditional kerns, raising and|/|or
lowering and messing around with dimensions. It's just that when manipulating
such rather complex constructs a little help (and efficiency) makes a difference,
also at the \LUA\ end. Of course one can argue the result but all is
programmable in the end.

\stopsection

\startsection[title={Considerations}]

Just in case you wonder if using these offsets is better than using normal kerning
and shifting, in practice offsets are not more efficient. Let's compare the
alternatives. We go from most to least efficient.

\starttyping
\setbox\scratchbox\hpack{}
\boxxoffset\scratchbox\scratchdimen
\boxyoffset\scratchbox\scratchdimen
\stoptyping

This sets the offsets and by setting them we also trigger the transform. Scanning
is fast and so is setting them. One million times expanding this takes (as
reference) 0.73 seconds on my current machine.

\starttyping
\setbox\scratchbox\hpack
  orientation \zerocount
  xoffset     \scratchdimen
  yoffset     \scratchdimen
  {}
\stoptyping

This takes a bit more time, 1.11 seconds, because the keywords have to be scanned
which happens on a token by token base.

\starttyping
\setbox\scratchbox\hpack{}
\scratchheight\ht\scratchbox
\scratchdepth\dp\scratchbox
\setbox\scratchbox\hpack
  {\kern\scratchdimen
   \raise\scratchdimen\box\scratchbox
   \kern\scratchdimen}
\ht\scratchbox\scratchheight
\dp\scratchbox\scratchdepth
\stoptyping

Now we're up to 1.69 seconds for the million expansions. Not only do we have some
parsing going on, but we also have assignments and extra packing, which means
calculations taking place.

\starttyping
\setbox\scratchbox\hpack{}
\scratchwidth\wd\scratchbox
\scratchheight\ht\scratchbox
\scratchdepth\dp\scratchbox
\setbox\scratchbox\hpack
  {\kern\scratchdimen
   \raise\scratchdimen\box\scratchbox}
\wd\scratchbox\scratchwidth
\ht\scratchbox\scratchheight
\dp\scratchbox\scratchdepth
\stoptyping

This variant is about as fast, as I measured 1.72 seconds. So, compared to the
0.73 seconds for the first variant, is this better? Does it help when we look at
our existing macros and adapt them?

Normally we don't have an empty box and normally we use \type {\hbox} because we
want the content to be processed. And a million times building a list and
processing content (which means runs over the list) will make the differences
in timing become noise. Add to that garbage collection (in \LUA) and memory
management (in \TEX) and it even becomes unpredictable. Seeing differences of
a factor two in such timings is no exception.

Another aspect is the parsing. When these commands are wrapped in macros we're
talking expanding tokens which is pretty fast. When it comes from the input file
a conversion to tokens has to happen too. And we will never see millions of such
sequences in a source file.

The backend also plays a role. Handling a kern or shift is more efficient than
analyzing transforms (and offsets) especially in a \LUA\ variant. But on the
other hand, we don't have an extra wrapping in a box so that actually saves work.

So, before a \CONTEXT\ user thinks \quotation {Let's update macros and change
policy.}, just consider staying with proven good old \TEX\ approaches. These
features are mostly meant for efficient low level manipulations as discussed in
relation to for instance handling scripts. In the rather large \CONTEXT\ code
base there are really only a few places where it will make code look nicer, but
there I don't expect an impact on performance.

\stopsection

\startsection[title={Integration}]

How these mechanisms are used depends on ones needs and the macro package used.
It makes no sense to cook up generic solutions because integration in a macro
package is too different. But anyhow we'll give an example of some (definitely
non optimized) \LUA\ magic.

\startbuffer
\startluacode
local glyph_id = node.id("glyph")
local fontdata = fonts.hashes.identifiers -- assumes generic font loader

local function is_vertical(c)
  -- more ranges matter but this will do here
  return c >= 0x04E00 and c <= 0x09FFF
end

function document.go_vertical(boxnumber)
  local box = tex.getbox(boxnumber)
  local n   = box.list
  while n do
    if n.id == glyph_id and is_vertical(n.char) then
      local o = .2 * fontdata[n.font].parameters.xheight
      local prev, next = n.prev, n.next
      n.next, n.prev = nil, nil
      local l = nodes.new("hlist")
      l.list = n
      local w, h, d = n.width, n.height, n.depth
      if prev then
          prev.next, l.prev = l, prev
      else
          box.list = l
      end
      if next then
          l.next, next.prev = next, l
      end
      l.width, l.height, l.depth  = h + d + o, w, 0
      l.orientation = 0x003
      l.xoffset, l.yoffset = o/2, -o/2
      l.hoffset, l.doffset = h, d - o
      n = next
    else
      n = n.next
    end
  end
end
\stopluacode
\stopbuffer

\typebuffer \getbuffer

We will use some other magic that we won't discuss here which relates to handling
scripts. For Hangul one needs to inject breakpoints and if needed also glue
between characters. The script environment does this. We also need to bump the
interline spacing. First we define a regular text helper and an auxiliary box.

\startbuffer[1]
\unexpanded\def\stripe#1%
  {\hbox orientation 0 yoffset .2\exheight{\strut #1}}

\newbox\MyVerticalBox
\stopbuffer

\typebuffer[1]

Next we fill that box with some mix of text (I have no clue what, as I just
copied it from some web page).

\startbuffer[2a]
\setbox\MyVerticalBox\hbox \bgroup
    \NotoCJK
    \startscript[hangul]%
    \dorecurse{20}{通用规范汉字表 \stripe{test #1} }%
    \unskip % remove last space
    \stopscript
\egroup
\stopbuffer

\typebuffer[2a]

We then apply the \LUA\ magic to the result:

\startbuffer[3a]
\ctxlua{document.go_vertical(\number\MyVerticalBox)}
\stopbuffer

\typebuffer[3a]

and finally assemble the result:

\startbuffer[4a]
\ruledvbox orientation 1 to \textwidth \bgroup
    \setupinterlinespace[40pt]
    \hsize .95\textheight
    \unhbox\MyVerticalBox
    \vfill
\egroup
\stopbuffer

\typebuffer[4a]

The result is shown in \in {figure} [fig:verticalmagic-1]. Of course this
approach is not that user friendly but it just serves as example. In \CONTEXT\ we
can follow a different route. First we define a new font feature. It is probably
clear that we need some code elsewhere that does something useful with this
information, but I will nos show this as it is rather \CONTEXT\ dependent.

\startbuffer[2b]
\definefontfeature
  [vertical]
  [vertical={%
    orientation=3,%
    down=.1,%
    right=.1,%
    ranges={%
      cjkcompatibility,%
      cjkcompatibilityforms,%
      cjkcompatibilityideographs,%
      cjkcompatibilityideographssupplement,%
      cjkradicalssupplement,%
    % cjkstrokes,%
      cjksymbolsandpunctuation,%
      cjkunifiedideographs,%
      cjkunifiedideographsextensiona,%
      cjkunifiedideographsextensionb,%
      cjkunifiedideographsextensionc,%
      cjkunifiedideographsextensiond,%
      cjkunifiedideographsextensione,%
      cjkunifiedideographsextensionf,%
    }%
  }]
\stopbuffer

\typebuffer[2b]

We apply this feature to a font:

\startbuffer[3b]
\definefont
  [NotoCJKvertical]
  [NotoSansCJKtc-Regular*default,vertical @ 24pt]
\stopbuffer

\typebuffer[3b]

\startbuffer[4b]
\setbox\MyVerticalBox\hbox\bgroup
    \NotoCJKvertical
    \startscript[hangul]%
    \dorecurse{20}{通用规范汉字表 \stripe{test #1} }%
    \unskip
    \stopscript
\egroup
\stopbuffer

\typebuffer[4b]

\startbuffer[5b]
\ruledvbox orientation 1 to \textwidth \bgroup
    \setupinterlinespace[40pt]
    \hsize .95\textheight
    \unhbox\MyVerticalBox
    \vfill
\egroup
\stopbuffer

\typebuffer[5b]

The result is shown in \in {figure} [fig:verticalmagic-2]. Again this approach is
not that user friendly but it already is a bit easier.

\startplacefigure[reference=fig:verticalmagic-1,title={Some vertical magic using manipulations.}]
    \getbuffer[1,2a,3a,4a]
\stopplacefigure

\startplacefigure[reference=fig:verticalmagic-2,title={Some vertical magic using fonts.}]
    \getbuffer[1,2b,3b,4b,5b]
\stopplacefigure

\stopsection

\stopchapter

\stopcomponent