% language=us

% green  -> more
% yellow -> less

\environment hybrid-environment

\definecombination
  [whatever]
  [location=top]

\startcomponent hybrid-partests

\startchapter[title={Optical optimization}]

One of the objectives of the oriental \TEX\ project has always been to play with
paragraph optimization. The original assumption was that we needed an advanced
non|-|standard paragraph builder to Arabic done right but in the end we found out
that a more straightforward approach is to use a sophisticated \OPENTYPE\ font in
combination with a paragraph postprocessor that uses the advanced font
capabilities. This solution is somewhat easier to imagine that a complex
paragraph builder but still involves quite some juggling.

At the June 2012 meeting of the \NTG\ there was a talk about typesetting
Devanagari and as fonts are always a nice topic (if only because there is
something to show) it made sense to tell a bit more about optimizing Arabic at
the same time. In fact, that presentation was already a few years too late
because a couple of years back, when the oriental \TEX\ project was presented at
TUG and Dante meetings, the optimizer was already part of the \CONTEXT\ core
code. The main reason for not advocating is was the simple fact that no font
other than the (not yet finished) Husayni font provided the relevant feature set.

The lack of advanced fonts does not prevent us from showing what we're dealing
with. This is because the \CONTEXT\ mechanisms are generic in the sense that they
can also be used with regular Latin fonts, although it does not make that much
sense. Of course only \MKIV\ is supported. In this chapter we will stick to
Latin. A more extensive article is published by Idris Samawi Hamid and myself in
the proceedings of the combined euro\TEX and \CONTEXT\ conference.

When discussing optical optimization of a paragraph, a few alternatives come to
mind:

\startitemize

\startitem One can get rid of extensive spaces by adding additional kerns between
glyphs. This is often used by poor mans typesetting programns (or routines) and
can be applied to non|-|connecting scripts. It just looks bad. \stopitem

\startitem Glyphs can be widened a few percent and this is an option that
\LUATEX\ inherits from its predecessor \PDFTEX. Normally this goes unnoticed
although excessive scaling makes things worse, and yes, one can run into such
examples. This strategy goes under the name hz|-|optimization (the hz refers to
Hermann Zaph, who first came with this solution). \stopitem

\startitem A real nice solution is to replace glyphs by narrower or wider
variants. This is in fact the ideal hz solution but for it to happen one not only
needs needs fonts with alternative shapes, but also a machinery that can deal
with them. \stopitem

\startitem An already old variant is the one first used by Gutenberg, who used
alternative cuts for certain combinations of characters. This is comparable with
ligatures. However, to make the look and feel optimal, one needs to analyze the
text and make decisions on what to replace without loosing consistency. \stopitem

\stopitemize

The solution described here does a bit of everything. As it is mostly meant for a
connective script, the starting point is how a scribe works when filling up a
line nicely. Depending on how well he or she can see it coming, the writing can
be adapted to widen or narrow following words. And it happens that in Arabic
scripts there are quite some ways to squeeze more characters in a small area
and|/|or expand some to the extreme to fill up the available space. Shapes can be
wider or narrower, they can be stacked and they can get replaced by ligatures. Of
course there is some interference with the optional marks on top and below but
even there we have some freedom. The only condition is that the characters in a
word stay connected.

So, given enough alternative glyphs, one can imagine that excessive interword
spacing can be avoided. However, it is non|-|trivial to check all possible
combinations. Actually, it is not needed either, as esthetic rules put some
bounds on what can be done. One should more think in terms of alternative
strategies or solutions and this is the terminology that we will therefore use.

Easiest is to demonstrate this with Latin, if only because it's more intuitive to
see what happens. This is not the place to discuss all the gory details so you
have to take some of the configuration options on face value. Once this mechanism
is stable and used, the options can be described. For now we stick to presenting
the idea.

Let's assume that you know what font features are. The idea is to work with
combinations of such features and figure out what combination suits best. In
order not to clutter a document style, these sets are defined in so called goodie
files. Here is an except of \type {demo.lfg}:

\starttyping
return {
  name = "demo",
  version = "1.01",
  comment = "An example of goodies.",
  author = "Hans Hagen",
  featuresets = {
    simple = {
      mode   = "node",
      script = "latn"
    },
    default = {
      mode   = "node",
      script = "latn",
      kern   = "yes",
    },
    ligatures = {
      mode   = "node",
      script = "latn",
      kern   = "yes",
      liga   = "yes",
    },
    smallcaps = {
      mode   = "node",
      script = "latn",
      kern   = "yes",
      smcp   = "yes",
    },
  },
  solutions = {
    experimental = {
      less = {
        "ligatures", "simple",
      },
      more = {
        "smallcaps",
      },
    },
  },
}
\stoptyping

We see four sets of features here. You can use these sets in a \CONTEXT\
feature definition, like:

\startbuffer
\definefontfeature
  [solution-demo]
  [goodies=demo,
   featureset=default]
\stopbuffer

\typebuffer \getbuffer

You can use a set as follows:

\startbuffer
\definefont
  [SomeTestFont]
  [texgyrepagellaregular*solution-demo at 10pt]
\stopbuffer

\typebuffer \getbuffer

So far, there is nothing special and new, but we can go a step further.

\startbuffer[solution-a-b]
\definefontsolution
  [solution-a]
  [goodies=demo,
   solution=experimental,
   method={normal,preroll},
   criterium=1]

