summaryrefslogtreecommitdiff
path: root/doc/context/sources/general/manuals/ontarget/ontarget-gettingridof.tex
blob: 75b7f5bc0400c6b0c1cf93ff5b9899734efb655e (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
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
% language=us runpath=texruns:manuals/ontarget

\startcomponent ontarget-gettingridof

\environment ontarget-style

\startchapter[title={Issues in math fonts}]

\startsection[title=Introduction]

After trying to improve math rendering of \OPENTYPE\ math fonts, we \footnote
{Mikael Sundqvist and Hans Hagen} ended up with a mix of improving the engine and
fixing fonts runtime, and we are rather satisfied with the results so far.

However, as we progress and also improve the more structural and input related
features of \CONTEXT, we wonder why we don't simply are more drastic when it
comes to fonts. The \OPENTYPE\ specifications are vague, and most existing
\OPENTYPE\ math fonts use a mixture of the \OPENTYPE\ features and the old \TEX\
habits, so we are sort of on our own. The advantage of this situation is that we
feel free to experiment and do as we like.

In another article we discuss our issues with \UNICODE\ math, and we have
realized that good working solutions will be bound to a macro package anyway.
Also, math typesetting has not evolved much after Don Knuth set the standard,
even if the limitations of those times in terms of memory, processing speed and
font technologies have been lifted already for a while. And right from the start
Don invited users to extend and adapt \TEX\ to one's needs.

Here we will zoom in on a few aspects: font parameters, glyph dimensions and
properties and kerning of scripts and atoms. We discuss \OPENTYPE\ math fonts
only, and start with a summary of how we tweak them. We leave a detailed engine
discussion to a future article, since that would demand way more pages, and could
confuse the reader.
\stopsection

\startsection[title={Tweaks, also known as goodies}]

The easiest tweaks to describe are those that wipe features. Because the
\TEXGYRE\ fonts have many bad top accent anchors (they sit above the highest
point of the shape) the \typ {wipeanchors} tweak can remove them, and we do that
per specified alphabet.

\bgroup
\definefontfeature[mathextra][goodies=]
\switchtobodyfont[modern]
\startformula
\scale[s=2]{$\widehat{7}$}
% \widehat{7}
\stopformula
\egroup
\stopformulas

In a similar fashion we \typ {wipeitalics} from upright shapes. Okay, maybe they
can play a role for subscript placement, but then they can also interfere, and
they do not fit with the \OPENTYPE\ specification. The \typ {wipecues} tweak
zeros the dimensions of the invisible times and friends so that they don't
interfere and \typ {wipevariants} gets rid of bad variants of specified
characters.

The fixers is another category, and the names indicate what gets fixed. Tweaks
like these take lists of code points and specific properties to fix. We could
leave it to your imagination what \typ {fixaccents}, \typ {fixanchors}, \typ
{fixellipses}, \typ {fixoldschool}, \typ {fixprimes}, \typ {fixradicals} and \typ
{fixslashes} do, but here are some details. Inconsistencies in the dimensions of
accents make them jump all over the place so we normalize them. We support
horizontal stretching at the engine level.

\startformula
\scale[s=2]{\dm{\widehat{a+b+c+d} = \widetilde{u+v+w+x+y}}}
\stopformula

It required only a few lines of code thanks to already present scaling features.

% MPS: I thought of an example showing the accents, but I could
%      not get it to work fine with the goodies loaded the second
%      time the font was loaded
%
% \startformulas
% \bgroup \definefontfeature[mathextra][goodies=]\setupbodyfont[modern]
% \startformula[width=2em]
% \widehat{7}
% \stopformula
% \egroup
% \bgroup\setupbodyfont[modern]
% \startformula[width=2em]
% \widehat{7}
% \stopformula
% \egroup
% \stopformulas

Anchors can be off so we fix these in a way so that they look better on
especially italic shapes. We make sure that the automated sizing works
consistently, as this is driven by width and overshoot. Several kind of ellipses
can be inconsistent with each other as well as with periods (shape and size wise)
so we have to deal with that. Radicals and other extensibles have old school
dimensions (\TEX\ fonts have a limited set of widths and heights). We need to fix
for instance fences of various size because we want to apply kerns to scripts on
the four possible corners for which we need to know the real height and depth,

Discussing primes would take many paragraphs so we stick to mentioning that they
are a mess. We now have native prime support in the engine as well as assume
properly dimensioned symbols to be used. Slashes are used for skewed fractions so
we'd better make sure they are set up right.

A nice tweak is \typ {replacealphabets}. We use this to provide alternative
script (roundhand) and calligraphic (chancery) alphabets (yes we have both
natively in \CONTEXT\ while \UNICODE\ combines them in one alphabet). Many
available \OPENTYPE\ math fonts come with one of the two alphabets only, some
with roundhand and some with chancery. For the record: this tweak replaces the
older \typ {variants} tweak that filtered scripts from a stylistic font feature.

We also use the \typ {replacealphabets} tweak to drop in Arabic shapes so that we
can do bidirectional math. In practice that doesn't really boil down to a
replacement but more to an addition. The \typ {addmirrors} features accompanies
this, and it is again a rather small extension to the engine to make sure we can
do this efficiently: when a character is looked up we check a mirror variant when
we are in r2l mode, just like we look up a smaller variant when we're in compact
font mode (a \CONTEXT\ feature).

\bgroup
\definefontfeature[mathextra][mathxitsarabic=yes]
\switchtobodyfont[bonum]
\setupmathematics[bidi=yes,align=righttoleft]\par
\setupalign[righttoleft] %
\startformula
\scale[s=2]{\dm{
\sum_{\char"1EE4E=\char"1EE01}^{\char"1EE02} \char"1EE03^{\char"1EE4E} =
\char"1EE03^{\char"1EE01}\frac{\char"0661 - \char"1EE03^{\char"1EE02 -
\char"1EE01 + \char"0661}}{\char"0661 - \char"1EE03} \quad (\char"1EE03\neq
\char"0661)
}}

% \int_{\char"0627}^{\char"0628} \char"1EE03 '(\char"1EE4E)
% %\mathatom class \mathdifferentialcode {\char"062F}
% \dd
% \char"1EE4E
% = \char"1EE03(\char"0628) - \char"1EE03(\char"0627)
% \stopformula
% \startformula
% \sqrt[\char"0663](\char"1EE30) = (\char"1EE30)^{1/\char"0663}
\stopformula
\egroup

Another application of \typ {replacealphabets} is to drop in single characters
from another font. We use this for instance to replace the \quote {not really an
alpha} in Bonum by one of our own liking. Below we show a math italic a and the
original alpha, together with the modified alpha.

\startformula
\scale[s=2]{\dm{
a + \text{\getnamedglyphdirect{file:TeXGyreBonumMath-Companion.otf}{alpha.old}} + \alpha
}}
\stopformula

For that we ship a companion font. On our disks (and in the distribution) you can
find:

\starttyping
/tex/texmf-fonts/fonts/data/cms/companion/RalphSmithsFormalScript-Companion.otf
/tex/texmf-fonts/fonts/data/cms/companion/TeXGyreBonumMath-Companion.otf
/tex/texmf-fonts/fonts/data/cms/companion/XITSMath-Companion.otf
\stoptyping

All these are efficient drop|-|ins that are injected by the \typ
{replacealphabets}, some under user control, some always. We tried to limit the
overhead and actually bidirectional math could be simplified which also had the
benefit that when one does tens of thousands of bodyfont switches a bit of
runtime is gained.

There are more addition tweaks: \typ {addactuarian} creates the relevant symbols
which is actually a right sided radical (the engine has support for two|-|sided
radicals). It takes a bit of juggling with virtual glyphs and extensible recipes,
but the results are rewarding.

\setupmathradical[annuity][strut=no]
\definemathdelimited
   [myannuity]
   [topoffset=.2\exheight,
    strut=no,
    rightmargin=.05\emwidth,
    right=\delimitedrightanutityuc]

\startformula
\scale[s=2]{\dm{
\widebar{A}__{\myannuity{m}}^^{2}_{x:\annuity{n}}^{1}
}}
\stopformula

In a similar fashion we try to add missing extensible arrows with \typ
{addarrows}, bars with \typ {addbars}, equals with \typ {addequals} and again
using the radical mechanism fourier notation symbols (like hats) with \typ
{addfourier}. That one involves subtle kerning because these symbols end up at
the right top of a fence like symbol.

\startformula
\scale[s=2]{\dm{
\widehat{f \ast g \ast h}(\xi) = \fourier{\F1\left(f\ast g \ast h\right)}(\xi)
}}
\stopformula

It was actually one of the reasons to introduce a more advanced kerning mechanism
in the engine, which is not entirely trivial because one has to carry around more
information, since all this is font and character bound, and when wrapped in
boxes that gets hard to analyze. The \typ {addrules} makes sure that we can do
bars over and under constructs properly. The \typ {addparts} is there to add
extensible recipes to characters.

Some of these tweaks actually are not new and are also available in \MKIV\ but
more as features (optionally driven by the goodie file). An example is \typ
{addscripts} that is there for specially positioned and scaled signs (high minus
and such) but that tweak will probably be redone as part of the \quotation {deal
with all these plus and minus issues}. The dedicated to Alan Braslau \typ
{addprivates} tweak is an example of this: we add specific variants for unary
minus and plus that users can enable on demand, which in turn of course gives
class specific spacing, but we promised not to discuss those engine features
here.

\startformula
\scale[s=2]{\dm{
\int_1^2 \left[(x+2)^{\frac[strut=no]{1}{2}} - (x+2)^{\um\frac[strut=no]{1}{2}}\right] \dd x
}}
\stopformula

There is a handful of tweaks that deals with fixing glyph properties (in detail).
We mention: \typ {dimensions} and \typ {accentdimensions} that can reposition in
the boundingbox, fix the width and italic correction, squeeze and expand etc. The
\typ {kernpairs} tweak adds kern pairs to combinations of characters. The \typ
{kerns} provides a way to add top left, bottom left, top right and bottom right
kerns and those really make the results look better so we love it!

\startformula
\scale[s=2]{\showglyphs\dm{\F3\left(\frac{1}{1+x^2}\right)^n \quad x^2/(1+x)}}
\stopformula

The \typ {margins} tweak sets margin fields that the engine can use to calculate
accents over the base character better. The same is true for \typ {setovershoots}
that can make accents lean over a bit. The \typ {staircase} feature can be used
to add the somewhat complicated \OPENTYPE\ kerns. From all this you can deduce
that the engine has all types of kerning that \OPENTYPE\ requires, and more.

Accents as specified in fonts can be a pain to deal with so we have more tweaks
for them: \typ {copyaccents} moves them to the right slots and \typ
{extendaccents} makes sure that we can extend them. Not all font makers have the
same ideas about where these symbols should sit and what their dimensions should
be.

The \typ {checkspacing} tweak fixes bad or missing spacing related to \UNICODE\
character entries in the font, because after all, we might need them. We need to
keep for instance \MATHML\ in mind, which means: processing content that we don't
see and that can contain whatever an editor puts in. The \typ {replacements}
feature replaces one character by another from the same font. The \typ
{substitutes} replaces a character by one from a stylistic feature.

Relatively late we added the \typ {setoptions} which was needed to control the
engine for specific fonts. The rendering is controlled by a bunch of options
(think of kerning, italic correction, and such). Some are per font, many per
class. Because we can (and do) use mixed math fonts in a document, we might need
to adapt the engine level options per font, and that is what this tweak does: it
passes options to the font so that the engine can consult them and prefer them
over the \quote {global} ones. We needed this for some fonts that have old school
dimensions for extensibles (like Lucida), simply because they imitated Computer
Modern. Normally that goes unnoticed, but, as mentioned before, it interferes
with our optional kerning. The \typ {fixoldschool} tweak sort of can fix that too
so \typ {setoptions} is seldom needed. Luckily, some font providers are willing
to fix their fonts!

We set and configure all these tweaks in a so-called goodie file, basically a
runtime module that returns a \LUA\ table with specifications. In addition to the
tweaks subtable in the math namespace, there is a subtable that overloads the
font parameters: the ones that \OPENTYPE\ specifies, but also new ones that we
added. In the next section we elaborate more on these font bound parameters.

\stopsection

\startsection[title=Font parameters]

At some point in the upgrading of the math machinery we discussed some of the
inconsistencies between the math constants of the XITS and STIX fonts. Now, one
has to keep in mind that XITS was based on a first release of STIX that only had
\TYPEONE\ fonts so what follows should not to be seen as criticism, but more as
observations and reason for discussion, as well as a basis for decisions to be
made.

One thing we have to mention in advance, is that we often wonder why some weird
and|/|or confusing stuff in math fonts go unnoticed. We have some suggestions:

\startitemize
\startitem
    The user doesn't care that much how math comes out. This can easily be
    observed when you run into documents on the internet or posts on forums. And
    publishers don't always seem to care either. Consistency with old documents
    sometimes seems to be more important than quality.
\stopitem
\startitem
    The user switches to another math font when the current one doesn't handle
    its intended math domain well. We have seen that happening and it's the
    easiest way out when you have not much control anyway (for instance when
    using online tools).
\stopitem
\startitem
    The user eventually adds some skips and kerns to get things right, because
    after all \TEX\ is also about tweaking.
\stopitem
\startitem
    The user doesn't typeset that complex math. It's mostly inline math with an
    occasional alignment (also in text style) and very few multi|-|level display
    math (with left and right fences that span at most a fraction).
\stopitem
\stopitemize

We do not claim to be perfect, but we care for details, so let's go on. The next
table shows the math constants as they can be found in the \STIX\ (two) and
\XITS\ (one) fonts. When you typeset with these fonts you will notice that \XITS\
is somewhat smaller, so two additional columns show the values compensated for
the axis height and accent base height.

\startluacode
local one = {
   ["AccentBaseHeight"]=450,
   ["AxisHeight"]=250,
   ["DelimitedSubFormulaMinHeight"]=1500,
   ["DisplayOperatorMinHeight"]=1450,
   ["FlattenedAccentBaseHeight"]=662,
   ["FractionDenominatorDisplayStyleGapMin"]=198,
   ["FractionDenominatorDisplayStyleShiftDown"]=700,
   ["FractionDenominatorGapMin"]=66,
   ["FractionDenominatorShiftDown"]=480,
   ["FractionNumeratorDisplayStyleGapMin"]=198,
   ["FractionNumeratorDisplayStyleShiftUp"]=580,
   ["FractionNumeratorGapMin"]=66,
   ["FractionNumeratorShiftUp"]=480,
   ["FractionRuleThickness"]=66,
   ["LowerLimitBaselineDropMin"]=600,
   ["LowerLimitGapMin"]=150,
   ["MathLeading"]=150,
   ["MinConnectorOverlap"]=50,
   ["OverbarExtraAscender"]=66,
   ["OverbarRuleThickness"]=66,
   ["OverbarVerticalGap"]=198,
   ["RadicalDegreeBottomRaisePercent"]=70,
   ["RadicalDisplayStyleVerticalGap"]=186,
   ["RadicalExtraAscender"]=66,
   ["RadicalKernAfterDegree"]=-555,
   ["RadicalKernBeforeDegree"]=277,
   ["RadicalRuleThickness"]=66,
   ["RadicalVerticalGap"]=82,
   ["ScriptPercentScaleDown"]=75,
   ["ScriptScriptPercentScaleDown"]=60,
   ["SkewedFractionHorizontalGap"]=300,
   ["SkewedFractionVerticalGap"]=66,
   ["SpaceAfterScript"]=41,
   ["StackBottomDisplayStyleShiftDown"]=900,
   ["StackBottomShiftDown"]=800,
   ["StackDisplayStyleGapMin"]=462,
   ["StackGapMin"]=198,
   ["StackTopDisplayStyleShiftUp"]=580,
   ["StackTopShiftUp"]=480,
   ["StretchStackBottomShiftDown"]=600,
   ["StretchStackGapAboveMin"]=150,
   ["StretchStackGapBelowMin"]=150,
   ["StretchStackTopShiftUp"]=300,
   ["SubSuperscriptGapMin"]=264,
   ["SubscriptBaselineDropMin"]=50,
   ["SubscriptShiftDown"]=250,
   ["SubscriptTopMax"]=400,
   ["SuperscriptBaselineDropMax"]=375,
   ["SuperscriptBottomMaxWithSubscript"]=400,
   ["SuperscriptBottomMin"]=125,
   ["SuperscriptShiftUp"]=400,
   ["SuperscriptShiftUpCramped"]=275,
   ["UnderbarExtraDescender"]=66,
   ["UnderbarRuleThickness"]=66,
   ["UnderbarVerticalGap"]=198,
   ["UpperLimitBaselineRiseMin"]=300,
   ["UpperLimitGapMin"]=150,
}

local two = {
   ["AccentBaseHeight"]=480,
   ["AxisHeight"]=258,
   ["DelimitedSubFormulaMinHeight"]=1325,
   ["DisplayOperatorMinHeight"]=1800,
   ["FlattenedAccentBaseHeight"]=656,
   ["FractionDenominatorDisplayStyleGapMin"]=150,
   ["FractionDenominatorDisplayStyleShiftDown"]=640,
   ["FractionDenominatorGapMin"]=68,
   ["FractionDenominatorShiftDown"]=585,
   ["FractionNumeratorDisplayStyleGapMin"]=150,
   ["FractionNumeratorDisplayStyleShiftUp"]=640,
   ["FractionNumeratorGapMin"]=68,
   ["FractionNumeratorShiftUp"]=585,
   ["FractionRuleThickness"]=68,
   ["LowerLimitBaselineDropMin"]=670,
   ["LowerLimitGapMin"]=135,
   ["MathLeading"]=150,
   ["MinConnectorOverlap"]=100,
   ["OverbarExtraAscender"]=68,
   ["OverbarRuleThickness"]=68,
   ["OverbarVerticalGap"]=175,
   ["RadicalDegreeBottomRaisePercent"]=55,
   ["RadicalDisplayStyleVerticalGap"]=170,
   ["RadicalExtraAscender"]=78,
   ["RadicalKernAfterDegree"]=-335,
   ["RadicalKernBeforeDegree"]=65,
   ["RadicalRuleThickness"]=68,
   ["RadicalVerticalGap"]=85,
   ["ScriptPercentScaleDown"]=70,
   ["ScriptScriptPercentScaleDown"]=55,
   ["SkewedFractionHorizontalGap"]=350,
   ["SkewedFractionVerticalGap"]=68,
   ["SpaceAfterScript"]=40,
   ["StackBottomDisplayStyleShiftDown"]=690,
   ["StackBottomShiftDown"]=385,
   ["StackDisplayStyleGapMin"]=300,
   ["StackGapMin"]=150,
   ["StackTopDisplayStyleShiftUp"]=780,
   ["StackTopShiftUp"]=470,
   ["StretchStackBottomShiftDown"]=590,
   ["StretchStackGapAboveMin"]=68,
   ["StretchStackGapBelowMin"]=68,
   ["StretchStackTopShiftUp"]=800,
   ["SubSuperscriptGapMin"]=150,
   ["SubscriptBaselineDropMin"]=160,
   ["SubscriptShiftDown"]=210,
   ["SubscriptTopMax"]=368,
   ["SuperscriptBaselineDropMax"]=230,
   ["SuperscriptBottomMaxWithSubscript"]=380,
   ["SuperscriptBottomMin"]=120,
   ["SuperscriptShiftUp"]=360,
   ["SuperscriptShiftUpCramped"]=252,
   ["UnderbarExtraDescender"]=68,
   ["UnderbarRuleThickness"]=68,
   ["UnderbarVerticalGap"]=175,
   ["UpperLimitBaselineRiseMin"]=300,
   ["UpperLimitGapMin"]=135,
}

local designrelated = {
   ["AccentBaseHeight"]                = "optional**",
   ["AxisHeight"]                      = "mandate",
   ["FlattenedAccentBaseHeight"]       = "optional**",
   ["FractionRuleThickness"]           = "optional",
   ["MinConnectorOverlap"]             = "mandate",
   ["OverbarRuleThickness"]            = "optional*",
   ["RadicalDegreeBottomRaisePercent"] = "mandate",
   ["UnderbarRuleThickness"]           = "optional*",
}

local a1 = two.AccentBaseHeight / one.AccentBaseHeight
local a2 = two.AxisHeight / one.AxisHeight

context.starttabulate { "|l|r|r|r|r|l|" }
    context.FL()
        context.BC() context("constant")
        context.BC() context("stix")
        context.BC() context("xits")
        context.BC() context("base")
        context.BC() context("axis")
        context.BC() context("relevance")
        context.BC() context.NR()
    context.ML()
        for key, oldvalue in table.sortedhash(one) do
            local newvalue = two[key]
            local accvalue = math.round(oldvalue * a1)
            local axivalue = math.round(oldvalue * a2)
            context.NC() context(key)
            context.NC() context(newvalue)
            context.NC() context(oldvalue)
            context.NC() if newvalue == accvalue then context.bold(accvalue) else context(accvalue) end
            context.NC() if newvalue == axivalue then context.bold(axivalue) else context(axivalue) end
            context.NC() context(designrelated[key])
            context.NC() context.NR()
        end
    context.LL()
context.stoptabulate()
\stopluacode

Very few values are the same. So, what exactly do these constants tell us? You
can even wonder why they are there at all. Just think of this: we want to typeset
math, and we have an engine that we can control. We know how we want it to look.
So, what do these constants actually contribute? Plenty relates to the height and
depth of the nucleus and|/|or the axis. The fact that we have to fix some in the
goodie files, and the fact that we actually need more variables that control
positioning, makes for a good argument to just ignore most of the ones provided
by the font, especially when they seem somewhat arbitrarily. Can it be that font
designers are just gambling a bit, looking at another font, and starting from
there?

The relationship between \TEX's math font parameters and the \OPENTYPE\ math
constants is not one|-|to|-|one. Mapping them onto each other is possible but
actually is font dependent. However, we can assume that the values of Computer
Modern are leading.

The \typ {AxisHeight}, \typ {AccentBaseHeight} and \typ
{FlattenedAccentBaseHeight} are set to the x|-|height, a value that is defined in
all fonts. The \typ {SkewedFractionVerticalGap} also gets that value. Other
variables relate to the em|-|width (or \type {\quad}), for instance the \typ
{SkewedFractionHorizontalGap} that gets half that value. Of course these last two
then assume that the engine handles skewed fractions.

Variables that directly map onto each other are \typ {StretchStackGapBelowMin} as
\typ {bigopspacing1}, \typ {StretchStackTopShiftUp} as \typ {bigopspacing3}, \typ
{StretchStackGapAboveMin} as \typ {bigopspacing2} and \typ
{StretchStackBottomShiftDown} as \typ {bigopspacing4}. However, these clash with
\typ {UpperLimitBaselineRiseMin} as \typ {bigopspacing3}, \typ {UpperLimitGapMin}
as \typ {bigopspacing1}, \typ {LowerLimitBaselineDropMin} as \typ {bigopspacing4}
and \typ {LowerLimitGapMin} as \typ {bigopspacing2}. Where in traditional fonts
these are the same, in \OPENTYPE\ they can be different. Should they be?

Internally we use different names for variables, simply because the engine has
some parameters that \OPENTYPE\ maths hasn't. So we have \typ {limit_above_kern}
and \typ {limit_below_kern} for \typ {bigopspacing5}.

A couple of parameters have different values for (cramped) displaystyle. The \typ
{FractionDelimiterSize} and \typ {FractionDelimiterDisplayStyleSize} use \typ
{delim2} and \typ {delim1}. The \typ {FractionDenominatorShiftDown} and \typ
{FractionDenominatorDisplayStyleShiftDown} map onto \typ {denom2} and \typ
{denom1} and their numerator counterparts from \typ {num2} and \typ {num1}. The
\typ {Stack*} parameters also use these. The \typ {sub1}, \typ{sub2}, \typ{sup1},
\typ{sup2}, \typ{sup3}, and \typ {supdrop} can populate the \type {Sub*} and
\type {Super*} parameters, also in different styles.

The rest of the parameters can be defined in terms of the default rulethickness,
quad or xheight, often multiplied by a factor. For some we see the \type {1/18}
show up a number that we also see with muskips. Some constants can be set from
registers, like \typ {SpaceAfterScript} which is just \type {\scriptspace}.

If you look at the \LUATEX\ source you wil find a section where this mapping is
done in the case of a traditional font, that is: one without a math constants
table. In \LUAMETATEX\ we don't need to do this because font loading happens in
\LUA. So we simply issue an error when the math engine can't resolve a mandate
parameter. The fact that we have a partial mapping from math constants onto
traditional parameters and that \LUATEX\ has to deal with the traditional ones
too make for a somewhat confusing landscape. When in \LUAMETATEX\ we assume wide
fonts to be used that have a math constants table, we can probably clean up some
of this.

We need to keep in mind that Cambria was the starting point, and it did borrow
some concepts from \TEX. But \TEX\ had parameters because there was not enough
information in the glyphs! Also, Cambria was meant for \MSWORD, and a word
processor is unlikely to provide the level of control that \TEX\ offers, so it
needs some directions with respect to e.g.\ spacing. Without user control, it has
to come up with acceptable compromises. So actually the \LUAMETATEX\ math engine
can be made a bit cleaner when we just get rid of these parameters.

So, which constants are actually essential? The \typ {AxisHeight} is important
and also design related. Quite likely this is where the minus sits above the
baseline. It is used for displacements of the baseline so that for instance
fractions nicely align. When testing script anchored to fences we noticed that
the parenthesis in XITS had too little depth while STIX had the expected amount.
This relates to anchoring relative to the math axis.

Is there a reason why \typ {UnderbarRuleThickness} and \typ
{OverbarRuleThickness} should differ? If not, then we only need a variable that
somehow tells us what thickness fits best with the other top and bottom accents.
It is quite likely the same as the \typ {RadicalRuleThickness}, which is needed
to extend the radical symbol. So, here three constants can be replaced by one
design related one. The \typ {FractionRuleThickness} can also be derived from
that, but more likely is that it is a quantity that the macro package sets up
anyway, maybe related to rules used elsewhere.

The \typ {MinConnectorOverlap} and \typ {RadicalDegreeBottomRaisePercent} also
are related to the design although one could abuse the top accent anchor for the
second one. So they are important. However, given the small number of
extensibles, they could have been part of the extensible recipes.

The \typ {AccentBaseHeight} and \typ {FlattenedAccentBaseHeight} might relate to
the margin that the designer put below the accent as part of the glyph, so it is
kind of a design related constant. Nevertheless, we fix quite some accents in the
goodie files because they can be inconsistent. That makes these constants
somewhat dubious too. If we have to check a font, we can just as well set up
constants that we need in the goodie file. Also, isn't it weird that there are no
bottom variants?

We can forget about \typ {MathLeading} as it serves no purpose in \TEX. The \typ
{DisplayOperatorMinHeight} is often set wrong so although we fix that in the
goodie file it might be that we just can use an internal variable. It is not the
font designer who decides that anyway. The same is true for \typ
{DelimitedSubFormulaMinHeight}.

If we handle skewed fractions, \typ {SkewedFractionHorizontalGap} and \typ
{SkewedFractionVerticalGap} might give an indication of the tilt but why do we
need two? It is design related though, so they have some importance, when set
right.

The rest can be grouped, and basically we can replace them by a consistent set of
engine parameters. We can still set them up per font, but at least we can then
use a clean set. Currently, we already have more. For instance, why only \typ
{SpaceAfterScript} and not one for before, and how about prescripts and primes?
If we have to complement them with additional ones and also fix them, we can as
well set up all these script related variables.

For fractions the font provides \typ {FractionDenominatorDisplayStyleGapMin},
\typ {FractionDenominatorDisplayStyleShiftDown}, \typ
{FractionDenominatorGapMin}, \typ {FractionDenominatorShiftDown}, \typ
{FractionNumeratorDisplayStyleGapMin}, \typ
{FractionNumeratorDisplayStyleShiftUp}, \typ {FractionNumeratorGapMin} and \typ
{FractionNumeratorShiftUp}. We might try to come up with a simpler model.

Limits have: \typ {LowerLimitBaselineDropMin}, \typ {LowerLimitGapMin}, \typ
{UpperLimitBaselineRiseMin} and \typ {UpperLimitGapMin}. Limits are tricky anyway
as they also depend on abusing the italic correction for anchoring.

Horizontal bars are driven by \typ {OverbarExtraAscender}, \typ
{OverbarVerticalGap}, \typ {UnderbarExtraDescender} and \typ
{UnderbarVerticalGap}, but for e.g.\ arrows we are on our own, so again a not so
useful set.

Then radicals: we need some more than these \typ
{RadicalDisplayStyleVerticalGap}, \typ {RadicalExtraAscender}, \typ
{RadicalKernAfterDegree}, \typ {RadicalKernBeforeDegree} and \typ
{RadicalVerticalGap}, and because we really need to check these there is no gain
having them in the font.

Isn't it more a decision by the macro package how script and scriptscript should
be scaled? Currently we listen to \typ {ScriptPercentScaleDown} and \typ
{ScriptScriptPercentScaleDown}, but maybe it relates more to usage.

We need more control than just \typ {SpaceAfterScript} and an engine could
provide it more consistently. It's a loner.

How about \typ {StackBottomDisplayStyleShiftDown}, \typ {StackBottomShiftDown},
\typ {StackDisplayStyleGapMin}, \typ {StackGapMin}, \typ
{StackTopDisplayStyleShiftUp} and \typ {StackTopShiftUp}? And isn't this more for
the renderer to decide: \typ {StretchStackBottomShiftDown}, \typ
{StretchStackGapAboveMin}, \typ {StretchStackGapBelowMin} and \typ
{StretchStackTopShiftUp}?

This messy bit can also be handled more convenient so what exactly is the
relationship with the font design of \typ {SubSuperscriptGapMin}, \typ
{SubscriptBaselineDropMin}, \typ {SubscriptShiftDown}, \typ {SubscriptTopMax},
\typ {SuperscriptBaselineDropMax}, \typ {SuperscriptBottomMaxWithSubscript}, \typ
{SuperscriptBottomMin}, \typ {SuperscriptShiftUp} and \typ
{SuperscriptShiftUpCramped}?

Just for the record, here are the (font related) ones we added so far. A set of
prime related constants similar to the script ones: \typ {PrimeRaisePercent},
\typ {PrimeRaiseComposedPercent}, \typ {PrimeShiftUp}, \typ
{PrimeBaselineDropMax}, \typ {PrimeShiftUpCramped}, \typ {PrimeSpaceAfter} and
\typ {PrimeWidthPercent}. Of course, we also added \typ {SpaceBeforeScript} just
because we want to be symmetrical in the engine where we also have to deal with
prescripts.

These we provide for some further limit positioning: \typ {NoLimitSupFactor} and
\typ {NoLimitSubFactor}; these for delimiters: \typ {DelimiterPercent} and \typ
{DelimiterShortfall}; and these for radicals in order to compensate for sloping
shapes: \typ {RadicalKernAfterExtensible} and \typ {RadicalKernBeforeExtensible}
because we have doublesided radicals.

Finally, there are quite some (horrible) accent tuning parameters: \typ
{AccentTopShiftUp}, \typ {AccentBottomShiftDown}, \typ
{FlattenedAccentTopShiftUp}, \typ {FlattenedAccentBottomShiftDown}, \typ
{AccentBaseDepth}, \typ {AccentFlattenedBaseDepth}, \typ {AccentTopOvershoot},
\typ {AccentBottomOvershoot}, \typ {AccentSuperscriptDrop}, \typ
{AccentSuperscriptPercent} and \typ {AccentExtendMargin}, but we tend to move
some of that to the tweaks on a per accent basis.

Setting these parameters right is not trivial, and also a bit subjective. We might,
however, assume that for instance the math axis is set right, but alas, when we
were fixing the less and greater symbols in Lucida Bright Math, we found that all
symbols actually were designed for a math axis of 325, instead of the given
value 313, and that difference can be seen!

\startbuffer
\scale[s=2]{\dm{
    2 > -\left\{\frac{1}{1+x^2}\right\}
}}
\stopbuffer

\startlinecorrection
\startcombination[nx=2]
    \startcontent
    % \definefontfeature[mathextra][goodies=]
         \switchtobodyfont[lucidaold]
         \showglyphs
         \getbuffer
     \stopcontent
     \startcaption
         Old Lucida
     \stopcaption
     \startcontent
         \switchtobodyfont[lucida]
         \showglyphs
         \getbuffer
     \stopcontent
     \startcaption
         New Lucida
     \stopcaption
\stopcombination
\stoplinecorrection

The assumption is that the axis goes trough the middle of
the minus. Luckily it was relatively easy to fix these two symbols (they also had
to be scaled, maybe they originate in the text font?) and adapt the
axis. We still need to check all the other fonts, but it looks like they are okay,
which is good because the math axis plays an important role in rendering math.
It is one of the few parameters that has to be present and right. A nice side
effect of this is that we end up with discussing new (\CONTEXT) features. One
can for instance shift all non-character symbols down just a little and lower
the math axis, to get a bit more tolerance in lines with many inline fractions,
radicals or superscripts, that otherwise would result in interline skips.

A first step in getting out of this mess is to define {\em all} these parameters
in the goodie file where we fix them anyway. That way we are at least not
dependent on changes in the font. We are not a word processor so we have way more
freedom to control matters. And preset font parameters sometimes do more harm
than good. A side effect of a cleanup can be that we get rid of the evolved mix
of uppercase and lowercase math control variables and can be more consistent.
Ever since \LUATEX\ got support for \OPENTYPE, math constants names have been
mapped and matched to traditional \TEX\ font parameters.

\stopsection

\startsection[title=Metrics]

With metrics we refer to the dimensions and other properties of math glyphs. The
origin of digital math fonts is definitely Computer Modern and thereby the
storage of properties is bound to the \TFM\ file format. That format is binary
and can be loaded fast. It can also be stored in the format, unless you're using
\LUATEX\ or \LUAMETATEX\ where \LUA\ is the storage format. A \TFM\ file stores
per character the width, height, depth and italic correction. The file also
contains font parameters. In math fonts there are extensible recipes and there is
information about next in size glyphs. The file has kerning and ligature tables
too.

Given the times \TEX\ evolved in, the format is rather compact. For instance, the
height, depth and italic correction are shared and indices to three shared values
are used. There can be 16 heights and depths and 64 italic corrections. That way
much fits into a memory word.

The documentation tells us that \quotation {The italic correction of a character
has two different uses. (a)~In ordinary text, the italic correction is added to
the width only if the \TEX\ user specifies \quote{\type {\/}} after the
character. (b)~In math formulas, the italic correction is always added to the
width, except with respect to the positioning of subscripts.} It is this last
phenomena that gives us some trouble with fonts in \OPENTYPE\ math. The fact that
traditional fonts cheat with the width and that we add and selectively remove or
ignore the correction makes for fuzzy code in \LUATEX\ although splitting the
code paths and providing options to control all this helps a bit. In \LUAMETATEX\
we have more control but also expect an \OPENTYPE\ font. In \OPENTYPE\ math there
are italic corrections, and we even have the peculiar usage of it in positioning
limits. However, the idea was that staircase kerns do the detailed relative
positioning.

Before we dive into this a bit more, it is worth mentioning that Don Knuth paid a
lot of attention to details. The italic alphabet in math uses the same shapes as
the text italic but metrics are different as is shown below. We have also met fonts
where it looked like the text italics were taken, and where the metrics were handled
via more excessive italic correction, sometimes combined with staircase kerns that
basically were corrections for the side bearing. This is why we always come back to
Latin Modern and Cambria when we investigate fonts: one is based on the traditional
\TEX\ model, with carefully chosen italic corrections, and the other is based on the
\OPENTYPE\ model with staircase kerning. They are our reference fonts.

\startlinecorrection
\startcombination[nx=1,ny=2]
    \startcontent
        \definedfont[file:lmroman10italic.otf]%
        \showglyphs
        \scale[s=3]{abcdefghijklmnopqrstuvwxyz}
    \stopcontent
    \startcaption
        Latin Modern Roman Italic
    \stopcaption
    \startcontent
        \definedfont[file:latinmodernmath.otf]%
        \showglyphs
        \scale[s=3]{𝑎𝑏𝑐𝑑𝑒𝑓𝑔ℎ𝑖𝑗𝑘𝑙𝑚𝑛𝑜𝑝𝑞𝑟𝑠𝑡𝑢𝑣𝑤𝑥𝑦𝑧}
    \stopcontent
    \startcaption
        Latin Modern Math Italic
    \stopcaption
\stopcombination
\stoplinecorrection

In \CONTEXT\ \MKIV\ we played a lot with italic correction in math and there were
ways to enforce, ignore, selectively apply it, etc. But, because fonts actually
demand a mixture, in \LUAMETATEX\ we ended up with more extensive runtime
patching of them. Another reason for this was that math fonts can have weird
properties. It looks like when these standards are set and fonts are made, the
font makers can do as they like as long as the average formula comes out right,
and metrics to some extent resemble a traditional font. However, when testing how
well a font behaves in a real situation there can be all kind of interferences
from the macro package: inter|-|atom kerning, spacing corrections macros,
specific handling of cases, etc. We even see \OPENTYPE\ fonts that seem to
have the same limited number of heights, depths and italic corrections. And, as a
consequence we get for instance larger sizes of fences having the same depth for
all the size variants, something that is pretty odd for an \OPENTYPE\ font with no
limitations.

The italic correction in traditional \TEX\ math gets added to the width. When a
subscript is attached to a kernel character it sits tight against that character:
its position is driven by the width of the kernel. A superscript on the other
hand is moved over the italic width so that it doesn't overlap or touch the
likely sticking out bit of the kernel. This means that a traditional font (and
quite some \OPENTYPE\ math fonts are modelled after Computer Modern) have to find
compromises of width and italic correction for characters where the subscript is
supposed to move left (inside the bounding box of the kernel).

The \OPENTYPE\ specification has some vague remarks about applying italic
correction between the last in a series of slanted shapes and operators, as well
as positioning limits, and suggests that it relates to relative super- and
subscript positioning. It doesn't mention that the correction is to be added to
the width. However, the main mechanism for anchoring script are these top and
bottom edge kerns. It's why in fonts that provide these, we are unlikely to find
italic correction unless it is used for positioning limits.

It is for that reason that an engine can produce reasonable results for fonts
that either provide italics or provide kerns for anchoring: having both on the
same glyph would mean troubles. It means that we can configure the engine options
to add italic correction as well as kerns, assuming distinctive usage of those
features. For a font that uses both we need to make a choice (this is possible,
since we can configure options per font). But that will never lead to always nicely
typeset math. In fact, without tweaks many fonts will look right because in
practice they use some mixture. But we are not aiming at partial success, we want
all to look good.

Here is another thing to keep in mind (although now we are guessing a bit). There
is a limited number of heights and depths in \TEX\ fonts possible (16), but four
times as many italic corrections can be defined (64). Is it because Don Knuth
wanted to properly position the sub- and subscripts? Adding italic correction to
the width is pretty safe: shapes should not overlap. Choosing the right width for
a subscript needs more work because it's is more visual. In the end we have a
width that is mostly driven by superscript placement! That also means that as
soon as we remove the italic correction things start looking bad. In fact,
because also upright math characters have italic correction the term \quote
{italic} is a bit of a cheat: it's all about script positioning and has little to
do with the slope of the shapes.

One of the reasons why for instance spacing between an italic shape and an
upright one in \TEX\ works out okay is that in most cases they come from a
different font, which can be used as criterium for keeping the correction;
between a sequence of same|-|font characters it gets removed. However, in
\OPENTYPE\ math there is a good chance that all comes from the same font (at
least in \CONTEXT), unless one populates many families as in traditional \TEX. We
have no clue how other macro packages deal with this but it might well be the
case that using many families (one for each alphabet) works better in the end.
The engine is really shape and alphabet agnostic, but one can actually wonder if
we should add a glyph property indicating the distinctive range. It would provide
engine level control over a run of glyphs (like multiplying a variable
represented by a greek alpha by another variable presented by an upright b).

But glyph properties cannot really be used here because we are still dealing with
characters when the engine transforms the noad list into a node list. So, when we
discussed this, we started wondering how the engine could know about a specific
shape (and tilt) property at all, and that brought us to pondering about an
additional axis of options. We already group characters in classes, but we can
also group them with properties like \typ {tilted}, \typ {dotless}, \typ {bold}.
When we pair atoms we can apply options, spacing and such based on the specific
class pair, and we can do something similar with category pairs. It basically
boils down to for instance \type {\mccode} that binds a character to a category.
Then we add a command like \typ {\setmathcategorization} (analogue to \typ
{\setmathspacing}) that binds options to pairs of categories. An easier variant
of this might be to let the \type {\mccode} carry a (bit)set of options that then
get added to the already existing options that can be bound to character noads as
we create them. This saves us some configuration. Deciding what suits best
depends on what we want to do: the fact that \TEX\ doesn't do this means that
probably no one ever gave it much thought, but once we do have this mechanism it
might actually trigger demand, if only by staring at existing documents where
characters of a different kind sit next to each other (take this \quote {a}
invisible times \quote {x}). It would not be the first time that (in \CONTEXT)
the availability of some feature triggers creative (ab)usage.

Because the landscape has settled, because we haven't seen much fundamental
evolution in \OPENTYPE\ math, because in general \TEX\ math doesn't really
evolve, and because \CONTEXT\ in the past has not been seen as suitable for
 math, we can, as mentioned before, basically decide what approach we
follow. So, that is why we can pick up on this italic correction in a more
drastic way: we can add the correction to the width, thereby creating a nicely
bounded glyph, and moving the original correction to the right bottom kern, as
that is something we already support. In fact, this feature is already available,
we only had to add setting the right bottom kern. The good news is that we don't
need to waste time on trying to get something extra in the font format, which is
unlikely to happen anyway after two decades.

It is worth noticing that when we were exploring this as part of using \METAPOST\
to analyze and visualize these aspects, we also reviewed the \typ {wipeitalics}
tweak and wondered if, in retrospect, it might be a dangerous one when applied to
alphabets (for digits and blackboard bold letters it definitely makes
sense): it can make traditional super- and subscript anchoring less optimal.
However, for some fonts we found that improper bounding boxes can badly interfere
anyway: for instance the upright \quote {f} in EBGaramond sticks out left and
right, and has staircase kerns that make scripts overlap. The right top of the
shape sticks out a lot and that is because the text font variant is used. We already decided to
add a \typ {moveitalics} tweak that moves italic kerns into the
width and then setting a right bottom kern that compensates it that can be a
pretty good starting point for our further exploration of optimal kerns at the
corners. That tweak also fixes the side bearings (negative llx) and compensates
left kerns (when present) accordingly. An additional \typ {simplifykerns} tweak
can later migrate staircase kerns to simple kerns.

So, does that free us from tweaks like \typ {dimensions} and \typ {kerns}? Not
completely. But we can forget about the italic correction
in most cases. We have to set up less lower right kerns and maybe correct a few.
It is just a more natural solution. So how about these kerns that we need to
define? After all, we also have to deal with proper top kerns, and like to add
kerns that are not there simply because the mentioned comprise between width,
italic and the combination was impossible. More about that in the next section.

\stopsection

\startsection[title=Kerning]

In the next pictures we will try to explain more visual what we have in mind and
are experimenting with as we write this. In the traditional approach we have
shapes that can communicate the width, height, depth and italic correction to the
engine so that is what the engine can work with. The engine also has the
challenge to anchor subscripts and superscripts in a visual pleasing way.

\startMPdefinitions
    numeric UsedUnit ; UsedUnit = 1mm ;
    numeric UsedWidth ; UsedWidth := 10UsedUnit ;
    numeric UsedItalic ; UsedItalic := 2UsedUnit ;
    numeric UsedScript ; UsedScript = 5UsedUnit;
    picture LeftCharA ; LeftCharA := image(
        draw origin -- (UsedWidth,UsedWidth)
            withpen pencircle scaled 2UsedUnit
            withcolor .4white ;
        path p ; p := boundingbox currentpicture ;
        draw rightboundary currentpicture
            bottomenlarged -5UsedUnit
            withpen pencircle scaled .5UsedUnit ;
        setbounds currentpicture to p ;
        draw origin
            withpen pencircle scaled 1UsedUnit
            withcolor .1white ;
        setbounds currentpicture to boundingbox currentpicture
            leftenlarged -UsedItalic
            rightenlarged -UsedItalic ;
        draw boundingbox currentpicture
            withpen pencircle scaled .1UsedUnit ;
    ) ;
    picture RightCharA ; RightCharA := image(
        draw (0,UsedWidth) -- (UsedWidth,0)
            withpen pencircle scaled 2UsedUnit
            withcolor .6white ;
        path p ; p := boundingbox currentpicture ;
        draw rightboundary currentpicture
            bottomenlarged -5UsedUnit
            withpen pencircle scaled .5UsedUnit ;
        setbounds currentpicture to p ;
        draw origin
            withpen pencircle scaled 1UsedUnit
            withcolor .1white ;
        setbounds currentpicture to boundingbox currentpicture
            leftenlarged -UsedItalic
            rightenlarged -UsedItalic ;
        draw boundingbox currentpicture
            withpen pencircle scaled .1UsedUnit ;
    ) ;
    picture LeftCharB ; LeftCharB := image(
        draw origin -- (UsedWidth,UsedWidth)
            withpen pencircle scaled 2UsedUnit
            withcolor .4white ;
        path p ; p := boundingbox currentpicture ;
        draw origin
            withpen pencircle scaled 1UsedUnit
            withcolor .1white ;
        draw boundingbox currentpicture
            withpen pencircle scaled .1UsedUnit ;
        draw lrcorner p
            shifted (-UsedItalic,0)
            withpen pencircle scaled 1UsedUnit
            withcolor .1white ;
        draw urcorner p
            withpen pencircle scaled 1UsedUnit
            withcolor .1white ;
        setbounds currentpicture to p ;
    ) ;
    picture RightCharB ; RightCharB := image(
        draw (0,UsedWidth) -- (UsedWidth,0)
            withpen pencircle scaled 2UsedUnit
            withcolor .6white ;
        path p ; p := boundingbox currentpicture ;
        draw origin
            withpen pencircle scaled 1UsedUnit
            withcolor .1white ;
        draw boundingbox currentpicture
            withpen pencircle scaled .1UsedUnit ;
        draw lrcorner p
            shifted (-UsedItalic,0)
            withpen pencircle scaled 1UsedUnit
            withcolor .1white ;
        draw urcorner p
            withpen pencircle scaled 1mm
            withcolor .1white ;
        setbounds currentpicture to p ;
    ) ;
    picture SuperScript ; SuperScript := image(
        draw unitsquare scaled UsedScript
            shifted (0,-UsedScript/2)
    ) ;
    picture SubScript ; SubScript := image(
        draw unitsquare scaled UsedScript
            shifted (0,-UsedScript/2)
    ) ;
    def WidenResultA =
        setbounds currentpicture to boundingbox currentpicture
            leftenlarged 6UsedUnit
            rightenlarged 6UsedUnit;
    enddef ;
    def WidenResultB =
        setbounds currentpicture to boundingbox currentpicture
            topenlarged .5UsedScript
            leftenlarged 6UsedUnit
            rightenlarged 6UsedUnit;
    enddef ;
\stopMPdefinitions

\startlinecorrection
    \startcombination[nx=3,ny=1]
        \startcontent
            \startMPcode
                draw LeftCharA ;
                draw RightCharA xshifted (UsedWidth+UsedItalic+3UsedUnit) ;
                WidenResultA ;
            \stopMPcode
        \stopcontent
        \startcaption
            two characters
        \stopcaption
        \startcontent
            \startMPcode
                draw LeftCharA ;
                draw RightCharA xshifted UsedWidth ;
                WidenResultA ;
            \stopMPcode
        \stopcontent
        \startcaption
            width only
        \stopcaption
        \startcontent
            \startMPcode
                draw LeftCharA ;
                draw RightCharA xshifted (UsedWidth+UsedItalic) ;
                WidenResultA ;
            \stopMPcode
        \stopcontent
        \startcaption
            with italic
        \stopcaption
    \stopcombination
\stoplinecorrection

In this graphic we show two pseudo characters. The shown bounding box indicates
the width as seen by the engine. An example of such a shape is the math italic~f,
and as it is used a lot in formulas it is also one of the most hard ones to handle
when it comes to spacing: in nearly all fonts the right top sticks out and in
some fonts the left part also does that. Imagine how that works out with scripts,
fences and preceding characters.

When we put two such characters together they will overlap, and this is why we need
to add the italic correction. That is also why the \TEX\ documentation speaks in
terms of \quotation {always add the italic correction to the width}. This also
means that we need to remove it occasionally, something that you will notice when
you study for instance the \LUATEX\ source, that has a mix of traditional and
\OPENTYPE\ code paths. Actually, compensating can either be done by changing the
width property of a glyph node or by explicitly adding a kern. In \LUAMETATEX\ we
always add real kerns because we can then trace better.

The last graphic in the above set shows how we compensate the width for the bit
that sticks out. It also shows that we definitely need to take neighboring shapes
into account when we determine the width and italic correction, especially when
the later is {\em not} applied (read: removed).

\startlinecorrection
    \startcombination[nx=3,ny=1]
        \startcontent
            \startMPcode
                draw LeftCharA ;
                path p ; p := boundingbox currentpicture ;
                draw SuperScript
                    shifted urcorner p xshifted UsedScript ;
                draw SubScript
                    shifted lrcorner p xshifted UsedScript  ;
                WidenResultB ;
            \stopMPcode
        \stopcontent
        \startcaption
            kernel
        \stopcaption
        \startcontent
            \startMPcode
                draw LeftCharA ;
                path p ; p := boundingbox currentpicture ;
                draw SuperScript
                    shifted urcorner p ;
                draw SubScript
                    shifted lrcorner p ;
                WidenResultB ;
            \stopMPcode
        \stopcontent
        \startcaption
            subscript
        \stopcaption
        \startcontent
            \startMPcode
                draw LeftCharA ;
                path p ; p := boundingbox currentpicture ;
                draw SuperScript
                    shifted urcorner p
                    xshifted UsedItalic ;
                draw SubScript
                    shifted lrcorner p ;
                WidenResultB ;
            \stopMPcode
        \stopcontent
        \startcaption
            superscript
        \stopcaption
    \stopcombination
\stoplinecorrection

Here we anchored a super- and subscript. The subscript position it tight to the
advance width, again indicated by the box. The superscript however is moved by
the italic correction and in the engine additional spacing before and after can
be applied as well, but we leave that for now. It will be clear that when the
font designer chooses the width and italic correction, the fact that scripts get
attached has to be taken into account.

\startlinecorrection
    \startcombination[nx=2,ny=1]
        \startcontent
            \startMPcode
                draw LeftCharB ;
                draw RightCharB xshifted (UsedWidth+UsedItalic+3UsedUnit) ;
                WidenResultA ;
            \stopMPcode
        \stopcontent
        \startcaption
            two characters
        \stopcaption
        \startcontent
            \startMPcode
                draw LeftCharB ;
                draw RightCharB xshifted (UsedWidth+UsedItalic) ;
                WidenResultA ;
            \stopMPcode
        \stopcontent
        \startcaption
            width only
        \stopcaption
    \stopcombination
\stoplinecorrection

In this graphic we combine the italic correction with the width. Keep in mind
that in these examples we use tight values but in practice that correction can
also add some extra right side bearing (white space). This addition is an
operation that we can do when loading a font. At the same time we also compensate
the left edge for which we can use the x coordinate of the left corner of the
glyphs real bounding box. The advance width starts at zero and that corner is
then left of the origin. By looking at shapes we concluded that in most cases
that shift is valid for usage in math where we don't need that visual overlap. In
fact, when we tested some of that we found that the results can be quite horrible
when you don't do that; not all fonts have left bottom kerning implemented.

The dot at the right is actually indicating the old italic correction. Here we
let it sit on the edge but as mentioned there can be additional (or maybe less)
italic correction than tight.

\startlinecorrection
    \startcombination[nx=3,ny=1]
        \startcontent
            \startMPcode
                draw LeftCharB ;
                path p ; p := boundingbox currentpicture ;
                draw SuperScript
                    shifted urcorner p xshifted UsedScript ;
                draw SubScript
                    shifted lrcorner p xshifted UsedScript ;
                WidenResultB ;
            \stopMPcode
        \stopcontent
        \startcaption
            kernel
        \stopcaption
        \startcontent
            \startMPcode
                draw LeftCharB ;
                path p ; p := boundingbox currentpicture ;
                draw SuperScript
                    shifted urcorner p ;
                draw SubScript
                    shifted lrcorner p ;
                WidenResultB ;
            \stopMPcode
        \stopcontent
        \startcaption
            superscript
        \stopcaption
        \startcontent
            \startMPcode
                draw LeftCharB ;
                path p ; p := boundingbox currentpicture ;
                draw SuperScript
                    shifted urcorner p ;
                draw SubScript
                    shifted (-UsedItalic,0)
                    shifted lrcorner p ;
                WidenResultB ;
            \stopMPcode
        \stopcontent
        \startcaption
            subscript
        \stopcaption
    \stopcombination
\stoplinecorrection

Finally we add the scripts here. This time we position the superscript and
subscript at the top and bottom anchors. The bottom anchor is, as mentioned, the
old italic correction, and the top one currently just the edge. And this is what
our next project is about: identify the ideal anchors and use these instead.

In the \CONTEXT\ goodie files (the files that tweak the math fonts runtime) we
can actually already set these top and bottom anchors and the engine will use
them when set. These kerns are not to be confused with the more complicated
staircase kerns. They are much simpler and lightweight. The fact that we already
have them makes it relatively easy to experiment with this.

It must be noted that we talk about three kinds of kerns: inter character kerns,
corner kerns and staircase kerns. We can set them all up with tweaks but so far
we only did that for the most significant ones, like integrals. The question is:
can we automate this? We should be careful because the bad top accent anchors in
the \TEXGYRE\ fonts demonstrate how flawed heuristics can be. Interesting is that
the developers of these font used \METAPOST\ and are highly qualified in that
area. And for us using \METAPOST\ is also natural!

The approach that we follow is somewhat interactive. When working on the math
update we like to chat (with zoom) about these matters. We discuss and explore
plenty and with these kerns we do the same. Because \METAPOST\ produces such nice
and crispy graphics, and because \METAFUN\ is well integrated into \CONTEXT\ we
can link all these subsystems and just look at what we get. A lot is about
visualization: if we discuss so called \quote {grayness} in the perspective of
kerning, we end up with calculating areas, then look at what it tells us and as a
next step figure out some heuristic. And of course we challenge each other into
new trickery.

% THIS WILL BECOME A MODULE!

\startluacode
local formatters = string.formatters

local glyph  = nil
local mpdata = nil

local f_boundingbox = formatters["((%N,%N)--(%N,%N)--(%N,%N)--(%N,%N)--cycle)"]
local f_vertical    = formatters["((%N,%N)--(%N,%N))"]

function mp.lmt_glyphshape_start(id,character)
    if type(id) == "string" then
        id = fonts.definers.internal({ name = id } ,"<module:fonts:shapes:font>")
    end
    local fontid       = (id and id ~= 0 and id) or font.current()
    local shapedata    = fonts.hashes.shapes[fontid] -- by index
    local characters   = fonts.hashes.characters[fontid] -- by unicode
    local descriptions = fonts.hashes.descriptions[fontid] -- by unicode
    local shapeglyphs  = shapedata.glyphs or { }
    if type(character) == "string" and character ~= "" then
        local hex = string.match(character,"^0x(.+)")
        if hex then
            character = tonumber(hex,16)
        else
            character = utf.byte(character)
        end
    else
        character = tonumber(character)
    end
    local chardata = characters[character]
    local descdata = descriptions[character]
    if chardata then
        glyph = shapeglyphs[chardata.index]
        if glyph and (glyph.segments or glyph.sequence) and not glyph.paths then
            local units  = shapedata.units or 1000
            local factor = 100/units
            local width  = (descdata.width or 0)  * factor
            local height = descdata.boundingbox[4] * factor
            local depth  = descdata.boundingbox[2] * factor
            local math   = descdata.math
            local italic = (math and math.italic or 0) * factor
            local accent = (math and math.accent or 0) * factor
            mpdata = {
                paths       = fonts.metapost.paths(glyph,factor),
                boundingbox = fonts.metapost.boundingbox(glyph,factor),
                baseline    = fonts.metapost.baseline(glyph,factor),
                width       = width,
                height      = height,
                depth       = depth,
                italic      = italic,
                accent      = accent,
                usedbox     = f_boundingbox(0,depth,width,depth,width,height,0,height),
                usedline    = f_vertical(0,0,width,0),
            }
        end
    else
        print("NO",id,character)
    end
end

function mp.lmt_glyphshape_stop()
    glyph  = nil
    mpdata = nil
end

function mp.lmt_glyphshape_n()
    if mpdata then
        mp.print(#mpdata.paths)
    else
        mp.inject.numeric(0)
    end
end

function mp.lmt_glyphshape_path(i)
    if mpdata then
        mp.print(mpdata.paths[i])
    else
        mp.inject.pair(0,0)
    end
end

function mp.lmt_glyphshape_boundingbox()
    if mpdata then
        mp.print(mpdata.boundingbox)
    else
        mp.inject.pair(0,0)
    end
end
function mp.lmt_glyphshape_usedbox()
    if mpdata then
        mp.print(mpdata.usedbox)
    else
        mp.inject.pair(0,0)
    end
end

function mp.lmt_glyphshape_baseline()
    if mpdata then
        mp.print(mpdata.baseline)
    else
        mp.inject.pair(0,0)
    end
end
function mp.lmt_glyphshape_usedline()
    if mpdata then
        mp.print(mpdata.usedline)
    else
        mp.inject.pair(0,0)
    end
end

function mp.lmt_glyphshape_width () mp.print(mpdata and mpdata.width  or 0) end
function mp.lmt_glyphshape_depth () mp.print(mpdata and mpdata.depth  or 0) end
function mp.lmt_glyphshape_height() mp.print(mpdata and mpdata.height or 0) end
function mp.lmt_glyphshape_italic() mp.print(mpdata and mpdata.italic or 0) end
function mp.lmt_glyphshape_accent() mp.print(mpdata and mpdata.accent or 0) end

\stopluacode

\startMPdefinitions
    presetparameters "glyphshape" [
      % id        = "",
      % character = "",
        shape       = true,
        boundingbox = false,
        baseline    = false,
        usedline    = true,
        usedbox     = true,
    ] ;

def lmt_glyphshape = applyparameters "glyphshape" "lmt_do_glyphshape" enddef ;

vardef glyphshape_start(expr id, character) =
    lua.mp.lmt_glyphshape_start(id, character) ;
enddef ;

vardef glyphshape_stop         = lua.mp.lmt_glyphshape_stop() ;      enddef ;
vardef glyphshape_n            = lua.mp.lmt_glyphshape_n()           enddef ;
vardef glyphshape_path(expr i) = lua.mp.lmt_glyphshape_path(i)       enddef ;
vardef glyphshape_boundingbox  = lua.mp.lmt_glyphshape_boundingbox() enddef ;
vardef glyphshape_baseline     = lua.mp.lmt_glyphshape_baseline()    enddef ;
vardef glyphshape_usedbox      = lua.mp.lmt_glyphshape_usedbox()     enddef ;
vardef glyphshape_usedline     = lua.mp.lmt_glyphshape_usedline()    enddef ;
vardef glyphshape_width        = lua.mp.lmt_glyphshape_width()       enddef ;
vardef glyphshape_height       = lua.mp.lmt_glyphshape_height()      enddef ;
vardef glyphshape_depth        = lua.mp.lmt_glyphshape_depth()       enddef ;
vardef glyphshape_italic       = lua.mp.lmt_glyphshape_italic()      enddef ;
vardef glyphshape_accent       = lua.mp.lmt_glyphshape_accent()      enddef ;

vardef lmt_do_glyphshape =
    image (
        pushparameters "glyphshape" ;
            lua.mp.lmt_glyphshape_start(getparameter "id", getparameter "character") ;
            if getparameter "shape" :
                draw for i=1 upto lua.mp.lmt_glyphshape_n() :
                    lua.mp.lmt_glyphshape_path(i) &&
                endfor cycle ;
            fi ;
            if getparameter "boundingbox" :
                draw
                    lua.mp.lmt_glyphshape_boundingbox()
                    withcolor red
                ;
            fi ;
            if getparameter "usedline" :
                draw
                    lua.mp.lmt_glyphshape_usedline()
                    withcolor green
                ;
            fi ;
            if getparameter "usedbox" :
                draw
                    lua.mp.lmt_glyphshape_usedbox()
                    withcolor blue
                ;
            fi ;
            lua.mp.lmt_glyphshape_stop() ;
        popparameters ;
    )
enddef ;

\stopMPdefinitions

\startplacefigure[location=none]
\startMPcode[offset=1dk]
picture leftchar ;
picture rightchar ;
path leftbbox ;
path rightbbox ;
numeric leftitalic ;
numeric rightitalic ;
numeric leftaccent ;
numeric rightaccent ;

numeric N ; N := 50 ;

glyphshape_start("file:texgyrebonum-math.otf", "0x1D453") ;
    leftchar   := image (draw for i=1 upto glyphshape_n : glyphshape_path(i) && endfor cycle ;) ;
    leftbbox   := glyphshape_usedbox ;
    leftaccent := glyphshape_accent ;
    leftitalic := xpart urcorner leftbbox - glyphshape_italic ;
glyphshape_stop ;
glyphshape_start("file:texgyrebonum-math.otf", "0x1D45A") ;
    rightchar := image (draw for i=1 upto glyphshape_n : glyphshape_path(i) && endfor cycle ;) ;
    rightbbox := glyphshape_usedbox ;
    rightaccent := glyphshape_accent ;
    rightitalic := xpart urcorner rightbbox - glyphshape_italic ;
glyphshape_stop ;

rightchar := rightchar xshifted (xpart lrcorner leftbbox) ;
rightbbox := rightbbox xshifted (xpart lrcorner leftbbox) ;

rightaccent := rightaccent  + xpart lrcorner leftbbox ;
rightitalic := rightitalic  + xpart lrcorner leftbbox ;

numeric d ; d := (xpart lrcorner leftbbox) - leftitalic ;
rightchar := rightchar shifted (d,0);
rightbbox := rightbbox shifted (d,0);

draw leftbbox  withcolor 0.5white ;
draw rightbbox withcolor 0.5white ;
draw leftchar  withpen pencircle scaled 1 ;
draw rightchar withpen pencircle scaled 1 ;

numeric miny, maxy ;

miny := max(ypart lrcorner leftbbox, ypart llcorner rightbbox) ;
maxy := min(ypart urcorner leftbbox, ypart ulcorner rightbbox) ;

path testv ; testv := ((0,miny) -- (0,maxy)) xshifted (xpart lrcorner leftbbox) ;

% %   testv := testv shifted (d,0);
% draw testv withcolor darkred ;

path midpath, leftintersections, rightintersections ;
pair leftintersection[], rightintersection[] ;

numeric yta ; yta := 0 ;
numeric minl ; minl := 1000 ;

for i = 1 upto (N-1) :
    midpath := (0, ypart point (i/N) along testv) -- (xpart urcorner rightbbox, ypart point (i/N) along testv);
    for j within leftchar :
        midpath := midpath cutbeforelast pathpart j ;
    endfor
    for j within rightchar :
        midpath := midpath cutafterfirst pathpart j ;
    endfor

    if ( (i = 1) or ((xpart point 1 of midpath) - (xpart point 0 of midpath) < minl) ) :
        minl := (xpart point 1 of midpath) - (xpart point 0 of midpath) ;
    fi

    if ((xpart point 0 of midpath) < eps) or ((xpart point 1 of midpath) > ((xpart urcorner rightbbox) - eps)) :
        draw midpath withpen pencircle scaled 1 withcolor 0.1[white,darkgreen] withtransparency (1,0.5) ;
        midpath := (point 0 of midpath) && cycle ;
    fi

    draw midpath withcolor 0.4[white,darkgreen] ;
    draw point 0 of midpath withpen pencircle scaled 1 withcolor darkgreen ;
    draw point 1 of midpath withpen pencircle scaled 1.25 withcolor darkgreen ;

    yta := yta + (1/N)*((xpart point 1 of midpath) - (xpart point 0 of midpath)) ;
endfor

drawarrow (origin -- ((xpart lrcorner leftbbox) - leftitalic,0)) shifted (urcorner leftbbox) withcolor "orange" ;
drawarrow (origin -- ((xpart lrcorner rightbbox) - rightitalic - d,0)) shifted (urcorner rightbbox) withcolor "orange" ;

% draw (leftaccent,   (ypart urcorner leftbbox )) withcolor "darkblue" withpen pencircle scaled 3 ;
% draw (rightaccent + d,  (ypart urcorner rightbbox)) withcolor "darkblue" withpen pencircle scaled 3 ;

\stopMPcode

\stopplacefigure


We are sure that getting this next stage in the perfection of math typesetting in
\CONTEXT\ and \LUAMETATEX\ will take quite some time, but the good news is that
all machinery is in place. We also have to admit that it all might not work out
well, so that we stick to what we have now. But at least we had the fun then. And
it is also a nice example of both applying mathematics and programming graphics.

That said, if it works out well, we can populate the goodie files with output
from \METAPOST, tweak a little when needed, and that saves us some time. One
danger is that when we try to improve rendering the whole system also evolves
which in turn will give different output, but we can always implement all this as
features because after all \CONTEXT\ is very much about configuration. And it
makes nice topics for articles and talks too!

The kerns discussed in the previous paragraphs are not the ones that we
find in \OPENTYPE\ fonts. There we have \quote {staircase} kerns that stepwise go
up or down by height and kern. So, one can have different kerns depending on the
height and sort of follow the shape. This permits quite precise kerning between
for instance the right bottom of a kernel and left top of a subscript. So how is
that used in practice? The reference font Cambria has these kerns but close
inspection shows that these are not that accurate. Fortunately, we never enter
the danger zone with subscripts, because other parameters prevent that. If we look
at for instance Lucida and Garamond, then we see that their kerns are mostly used
as side bearing, and not really as staircase kerns.

\usemodule[s][fonts-shapes]

\startlinecorrection
\startcombination[nx=5,ny=1]
    \startcontent
        \ShowGlyphShape{name:cambria-math}{100bp}{0x1D6FD}
    \stopcontent
    \startcaption
        \type {U+1D6FD}
    \stopcaption
    \startcontent
        \ShowGlyphShape{name:cambria-math}{100bp}{0x003A4}
    \stopcontent
    \startcaption
        \type {U+003A4}
    \stopcaption
    \startcontent
        \ShowGlyphShape{name:cambria-math}{100bp}{0x1D4CC}
    \stopcontent
    \startcaption
        \type {U+1D4CC}
    \stopcaption
    \startcontent
        \ShowGlyphShape{name:cambria-math}{100bp}{0x1D6B8}
    \stopcontent
    \startcaption
        \type {U+1D6B8}
    \stopcaption
    \startcontent
        \ShowGlyphShape{name:cambria-math}{100bp}{0x1D70C}
    \stopcontent
    \startcaption
        \type {U+1D70C}
    \stopcaption
\stopcombination
\stoplinecorrection

In these figures you see a few glyphs from cambria with staircase kerns and
although we show them small you will notice that some kern boundaries touch the
shape. As subscripts never go that high it goes unnoticed but it also shows that
sticking to the lowest boundary makes sense.

We conclude that we can simplify these kerns, and just transform them into our
(upto four) corner kerns. It is unlikely that Cambria gets updates and that other
fonts become more advanced. One can even wonder if multiple steps really give
better results. The risk of overlap increases with more granularity because not
every pair of glyphs is checked. Also, the repertoire of math characters will
likely not grow and include shapes that differ much from what we can look at now.
Reducing these kerns to simple ones, that can easily be patched at will in a
goodie file, has advantages. We can even simplify the engine.

\stopsection

\startsection[title=Conclusion]

So how can we summarize the above? The first conclusion is that we can only get
good results when we runtime patch fonts to suite the engine and our (\CONTEXT)
need. The second conclusion is that we should seriously consider to drop (read:
ignore) most math font parameter and|/|or to reorganize them. There is no
need to be conforming, because these parameters are often not that well
implemented (thumb in mouth). The third conclusion (or observation) is that we
should get rid of the excessive use of italic correction, and go for our new
corner kerns instead. Last, we can conclude that it makes sense to explore how we
can use \METAPOST\ to analyze the shapes in such a way that we can improve inter
character kerning, corner kerns and maybe even, in a limited way, staircase kerns.

And, to come back to accents: very few characters need a top kern. Most can be
handled with centered anchors, and we need tweaks for margins and overshoot
anyway. The same is true for many other tweaks: they are there to stay.

This is how we plan to go forward:

\startitemize[packed]
    \startitem
        We pass no italic corrections in the math fonts to the engine,
        but instead we have four dedicated simple corner kerns, top and
        bottom anchors, and we also compensate negative left side bearing. We
        should have gone that route earlier (as follow up on a \MKIV\ feature)
        but were still in some backward compatibility mindset.
    \stopitem
    \startitem
        The \LUAMETATEX\ math engine might then be simplified by removing all
        code related to italic correction. Of course it hurts that we spent so
        much time on that over the years. We can anyway disable engine options
        related to italic correction in the \CONTEXT\ setup. Of course the engine
        is less old school generic then but that is the price of progress.
    \stopitem
    \startitem
        A default goodie file is applied that takes care of this when no goodie
        file is provided. We could do some in the engine, but there is no real
        need for that. We can simplify the mid 2022 goodie files because we have
        to fix less glyphs.
    \stopitem
    \startitem
        If we ever need italic correction (that is: backtrack) then we use the
        (new) \type {\mccode} option code that can identity sloped shapes. But,
        given that ignoring the correction between sloped shapes looks pretty bad,
        we can as well forget about this. After all, italic correction never
        really was about correcting italics, but more about anchoring scripts.
    \stopitem
    \startitem
        Staircase kerns can be reduced to simple corner kerns and the engine can
        be simplified a bit more. In the end, all we need is true widths and simple
        corner kerns.
    \stopitem
    \startitem
        We reorganize the math parameters and get rid of those that are not
        really font design dependent. This also removes a bit of overlap. This will
        be done as we document.
    \stopitem
    \startitem
        Eventually we can remove tweaks that are no longer needed in the new
        setup, which is a good thing as it also save us some documenting and
        maintenance.
    \stopitem
\stopitemize

All this will happen in the perspective of \CONTEXT\ and \LUAMETATEX\ but we
expect that after a few years of usage we can with confidence come to some
conclusions that can trickle back in the other engines so that other macro
packages can benefit from a somewhat radical different but reliable approach to
math rendering, one that works well with the old and new fonts.

\stopsection

\stopchapter

\stopcomponent