summaryrefslogtreecommitdiff
path: root/doc/context/sources/general/manuals/mk/mk-zapfino.tex
diff options
context:
space:
mode:
Diffstat (limited to 'doc/context/sources/general/manuals/mk/mk-zapfino.tex')
-rw-r--r--doc/context/sources/general/manuals/mk/mk-zapfino.tex561
1 files changed, 561 insertions, 0 deletions
diff --git a/doc/context/sources/general/manuals/mk/mk-zapfino.tex b/doc/context/sources/general/manuals/mk/mk-zapfino.tex
new file mode 100644
index 000000000..f427f13a1
--- /dev/null
+++ b/doc/context/sources/general/manuals/mk/mk-zapfino.tex
@@ -0,0 +1,561 @@
+% language=uk
+
+\startcomponent mk-zapfino
+
+\environment mk-environment
+
+\nonknuthmode
+
+\definefontfeature
+ [SampleFont]
+ [language=dflt,
+ script=latn,
+ calt=yes,
+ clig=yes,
+ rlig=yes,
+ tlig=yes,
+ mode=node]
+
+\font\Sample=ZapfinoExtraLTPro*SampleFont at 24pt
+
+\def\SampleChar#1{\dontleavehmode\struttedbox{\Sample\fontchar{#1}}}
+\def\SampleText#1{\dontleavehmode\struttedbox{\Sample#1}}
+
+\doifmodeelse {tug} {
+
+ \title{Zapfing fonts}
+
+ \subject{by Hans Hagen \& Taco Hoekwater}
+
+ This is Chapter~XII from \notabene {\CONTEXT, from \MKII\ to \MKIV}, a document
+ that describes our explorations, experiments and decisions made while
+ we develop \LUATEX. This text has not been copy-edited.
+
+ \blank[3*big]
+
+} {
+
+ \chapter{Zapfing fonts}
+
+}
+
+\subject {remark}
+
+{\it The actual form of the tables shown here might have changed
+in the meantime. However, since this document describes the
+stepwise development of \LUATEX\ and \CONTEXT\ \MKIV\ we don't
+update the following information. The rendering might differ from
+earlier rendering simply because the code used to process this
+chapter evolves.}
+
+\subject {features}
+
+In previous chapters we've seen support for \OPENTYPE\ features creep into \LUATEX\ and
+\CONTEXT\ \MKIV. However, it may not have been clear that so far we were just feeding
+the traditional \TEX\ machinery with the right data: ligatures and kerns. Here we will
+show what so called features can do for you. Not much \LUA\ code will be shown, if
+only because relatively complex code is needed to handle this kind of trickery with
+acceptable performance.
+
+In order to support features in their full glory more is needed than \TEX's ligature
+and kern mechanisms: we need to manipulate the node list. As a result, we have now a
+second mechanism built into \MKIV\ and users can choose what method they like most. The
+first method, called \type {base}, is less powerful and less complete
+than the one named \type {node}. Eventually \CONTEXT\ will use the node method by
+default.
+
+There are two variants of features: substitutions and positioning. Here we
+concentrate on substitutions of which there are several. Positioning is for instance
+used for specialized kerning as needed in for instance typesetting Arab.
+
+One character representation can be replaced by one or more fixed alternatives or alternatives
+chosen from a list of alternatives (substitutions or alternates). Multiple characters
+can be replaces by one character (substitutions, alternates or a ligature). The
+replacements can depend on preceding and|/|or following glyphs in which case we say that
+the replacement is driven by rules. Rules can deal with single glyphs, combinations of
+glyphs, classes (defined in the font) of glyphs and|/|or ranges of glyphs.
+
+Because the available documentation of \OPENTYPE\ is rather minimalistic and because
+most fonts are relatively simple, you can imagine that figuring out how to
+implement support for fonts with advanced features is not entirely trivial
+and involves some trial and error. What also complicate things is that features can
+interfere. Yet another complicating factor is that in the order of applying a rule may
+obscure a later rule. Such fonts don't ship with manuals and examples of correct output
+are not part of the buy.
+
+We like testing \LUATEX's open type support with Palatino Regular and Palatino Sans and
+good old \TYPEONE\ support with Optima Nova. So it makes sense to test advanced
+features with Zapfino Pro. This font has many features, which happen to be
+implemented by Adam Twardoch, a well known font expert and familiar with the \TEX\
+community. We had the feeling that when \LUATEX\ can support Zapfino Pro, designed by
+Hermann Zapf and enhanced by Adam, we have reached a crucial point in the development.
+
+The first thing that you will observe when using this font is that the files are larger
+than normal, especially the cached versions in \MKIV. This made me extend some of the
+serialization code that we use for caching font data so that it could handle huge
+tables better but at the cost of some speed. Once we could handle the data conveniently
+and as a side effect look into the font data with an editor, it became clear that
+implementing for the \type {calt} and \type {clig} features would take a bit
+of coding.
+
+\subject{example}
+
+Before some details will be discussed, we will show two of the test texts that \CONTEXT\
+users normally use when testing layouts or new features, a quote from E.R.\ Tufte and
+one from Hermann Zapf. The \TEX\ code shows how features are set in \CONTEXT.
+
+\startbuffer
+\definefontfeature
+ [zapfino]
+ [language=nld,script=latn,mode=node,
+ calt=yes,clig=yes,liga=yes,rlig=yes,tlig=yes]
+
+\definefont
+ [Zapfino]
+ [ZapfinoExtraLTPro*zapfino at 24pt]
+ [line=40pt]
+\Zapfino
+\input tufte \par
+\stopbuffer
+
+\typebuffer \blank[disable] \start \getbuffer \stop
+
+You don't even have to look too closely in order to notice that characters are
+represented by different glyphs, depending on the context in which they appear.
+
+\startbuffer
+\definefontsynonym
+ [Zapfino]
+ [ZapfinoExtraLTPro]
+ [features=zapfino]
+\definedfont
+ [Zapfino at 24pt]
+\setupinterlinespace
+ [line=40pt]
+\input zapf \par
+\stopbuffer
+
+\typebuffer \blank[disable] \start \getbuffer \stop
+
+\subject{obeying rules}
+
+When we were testing node based feature support, the only way to check this was to
+identify the rules that lead to certain glyphs. The more unique glyphs are good
+candidates for this. For instance
+
+\startitemize[packed]
+\item there is s special glyph representing \SampleChar{c_slash_o}
+\item in the input stream this is the character sequence \type{c/o}
+\item so there most be a rule that tells us that this sequence becomes that ligature
+\stopitemize
+
+As said, in this case, the replacement glyph is supposed to be a ligature and indeed
+there is such a ligature: \type {c_slash_o}. Of course, this replacement will only
+take place when the sequence is surrounded by spaces.
+
+However, when testing this, we were not looking at this rule but at the (randomly
+chosen) rule that was meant to intercept the alternative \type {h.2} followed
+by \type {z.4}. Interesting was that this resolved to a ligature indeed, but
+the shape associated with this ligature was an~\type {h}, which is not right.
+Actually, a few more of such rules turned out to be wrong. It took a bit of
+an effort to reach this conclusion because of the mentioned interferences
+of features and rules. At that time, the rule entry (in raw \LUATEX\ table
+format) looks as follows:
+
+\starttyping
+[44] = {
+ ["format"] = "coverage",
+ ["rules"] = {
+ [1] = {
+ ["coverage"] = {
+ ["ncovers"] = {
+ [1] = "h.2",
+ [2] = "z.4",
+ }
+ },
+ ["lookups"] = {
+ [1] = {
+ ["lookup_tag"] = "L084",
+ ["seq"] = 0,
+ }
+ }
+ }
+ }
+ ["script_lang_index"] = 1,
+ ["tag"] = "calt",
+ ["type"] = "chainsub"
+}
+\stoptyping
+
+Instead of reinventing the wheel, we used the \FONTFORGE\ libraries for reading the
+\OPENTYPE\ font files. Therefore the \LUATEX\ table is resembling the internal \FONTFORGE\
+data structures. Currently we show the version~1 format.
+
+Here \type {ncovers} means that when the current character has shape \SampleChar
+{h.2} (\type{h.2}) and the next one is \SampleChar{z.4} (\type{z.4}) (a sequence)
+then we need to apply the lookup internally tagged \type {L084}. Such a rule
+can be more extensive, for instance instead of \type {h.2} one can have a list of
+characters, and there can be \type {bcovers} and \type {fcovers} as well, which means
+that preceding or following character need to be taken into account.
+
+When this rule matches, it resolves to a specification like:
+
+\starttyping
+[6] = {
+ ["flags"] = 0,
+ ["lig"] = {
+ ["char"] = "h",
+ ["components"] = "h.2 z.4",
+ },
+ ["script_lang_index"] = 65535,
+ ["tag"] = "L084",
+ ["type"] = "ligature",
+}
+\stoptyping
+
+Here \type {tag} and \type {script_lang_index} are kind of special and
+are part of an private feature system, i.e.\ they make up the cross reference
+between rules and glyphs. Watch how the components don't match the character,
+which is even more peculiar when we realize that these are the initials of the
+author of the font. It took a couple of Skype sessions and mails before
+we came to the conclusion that this was probably a glitch in the font. So,
+what to do when a font has bugs like this? Should one disable the feature?
+That would be a pitty because a font like Zapfino depends on it. On the other
+hand, given the number of rules and given the fact that there are different
+rule sets for some languages, you can imagine that making up the rules and
+checking them is not trivial.
+
+We should realize that Zapfino is an extraordinary case, because it used
+the \OPENTYPE\ features extensively. We can also be sure that the problems will
+be fixed once they are known, if only because Adam Twardoch (who did the job)
+has exceptionally high standards but it may take a while before the fix reached
+the user (who then has to update his or her font). As said, it also takes some
+effort to run into the situation described here so the likelihood of running
+into this rule is small. This also brings to our attention the fact that fonts
+can now contain bugs and updating them makes sense but can break existing
+documents. Since such fonts are copyrighted and not available on line, font
+vendors need to find ways to communicate these fixes to their customers.
+
+Can we add some additional checks for problems like this? For a while I
+thought that it was possible by assuming that ligatures have names like
+\type {h.2_z.4} but alas, sequences of glyphs are mapped onto ligatures
+using mappings like the following:
+
+\starttabulate[||||]
+\NC \type{three fraction four.2} \NC \type{threequarters} \NC \SampleChar{threequarters} \NC\NR
+\NC \type{three fraction four} \NC \type{threequarters} \NC \SampleChar{threequarters} \NC\NR
+\NC \type{d r} \NC \type{d_r} \NC \SampleChar{d_r} \NC\NR
+\NC \type{e period} \NC \type{e_period} \NC \SampleChar{e_period} \NC\NR
+\NC \type{f i} \NC \type{fi} \NC \SampleChar{fi} \NC\NR
+\NC \type{f l} \NC \type{fl} \NC \SampleChar{fl} \NC\NR
+\NC \type{f f i} \NC \type{f_f_i} \NC \SampleChar{f_f_i} \NC\NR
+\NC \type{f t} \NC \type{f_t} \NC \SampleChar{f_t} \NC\NR
+\stoptabulate
+
+Some ligature have no \type {_} in their names and there are also some
+inconsistencies, compare the \type {fl} and \type {f_f_i}. Here font
+history is painfully reflected in inconsistency and no solution can be
+found here.
+
+So, in order to get rid of this problem, \MKIV\ implements a method to ignore
+certain rules but then, this only makes sense if one knows how the rules
+are tagged internally. So, in practice this is no solution. However, you can
+imagine that at some point \CONTEXT\ ships with a database of fixes that
+are applied to known fonts with certain version numbers.
+
+We also found out that the font table that we used was not good enough for our
+purpose because the exact order in what rules have to be applies was not
+available. Then we noticed that in the meantime \FONTFORGE\ had moved on
+to version~2 and after consulting the author we quickly came to the conclusion
+that it made sense to use the updated representation.
+
+In version~2 the snippet with the previously mentioned rule looks as follows:
+
+\starttyping
+["ks_latn_l_66_c_19"]={
+ ["format"]="coverage",
+ ["rules"]={
+ [1]={
+ ["coverage"]={
+ ["current"]={
+ [1]="h.2",
+ [2]="z.4",
+ }
+ },
+ ["lookups"]={
+ [1]={
+ ["lookup"]="ls_l_84",
+ ["seq"]=0,
+ }
+ }
+ }
+ },
+ ["type"]="chainsub",
+},
+\stoptyping
+
+The main rule table is now indexed by name which is possible because the order
+of rules is specified somewhere else. The key \type {ncovers} has been replaced
+by \type {current}. As long as \LUATEX\ is in beta stage, we have the freedom to
+change such labels as some of them are rather \FONTFORGE\ specific.
+
+This rule is mentioned in a feature specification table. Here specific features are
+associated with languages and scripts. This is just one of the entries concerning
+\type {calt}. You can imagine that it took a while to figure out how best to
+deal with this, but eventually the \MKIV\ code could do the trick. The cryptic
+names are replacements for pointers in the \FONTFORGE\ datastructure. In order to be
+able to use \FONTFORGE\ for font development and analysis, the decision was made to
+stick closely to its idiom.
+
+\starttyping
+ ["gsub"]={
+ ...
+ [67]={
+ ["features"]={
+ [1]={
+ ["scripts"]={
+ [1]={
+ ["langs"]={
+ [1]="AFK ",
+ [2]="DEU ",
+ [3]="NLD ",
+ [4]="ROM ",
+ [5]="TRK ",
+ [6]="dflt",
+ },
+ ["script"]="latn",
+ }
+ },
+ ["tag"]="calt",
+ }
+ },
+ ["name"]="ks_latn_l_66",
+ ["subtables"]={
+ [1]={
+ ["name"]="ks_latn_l_66_c_0",
+ },
+ ...
+ [20]={
+ ["name"]="ks_latn_l_66_c_19",
+ },
+ ...
+ },
+ ["type"]="gsub_context_chain",
+ },
+\stoptyping
+
+\subject{practice}
+
+The few snapshots of the font table probably don't make much sense if you
+haven't seen the whole table. Well, it certainly helps to see the whole picture,
+but we're talking of a 14 MB file (1.5 MB bytecode). When resolving ligatures,
+we can follow a straightforward approach:
+
+\startitemize[packed]
+\item walk over the nodelist and at each character (glyph node) call a function
+\item this function inspects the character and takes a look at the following ones
+\item when a ligature is identified, the sequence of nodes is replaced
+\stopitemize
+
+Substitutions are not much different but there we look at just one character.
+However, contextual substitutions (and ligatures) are more complex. Here we need
+to loop over a list of rules (dependent on script and language) and this involves
+a sequence as well as preceding and following characters. When we have a hit, the
+sequence will be replaced by another one, determined by a lookup in the character
+table. Since this is a rather time consuming operation, especially because many
+surrounding characters need to be taken into account, you can imagine that we need
+a bit of trickery to get an acceptable performance. Fortunately \LUA\ is pretty fast
+when it comes down to manipulating strings and tables, so we can prepare some handy
+datastructures in advance.
+
+When testing the implementation of features one need to be aware of the fact that
+some appearance are also implemented using the regular ligature mechanisms. Take the
+following definitions:
+
+\startbuffer[a]
+\definefontfeature
+ [none]
+ [language=dflt,script=latn,mode=node,liga=no]
+\definefontfeature
+ [calt]
+ [language=dflt,script=latn,mode=node,liga=no,calt=yes]
+\definefontfeature
+ [clig]
+ [language=dflt,script=latn,mode=node,liga=no,clig=yes]
+\definefontfeature
+ [dlig]
+ [language=dflt,script=latn,mode=node,liga=no,dlig=yes]
+\definefontfeature
+ [liga]
+ [language=dflt,script=latn,mode=node]
+\stopbuffer
+
+\startbuffer[b]
+\starttabulate[||||]
+\NC \type{none } \NC \definedfont[ZapfinoExtraLTPro*none at 24pt]\hbox{on the synthesis}\NC\definedfont[ZapfinoExtraLTPro*none at 24pt]\hbox{winnow the wheat}\NC \NR
+\NC \type{calt } \NC \definedfont[ZapfinoExtraLTPro*calt at 24pt]\hbox{on the synthesis}\NC\definedfont[ZapfinoExtraLTPro*calt at 24pt]\hbox{winnow the wheat}\NC \NR
+\NC \type{clig } \NC \definedfont[ZapfinoExtraLTPro*clig at 24pt]\hbox{on the synthesis}\NC\definedfont[ZapfinoExtraLTPro*clig at 24pt]\hbox{winnow the wheat}\NC \NR
+\NC \type{dlig } \NC \definedfont[ZapfinoExtraLTPro*dlig at 24pt]\hbox{on the synthesis}\NC\definedfont[ZapfinoExtraLTPro*dlig at 24pt]\hbox{winnow the wheat}\NC \NR
+\NC \type{liga } \NC \definedfont[ZapfinoExtraLTPro*liga at 24pt]\hbox{on the synthesis}\NC\definedfont[ZapfinoExtraLTPro*liga at 24pt]\hbox{winnow the wheat}\NC \NR
+\stoptabulate
+\stopbuffer
+
+\typebuffer[a]
+
+This gives:
+
+\start \getbuffer[a] \getbuffer[b] \stop
+
+Here are Adam's recommendations with regards to the \type {dlig} feature:
+\quotation {The \type{dlig} feature is supposed to by use only upon user's
+discretion, usually on single runs, words or even pairs. It makes little
+sense to enable \type {dlig} for an entire sentence or paragraph. That's
+how the \OPENTYPE\ specification envisions it.}
+
+When testing features it helps to use words that look similar so next we will
+show some examples that used. When we look at these examples, we need to
+understand that when a specific character representation is analyzed, the
+rules can take preceding and following characters into account. The rules
+take characters as well as their shapes, or more precisely: one of their
+shapes since Zapfino has many variants, into account. Since different rules
+are used for languages (okay, this is limited to only a subset of languages
+that use the latin script) not only shapes but also the way words are
+constructed are taken into account. Designing te rules is definitely non trivial.
+
+When testing the implementation we ran into cases where the initial \type
+{t} showed up wrong, for instance in the the Dutch word \type {troef}.
+Because space can be part of the rules, we need to handle the
+cases where words end and start and boxes are then kind of special.
+
+\definefontfeature
+ [zapfing]
+ [language=dflt,
+ script=latn,
+ calt=yes,
+ clig=yes,
+ rlig=yes,
+ tlig=yes,
+ mode=node]
+
+\font\Zapfing=ZapfinoExtraLTPro*zapfing at 24pt
+
+\startbuffer
+troef troef troef troeftroef troef \par
+\ruledhbox{troef troef troef troeftroef troef} \par
+\ruledhbox{troef 123} \par
+\ruledhbox{troef} \ruledhbox{troef } \ruledhbox{ troef} \ruledhbox { troef } \par
+\stopbuffer
+
+\typebuffer \start \Zapfing \getbuffer \stop
+
+Unfortunately, this does not work well with punctuation, which is less
+prominent in the rules than space. In our favourite test quote of Tufte, we have
+lots of commas and there it shows up:
+
+\startbuffer
+review review review, review \par
+itemize, review \par
+itemize, review, \par
+\stopbuffer
+
+\typebuffer \start \Zapfing \getbuffer \stop
+
+Of course we can decide to extend the rule base at runtime and this may
+well happen when we experiment more with this font.
+
+The next one was one of our first test lines, Watch the initial and the
+Zapfino ligature.
+
+\startbuffer
+Welcome to Zapfino
+\stopbuffer
+
+\typebuffer \start \Zapfing \getbuffer \stop
+
+For a while there was a bug in the rule handler that resulted in the variant of
+the \type {y} that has a very large descender. Incidentally the word \type
+{synthesize} is also a good test case for the \type {the} pattern which gets
+special treatment because there is a ligature available.
+
+\startbuffer
+synopsize versus synthesize versus
+synthase versus sympathy versus synonym
+\stopbuffer
+
+\typebuffer \start \Zapfing \getbuffer \stop
+
+Here are some examples that use the \type {g}, \type {d} and \type {f} in
+several places.
+
+\startbuffer
+eggen groet ogen hagen \par
+dieren druiven onder aard donder modder \par
+fiets effe flater triest troef \par
+\stopbuffer
+
+\typebuffer \start \Zapfing \getbuffer \stop
+
+Let's see how well Hermann has taken care of the \type {h}'s
+representations. There are quite some variants of the lowercase one:
+
+\starttabulate
+\NC \type {h} \NC \SampleChar{h} \NC \NR
+\NC \type {h.2} \NC \SampleChar{h.2} \NC \NR
+\NC \type {h.3} \NC \SampleChar{h.3} \NC \NR
+\NC \type {h.4} \NC \SampleChar{h.4} \NC \NR
+\NC \type {h.5} \NC \SampleChar{h.5} \NC \NR
+\NC \type {h.init} \NC \SampleChar{h.init} \NC \NR
+\NC \type {h.sups} \NC \SampleChar{h.sups} \NC \NR
+\NC \type {h.sc} \NC \SampleChar{h.sc} \NC \NR
+\NC \type {orn.73} \NC \SampleChar{orn.73} \NC \NR
+\stoptabulate
+
+How about the uppercase variant, as used in his name:
+
+\startbuffer
+M Mr Mr. H He Her Herm Herma Herman Hermann Z Za Zap Zapf \par
+Mr. Hermann Zapf
+\stopbuffer
+
+\typebuffer \start \Zapfing \getbuffer \stop
+
+Of course we have to test another famous name:
+
+\startbuffer
+D Do Don Dona Donal Donald K Kn Knu Knut Knuth \par
+Don Knuth Donald Knuth Donald E. Knuth DEK \par
+Prof. Dr. Donald E. Knuth \par
+\stopbuffer
+
+\typebuffer \start \Zapfing \getbuffer \stop
+
+Unfortunately the \LUA\ and \TEX\ logos don't come out that well:
+
+\startbuffer
+L Lu Lua l lu lua t te tex TeX luatex luaTeX LuaTeX
+\stopbuffer
+
+\typebuffer \start \Zapfing \getbuffer \stop
+
+This font has quite some ornaments and there is an \type {ornm} feature
+that can be applied. We're still not sure about its usage, but when one
+keys in text in lowercase, \type {hermann} comes out as follows:
+
+\definefontfeature
+ [gebarentaal]
+ [language=dflt,
+ script=latn,
+ mode=node,
+ ornm=yes,
+ liga=no]
+
+{\font\Sample=ZapfinoExtraLTPro*gebarentaal at 24pt \Sample hermann}
+
+As said in the beginning, dirty implementation details will be kept away from
+the reader. Also, you should not be surprised if the current code had some
+bugs or does some things wrong. Also, if spacing looks a bit weird to you,
+keep in mind that we're still in the middle of sorting things out.
+
+\start \Zapfing Taco Hoekwater \& Hans Hagen \stop
+
+\stopcomponent