summaryrefslogtreecommitdiff
path: root/doc/context/sources/general/manuals/fonts/fonts-extensions.tex
diff options
context:
space:
mode:
Diffstat (limited to 'doc/context/sources/general/manuals/fonts/fonts-extensions.tex')
-rw-r--r--doc/context/sources/general/manuals/fonts/fonts-extensions.tex2729
1 files changed, 2729 insertions, 0 deletions
diff --git a/doc/context/sources/general/manuals/fonts/fonts-extensions.tex b/doc/context/sources/general/manuals/fonts/fonts-extensions.tex
new file mode 100644
index 000000000..afe6fd823
--- /dev/null
+++ b/doc/context/sources/general/manuals/fonts/fonts-extensions.tex
@@ -0,0 +1,2729 @@
+% language=uk
+
+\startcomponent fonts-extensions
+
+\environment fonts-environment
+
+\startchapter[title=Extensions][color=darkorange]
+
+\startsection[title=Introduction]
+
+One of the benefits of using \TEX\ is that you can add your own features and try
+to optimize the look and feel. Of course this can also go wrong and output can
+look pretty awful when you don't know what you're doing, but on the average it
+works out well. In many aspects the move to an \UNICODE\ data path and \OPENTYPE\
+fonts is a good one and solves a lot of problems with traditional \TEX\ engines
+and helps us to avoid complex and ugly hacks. But, if you look into the source
+code of \CONTEXT\ you will notice that there's still quite some complex coding
+needed. This is because we want to control mechanisms, even if it's only for
+dealing with some border cases. It's also the reason why \LUATEX\ is what it is:
+an extensible engine, building on tradition.
+
+As always with \TEX, fonts are an area where many tuning happens and this is also
+true in \CONTEXT. In this chapter some of the extensions will be discussed. Some
+extensions run on top of the (rather generic) feature mechanism and some are
+using dedicated code.
+
+\stopsection
+
+\startsection[title=Italics]
+
+Although \OPENTYPE\ fonts are more rich in features than traditional \TEX\ and
+\TYPEONE\ fonts, one important feature is missing: italic correction. This might
+sound strange but you need to keep in mind that in practice it's a feature that
+needs to be applied manually.
+
+\starttyping
+test {\it test\/} test
+\stoptyping
+
+It is possible to automate this mechanism and this is what the \type {\em} command
+does in \MKII:
+
+\starttyping
+test {\em test} test
+\stoptyping
+
+This command knows that it switches to italic (or slanted) and when used nested it
+knows to switch back. It also knows if a bold italic or slanted font is used. Therefore
+it can add italic correction between an italic and upright shape.
+
+An italic correction is bound to a glyph and bound to a font. In \in {figure}
+[latinmodern-italic] we see how an italic shape extends out of the bounding box.
+This is not the case in Dejavu: watch \in {figure} [dejavu-italic].
+
+\startplacefigure[reference=latinmodern-italic,title={Italic overshoot in Latin Modern.}]
+ \startcombination
+ \startcontent
+ \backgroundline[gray]{\color[maincolor]{\definedfont[lmroman10-regular*default sa 8]test}}
+ \stopcontent
+ \startcaption
+ Latin Modern Roman Regular
+ \stopcaption
+ \startcontent
+ \backgroundline[gray]{\color[maincolor]{\definedfont[lmroman10-italic*default sa 8]test}}
+ \stopcontent
+ \startcaption
+ Latin Modern Roman Italic
+ \stopcaption
+ \stopcombination
+\stopplacefigure
+
+\startplacefigure[reference=dejavu-italic,title={Italic overshoot in Dejavu Serif.}]
+ \startcombination
+ \startcontent
+ \backgroundline[gray]{\color[maincolor]{\definedfont[dejavuserif*default sa 8]test}}
+ \stopcontent
+ \startcaption
+ Dejavu Regular
+ \stopcaption
+ \startcontent
+ \backgroundline[gray]{\color[maincolor]{\definedfont[dejavuserifitalic*default sa 8]test}}
+ \stopcontent
+ \startcaption
+ Dejavu Italic
+ \stopcaption
+ \stopcombination
+\stopplacefigure
+
+This means that the application of italic correction should never been applied without
+knowing the font. In \in {figure} [italic-upright] we see an upright word following
+an italic. The space is determined by the upright one.
+
+\startplacefigure[reference=italic-upright,title={Italic followed by upright.}]
+ \startcombination
+ \startcontent
+ \backgroundline
+ [gray]
+ {\color[maincolor]{\definedfont[lmroman10-italic*default sa 4]test}
+ \color[maincolor]{\definedfont[lmroman10-regular*default sa 4]\space test}}
+ \stopcontent
+ \startcaption
+ Latin Modern
+ \stopcaption
+ \startcontent
+ \backgroundline
+ [gray]
+ {\color[maincolor]{\definedfont[dejavuserifitalic*default sa 4]test}%
+ \color[maincolor]{\definedfont[dejavuserif*default sa 4]\space test}}
+ \stopcontent
+ \startcaption
+ Dejavu
+ \stopcaption
+ \stopcombination
+\stopplacefigure
+
+Because it is to be used with care you need to enable this feature per font, You
+also need to explicitly enable the application of this correction. in \in {figure}
+[italic-one] we see italic correction in action.
+
+\startbuffer
+\definefontfeature
+ [italic]
+ [default]
+ [itlc=yes]
+\stopbuffer
+
+\typebuffer
+
+\getbuffer
+
+\startplacefigure[reference=italic-one,title={Italic correction.}]
+ \startcombination
+ \startcontent
+ \backgroundline
+ [maincolor]
+ {\color[white]{\definedfont[lmroman10-italic*default sa 4]test}
+ \color[white]{\definedfont[lmroman10-regular*default sa 4]\space test}}
+ \stopcontent
+ \startcaption
+ \backgroundline
+ [maincolor]
+ {\setupitaliccorrection[text]%
+ \color[white]{\definedfont[lmroman10-italic*italic sa 4]test}
+ \color[white]{\definedfont[lmroman10-regular*default sa 4]\space test}}
+ \stopcaption
+ \startcontent
+ \backgroundline
+ [maincolor]
+ {\color[white]{\definedfont[dejavuserifitalic*default sa 4]test}
+ \color[white]{\definedfont[dejavuserif*default sa 4]\space test}}
+ \stopcontent
+ \startcaption
+ \backgroundline
+ [maincolor]
+ {\setupitaliccorrection[text]%
+ \color[white]{\definedfont[dejavuserifitalic*italic sa 4]test}
+ \color[white]{\definedfont[dejavuserif*default sa 4]\space test}}
+ \stopcaption
+ \stopcombination
+\stopplacefigure
+
+This only signals the font constructor that additional italic information has
+to be added to the font metrics. As we already mentioned, the application of
+correction is driven by the \type {\/} primitive and that one consults the
+font metrics. Because the correction is not part of the original font
+metrics it is calculated automatically by adding a small value to the
+width. This value is calculated as follows:
+
+\starttyping
+factor * (parameters.uwidth or 40) / 2
+\stoptyping
+
+The \type {uwidth} parameter is sometimes part of the specification but if not, we
+take a reasonable default. The factor is under user control:
+
+\startbuffer
+\definefontfeature
+ [moreitalic]
+ [default]
+ [itlc=5]
+\stopbuffer
+
+\typebuffer
+
+\getbuffer
+
+This is demonstrated in \in {figure} [italic-two]. You will notice that for Latin
+Modern (any) correction makes sense, but for Dejavu it probably makes things look
+worse. This is why italic correction is disabled by default. When enabled there
+are several variants:
+
+\starttabulate[|Bl|l|]
+\NC global \NC always apply correction \NC \NR
+\NC text \NC only apply correction to text \NC \NR
+\NC always \NC apply correction between text and boxes \NC \NR
+\NC none \NC forget about correction \NC \NR
+\stoptabulate
+
+We keep track of the state using attributes but that comes at a (small) price in terms
+of extra memory and runtime. The \type {global} option simply assumes that we always
+need to check for correction (of course only for fonts that have this feature enables).
+In the given example we used:
+
+\starttyping
+\setupitaliccorrection
+ [text]
+\stoptyping
+
+You can combine keys:
+
+\starttyping
+\setupitaliccorrection
+ [global,always]
+\stoptyping
+
+\startplacefigure[reference=italic-two,title={Italic correction (factor 5).}]
+ \startcombination
+ \startcontent
+ \backgroundline
+ [maincolor]
+ {\color[white]{\definedfont[lmroman10-italic*default sa 4]test}
+ \color[white]{\definedfont[lmroman10-regular*default sa 4]\space test}}
+ \stopcontent
+ \startcaption
+ \backgroundline
+ [maincolor]
+ {\setupitaliccorrection[text]%
+ \color[white]{\definedfont[lmroman10-italic*italic sa 4]test}
+ \color[white]{\definedfont[lmroman10-regular*default sa 4]\space test}}
+ \stopcaption
+ \startcontent
+ \backgroundline
+ [maincolor]
+ {\color[white]{\definedfont[dejavuserifitalic*default sa 4]test}
+ \color[white]{\definedfont[dejavuserif*default sa 4]\space test}}
+ \stopcontent
+ \startcaption
+ \backgroundline
+ [maincolor]
+ {\setupitaliccorrection[text]%
+ \color[white]{\definedfont[dejavuserifitalic*italic sa 4]test}
+ \color[white]{\definedfont[dejavuserif*default sa 4]\space test}}
+ \stopcaption
+ \stopcombination
+\stopplacefigure
+
+The \type {itlc} feature controls if a font gets italic correction applied. In
+principle this is all that the user needs to do, given that the mechanism is
+enabled. These is an extra feature that controls the implementation:
+
+\starttabulate[|T|T|p|]
+\NC itlc \NC no \NC don't apply italic correction (default) \NC \NR
+\NC \NC yes \NC apply italic correction \NC \NR
+\NC textitalics \NC no \NC precalculate italic corrections (permit engine usage) \NC \NR
+\NC \NC yes \NC precalculate italic corrections (inhibit engine) \NC \NR
+\NC \NC delay \NC delay calculation of corrections \NC \NR
+\stoptabulate
+
+When \type {textitalics} is set to \type {yes} or \type {delay} the mechanism
+built into the engine is completely disabled. When set to \type {no} the engine
+can kick in but normally the alternative method takes precedence so that the
+engine sees no reason for further action. You can trace italic corrections with:
+
+\starttyping
+\enabletrackers[typesetters.italics]
+\stoptyping
+
+\stopsection
+
+\startsection[title=Bounding boxes]
+
+\startbuffer
+\definefontfeature
+ [withbbox]
+ [boundingbox=yes]
+
+\definefont
+ [FontWithBB]
+ [Normal*withbbox]
+\stopbuffer
+
+\start \getbuffer \FontWithBB
+
+There are some features that are rather useless and only make sense when figuring out
+issues. An example of such a feature is the following:
+
+\typebuffer
+
+This feature adds a background to each character in a font. In some fonts a glyph
+has a tight bounding box, while on other fonts some extra space is put on the left
+and right. Keep in mind that this feature blocks colored text.
+
+\par \stop
+
+\stopsection
+
+\startsection[title=Math italics]
+
+In the traditional \TEX\ fonts the width of a glyph was not the real width because
+one had to add the italic correction to it. The engine then juggles a bit with
+these properties. If you run into fonts that are designed this way, you can do this:
+
+\starttyping
+\definefontfeature[mathextra][italicwidths=yes] % fix latin modern
+\stoptyping
+
+This might make \type {$\left|V\right| = \left|W\right|$} look better for such
+fonts. Of course there can be side effects because these fonts assume a
+traditional engine.
+
+\stopsection
+
+\startsection[title=Slanting]
+
+This features (as well as the one described in the next section) are seldom used
+but provided because they were introduced in \PDFTEX.
+
+\startbuffer[define]
+\definefontfeature
+ [abitslanted]
+ [default]
+ [slant=.1]
+
+\definefontfeature
+ [abitmoreslanted]
+ [default]
+ [slant=.2]
+\stopbuffer
+
+\startbuffer[sample]
+\definedfont[Normal*abitslanted]This is a bit slanted.
+\definedfont[Normal*abitmoreslanted]And this is a bit more slanted.
+\stopbuffer
+
+\typebuffer[define,sample]
+
+The result is:
+
+\getbuffer[define]
+
+\startlines
+\getbuffer[sample]
+\stoplines
+
+\stopsection
+
+\startsection[title=Extending]
+
+The second manipulation is extending the shapes horizontally:
+
+\startbuffer[define]
+\definefontfeature
+ [abitbolder]
+ [default]
+ [extend=1.3]
+
+\definefontfeature
+ [abitnarrower]
+ [default]
+ [extend=0.7]
+\stopbuffer
+
+\startbuffer[sample]
+\definedfont[Normal*abitbolder]This looks a bit bolder.
+\definedfont[Normal*abitnarrower]And this is a bit narrower.
+\stopbuffer
+
+\typebuffer[define,sample]
+
+The result is:
+
+\getbuffer[define]
+
+\startlines
+\getbuffer[sample]
+\stoplines
+
+We can also combine slanting and extending:
+
+\startbuffer[define]
+\definefontfeature
+ [abitofboth]
+ [default]
+ [extend=1.3,
+ slant=.1]
+\stopbuffer
+
+\startbuffer[sample]
+\definedfont[Normal*abitofboth]This is a bit bolder but also slanted.
+\stopbuffer
+
+\typebuffer[define,sample]
+
+If you remember those first needle matrix printers you might recognize the
+next rendering:
+
+\getbuffer[define]
+
+\startlines
+\getbuffer[sample]
+\stoplines
+
+\stopsection
+
+\startsection[title=Fixing] % dimensions
+
+This is a rather special one. First we show a couple of definitions:
+
+\startbuffer
+\definefontfeature
+ [dimensions-a]
+ [default]
+ [dimensions={1,1,1}]
+
+\definefontfeature
+ [dimensions-b]
+ [default]
+ [dimensions={1,2,3}]
+
+\definefontfeature
+ [dimensions-c]
+ [default]
+ [dimensions={1,3,2}]
+
+\definefontfeature
+ [dimensions-d]
+ [default]
+ [dimensions={3,3,3}]
+\stopbuffer
+
+\typebuffer \getbuffer
+
+When you don't want a dimension to change you leave an entry empty, so
+valid entries are for instance: \type {,3,} and \type {1,,}.
+
+As usual you apply such a feature as follows:
+
+\starttyping
+\definefont[MyFont][Serif*dimensions-a sa 2]
+\stoptyping
+
+Alternatively you can use such a feature on its own:
+
+\starttyping
+\definefontfeature
+ [dimensions-333]
+ [dimensions={3,3,3}]
+\definefont[MyFont][Serif*default,dimensions-333 sa 2]
+\stoptyping
+
+In \in {figure} [dimensions-side-by-side] you see these four definitions in
+action. The leftmost rendering is the default rendering. The three numbers in the
+definitions represent the width (in em), height and depth (in ex).
+
+\startplacefigure[reference={dimensions-side-by-side},title={Freezing dimensions of glyphs.}]
+ \startcombination[5*1]
+ \startcontent \hbox to 7em {\hss\ruledhbox{\definedfont[Serif*default sa 2]g}\hss}\stopcontent \startcaption default \stopcaption
+ \startcontent \hbox to 7em {\hss\ruledhbox{\definedfont[Serif*dimensions-a sa 2]g}\hss}\stopcontent \startcaption \hbox{1em 1ex 1ex} \stopcaption
+ \startcontent \hbox to 7em {\hss\ruledhbox{\definedfont[Serif*dimensions-b sa 2]g}\hss}\stopcontent \startcaption \hbox{1em 2ex 3ex} \stopcaption
+ \startcontent \hbox to 7em {\hss\ruledhbox{\definedfont[Serif*dimensions-c sa 2]g}\hss}\stopcontent \startcaption \hbox{1em 3ex 2ex} \stopcaption
+ \startcontent \hbox to 7em {\hss\ruledhbox{\definedfont[Serif*dimensions-d sa 2]g}\hss}\stopcontent \startcaption \hbox{3em 3ex 3ex} \stopcaption
+ \stopcombination
+\stopplacefigure
+
+This feature only makes sense for fonts that need a fixed width, like the
+\CJK\ fonts that are used for asian scripts. Normally those fonts already
+have fixed dimensions, but this feature can be used to fix problematic
+fonts or add some more space. However, for such large fonts this also brings a
+larger memory footprint.
+
+A special case is the following:
+
+\startbuffer
+\definefontfeature
+ [dimensions-e]
+ [dimensions=strut]
+\stopbuffer
+
+\typebuffer \getbuffer
+
+This will make the height and depth the same as the {\em current} strut height
+and depth:
+
+\startbuffer
+\ruledhbox{\definedfont[Serif*default,dimensions-e at 8pt]clipped}
+\ruledhbox{\definedfont[Serif*default,dimensions-e at 12pt]clipped}
+\ruledhbox{\definedfont[Serif*default,dimensions-e at 24pt]clipped}
+\stopbuffer
+
+\typebuffer
+
+The dimensions are (in this case) limited:
+
+\startlinecorrection[blank] \dontleavehmode \hpack{\maincolor\inlinebuffer} \stoplinecorrection
+
+Another special case is \type {dimensions=mono} which will make an characters the
+fonts em|-|width. This is handy when you define font fallbacks where glyphs come
+from a non monospaced font.
+
+\stopsection
+
+\startsection[title=Unicoding]
+
+Nowadays we will mostly use fonts that ship with a \UNICODE\ aware encoding. And
+in \CONTEXT, even if we use a \TYPEONE\ font, it gets mapped onto \UNICODE.
+However, there are some exceptions, for instance the Zapf Dingbats in \TYPEONE\
+format. These have a rather obscure private encoding and the glyph names run from
+\type {a1} upto \type {a206} and have no relation to what the glyph represents.
+
+In the case of Dingbats we're somewhat lucky that they ended up in \UNICODE, so
+we can relocate the glyphs to match their rightful place. This is done by means
+of a goodies file. We already discussed this in \in {section} [goodies] so we
+only repeat the usage.
+
+\startbuffer
+\definefontfeature
+ [dingbats]
+ [mode=base,
+ goodies=dingbats,
+ unicoding=yes]
+
+\definefontsynonym
+ [ZapfDingbats]
+ [file:uzdr.afm]
+ [features=dingbats]
+\stopbuffer
+
+\typebuffer \getbuffer
+
+I tend to qualify the Dingbat font in \TEX\ distributions as rather unstable
+because of name changes and them either or not being included. Therefore it's best to
+use the hard coded name because that triggers the most visible error message when
+the font is not found.
+
+A font like this can for instance be used with the glyph placement macros as is
+demonstrated below. In the last line we see that a direct \UTF\ input also works
+out well.
+
+\starttabulate[|||T|]
+\HL
+\NC \type{\getglyphdirect {ZapfDingbats*dingbats}{\number"2701}} \NC \getglyphdirect {ZapfDingbats*dingbats}{\number"2701} \NC \NC \NR
+\NC \type{\getglyphdirect {ZapfDingbats*dingbats}{\char"2701}} \NC \getglyphdirect {ZapfDingbats*dingbats}{\char"2701} \NC \NC \NR
+\NC \type{\getnamedglyphdirect{ZapfDingbats*dingbats}{a1}} \NC \getnamedglyphdirect{ZapfDingbats*dingbats}{a1} \NC \NC \NR
+\NC \type{\getnamedglyphdirect{ZapfDingbats*dingbats}{a11}} \NC \getnamedglyphdirect{ZapfDingbats*dingbats}{a11} \NC \NC \NR
+\HL
+\NC \type{\getglyphdirect {ZapfDingbats}{\number"2701}} \NC \getglyphdirect {ZapfDingbats}{\number"2701} \NC unknown \NC \NR
+\NC \type{\getglyphdirect {ZapfDingbats}{\char"2701}} \NC \getglyphdirect {ZapfDingbats}{\char"2701} \NC unknown \NC \NR
+\NC \type{\getnamedglyphdirect{ZapfDingbats}{a1}} \NC \getnamedglyphdirect{ZapfDingbats}{a1} \NC \NC \NR
+\NC \type{\getnamedglyphdirect{ZapfDingbats}{a11}} \NC \getnamedglyphdirect{ZapfDingbats}{a11} \NC \NC \NR
+\HL
+\NC \type{\definedfont[ZapfDingbats*dingbats]✁} \NC \definedfont[ZapfDingbats*dingbats]✁ \NC \NC \NR
+\HL
+\stoptabulate
+
+Keep in mind that fonts like Dejavu (that we use here as document font) already
+has these characters which is why it shows up in the verbose part of the table.
+
+\stopsection
+
+\startsection[title=Protrusion]
+
+Protrusion is a feature that \LUATEX\ inherits from \PDFTEX. It is sometimes
+referred to as hanging punctuation but in our case any character qualifies. Also,
+hanging is not frozen but can be tuned in detail. Currently the engine defines
+protrusion in terms of the emwidth which is unfortunate and likely to change.
+\footnote {In general the low level implementation can be optimized as there are
+better mechanisms in \LUATEX.}
+
+It is sometimes believed that protrusion improves for instance narrower columns,
+but I'm pretty sure that this is not the case. It is true that it is taken into
+account when breaking a paragraph into lines, and that we then have a little bit
+more width available, but at the same time it is an extra constraint: if we
+protrude we have to do it for each line (and the whole main body of text) so it's
+just a different solution space. The main reason for applying this feature is
+{\em not} that the lines look better or that we get better looking narrow lines
+but that the right and left margins look nicer. Personally I don't like half
+protrusion of punctuation and hyphens. Best is to have small values for regular
+characters to improve the visual appearance and use full protrusion for hyphens
+(and maybe punctuation).
+
+\startsubsubject[title=protrusion classes]
+
+In \CONTEXT\ we've always defined protrusion as a percentage of the width of a
+glyph. From \MKII\ we inherit the level of control as well as the ability to
+define vectors. The shared properties are collected in so called classes and the
+character specific properties in vectors. The following classes are predefined:
+
+\showprotrusionclass
+
+The names are used in the definitions:
+
+\starttyping
+\definefontfeature[default][protrusion=quality]
+\stoptyping
+
+Currently adding a class only has a \LUA\ interface.
+
+\startbuffer
+\startluacode
+fonts.protrusions.classes.myown = {
+ vector = 'myown',
+ factor = 1,
+}
+\stopluacode
+\stopbuffer
+
+\typebuffer \getbuffer
+
+\stopsubsubject
+
+\startsubsubject[title=protrusion vectors]
+
+Vectors are larger but not as large as you might expect. Only a subset of
+characters needs to be defined. This is because in practice only latin scripts
+are candidates and these scripts have glyphs that look a lot like each other. As
+we only operate on the horizontal direction characters like \quote
+{aàáâãäå} look the same from the left and right so we only have to define
+the protrusion for \quote {a}.
+
+As with classes, you can define your own vectors:
+
+\startbuffer
+\startluacode
+fonts.protrusions.vectors.myown = table.merged (
+ fonts.protrusions.vectors.quality,
+ {
+ [0x002C] = { 0, 2 }, -- comma
+ }
+)
+\stopluacode
+\stopbuffer
+
+\typebuffer \getbuffer
+
+\stopsubsubject
+
+\startsubsubject[title=protrusion vector pure]
+ \showprotrusionvector[name=pure]
+\stopsubsubject
+
+\startsubsubject[title=protrusion vector punctuation]
+ \showprotrusionvector[name=punctuation]
+\stopsubsubject
+
+\startsubsubject[title=protrusion vector alpha]
+ \showprotrusionvector[name=alpha]
+\stopsubsubject
+
+\startsubsubject[title=protrusion vector quality]
+ \showprotrusionvector[name=quality]
+\stopsubsubject
+
+\startsubsubject[title=examples of protrusion]
+
+Next we show the quality protrusion. For this we use \type {tufte.tex} as
+this one for sure will result in punctuation and other candidates for
+protrusion.
+
+\startbuffer[define]
+\definefontfeature
+ [whatever]
+ [default]
+ [protrusion=quality]
+
+\definefont[MyTestA][Serif*default at 10pt]
+\definefont[MyTestB][Serif*whatever at 10pt]
+\stopbuffer
+
+\startbuffer[example]
+\startoverlay
+ {\ruledvbox \bgroup
+ \hsize\textwidth
+ \MyTestA
+ \setupalign[normal]
+ \input{tufte}
+ \egroup}
+ {\ruledvbox \bgroup
+ \hsize\textwidth
+ \MyTestB
+ \setupalign[hanging,normal]
+ \maincolor
+ \input{tufte}
+ \egroup}
+\stopoverlay
+\stopbuffer
+
+\typebuffer[define]
+\getbuffer [define]
+
+We use the following example. The results are shown in \in {figure}
+[protrusion:quality]. The colored text is the protruding one.
+
+\typebuffer[example]
+
+\startplacefigure[reference=protrusion:quality,title=The difference between no protrusion and quality protrusion.]
+ \getbuffer [example]
+\stopplacefigure
+
+The previously defined own class and vector is somewhat more extreme:
+
+\startbuffer[define]
+\definefontfeature
+ [whatever]
+ [default]
+ [protrusion=myown]
+
+\definefont[MyTestA][Serif*default at 10pt]
+\definefont[MyTestB][Serif*whatever at 10pt]
+\stopbuffer
+
+\typebuffer[define]
+\getbuffer [define]
+
+In \in {figure} [protrusion:myown] we see that the somewhat extreem definition of
+the comma also pulls the preceding character into the margin.
+
+\startplacefigure[reference=protrusion:myown,title=The influence of extreme protrusion on preceding characters.]
+ \getbuffer [example]
+\stopplacefigure
+
+\stopsubsubject
+
+\stopsection
+
+\startsection[title=Expansion]
+
+Expansion is also an inheritance of \PDFTEX. \footnote {As with protrusion the
+implementation in the engine is somewhat suboptimal and inefficient and will be
+upgraded to a more \LUATEX-ish way.} This mechanism selectively expands
+characters, normally upto 5\%. One reason for applying it is that we have less
+visually incompatible spacing, especially when we have underfull or cramped
+lines. For each (broken) line the badness is reconsidered with either shrink or
+stretch applied to all characters in that line. So, in the worst case a shrunken
+line is followed by a stretched one and that can be visible when the scaling
+factors are chosen wrong.
+
+As with protrusion, the solution space is larger but so are the constraints. But
+contrary to protrusion here the look and feel of the whole line can be made
+better but at the cost of much more runtime and larger (\PDF) files.
+
+\startsubsubject[title=protrusion classes]
+
+The amount of expansion depends in the shape of the character. Vertical strokes
+are more sensitive for expansion then horizontal ones. So an \quote {o} can
+get a different scaling than an \quote {m}. As with protrusion we have collected
+the properties in classes:
+
+\showexpansionclass
+
+The smaller the step, the more instances of a font we get, the better it
+looks, and the larger the files become. it's best not to use too many stretch
+and shrink steps. A stretch of 2 and shrink of 2 and step of .25 results in
+upto 8~instances plus the regular sized one.
+
+\stopsubsubject
+
+\startsubsubject[title=expansion vectors]
+
+We only have one vector: \type {quality}:
+
+\showexpansionvector[name=quality]
+
+\stopsubsubject
+
+\startsubsubject[title=an example of expansion]
+
+We use \type {zapf.tex} as example text, if only because Hermann Zapf introduced
+this optimization. Keep in mind that you can combine expansion and protrusion.
+
+\startbuffer[define]
+\definefontfeature
+ [whatever]
+ [default]
+ [expansion=quality]
+
+\definefont[MyTestA][Serif*default at 10pt]
+\definefont[MyTestB][Serif*whatever at 10pt]
+\stopbuffer
+
+\startbuffer[example]
+\startoverlay
+ {\ruledvbox \bgroup
+ \hsize\textwidth
+ \MyTestA
+ \setupalign[normal]
+ \input{tufte}
+ \egroup}
+ {\ruledvbox \bgroup
+ \hsize\textwidth
+ \MyTestB
+ \setupalign[hz,normal]
+ \maincolor
+ \input{tufte}
+ \egroup}
+\stopoverlay
+\stopbuffer
+
+\typebuffer[define]
+\getbuffer [define]
+
+We use the following example. The results are shown in \in {figure}
+[expansion:quality]. The colored text is the protruding one.
+
+\typebuffer[example]
+
+\startplacefigure[reference=expansion:quality,title=The difference between no expansion and quality expansion.]
+ \getbuffer [example]
+\stopplacefigure
+
+You can see what happens in \in {figure} [expansion:visualized].
+
+\startbuffer[example]
+ \setupalign[hz]
+ \enabletrackers[*expansion*]
+ \definefontfeature[boundingbox][boundingbox={frame,empty}]
+ \definedfont[Serif*default,quality,boundingbox @ 12.1pt]
+ \samplefile{sapolsky}\par
+ \disabletrackers[*expansion*]
+\stopbuffer
+
+\typebuffer[example]
+
+\startplacefigure[reference=expansion:visualized,title=The injected expansion kerns.]
+ \getbuffer [example]
+\stopplacefigure
+
+\stopsubsubject
+
+\startsubsubject[title=Expansion and kerning]
+
+When we expand glyphs we also need to look at the font kerns between them. In the
+original implementation taken from \PDFTEX\ expansion was implemented using pseudo
+fonts (with expanded glyph widths) and expansion of inter|-|character kerns was
+based on font information. In \LUATEX\ we have expansion factors in glyph nodes
+instead which is more efficient and gives a cleaner separation between front- and
+backend as the backend has no need to consult the font.
+
+For the font kerns we set the kern compensation directly and for that we use the
+average expansion factors of the neighbouring fonts so technically we support
+kerns between different fonts). This also has the advantage that kerns injected
+in node mode are treated well, given that they are tagged as font kern.
+
+So what is the effect (and need) of scaling font kerns? Let's look at an example.
+Kerns can be positive but also negative:
+
+\startlinecorrection
+\startcombination
+ {\vbox {
+ \forgetall
+ \hpack to 3cm{\hss\ruledhbox{\maincolor V\kern-1ptA}\hss}
+ \hpack to 3cm{\hss\ruledhbox{\maincolor V\kern 0ptA}\hss}
+ }} {negative}
+ {\vbox {
+ \forgetall
+ \hpack to 3cm{\hss\ruledhbox{\maincolor I\kern.25ptI}\hss}
+ \hpack to 3cm{\hss\ruledhbox{\maincolor I\kern 0ptI}\hss}
+ }} {positive}
+\stopcombination
+\stoplinecorrection
+
+If we use a rediculous amount of stretch we get the following. In the top line we
+scale the kern, in the bottom line we don't.
+
+\startlinecorrection
+\startcombination
+ {\vbox {
+ \definedfont[file:texgyrepagella-regular.otf at 12pt]%
+ \forgetall
+ \hpack to 3cm{\maincolor \hss\strut \scale[xscale=5000]{V}\kern-5pt\scale[xscale=5000]{A}\hss}
+ \hpack to 3cm{\maincolor \hss\strut \scale[xscale=5000]{V}\kern-1pt\scale[xscale=5000]{A}\hss}
+ }} {negative}
+ {\vbox {
+ \definedfont[file:texgyrepagella-regular.otf at 12pt]%
+ \forgetall
+ \hpack to 3cm{\maincolor \hss\strut \scale[xscale=5000]{I}\kern1.25pt\scale[xscale=5000]{I}\hss}
+ \hpack to 3cm{\maincolor \hss\strut \scale[xscale=5000]{I}\kern0.25pt\scale[xscale=5000]{I}\hss}
+ }} {positive}
+\stopcombination
+\stoplinecorrection
+
+The reason that we mention this is that when we apply \OPENTYPE\ features,
+positioning not necessarily result in font kerns. For instance ligatures can be
+the result of careful applied kerns and in some scripts kerns are used to connect
+glyphs. This means that we best cannot expand kerns by default. How bad is
+that? By looking at the examples above one would say \quotation {real bad}.
+
+But say that we have about 1pt of font kerns, then a 5\% expansion (which is
+already a lot) amounts to 0.05pt so to \blackrule [width=1pt, height=max,
+depth=max] we add \blackrule [width=.05pt, height=max, depth=max] which is so
+little that it probably goes unnoticed. Even if we use extreme kerns, as between
+VA, in practice the small amount of stretch or shrink added to a font kern goes
+unnoticed.
+
+In \in {figure} [hz:natural] we have overlayed the different strategies. The
+sample and width is chosen such that we see something. On a display you can
+scale up these examples and inspect if there is really something to see,
+but on paper zooming in helps, as in \in {figure} [hz:zoomed]. Even then the
+effect of expanded kerns is invisible. The used definitions are:
+
+\definecolor[hz:test:tr][r=1,a=1,t=.5]
+\definecolor[hz:test:tg][g=1,a=1,t=.5]
+\definecolor[hz:test:tb][b=1,a=1,t=.5]
+
+\startbuffer
+\setupfontexpansion
+ [extremehz]
+ [stretch=5,shrink=5,step=.5,vector=default,factor=1]
+\setupfontexpansion
+ [regularhz]
+ [stretch=2,shrink=2,step=.5,vector=default,factor=1]
+\setupfontexpansion
+ [minimalhz]
+ [stretch=2,shrink=2,step=.5,vector=default,factor=.5]
+
+\definefontfeature
+ [extremehz] [default]
+ [mode=node,expansion=extremehz]
+\definefontfeature
+ [regularhz] [default]
+ [mode=node,expansion=regularhz]
+\definefontfeature [minimalhz] [default]
+ [mode=node,expansion=minimalhz]
+
+\definefont
+ [ExtremeHzFont]
+ [file:texgyrepagella-regular.otf*extremehz at 10pt]
+\definefont
+ [RegularHzFont]
+ [file:texgyrepagella-regular.otf*regularhz at 10pt]
+\definefont
+ [MinimalHzFont]
+ [file:texgyrepagella-regular.otf*minimalhz at 10pt]
+\stopbuffer
+
+\typebuffer \getbuffer
+
+\edef\HzSampleText{\cldloadfile{ward}}
+
+\def\NoHzSample {\vbox{\hsize 10cm \color[hz:test:tr]{\setupalign [nohz]\HzSampleText\par}}}
+\def\HzSample {\vbox{\hsize 10cm \color[hz:test:tg]{\setupalign [hz]\HzSampleText\par}}}
+\def\FullHzSample{\vbox{\hsize 10cm \color[hz:test:tb]{\setupalign[fullhz]\HzSampleText\par}}}
+
+\startplacefigure[reference=hz:natural,title={The two expansion methods compared.}]
+ \showfontkerns
+ \dontcomplain
+ \startcombination[1*3]
+ {\ExtremeHzFont\ruledhpack{\startoverlay {\NoHzSample} {\HzSample } \stopoverlay}} {no hz \& hz}
+ {\ExtremeHzFont\ruledhpack{\startoverlay {\NoHzSample} {\FullHzSample} \stopoverlay}} {no hz \& full hz}
+ {\ExtremeHzFont\ruledhpack{\startoverlay {\HzSample } {\FullHzSample} \stopoverlay}} {hz \& full hz}
+ \stopcombination
+\stopplacefigure
+
+\startplacefigure[reference=hz:zoomed,title={The two expansion methods compared (zoomed in).}]
+ \showfontkerns
+ \dontcomplain
+ \startcombination[3*3]
+
+ {\ExtremeHzFont
+ \clip[nx=6,ny=5,x=2,y=2,sx=2]{\startoverlay {\NoHzSample} {\HzSample } \stopoverlay}} {extreme: no hz \& hz}
+ {\ExtremeHzFont
+ \clip[nx=6,ny=5,x=2,y=2,sx=2]{\startoverlay {\NoHzSample} {\FullHzSample} \stopoverlay}} {extreme: no hz \& full hz}
+ {\ExtremeHzFont
+ \clip[nx=6,ny=5,x=2,y=2,sx=2]{\startoverlay {\HzSample } {\FullHzSample} \stopoverlay}} {extreme: hz \& full hz}
+
+ {\RegularHzFont
+ \clip[nx=6,ny=5,x=2,y=2,sx=2]{\startoverlay {\NoHzSample} {\HzSample } \stopoverlay}} {regular: no hz \& hz}
+ {\RegularHzFont
+ \clip[nx=6,ny=5,x=2,y=2,sx=2]{\startoverlay {\NoHzSample} {\FullHzSample} \stopoverlay}} {regular: no hz \& full hz}
+ {\RegularHzFont
+ \clip[nx=6,ny=5,x=2,y=2,sx=2]{\startoverlay {\HzSample } {\FullHzSample} \stopoverlay}} {regular: hz \& full hz}
+
+ {\MinimalHzFont
+ \clip[nx=6,ny=5,x=2,y=2,sx=2]{\startoverlay {\NoHzSample} {\HzSample } \stopoverlay}} {minimal: no hz \& hz}
+ {\MinimalHzFont
+ \clip[nx=6,ny=5,x=2,y=2,sx=2]{\startoverlay {\NoHzSample} {\FullHzSample} \stopoverlay}} {minimal: no hz \& full hz}
+ {\MinimalHzFont
+ \clip[nx=6,ny=5,x=2,y=2,sx=2]{\startoverlay {\HzSample } {\FullHzSample} \stopoverlay}} {minimal: hz \& full hz}
+
+ \stopcombination
+\stopplacefigure
+
+In \CONTEXT\ the \type {hz} alignment option only enables expansion of glyphs,
+while \type {fullhz} also applies it to kerns. It will be clear that you can just
+stick to using the \type {hz} directive (if you want expansion at all) because
+this directive is normally disabled and because most fonts are processed in node
+mode.
+
+\stopsubsubject
+
+\stopsection
+
+\startsection[title=Composing]
+
+This feature is seldom needed but can come in handy for old fonts or when
+some special language is to be supported. When writing this section I tested
+this feature with Dejavu and only two additional characters were added:
+
+\definefontfeature
+ [default-plus-compose]
+ [compose=yes]
+
+\definefont
+ [MyComposedSerif]
+ [Serif*default-plus-compose]
+
+% we need to cheat a bit as we don't have the main character in mono
+
+\startlines \MyComposedSerif
+\type{fonts > combining > }\hbox to .5em{\hss Ѷ\hss}\type{ (U+00476) = }\hbox to .5em{\hss Ѵ\hss}\type{ (U+00474) + ̏ (U+0030F)}
+\type{fonts > combining > }\hbox to .5em{\hss ѷ\hss}\type{ (U+00477) = }\hbox to .5em{\hss ѵ\hss}\type{ (U+00475) + ̏ (U+0030F)}
+\stoplines
+
+This trace showed up after giving:
+
+\starttyping
+\enabletrackers
+ [fonts.composing.define]
+
+\definefontfeature
+ [default-plus-compose]
+ [compose=yes]
+
+\definefont
+ [MyFont]
+ [Serif*default-plus-compose]
+\stoptyping
+
+Fonts like Latin Modern have lots of glyphs but still lack some. Although the
+composer can add some of the missing, some of those new virtual glyphs probably
+will never look real good. For instance, putting additional accents on top of
+already accented uppercase characters will fail when that character has a rather
+tight (or even clipped) boundingbox in order not to spoil the lineheight. You can
+get some more insight in the process by turning on tracing:
+
+\starttyping
+\enabletrackers[fonts.composing.visualize]
+\stoptyping
+
+One reason why composing can be suboptimal is that it uses the boundingbox of the
+characters that are combined. If you really depend on a specific font and need
+some of the missing characters it makes sense to spend some time on optimizing
+the rendering. This can be done via the goodies mechanism. As an example we've
+added \type {lm-compose-test.lfg} to the distribution. First we show how it
+looks at the \TEX\ end:
+
+\startbuffer
+\enabletrackers[fonts.composing.visualize]
+
+\definefontfeature
+ [default-plus-compose]
+ [compose=yes]
+
+\loadfontgoodies
+ [lm-compose-test] % playground
+
+\definefont
+ [MyComposedSerif]
+ [file:lmroman10regular*default-plus-compose at 48pt]
+\stopbuffer
+
+\typebuffer \getbuffer
+
+\blank
+\backgroundline
+ [halfcolor]
+ {\MyComposedSerif B\quad\char"1E02\quad\char"1E04}
+\blank
+
+The positions of the dot accents on top and below the capital B is defined
+in a goodie file:
+
+\starttyping
+return {
+ name = "lm-compose-test",
+ version = "1.00",
+ comment = "Goodies that demonstrate composition.",
+ author = "Hans and Mojca",
+ copyright = "ConTeXt development team",
+ compositions = {
+ ["lmroman12-regular"] = compose,
+ }
+}
+\stoptyping
+
+As this is an experimental feature there are several ways to deal with
+this. For instance:
+
+\starttyping
+local defaultfraction = 10.0
+
+local compose = {
+ dy = defaultfraction,
+ [0x1E02] = { -- B dot above
+ dy = 150
+ },
+ [0x1E04] = { -- B dot below
+ dy = 150
+ },
+}
+\stoptyping
+
+Here the fraction is relative to the difference between the height of the
+accentee and the accent. A better solution is the following:
+
+\starttyping
+local compose = {
+ [0x1E02] = { -- B dot above
+ anchored = "top",
+ },
+ [0x1E04] = { -- B dot below
+ anchored = "bottom",
+ },
+ [0x0042] = { -- B
+ anchors = {
+ top = {
+ x = 300, y = 700,
+ },
+ bottom = {
+ x = 300, y = -30,
+ },
+ },
+ },
+ [0x0307] = {
+ anchors = {
+ top = {
+ x = -250, y = 550,
+ },
+ },
+ },
+ [0x0323] = {
+ anchors = {
+ bottom = {
+ x = -250, y = -80,
+ },
+ },
+ },
+}
+\stoptyping
+
+This approach is more or less the same as \OPENTYPE\ anchoring. It takes a bit
+more effort to define these tables but the result is better.
+
+\stopsection
+
+\startsection[title=Kerning]
+
+Inter|-|character kerning is not supported at the font level and with good
+reason. The fact that something is conceptually possible doesn't mean that we
+should use or support it. Normally proper kerning (or the lack of it) is part
+of a font design and for some scripts different kerning is not even an option.
+
+On the average \TEX\ does a proper job on justification but not all programs
+are that capable. As a consequence designers (at least we ran into it) tend to
+stick to flush left rendering because they don't trust their system to do a
+proper job otherwise. On the other hand they seem to have no problem with
+messing up the inter|-|character spacing and even combine that with excessive
+inter|-|word spacing {\em if} they want to achieve justification (without
+hyphenation). And it can become even worse when extreme glyph expansion (like
+hz) is applied.
+
+Anyhow, it will be clear that consider messing with properties like kerning that
+are part of the font design is to be done careful.
+
+\definecharacterkerning [extremekerning] [factor=.125]
+
+\start \setcharacterkerning[extremekerning]
+
+For running text additional kerning makes no sense. It not only looks
+bad, it also spoils the grayness of a text. When it is applied we need
+to deal with special cases. For instance ligatures make no sense so they
+should be disabled. Additional kerning should relate to already present
+kerning and interword spacing should be adapted accordingly. Embedded
+non|-|characters also need to be treated well.
+
+\par \stop
+
+This paragraph was typeset as follows:
+
+\starttyping
+\definecharacterkerning [extremekerning] [factor=.125]
+
+\setcharacterkerning[extremekerning] ... text ...
+\stoptyping
+
+Where additional kerning can make sense, is in titles. The previous
+command can do that job. In addition we have a mechanism that
+fills a given space. This mechanism uses the following definition:
+
+\starttyping
+\setupcharacterkerning
+ [stretched]
+ [factor=max,
+ width=\availablehsize]
+\stoptyping
+
+\startbuffer
+\stretched{\bfd to the limit}
+\stopbuffer
+
+\typebuffer
+
+\blank \start \color[maincolor]{\getbuffer} \stop \blank
+
+The following does not work:
+
+\startbuffer
+\ruledhbox to 5cm{\stretched{\bfd to the limit}}
+\stopbuffer
+
+\typebuffer
+
+\blank \start \color[maincolor]{\getbuffer} \stop \blank
+
+But this works ok:
+
+\startbuffer
+\setupcharacterkerning
+ [stretched]
+ [width=]
+
+\stretched{\bfd to the limit}
+\stopbuffer
+
+\typebuffer
+
+\blank \start \color[maincolor]{\getbuffer} \stop \blank
+
+You can also say this:
+
+\startbuffer
+\stretched[width=]{\bfd to the limit}
+\stopbuffer
+
+\typebuffer
+
+\blank \start \color[maincolor]{\getbuffer} \stop \blank
+
+or:
+
+\startbuffer
+\ruledhbox{\stretched[width=10cm]{\bfd to the limit}}
+\stopbuffer
+
+\typebuffer
+
+\blank \start \color[maincolor]{\getbuffer} \stop \blank
+
+You can get some insight in what kerning does to your font by the following
+command:
+
+\startbuffer
+\usemodule[typesetting-kerning]
+
+\starttext
+ \showcharacterkerningsteps
+ [style=Bold,
+ sample=how to violate a proper font design,
+ text=rubish,
+ first=0,
+ last=45,
+ step=5]
+\stoptext
+\stopbuffer
+
+\typebuffer
+
+\blank \getbuffer \blank
+
+\stopsection
+
+\startsection[title=Extra font kerns]
+
+Fonts are processed independent of each other. Sometimes that is unfortunate for
+kerning, although in practice it won't happen that often. We can enable an
+additional kerning mechanism to deal with these cases. The \type
+{\setextrafontkerns} command takes one argument between square brackets. The
+effect can be seen below:
+
+\startbuffer
+ VA {\smallcaps va} V{\smallcaps a}
+ VA {\bf VA} V{\bf A} {\bf V}A
+ V{\it A}
+\stopbuffer
+
+\starttabulate[|Tl|l|p|]
+\HL
+\BC key \BC result \BC logic \NC \NR
+\HL
+\NC no kerns \NC \showfontkerns\setextrafontkerns[reset]\subff{f:kern}\inlinebuffer \NC no kerns at all \NC \NR
+\NC kerns \NC \showfontkerns\setextrafontkerns[reset]\inlinebuffer \NC kerns within a font (feature) run \NC \NR
+\HL
+\NC none \NC \showfontkerns\setextrafontkerns [none]\inlinebuffer \NC only extra kerns within fonts \NC \NR
+\NC min \NC \showfontkerns\setextrafontkerns [min]\inlinebuffer \NC minimal kerns within and across fonts \NC \NR
+\NC max \NC \showfontkerns\setextrafontkerns [max]\inlinebuffer \NC maximum kerns within and across fonts \NC \NR
+\NC mixed \NC \showfontkerns\setextrafontkerns[mixed]\inlinebuffer \NC averaged kerns within and across fonts \NC \NR
+\HL
+\stoptabulate
+
+The content is defined as:
+
+\typebuffer
+
+This mechanism obeys grouping so you have complete control over where and when
+it gets applied. The \type {\showfontkerns} command can be used to trace the
+injection of (font) kerns.
+
+\stopsection
+
+\startsection[title=Ligatures]
+
+For some Latin fonts ligature building is quite advanced, take Unifraktur. I have no
+problem admitting that I find fraktur hard to read, but this one actually is sort of
+an exception. It's also a good candidate for a screen presentation where you mainly
+made notes for yourself: no one has to read it, but it looks great, especially if
+you consider it to be drawn by a pen.
+
+Anyway, we will use the following code as example (based on some remarks on the
+fonts website).
+
+\startbuffer[sample]
+sitzen / ſitzen / effe fietsen / ch ck ſt tz ſi fi
+\stopbuffer
+
+\typebuffer[sample]
+
+Some ligatures are implemented in the usual way, using the \type {liga} and \type {dlig}
+features, others kick in thanks to \type {ccmp}. This fact alone is an illustration that
+the low level \OPENTYPE\ ligature feature is not related to ligatures at all but a more
+generic mechanism: you can basically combine multiple shapes into one in all features
+exposed to the user.
+
+We define a bunch of specific feature sets:
+
+\startbuffer
+\definefontfeature
+ [unifraktur-a]
+ [default]
+\definefontfeature
+ [unifraktur-b]
+ [default]
+ [goodies=unifraktur,keepligatures=yes]
+\definefontfeature
+ [unifraktur-c]
+ [default]
+ [ccmp=yes]
+\definefontfeature
+ [unifraktur-d]
+ [default]
+ [ccmp=yes,goodies=unifraktur,keepligatures=yes]
+\definefontfeature
+ [unifraktur-e]
+ [default]
+ [liga=no,rlig=no,clig=no,dlig=no,ccmp=yes,keepligatures=auto]
+\stopbuffer
+
+\getbuffer \typebuffer
+
+and also some fonts:
+
+\startbuffer
+\definefont[TestA][UnifrakturCook*unifraktur-a sa 0.9]
+\definefont[TestB][UnifrakturCook*unifraktur-b sa 0.9]
+\definefont[TestC][UnifrakturCook*unifraktur-c sa 0.9]
+\definefont[TestD][UnifrakturCook*unifraktur-d sa 0.9]
+\definefont[TestE][UnifrakturCook*unifraktur-e sa 0.9]
+\stopbuffer
+
+\getbuffer \typebuffer
+
+We show these five alternatives here:
+
+\starttabulate[|T||]
+\NC liga \NC \TestA\getbuffer[sample] \NC \NR
+\NC liga + keepligatures \NC \TestB\getbuffer[sample] \NC \NR
+\NC liga + ccmp \NC \TestC\getbuffer[sample] \NC \NR
+\NC liga + ccmp + keepligatures \NC \TestD\getbuffer[sample] \NC \NR
+\NC ccmp + keepligatures \NC \TestE\getbuffer[sample] \NC \NR
+\stoptabulate
+
+The real fun starts when we want to add extra spacing between characters. Some
+ligatures need to get broken and some kept.
+
+\startbuffer
+\setupcharacterkerning[kerncharacters][factor=0.5]
+\setupcharacterkerning[letterspacing] [factor=0.5]
+\stopbuffer
+
+\getbuffer \typebuffer
+
+\enabletrackers[typesetters.kerns.ligatures]
+
+Next we will see how ligatures behave depending on how the mechanisms are set
+up. The colors indicate what trickery is used:
+
+\starttabulate[|T||]
+\NC \color[darkred] {red} \NC kept by dynamic feature \NC \NR
+\NC \color[darkgreen]{green} \NC kept by static feature \NC \NR
+\NC \color[darkblue] {blue} \NC keep by goodie \NC \NR
+\stoptabulate
+
+First we use \type {\kerncharacters}:
+
+\starttabulate[|T||]
+\NC liga \NC \kerncharacters {\TestA\getbuffer[sample]} \NC \NR
+\NC liga + keepligatures \NC \kerncharacters {\TestB\getbuffer[sample]} \NC \NR
+\NC liga + ccmp \NC \kerncharacters {\TestC\getbuffer[sample]} \NC \NR
+\NC liga + ccmp + keepligatures \NC \kerncharacters {\TestD\getbuffer[sample]} \NC \NR
+\NC ccmp + keepligatures \NC \kerncharacters {\TestE\getbuffer[sample]} \NC \NR
+\stoptabulate
+
+In the next example we use \type {\letterspacing}:
+
+\starttabulate[|T||]
+\NC liga \NC \letterspacing {\TestA\getbuffer[sample]} \NC \NR
+\NC liga + keepligatures \NC \letterspacing {\TestB\getbuffer[sample]} \NC \NR
+\NC liga + ccmp \NC \letterspacing {\TestC\getbuffer[sample]} \NC \NR
+\NC liga + ccmp + keepligatures \NC \letterspacing {\TestD\getbuffer[sample]} \NC \NR
+\NC ccmp + keepligatures \NC \letterspacing {\TestE\getbuffer[sample]} \NC \NR
+\stoptabulate
+
+\disabletrackers[typesetters.kerns.ligatures]
+
+The difference is that the letterspacing variant dynamically adds the predefined
+featureset \type {letterspacing} which is defined in a similar way as \type
+{unifraktur-e}. In the case of this font, this variant is the better one to use.
+In fact, this variant probably works okay with most fonts. However, by not hard
+coding this behaviour we keep control, as one never knows what the demands are.
+When no features are used, information from the (given) goodie file \type
+{unifraktur.lfg} is consulted:
+
+\starttyping
+letterspacing = {
+ -- watch it: zwnj's are used (in the tounicodes too)
+ keptligatures = {
+ ["c_afii301_k.ccmp"] = true, -- ck
+ ["c_afii301_h.ccmp"] = true, -- ch
+ ["t_afii301_z.ccmp"] = true, -- tz
+ ["uniFB05"] = true, -- ſt
+ },
+}
+\stoptyping
+
+These kick in when we don't disable ligatures by setting features (case~e).
+
+There are two pseudo features that can help us out when a font doesn't provide
+the wanted ligatures but has the right glyphs for building them. The \UNICODE\
+database has some information about how characters can be (de)composed and we can
+use that information to create virtual glyphs:
+
+\starttyping
+\definefontfeature
+ [default] [default]
+ [char-ligatures=yes,mode=node]
+\stoptyping
+
+and:
+
+\starttyping
+\definefontfeature
+ [default] [default]
+ [compat-ligatures=yes,mode=node]
+\stoptyping
+
+This feature was added after some discussion on the \CONTEXT\ mailing list about
+the following use case.
+
+\startbuffer
+\definefontfeature
+ [default-l] [default]
+ [char-ligatures=yes,
+ compat-ligatures=yes,
+ mode=node]
+
+\definefont[LigCd][cambria*default]
+\definefont[LigPd][texgyrepagellaregular*default]
+\definefont[LigCl][cambria*default-l]
+\definefont[LigPl][texgyrepagellaregular*default-l]
+\stopbuffer
+
+\typebuffer \getbuffer
+
+These definitions result in:
+
+\starttabulate[|l|l|l|l|l|]
+\NC \NC \type {\LigCd} \NC \type {\LigPd} \NC \type {\LigCl} \NC \type {\LigPl} \NC \NR
+\NC \type{PEL·LÍCULES} \NC \LigCd PEL·LÍCULES \NC \LigPd PEL·LÍCULES \NC \LigCl PEL·LÍCULES \NC \LigPl PEL·LÍCULES \NC \NR
+\NC \type{pel·lícules} \NC \LigCd pel·lícules \NC \LigPd pel·lícules \NC \LigCl pel·lícules \NC \LigPl pel·lícules \NC \NR
+\NC \type{PEĿLÍCULES} \NC \LigCd PEĿLÍCULES \NC \LigPd PEĿLÍCULES \NC \LigCl PEĿLÍCULES \NC \LigPl PEĿLÍCULES \NC \NR
+\NC \type{peŀlícules} \NC \LigCd peŀlícules \NC \LigPd peŀlícules \NC \LigCl peŀlícules \NC \LigPl peŀlícules \NC \NR
+\stoptabulate
+
+Of course one can wonder is this is the right approach and if it's not better to
+use a font that provides the needed characters in the first place.
+
+\stopsection
+
+\startsection[title=New features]
+
+\startsubsection[title=Substitution]
+
+It is possible to add new features via \LUA. Here is an example of a single
+substitution:
+
+\startbuffer
+\startluacode
+ fonts.handlers.otf.addfeature {
+ name = "stest",
+ type = "substitution",
+ data = {
+ a = "X",
+ b = "P",
+ }
+ }
+\stopluacode
+\stopbuffer
+
+\typebuffer \getbuffer
+
+We show an overview at the end of this section, but here is a simple example
+already. You need to define the feature before defining a font because otherwise
+the font will not know about it.
+
+\startbuffer
+\definefontfeature[stest][stest=yes]
+\definedfont[file:dejavu-serifbold.ttf*default]
+abracadabra: \addff{stest}abracadabra
+\stopbuffer
+
+\typebuffer \start \blank \maincolor \getbuffer \blank \stop
+
+Instead of (more readable) glyph names you can also give \UNICODE\ numbers:
+
+\starttyping
+\startluacode
+ fonts.handlers.otf.addfeature {
+ name = "stest",
+ type = "substitution",
+ data = {
+ [0x61] = 0x58
+ [0x62] = 0x50
+ }
+ }
+\stopluacode
+\stoptyping
+
+The definition is quite simple: we just map glyph names (or unicodes) onto
+other ones. An alternate is also possible:
+
+\startbuffer
+\startluacode
+ fonts.handlers.otf.addfeature {
+ name = "atest",
+ type = "alternate",
+ data = {
+ a = { "X", "Y" },
+ b = { "P", "Q" },
+ }
+ }
+\stopluacode
+\stopbuffer
+
+\typebuffer \getbuffer
+
+Less useful is a multiple substitution. Normally this one is part of a chain of
+replacements.
+
+\startbuffer
+\startluacode
+ fonts.handlers.otf.addfeature {
+ name = "mtest",
+ type = "multiple",
+ data = {
+ a = { "X", "Y" },
+ b = { "P", "Q" },
+ }
+ }
+\stopluacode
+\stopbuffer
+
+\typebuffer \getbuffer
+
+A ligature (or multiple to one) is also possible but normally only makes sense when
+there is indeed a ligature. We use a similar definition for mapping the \TEX\ input
+sequence \type {---} onto an \emdash.
+
+\startbuffer
+\startluacode
+ fonts.handlers.otf.addfeature {
+ name = "ltest",
+ type = "ligature",
+ data = {
+ ['1'] = { "a", "b" },
+ ['2'] = { "d", "a" },
+ }
+ }
+\stopluacode
+\stopbuffer
+
+\typebuffer \getbuffer
+
+\stopsubsection
+
+\startsubsection[title=Positioning]
+
+You can define a kern feature too but when doing so you need to use measures in
+font units.
+
+\startbuffer
+\startluacode
+ fonts.handlers.otf.addfeature {
+ name = "ktest",
+ type = "kern",
+ data = {
+ a = { b = -500 },
+ }
+ }
+\stopluacode
+\stopbuffer
+
+\typebuffer \getbuffer
+
+Pairwise positioning is more complex and involves two (optional) arrays
+that specify \type {{dx dy wd ht}} for each of the two glyphs. In the next
+example we only displace the second glyph.
+
+\startbuffer
+\startluacode
+ fonts.handlers.otf.addfeature {
+ name = "ptest",
+ type = "pair",
+ data = {
+ ["a"] = { ["b"] = { false, { -1000, 1200, 0, 0 } } },
+ }
+ }
+\stopluacode
+\stopbuffer
+
+\typebuffer \getbuffer
+
+Of course you need to know a bit about the metrics of the glyphs involved so in
+practice this boils down to trial and error.
+
+A single character (glyph) can also be tweaked, although normally this is done
+better in a manipulator when loading the font. Anyway:
+
+\startbuffer
+\startluacode
+ fonts.handlers.otf.addfeature {
+ name = "stest",
+ type = "single",
+ data = {
+ a = { -30, 0, -50, 0 },
+ }
+ }
+\stopluacode
+\stopbuffer
+
+\typebuffer \getbuffer
+
+This will reduce the left and right edges and make the glyph a pretty tight one. The
+values are for Latin Modern.
+
+\stopsubsection
+
+\startsubsection[title=Examples]
+
+We didn't show usage yet. This is because we need to define a feature before we
+define a font. New features will be added to a font when it gets defined.
+
+\startbuffer
+\definefontfeature[stest][stest=yes]
+\definefontfeature[atest][atest=2]
+\definefontfeature[mtest][mtest=yes]
+\definefontfeature[ltest][ltest=yes]
+\definefontfeature[ktest][ktest=yes]
+\definefontfeature[ptest][ptest=yes]
+\definefontfeature[ctest][ctest=yes]
+
+\definedfont[file:dejavu-serif.ttf*default]
+
+\starttabulate[|l|l|l|]
+\NC operation \NC feature \NC abracadabra \NC \NR
+\HL
+\NC substitution \NC \type {stest} \NC \addff{stest}abracadabra \NC \NR
+\NC alternate \NC \type {atest} \NC \addff{atest}abracadabra \NC \NR
+\NC multiple \NC \type {mtest} \NC \addff{mtest}abracadabra \NC \NR
+\NC ligature \NC \type {ltest} \NC \addff{ltest}abracadabra \NC \NR
+\NC kern \NC \type {ktest} \NC \addff{ktest}abracadabra \NC \NR
+\NC pair \NC \type {ptest} \NC \addff{ptest}abracadabra \NC \NR
+\NC chain sub \NC \type {ctest} \NC \addff{ctest}abracadabra \NC \NR
+\stoptabulate
+\stopbuffer
+
+\typebuffer \getbuffer
+
+\stopsubsection
+
+\startsubsection[title=Contexts]
+
+A more complex substitution is the following:
+
+\startbuffer
+\startluacode
+ fonts.handlers.otf.addfeature {
+ name = "ytest",
+ type = "chainsubstitution",
+ lookups = {
+ {
+ type = "substitution",
+ data = {
+ ["b"] = "B",
+ ["c"] = "C",
+ },
+ },
+ },
+ data = {
+ rules = {
+ {
+ before = { { "a" } },
+ current = { { "b", "c" } },
+ lookups = { 1 },
+ },
+ },
+ },
+ }
+\stopluacode
+\stopbuffer
+
+\typebuffer \getbuffer
+
+Here the dataset is a sequence of rules. There can be a \type {before}, \type
+{current} and \type {after} match. The replacements are specified with the \type
+{lookups} entry and the numbers are indices in the provided \type {lookups}
+table.
+
+Here is another example. This one demonstrates that one can check against spaces
+(some fonts kerns against them) and against boundaries as well. The later is
+something \CONTEXT\ specific. First we define a feature that create ligatures but
+only when we touch a space:
+
+\startbuffer
+\startluacode
+ fonts.handlers.otf.addfeature {
+ name = "test-a",
+ type = "chainsubstitution",
+ lookups = {
+ {
+ type = "ligature",
+ data = {
+ ['1'] = { "a", "b" },
+ ['2'] = { "c", "d" },
+ },
+ },
+ },
+ data = {
+ rules = {
+ {
+ before = { { " " } },
+ current = { { "a" }, { "b" } },
+ lookups = { 1 },
+ },
+ {
+ current = { { "c" }, { "d" } },
+ after = { { " " } },
+ lookups = { 1 },
+ },
+ },
+ },
+ }
+\stopluacode
+\stopbuffer
+
+\typebuffer \getbuffer
+
+The next example also checks against whatever boundary we have.
+
+\startbuffer
+\startluacode
+ fonts.handlers.otf.addfeature {
+ name = "test-b",
+ type = "chainsubstitution",
+ lookups = {
+ {
+ type = "ligature",
+ data = {
+ ['1'] = { "a", "b" },
+ ['2'] = { "c", "d" },
+ },
+ },
+ },
+ data = {
+ rules = {
+ {
+ before = { { " ", 0xFFFC } },
+ current = { { "a" }, { "b" } },
+ lookups = { 1 },
+ },
+ {
+ current = { { "c" }, { "d" } },
+ after = { { 0xFFFC, " " } },
+ lookups = { 1 },
+ },
+ },
+ },
+ }
+\stopluacode
+\stopbuffer
+
+\typebuffer \getbuffer
+
+We can actually simplify this one to:
+
+\startbuffer
+\startluacode
+ fonts.handlers.otf.addfeature {
+ name = "test-c",
+ type = "chainsubstitution",
+ lookups = {
+ {
+ type = "ligature",
+ data = {
+ ['1'] = { "a", "b" },
+ ['2'] = { "c", "d" },
+ },
+ },
+ },
+ data = {
+ rules = {
+ {
+ before = { { 0xFFFC } },
+ current = { { "a" }, { "b" } },
+ lookups = { 1 },
+ },
+ {
+ current = { { "c" }, { "d" } },
+ after = { { 0xFFFC } },
+ lookups = { 1 },
+ },
+ },
+ },
+ }
+\stopluacode
+\stopbuffer
+
+\typebuffer \getbuffer
+
+As a bonus we show how to do more complex things:
+
+\startbuffer
+\startluacode
+ fonts.handlers.otf.addfeature {
+ name = "test-d",
+ type = "chainsubstitution",
+ lookups = {
+ {
+ type = "substitution",
+ data = {
+ ["a"] = "A",
+ ["b"] = "B",
+ ["c"] = "C",
+ ["d"] = "D",
+ },
+ },
+ {
+ type = "ligature",
+ data = {
+ ['1'] = { "a", "b" },
+ ['2'] = { "c", "d" },
+ },
+ },
+ },
+ data = {
+ rules = {
+ {
+ before = { { 0xFFFC } },
+ current = { { "a" }, { "b" } },
+ lookups = { 2 },
+ },
+ {
+ current = { { "c" }, { "d" } },
+ after = { { 0xFFFC } },
+ lookups = { 2 },
+ },
+ {
+ current = { { "a" } },
+ after = { { "b" } },
+ lookups = { 1 },
+ },
+ {
+ current = { { "c" } },
+ after = { { "d" } },
+ lookups = { 1 },
+ },
+ },
+ },
+ }
+\stopluacode
+\stopbuffer
+
+\typebuffer \getbuffer
+
+\definefontfeature[test-a][test-a=yes]
+\definefontfeature[test-b][test-b=yes]
+\definefontfeature[test-c][test-c=yes]
+\definefontfeature[test-d][test-d=yes]
+
+\startbuffer
+abababcdcd abababcdcd abababcdcd
+\stopbuffer
+
+With the test text:
+
+\typebuffer
+
+These four result in:
+
+\blank \start
+
+ \definedfont[file:dejavu-serif.ttf*default]
+
+ \start \addff{test-a} \getbuffer \stop\par
+ \start \addff{test-b} \getbuffer \stop\par
+ \start \addff{test-c} \getbuffer \stop\par
+ \start \addff{test-d} \getbuffer \stop\par
+
+\stop \blank
+
+\stopsubsection
+
+\startsubsection[title={Language dependencies}]
+
+When \OPENTYPE\ was not around we only had to deal with ligatures, smallcaps and
+oldstyle and of course kerns. Their number was so small that the term \quote
+{features} was not even used. In practice one just loaded a font that had
+oldstyle or smallcaps or none of that and was done. There were different fonts and
+sold separately.
+
+In \OPENTYPE\ we have more variation and although these fonts can be much more
+advanced the lack of standardization (for instance what gets initialized, or what
+shapes are in the default slots) can lead to messy setups. Some fonts bind
+features to scripts, some don't, which means that:
+
+\starttyping
+\definefontfeature[smallcaps][smcp=yes,script=dflt]
+\definefontfeature[smallcaps][smcp=yes,script=latn]
+\definefontfeature[smallcaps][smcp=yes,script=cyrl]
+\stoptyping
+
+are in fact different and you don't know in advance if you need to specify \type
+{dflt} or \type {latn}. In practice for a feature like smallcaps there is no
+difference between languages, but for ligatures there can be.
+
+When we extend an existing feature we can think of:
+
+\starttyping
+\definefontfeature[smallcaps][default][smcp=yes,script=auto]
+\definefontfeature[smallcaps][default][smcp=yes,script=*]
+\stoptyping
+
+but that can have side effects too (for instance disabling language specific
+features). The easiest way to explore this language dependency is to make
+a feature of our own.
+
+\startbuffer
+\startluacode
+fonts.handlers.otf.addfeature {
+ name = "simplify",
+ type = "multiple",
+ prepend = true,
+ features = {
+ ["*"] = {
+ ["deu"] = true
+ }
+ },
+ data = {
+ [utf.byte("ä")] = { "a", "e" },
+ [utf.byte("Ä")] = { "A", "E" },
+ [utf.byte("ü")] = { "u", "e" },
+ [utf.byte("Ü")] = { "U", "E" },
+ [utf.byte("ö")] = { "o", "e" },
+ [utf.byte("Ö")] = { "O", "E" },
+ [utf.byte("ß")] = { "s", "z" },
+ [utf.byte("ẞ")] = { "S", "Z" },
+ },
+}
+\stopluacode
+\stopbuffer
+
+\typebuffer \getbuffer
+
+Here we implement a language specific feature that we use at the \TEX\ end:
+
+\startbuffer
+\definefontfeature
+ [simplify-de]
+ [simplify=yes,
+ language=deu]
+\stopbuffer
+
+\typebuffer \getbuffer
+
+that we can use as:
+
+\startbuffer
+\definedfont[Serif*default,simplify-de]%
+äüöß
+{\de äüöß}
+{\nl äüöß}
+\stopbuffer
+
+\typebuffer
+
+and get: \start \maincolor \inlinebuffer \stop, but as you see, both German and
+Dutch get the same treatment, which might not be what you want, because in Dutch
+the diearesis has a different meaning.
+
+\startbuffer
+\definedfont[Serif*default]%
+ äüöß
+{\de\addff{simplify-de}äüöß}
+{\nl äüöß}
+\stopbuffer
+
+\typebuffer
+
+The above is restricts the usage so now we get: \start \maincolor \inlinebuffer
+\stop, which is more language bound. You don't need much imagination for
+extending this:
+
+\startbuffer
+\definefontfeature
+ [simplify]
+ [simplify=yes,
+ language=deu]
+\stopbuffer
+
+\typebuffer \getbuffer
+
+\startbuffer
+\definedfont[Serif*default]%
+ äüöß
+{\de\addff{simplify}äüöß}
+{\nl\addff{simplify}äüöß}
+\stopbuffer
+
+So what do we expect with the next?
+
+\typebuffer
+
+We get: \start \maincolor \inlinebuffer \stop, and we see that the language
+setting is not taken into account! This is because the font already has been set
+up with a script and language combination. The solution is to temporary set the
+font related language explicitly:
+
+\definefontfeature
+ [simplify]
+ [simplify=yes]
+
+\startbuffer
+\definedfont[Serif*default]%
+ äüöß
+{\de\addfflanguage\addff{simplify}äüöß}
+{\nl\addfflanguage\addff{simplify}äüöß}
+\stopbuffer
+
+\typebuffer
+
+So we can automatically switch to language specific features if we want to:
+\start \maincolor \inlinebuffer \stop.
+
+Let's now move to another level of complexity: support for more than one language
+as in fact this example was made for Dutch in the first place, but the German
+outcome is a bit more visible.
+
+\startbuffer
+\startluacode
+fonts.handlers.otf.addfeature {
+ name = "simplify",
+ type = "multiple",
+ prepend = true,
+ -- prepend = "smcp",
+ dataset =
+ {
+ {
+ features = {
+ ["*"] = {
+ ["nld"] = true
+ }
+ },
+ data = {
+ -- [utf.byte("ä")] = { "a" },
+ -- [utf.byte("Ä")] = { "A" },
+ -- [utf.byte("ü")] = { "u" },
+ -- [utf.byte("Ü")] = { "U" },
+ -- [utf.byte("ö")] = { "o" },
+ -- [utf.byte("Ö")] = { "O" },
+ [utf.byte("ij")] = { "i", "j" },
+ [utf.byte("IJ")] = { "I", "J" },
+ [utf.byte("æ")] = { "a", "e" },
+ [utf.byte("Æ")] = { "A", "E" },
+ },
+ },
+ {
+ -- type = "multiple", -- local values possible
+ features = {
+ ["*"] = {
+ ["deu"] = true
+ }
+ },
+ data = {
+ [utf.byte("ä")] = { "a", "e" },
+ [utf.byte("Ä")] = { "A", "E" },
+ [utf.byte("ü")] = { "u", "e" },
+ [utf.byte("Ü")] = { "U", "E" },
+ [utf.byte("ö")] = { "o", "e" },
+ [utf.byte("Ö")] = { "O", "E" },
+ [utf.byte("ß")] = { "s", "z" },
+ [utf.byte("ẞ")] = { "S", "Z" },
+ },
+ }
+ }
+}
+\stopluacode
+\stopbuffer
+
+\typebuffer \getbuffer
+
+For this we use the following example:
+
+\startbuffer
+\definedfont[Serif*default,simplify]%
+ äüöß ijæ
+{\de\addfflanguage äüöß ijæ}
+{\nl\addfflanguage äüöß ijæ}
+\stopbuffer
+
+\typebuffer
+
+Because the Dutch is hard to check we use an \type {æ} replacement too and
+commented the similarities with German: \start \maincolor \inlinebuffer \stop.
+But still we're not done, say that we want smallcaps too:
+
+\startbuffer
+\definefontfeature[alwayssmcp][smcp=always]%
+\definedfont[Serif*default,simplify,alwayssmcp]%
+ äüöß ijæ
+{\de\addfflanguage äüöß ijæ}
+{\nl\addfflanguage äüöß ijæ}
+\stopbuffer
+
+\typebuffer
+
+This comes out as: \start \maincolor \inlinebuffer \stop.
+
+The reason for specifying \type{smcp} as \type {always} is that otherwise we
+get language specific smallcaps while often they are not bound to a language
+but to the defaults. The good news is that we can do this automatically:
+
+\startbuffer
+\setupfonts[language=auto]%
+\definefontfeature[alwayssmcp][smcp=always]%
+\definedfont[Serif*default,simplify,alwayssmcp]%
+ äüöß ijæ
+{\de äüöß ijæ}
+{\nl äüöß ijæ}
+\stopbuffer
+
+\typebuffer
+
+But be aware that this applies to all situations. Here we get: \start \maincolor
+\inlinebuffer \stop.
+
+\stopsubsection
+
+\startsubsection[title=Syntax summary]
+
+In the examples we have seen several ways to define features. One of the
+differences is that you either set a \type {data} field directly, or that you
+specify a dataset. The fields in a dataset entry overload the ones given at the
+top level or when not set the top level value will be taken. There is a bit
+of (downward compatibility) tolerance built in, but best not depend on that.
+
+\starttyping
+fonts.handlers.otf.addfeature {
+ name = "demo",
+ features = {
+ [<script>] = {
+ [<language>] = true
+ }
+ },
+ prepend = true | featurename | position,
+ dataset = {
+ {
+ type = "substitution",
+ data = {
+ [<char|code>] = <char|code>,
+ }
+ },
+ {
+ type = "alternate",
+ data = {
+ [<char|code>] = { <char|code>, <char|code>, ... },
+ }
+ },
+ {
+ type = "multiple",
+ data = {
+ [<char|code>] = { <char|code>, <char|code>, ... },
+ }
+ },
+ {
+ type = "ligature",
+ data = {
+ [<char|code>] = { <char|code>, <char|code>, ... },
+ }
+ },
+ {
+ type = "kern",
+ data = {
+ [<char|code>] = { [<char|code>] = <value> },
+ }
+ },
+ {
+ type = "pair",
+ data = {
+ [<char|code>] = {
+ [<char|code>] = {
+ false | { <value>, <value>, <value>, <value> },
+ false | { <value>, <value>, <value>, <value> }
+ }
+ }
+ }
+ },
+ {
+ type = "chainsubstitution",
+ lookups = {
+ {
+ type = <typename>,
+ data = <mapping>,
+ },
+ },
+ data = {
+ rules = {
+ {
+ before = { { [<char|code>], ... } },
+ current = { { [<char|code>], ... } },
+ after = { { [<char|code>], ... } },
+ lookups = { <index>, ... },
+ },
+ },
+ },
+ },
+ },
+}
+\stoptyping
+
+\stopsubsection
+
+\startsubsection[title=Extra characters]
+
+\startbuffer[hyphenchars]
+\startluacode
+
+ local privateslots = fonts.constructors.privateslots
+
+ local function addspecialhyphen(tfmdata)
+
+ local exheight = tfmdata.parameters.xheight
+ local emwidth = tfmdata.parameters.quad
+ local width = emwidth / 4
+ local height = exheight / 10
+ local depth = exheight / 2
+ local offset = emwidth / 6
+
+ tfmdata.characters[privateslots.righthyphenchar] = {
+ -- no dimensions
+ commands = {
+
+ { "right", offset },
+
+ { "push" },
+ { "right", -width },
+ { "down", depth },
+ { "rule", height, width },
+ { "pop" },
+
+ { "right", -width/5 },
+ { "down", depth + height },
+ { "rule", 3*height, width/5 },
+
+ }
+ }
+
+ tfmdata.characters[privateslots.lefthyphenchar] = {
+ -- no dimensions
+ commands = {
+
+ { "right", -offset },
+
+ { "push" },
+ { "down", depth + height },
+ { "rule", 3*height, width/5 },
+ { "pop" },
+
+ { "down", depth },
+ { "rule", height, width },
+
+ }
+ }
+
+ end
+
+ fonts.constructors.features.otf.register {
+ name = "specialhyphen",
+ description = "special hyphen",
+ manipulators = {
+ base = addspecialhyphen,
+ node = addspecialhyphen,
+ }
+ }
+
+\stopluacode
+\stopbuffer
+
+You can add virtual characters to fonts. Here we give an example that is derived
+from an example posted on the mailing list. By default, when we hyphenated a word,
+we get this:
+
+\definefont[DemoFont] [Serif*default]
+
+\blank \start \DemoFont \maincolor \hsize 1mm averylongword \par \stop \blank
+
+The default character that is appended at the end and beginning of a line
+can be specified as follows:
+
+\startbuffer
+\setuplanguage
+ [en]
+ [righthyphenchar=45,
+ lefthyphenchar=45]
+\stopbuffer
+
+\typebuffer
+
+So now we get:
+
+\blank \start \getbuffer \DemoFont \maincolor \hsize 1mm averylongword \par \stop \blank
+
+Say that we want a different signal, for instance some rule. Here is how that can
+be done:
+
+\typebuffer[hyphenchars]
+
+\getbuffer[hyphenchars]
+
+Watch the way we use private slots. You can best use a unique glyph name as these
+numbers are shared between fonts. With:
+
+\startbuffer
+\definefontfeature
+ [default]
+ [default]
+ [specialhyphen=yes]
+\definefont
+ [DemoFont]
+ [Serif*default at 24pt]
+\setuplanguage
+ [en]
+ [righthyphenchar=\getprivateglyphslot{righthyphenchar},
+ lefthyphenchar=\getprivateglyphslot{lefthyphenchar}]
+\stopbuffer
+
+\typebuffer
+
+We get:
+
+\startlinecorrection[blank]
+\getbuffer
+\framed
+ [foregroundstyle=\DemoFont \setupinterlinespace,
+ offset=none,
+ frame=no,
+ width=1mm,
+ align={flushleft}]
+ {\hsize 1mm \maincolor averylongword\par}
+\stoplinecorrection
+
+You need to keep in mind that some of these settings are global but in practice that is
+not a real problem. Here is how you reset:
+
+\startbuffer
+\definefontfeature
+ [default]
+ [default]
+ [specialhyphen=no]
+\setuplanguage
+ [en]
+ [righthyphenchar=45,
+ lefthyphenchar=0]
+\stopbuffer
+
+\typebuffer \getbuffer
+
+\stopsubsection
+
+\startsubsection[title=Goodies]
+
+The examples above extend a font in the \TEX\ document (normally a style) but you
+can use a goodies file too, for instance \type {cambria.lfg}.
+
+\starttyping
+return {
+ name = "cambria",
+ version = "1.00",
+ comment = "Goodies that complement cambria.",
+ author = "Hans Hagen",
+ copyright = "ConTeXt development team",
+ extensions = {
+ {
+ name = "kern", -- adds to kerns
+ type = "pair",
+ data = {
+ [0x0153] = { -- combining acute
+ [0x0301] = { -- aeligature
+ false,
+ { -500, 0, 0, 0 }
+ }
+ },
+ }
+ }
+ }
+}
+\stoptyping
+
+Here we use the feature name \type {kern} and therefore we don't have to define a
+specific (new) feature for it. Such a goodie is then used as follows:
+
+\starttyping
+\definefontsynonym
+ [Serif]
+ [cambria]
+ [features=default,
+ goodies=cambria]
+\stoptyping
+
+You can find such definitions in the \type {type-imp-*.mkiv} files.
+
+\stopsubsection
+
+\stopsection
+
+\startsection[title=Spacing]
+
+% By default the font loader deduces the spacing from the space character or
+% other font properties. You can influence this by the \type {space} feature.
+%
+% \starttyping
+% \definefontfeature
+% [korean]
+% [default]
+% [script=hang,
+% language=kor,
+% space=local] % or locl
+% \stoptyping
+%
+% Instead of the usual \type {yes} (which means: use character 32), \type {local}
+% or \type {locl} (which means: use a replacement provided by the \type{locl}
+% feature), you can also pass a character, so
+%
+% \starttyping
+% \definefontfeature
+% [spacy]
+% [default]
+% [space=A]
+% \stoptyping
+%
+% is valid.
+
+As you probably know, \TEX\ has no space character. When the input is read,
+characters tagged as space are intercepted and become glue. Compare this:
+
+\startlinecorrection[blank]
+ \startcombination
+ {\framed
+ [width=3cm,height=15mm,align={middle,lohi},foregroundcolor=maincolor]
+ {\dorecurse{5}{test }}}
+ {\type{text test...}}
+ {\framed
+ [width=3cm,height=15mm,align={middle,lohi},foregroundcolor=maincolor]
+ {\dorecurse{5}{test\char32\relax}}}
+ {\type{text\char32test...}}
+ \stopcombination
+\stoplinecorrection
+
+Most fonts have a space character and you can actually use it and indeed a space
+character will be injected but as it is not glue, the line break algorithm will
+not see it as space.
+
+Al the magic done with space characters other than the native space character
+(decimal 32) are at some point translated into glue.
+
+\starttabulate[||T|p|]
+\NC \bf command \NC \UNICODE \NC width \NC \NR
+
+\NC \type{\nobreakspace}
+ \type{\nbsp} \NC U+00A0 \NC space \NC \NR
+\NC \type{\ideographicspace} \NC U+2000 \NC quad/2 \NC \NR
+\NC \type{\ideographichalffillspace} \NC U+2001 \NC quad \NC \NR
+\NC \type{\twoperemspace}
+ \type{\enspace} \NC U+2002 \NC quad/2 \NC \NR
+\NC \type{\emspace}
+ \type{\quad} \NC U+2003 \NC quad \NC \NR
+\NC \type{\threeperemspace} \NC U+2004 \NC quad/3 \NC \NR
+\NC \type{\fourperemspace} \NC U+2005 \NC quad/4 \NC \NR
+\NC \type{\fiveperemspace} \NC \NC quad/5 \NC \NR
+\NC \type{\sixperemspace} \NC U+2006 \NC quad/6 \NC \NR
+\NC \type{\figurespace} \NC U+2007 \NC width of zero \NC \NR
+\NC \type{\punctuationspace} \NC U+2008 \NC width of period \NC \NR
+\NC \type{\breakablethinspace} \NC U+2009 \NC quad/8 \NC \NR
+\NC \type{\hairspace} \NC U+200A \NC quad/8 \NC \NR
+\NC \type{\zerowidthspace} \NC U+200B \NC 0 \NC \NR
+\NC \type{\zerowidthnonjoiner}
+ \type{\zwnj} \NC U+200C \NC 0 \NC \NR
+\NC \type{\zerowidthjoiner}
+ \type{\zwj} \NC U+200D \NC 0 \NC \NR
+\NC \type{\narrownobreakspace} \NC U+202F \NC quad/8 \NC \NR
+\NC \type{\zerowidthnobreakspace} \NC U+FEFF \NC \NC \NR
+\NC \type{\optionalspace} \NC \NC space when not followed by punctuation \NC \NR
+\stoptabulate
+
+% "205F % space/8 (math)
+
+The last one is not un \UNICODE\ and the fifths of an emspace is not in \UNICODE\
+either. This emspace (or quad in \TEX\ speak) is a font property. The width of
+the space used by \CONTEXT\ is dreived form this value. In case of a monospace
+fonts, the following logic is applied:
+
+\startitemize
+ \startitem
+ When there is a space character, the width of that character is used.
+ \stopitem
+ \startitem
+ Otherwise, when there is an emdash present, the width if that character
+ is used.
+ \stopitem
+ \startitem
+ Otherwise, when there is an \type {charwidth} property available (the
+ average width), that valua is used.
+ \stopitem
+\stopitemize
+
+When a proportional font is used, we do as follows:
+
+\startitemize
+ \startitem
+ When there is a space character, the width of that character is used.
+ \stopitem
+ \startitem
+ Otherwise, when there is an emdash present, the width of that character
+ divided by two is used.
+ \stopitem
+ \startitem
+ Otherwise, when there is an \type {charwidth} property available (the
+ average width), that value is used.
+ \stopitem
+\stopitemize
+
+In both cases, when no value is set we use the units of the font (often 1000 or
+2048). In \TEX\ a space glue also has stretch and shrink. Here we follow the
+traditional \TEX\ logic:
+
+\startitemize
+ \startitem
+ The stretch is set to half the width of a space but to zero with a mono
+ spaced font.
+ \stopitem
+ \startitem
+ The shrink is set to one third of the width of a space but to zero with a
+ mono spaced font.
+ \stopitem
+\stopitemize
+
+The xheight is set to the values specified by the font and when this is unset the
+height of the character \type {x} will be used but when this character is not in
+the font, we use two fifths of the font's units (normally the same as the
+emwidth). The italic angle is also taken from the font (and is of course zero for
+a not italic font). Most fonts have these properties set so we seldom have to
+fall back to a guess.
+
+\stopsection
+
+\startsection[title=Ligatures]
+
+Not all fonts provide ligature control (normally related to languages), so here is a
+trick.
+
+\starttyping
+\blockligatures[fi,ff]
+\blockligatures[fl]
+
+\definefontfeature
+ [default]
+ [default]
+ [blockligatures=yes]
+
+\setupbodyfont[pagella]
+
+...
+\stoptyping
+
+This way it works globally. Of course you can also bind it to a font instance:
+
+\startbuffer
+\blockligatures[fi,fl]
+
+\definefontfeature
+ [default:blockligs]
+ [default]
+ [blockligatures=yes]
+
+\definefont[DemoBlockY][Serif*default:blockligs at 20pt]
+\definefont[DemoBlockN][Serif*default at 20pt]
+
+Here we have no ligatures: {\DemoBlockY fi ff fl}, while here we get
+them: {\DemoBlockN fi ff fl}. Of course it also depends on the font.
+\stopbuffer
+
+\typebuffer \start \showfontkerns \getbuffer \par \stop
+
+There is one limitation: you need to specify the blocked ligatures before a font
+gets defined and because we share resources it even has to happen before the
+first font gets loaded. So, the \type {\blockligatures} commands go before
+setting up the body font. This is no real problem because it's a hack anyway.
+
+The next example combines several tricks:
+
+\startbuffer[definitions]
+\startluacode
+ fonts.handlers.otf.addfeature {
+ name = "kernligatures",
+ type = "kern",
+ data = {
+ f = { i = 50, l = 50 },
+ }
+ }
+\stopluacode
+
+\blockligatures[u:fl:a]
+
+\definefontfeature[default:b][default][blockligatures=yes]
+\definefontfeature[default:k][default][blockligatures=yes,kernligatures=yes]
+
+\showfontkerns
+\stopbuffer
+
+\startbuffer[demo]
+{\definedfont[Brill*default @ 11pt]auflage}\par
+{\definedfont[Brill*default:b @ 11pt]auflage}\par
+{\definedfont[Brill*default:k @ 11pt]auflage}\par
+\stopbuffer
+
+\typebuffer[definitions,demo] \getbuffer[definitions]
+
+\startlinecorrection
+ \externalfigure[demo.buffer][width=4cm]
+\stoplinecorrection
+
+Processing fonts is complicated by the fact that a text can be hyphenated. This
+complicates for instance ligature building which can cross the pre, post and|/|or
+replace bounds. The current implementation does a decent job although there will
+always be border cases. And, figuring out what goes wrong is a pain. There are
+several ways to trace what happens and here's one. As mentioned, blocking only
+works when we haven't not yet defined a font instance, so we use a funny size
+here.
+
+\startbuffer
+\blockligatures[u:fl:a]
+
+\definefontfeature
+ [blockligatures]
+ [default]
+ [blockligatures=yes]
+
+\startotfcompositionlist{texgyrepagella-regular*blockligatures @ 14.5pt}{l2r}
+ \HL
+ \showotfcompositionsample{auflage}
+ \showotfcompositionsample{a\discretionary{-}{}{}uflage}
+ \showotfcompositionsample{au\discretionary{-}{}{}flage}
+ \showotfcompositionsample{auf\discretionary{-}{}{}lage}
+ \showotfcompositionsample{aufl\discretionary{-}{}{}age}
+ \showotfcompositionsample{aufla\discretionary{-}{}{}ge}
+ \showotfcompositionsample{auflag\discretionary{-}{}{}e}
+ \HL
+ \showotfcompositionsample{auflegt}
+ \showotfcompositionsample{a\discretionary{-}{}{}uflegt}
+ \showotfcompositionsample{au\discretionary{-}{}{}flegt}
+ \showotfcompositionsample{auf\discretionary{-}{}{}legt}
+ \showotfcompositionsample{aufl\discretionary{-}{}{}egt}
+ \showotfcompositionsample{aufle\discretionary{-}{}{}gt}
+ \showotfcompositionsample{aufleg\discretionary{-}{}{}t}
+ \HL
+\stopotfcompositionlist
+\stopbuffer
+
+\typebuffer \getbuffer
+
+Here is another example. This one demonstrates that ligatures can force
+collapsing of discretionaries.
+
+\startbuffer
+\startotfcompositionlist{Serif*default @ 11pt}{l2r}
+ \HL
+ \showotfcompositionsample{effe}
+ \showotfcompositionsample{efficient}
+ \HL
+\stopotfcompositionlist
+\stopbuffer
+
+\typebuffer \getbuffer
+
+\stopsection
+
+\startsection[title=Collections]
+
+ {\em Todo.}
+
+\stopsection
+
+\stopchapter