\definefontsolution
  [solution-b]
  [goodies=demo,
   solution=experimental,
   method={normal,preroll,split},
   criterium=1]
\stopbuffer

\typebuffer[solution-a-b] \getbuffer[solution-a-b]

Here we have defined two solutions. They refer to the \type {experimental}
solution in the goodie file \type {demo.lfg}. A solution has a \type {less}
and a \type {more} entry. The featuresets mentioned there reflect ways to
make a word narrower of wider. There can be more than one way to do that,
although it comes at a performance price. Before we see how this works out
we turn on a tracing option:

\startbuffer
\enabletrackers
  [builders.paragraphs.solutions.splitters.colors]
\stopbuffer

\typebuffer \getbuffer

This will color the words in the result according to what has happened. When a
featureset out of the \type {more} category has been applied, the words turn
green, when \type {less} is applied, the word becomes yellow. The \type
{preroll} option in the \type {method} list makes sure that we do a more
extensive test beforehand.

% \enabletrackers[builders.paragraphs.solutions.splitters.optimizer]
% \enabletrackers[builders.paragraphs.solutions.splitters.splitter]

\startbuffer[normal]
\SomeTestFont
\input zapf \par
\stopbuffer

\startbuffer[solution-a]
\SomeTestFont \startfontsolution[solution-a]
\input zapf \par
\stopfontsolution
\stopbuffer

\typebuffer[solution-a]

In \in {figure} [solution-a] we see what happens. In each already split line
words get wider or narrower until we're satisfied. A criterium of~1 is pretty
strict \footnote {This number reflects the maximum badness and future versions
might have a different measure with more granularity.}. Keep in mind that we use
some arbitrary features here. We try removing kerns to get narrower although
there is nothing that guarantees that kerns are positive. On the other hand,
using ligatures might help. In order to get wider we use smallcaps. Okay, the
result will look somewhat strange but so does much typesetting nowadays.

There is one pitfall here. This mechanism is made for a connective script where
hyphenation is not used. As a result a word here is actually split up when it has
discretionaries and of course this text fragment has. It goes unnoticed in the
rendering but is of course far from optimal.

\startbuffer[solution-b]
\SomeTestFont \startfontsolution[solution-b]
\input zapf \par
\stopfontsolution
\stopbuffer

\typebuffer[solution-b]

In this example (\in {figure} [solution-b]) we keep words as a whole but as a
side effect we skip words that are broken across a line. This is mostly because
it makes not much sense to implement it as Latin is not our target. Future
versions of \CONTEXT\ might get more sophisticated font machinery so then things
might look better.

We show two more methods:

\startbuffer[solution-c-d]
\definefontsolution
  [solution-c]
  [goodies=demo,
   solution=experimental,
   method={reverse,preroll},
   criterium=1]

\definefontsolution
  [solution-d]
  [goodies=demo,
   solution=experimental,
   method={random,preroll,split},
   criterium=1]
\stopbuffer

\typebuffer[solution-c-d] \getbuffer[solution-c-d]

In \in {figure} [solution-c] we start at the other end of a line. As we sort of
mimick a scribe, we can be one who plays safe at the start of corrects at the
end.

\startbuffer[solution-c]
\SomeTestFont \startfontsolution[solution-c]
\input zapf \par
\stopfontsolution
\stopbuffer

In \in {figure} [solution-d] we add some randomness but to what extent this works
well depends on how many words we need to retypeset before we get the badness of
the line within the constraints.

\startbuffer[solution-d]
\SomeTestFont \startfontsolution[solution-d]
\input zapf \par
\stopfontsolution
\stopbuffer

\startplacefigure[title={Solution a.},reference=solution-a]
  \startcombination[whatever]
    {\framed[strut=no,align={normal,verytolerant},width=.45\textwidth]{\showfontkerns\getbuffer[normal]}}     {normal}
    {\framed[strut=no,align={normal,verytolerant},width=.45\textwidth]{\showfontkerns\getbuffer[solution-a]}} {solution}
  \stopcombination
\stopplacefigure

\startplacefigure[title={Solution b.},reference=solution-b]
  \startcombination[whatever]
    {\framed[strut=no,align={normal,verytolerant},width=.45\textwidth]{\showfontkerns\getbuffer[normal]}}     {normal}
    {\framed[strut=no,align={normal,verytolerant},width=.45\textwidth]{\showfontkerns\getbuffer[solution-b]}} {solution}
  \stopcombination
\stopplacefigure

\startplacefigure[title={Solution c.},reference=solution-c]
  \startcombination[whatever]
    {\framed[strut=no,align={normal,verytolerant},width=.45\textwidth]{\showfontkerns\getbuffer[normal]}}     {normal}
    {\framed[strut=no,align={normal,verytolerant},width=.45\textwidth]{\showfontkerns\getbuffer[solution-c]}} {solution}
  \stopcombination
\stopplacefigure

\startplacefigure[title={Solution d.},reference=solution-d]
  \startcombination[whatever]
    {\framed[strut=no,align={normal,verytolerant},width=.45\textwidth]{\showfontkerns\getbuffer[normal]}}     {normal}
    {\framed[strut=no,align={normal,verytolerant},width=.45\textwidth]{\showfontkerns\getbuffer[solution-d]}} {solution}
  \stopcombination
\stopplacefigure

\stopchapter

\stopcomponent
