diff options
Diffstat (limited to 'doc/context/sources/general/manuals/fonts/fonts-extensions.tex')
-rw-r--r-- | doc/context/sources/general/manuals/fonts/fonts-extensions.tex | 2729 |
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 |