hybrid-partests.tex /size: 11 Kb    last modification: 2023-12-21 09:43
1% language=us
2
3% green  -> more
4% yellow -> less
5
6\environment hybrid-environment
7
8\definecombination
9  [whatever]
10  [location=top]
11
12\startcomponent hybrid-partests
13
14\startchapter[title={Optical optimization}]
15
16One of the objectives of the oriental \TEX\ project has always been to play with
17paragraph optimization. The original assumption was that we needed an advanced
18non|-|standard paragraph builder to Arabic done right but in the end we found out
19that a more straightforward approach is to use a sophisticated \OPENTYPE\ font in
20combination with a paragraph postprocessor that uses the advanced font
21capabilities. This solution is somewhat easier to imagine that a complex
22paragraph builder but still involves quite some juggling.
23
24At the June 2012 meeting of the \NTG\ there was a talk about typesetting
25Devanagari and as fonts are always a nice topic (if only because there is
26something to show) it made sense to tell a bit more about optimizing Arabic at
27the same time. In fact, that presentation was already a few years too late
28because a couple of years back, when the oriental \TEX\ project was presented at
29TUG and Dante meetings, the optimizer was already part of the \CONTEXT\ core
30code. The main reason for not advocating is was the simple fact that no font
31other than the (not yet finished) Husayni font provided the relevant feature set.
32
33The lack of advanced fonts does not prevent us from showing what we're dealing
34with. This is because the \CONTEXT\ mechanisms are generic in the sense that they
35can also be used with regular Latin fonts, although it does not make that much
36sense. Of course only \MKIV\ is supported. In this chapter we will stick to
37Latin. A more extensive article is published by Idris Samawi Hamid and myself in
38the proceedings of the combined euro\TEX and \CONTEXT\ conference.
39
40When discussing optical optimization of a paragraph, a few alternatives come to
41mind:
42
43\startitemize
44
45\startitem One can get rid of extensive spaces by adding additional kerns between
46glyphs. This is often used by poor mans typesetting programns (or routines) and
47can be applied to non|-|connecting scripts. It just looks bad. \stopitem
48
49\startitem Glyphs can be widened a few percent and this is an option that
50\LUATEX\ inherits from its predecessor \PDFTEX. Normally this goes unnoticed
51although excessive scaling makes things worse, and yes, one can run into such
52examples. This strategy goes under the name hz|-|optimization (the hz refers to
53Hermann Zaph, who first came with this solution). \stopitem
54
55\startitem A real nice solution is to replace glyphs by narrower or wider
56variants. This is in fact the ideal hz solution but for it to happen one not only
57needs needs fonts with alternative shapes, but also a machinery that can deal
58with them. \stopitem
59
60\startitem An already old variant is the one first used by Gutenberg, who used
61alternative cuts for certain combinations of characters. This is comparable with
62ligatures. However, to make the look and feel optimal, one needs to analyze the
63text and make decisions on what to replace without loosing consistency. \stopitem
64
65\stopitemize
66
67The solution described here does a bit of everything. As it is mostly meant for a
68connective script, the starting point is how a scribe works when filling up a
69line nicely. Depending on how well he or she can see it coming, the writing can
70be adapted to widen or narrow following words. And it happens that in Arabic
71scripts there are quite some ways to squeeze more characters in a small area
72and|/|or expand some to the extreme to fill up the available space. Shapes can be
73wider or narrower, they can be stacked and they can get replaced by ligatures. Of
74course there is some interference with the optional marks on top and below but
75even there we have some freedom. The only condition is that the characters in a
76word stay connected.
77
78So, given enough alternative glyphs, one can imagine that excessive interword
79spacing can be avoided. However, it is non|-|trivial to check all possible
80combinations. Actually, it is not needed either, as esthetic rules put some
81bounds on what can be done. One should more think in terms of alternative
82strategies or solutions and this is the terminology that we will therefore use.
83
84Easiest is to demonstrate this with Latin, if only because it's more intuitive to
85see what happens. This is not the place to discuss all the gory details so you
86have to take some of the configuration options on face value. Once this mechanism
87is stable and used, the options can be described. For now we stick to presenting
88the idea.
89
90Let's assume that you know what font features are. The idea is to work with
91combinations of such features and figure out what combination suits best. In
92order not to clutter a document style, these sets are defined in so called goodie
93files. Here is an except of \type {demo.lfg}:
94
95\starttyping
96return {
97  name = "demo",
98  version = "1.01",
99  comment = "An example of goodies.",
100  author = "Hans Hagen",
101  featuresets = {
102    simple = {
103      mode   = "node",
104      script = "latn"
105    },
106    default = {
107      mode   = "node",
108      script = "latn",
109      kern   = "yes",
110    },
111    ligatures = {
112      mode   = "node",
113      script = "latn",
114      kern   = "yes",
115      liga   = "yes",
116    },
117    smallcaps = {
118      mode   = "node",
119      script = "latn",
120      kern   = "yes",
121      smcp   = "yes",
122    },
123  },
124  solutions = {
125    experimental = {
126      less = {
127        "ligatures", "simple",
128      },
129      more = {
130        "smallcaps",
131      },
132    },
133  },
134}
135\stoptyping
136
137We see four sets of features here. You can use these sets in a \CONTEXT\
138feature definition, like:
139
140\startbuffer
141\definefontfeature
142  [solution-demo]
143  [goodies=demo,
144   featureset=default]
145\stopbuffer
146
147\typebuffer \getbuffer
148
149You can use a set as follows:
150
151\startbuffer
152\definefont
153  [SomeTestFont]
154  [texgyrepagellaregular*solution-demo at 10pt]
155\stopbuffer
156
157\typebuffer \getbuffer
158
159So far, there is nothing special and new, but we can go a step further.
160
161\startbuffer[solution-a-b]
162\definefontsolution
163  [solution-a]
164  [goodies=demo,
165   solution=experimental,
166   method={normal,preroll},
167   criterium=1]
168
169\definefontsolution
170  [solution-b]
171  [goodies=demo,
172   solution=experimental,
173   method={normal,preroll,split},
174   criterium=1]
175\stopbuffer
176
177\typebuffer[solution-a-b] \getbuffer[solution-a-b]
178
179Here we have defined two solutions. They refer to the \type {experimental}
180solution in the goodie file \type {demo.lfg}. A solution has a \type {less}
181and a \type {more} entry. The featuresets mentioned there reflect ways to
182make a word narrower of wider. There can be more than one way to do that,
183although it comes at a performance price. Before we see how this works out
184we turn on a tracing option:
185
186\startbuffer
187\enabletrackers
188  [builders.paragraphs.solutions.splitters.colors]
189\stopbuffer
190
191\typebuffer \getbuffer
192
193This will color the words in the result according to what has happened. When a
194featureset out of the \type {more} category has been applied, the words turn
195green, when \type {less} is applied, the word becomes yellow. The \type
196{preroll} option in the \type {method} list makes sure that we do a more
197extensive test beforehand.
198
199% \enabletrackers[builders.paragraphs.solutions.splitters.optimizer]
200% \enabletrackers[builders.paragraphs.solutions.splitters.splitter]
201
202\startbuffer[normal]
203\SomeTestFont
204\input zapf \par
205\stopbuffer
206
207\startbuffer[solution-a]
208\SomeTestFont \startfontsolution[solution-a]
209\input zapf \par
210\stopfontsolution
211\stopbuffer
212
213\typebuffer[solution-a]
214
215In \in {figure} [solution-a] we see what happens. In each already split line
216words get wider or narrower until we're satisfied. A criterium of~1 is pretty
217strict \footnote {This number reflects the maximum badness and future versions
218might have a different measure with more granularity.}. Keep in mind that we use
219some arbitrary features here. We try removing kerns to get narrower although
220there is nothing that guarantees that kerns are positive. On the other hand,
221using ligatures might help. In order to get wider we use smallcaps. Okay, the
222result will look somewhat strange but so does much typesetting nowadays.
223
224There is one pitfall here. This mechanism is made for a connective script where
225hyphenation is not used. As a result a word here is actually split up when it has
226discretionaries and of course this text fragment has. It goes unnoticed in the
227rendering but is of course far from optimal.
228
229\startbuffer[solution-b]
230\SomeTestFont \startfontsolution[solution-b]
231\input zapf \par
232\stopfontsolution
233\stopbuffer
234
235\typebuffer[solution-b]
236
237In this example (\in {figure} [solution-b]) we keep words as a whole but as a
238side effect we skip words that are broken across a line. This is mostly because
239it makes not much sense to implement it as Latin is not our target. Future
240versions of \CONTEXT\ might get more sophisticated font machinery so then things
241might look better.
242
243We show two more methods:
244
245\startbuffer[solution-c-d]
246\definefontsolution
247  [solution-c]
248  [goodies=demo,
249   solution=experimental,
250   method={reverse,preroll},
251   criterium=1]
252
253\definefontsolution
254  [solution-d]
255  [goodies=demo,
256   solution=experimental,
257   method={random,preroll,split},
258   criterium=1]
259\stopbuffer
260
261\typebuffer[solution-c-d] \getbuffer[solution-c-d]
262
263In \in {figure} [solution-c] we start at the other end of a line. As we sort of
264mimick a scribe, we can be one who plays safe at the start of corrects at the
265end.
266
267\startbuffer[solution-c]
268\SomeTestFont \startfontsolution[solution-c]
269\input zapf \par
270\stopfontsolution
271\stopbuffer
272
273In \in {figure} [solution-d] we add some randomness but to what extent this works
274well depends on how many words we need to retypeset before we get the badness of
275the line within the constraints.
276
277\startbuffer[solution-d]
278\SomeTestFont \startfontsolution[solution-d]
279\input zapf \par
280\stopfontsolution
281\stopbuffer
282
283\startplacefigure[title={Solution a.},reference=solution-a]
284  \startcombination[whatever]
285    {\framed[strut=no,align={normal,verytolerant},width=.45\textwidth]{\showfontkerns\getbuffer[normal]}}     {normal}
286    {\framed[strut=no,align={normal,verytolerant},width=.45\textwidth]{\showfontkerns\getbuffer[solution-a]}} {solution}
287  \stopcombination
288\stopplacefigure
289
290\startplacefigure[title={Solution b.},reference=solution-b]
291  \startcombination[whatever]
292    {\framed[strut=no,align={normal,verytolerant},width=.45\textwidth]{\showfontkerns\getbuffer[normal]}}     {normal}
293    {\framed[strut=no,align={normal,verytolerant},width=.45\textwidth]{\showfontkerns\getbuffer[solution-b]}} {solution}
294  \stopcombination
295\stopplacefigure
296
297\startplacefigure[title={Solution c.},reference=solution-c]
298  \startcombination[whatever]
299    {\framed[strut=no,align={normal,verytolerant},width=.45\textwidth]{\showfontkerns\getbuffer[normal]}}     {normal}
300    {\framed[strut=no,align={normal,verytolerant},width=.45\textwidth]{\showfontkerns\getbuffer[solution-c]}} {solution}
301  \stopcombination
302\stopplacefigure
303
304\startplacefigure[title={Solution d.},reference=solution-d]
305  \startcombination[whatever]
306    {\framed[strut=no,align={normal,verytolerant},width=.45\textwidth]{\showfontkerns\getbuffer[normal]}}     {normal}
307    {\framed[strut=no,align={normal,verytolerant},width=.45\textwidth]{\showfontkerns\getbuffer[solution-d]}} {solution}
308  \stopcombination
309\stopplacefigure
310
311\stopchapter
312
313\stopcomponent
314