% language=us runpath=texruns:manuals/cld

\startcomponent cld-macros

% \usemodule[man-01]
% \setvariables[document][title=Font Goodies, author=Hans Hagen]
% \setups[titlepage]

\environment cld-environment

\startchapter[title=Font goodies]

\startsection[title=Introduction]

One of the interesting aspects of \TEX\ is that it provides control over fonts
and \LUATEX\ provides quite some. In \CONTEXT\ we support basic functionality,
like \OPENTYPE\ features, as well as some extra functionality. We also have a
mechanism for making virtual fonts which is mostly used for the transition from
\TYPEONE\ math fonts to \OPENTYPE\ math fonts. Instead of hard coding specific
details in the core \LUA\ code, we use so called \LUA\ Font Goodies to control
them. These goodies are collected in tables and live in files. When a font is
loaded, one or more such goodie files can be loaded alongside.

In the following typescript we load a goodies file that defines a virtual Lucida
math font. The goodie file is loaded immediately and some information in the
table is turned into a form that permits access later on: the virtual font id
\type {lucida-math} that is used as part of the font specification.

\starttyping
\starttypescript [math] [lucida]
    \loadfontgoodies[lucida-math]
    \definefontsynonym[MathRoman][lucidamath@lucida-math]
\stoptypescript
\stoptyping

Not all information is to be used directly. Some can be accessed when needed. In
the following case the file \type {dingbats.lfg} gets loaded (only once) when the
font is actually used. In that file, there is information that is used by the
\type {unicoding} feature.

\starttyping
\definefontfeature
  [dingbats]
  [mode=base,
   goodies=dingbats,
   unicoding=yes]

\definefont[dingbats][file:dingbats][features=dingbats]
\stoptyping

In the following sections some aspects of goodies are discussed. We don't go into
details of what these goodies are, but just stick to the \LUA\ side of the
specification.

\stopsection

\startsection[title=Virtual math fonts]

A virtual font is defined using the \type {virtuals} entry in the \type
{mathematics} subtable. As \TYPEONE\ fonts are used, an additional table \type
{mapfiles} is needed to specify the files that map filenames onto real files.

\startsmalltyping
return {
  name = "px-math",
  version = "1.00",
  comment = "Goodies that complement px math.",
  author = "Hans Hagen",
  copyright = "ConTeXt development team",
  mathematics = {
    mapfiles = {
        "mkiv-px.map",
    },
    virtuals = {
      ["px-math"] = {
        { name = "texgyrepagella-regular.otf", features = "virtualmath", main = true },
        { name = "rpxr.tfm", vector = "tex-mr" } ,
        { name = "rpxmi.tfm", vector = "tex-mi", skewchar=0x7F },
        { name = "rpxpplri.tfm", vector = "tex-it", skewchar=0x7F },
        { name = "pxsy.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,
        { name = "pxex.tfm", vector = "tex-ex", extension = true } ,
        { name = "pxsya.tfm", vector = "tex-ma" },
        { name = "pxsyb.tfm", vector = "tex-mb" },
        { name = "texgyrepagella-bold.otf", vector = "tex-bf" } ,
        { name = "texgyrepagella-bolditalic.otf", vector = "tex-bi" } ,
        { name = "lmsans10-regular.otf", vector = "tex-ss", optional=true },
        { name = "lmmono10-regular.otf", vector = "tex-tt", optional=true },
      },
    }
  }
}
\stopsmalltyping

Here the \type {px-math} virtual font is defined. A series of fonts is loaded and
combined into one. The \type {vector} entry is used to tell the builder how to
map the glyphs onto \UNICODE. Additional vectors can be defined, for instance:

\starttyping
fonts.encodings.math["mine"] = {
    [0x1234] = 0x56,
}
\stoptyping

Eventually these specifications wil be replaced by real \OPENTYPE\ fonts, but
even then we will keep the virtual definitions around.

\startsection[title=Math alternates]

In addition to the official \type {ssty} feature for enforcing usage of script
and scriptscript glyphs, some stylistic alternates can be present.

\startsmalltyping
return {
  name = "xits-math",
  version = "1.00",
  comment = "Goodies that complement xits (by Khaled Hosny).",
  author = "Hans Hagen",
  copyright = "ConTeXt development team",
  mathematics = {
    alternates = {
      cal       = {
        feature = 'ss01',
        value   = 1,
        comment = "Mathematical Calligraphic Alphabet"
      },
      greekssup = {
        feature = 'ss02',
        value   = 1,
        comment = "Mathematical Greek Sans Serif Alphabet"
      },
      greekssit = {
        feature = 'ss03',
        value   = 1,
        comment = "Mathematical Italic Sans Serif Digits"
      },
      monobfnum = {
        feature = 'ss04',
        value   = 1,
        comment = "Mathematical Bold Monospace Digits"
      },
      mathbbbf  = {
        feature = 'ss05',
        value   = 1,
        comment = "Mathematical Bold Double-Struck Alphabet"
      },
      mathbbit  = {
        feature = 'ss06',
        value   = 1,
        comment = "Mathematical Italic Double-Struck Alphabet"
      },
      mathbbbi  = {
        feature = 'ss07',
        value   = 1,
        comment = "Mathematical Bold Italic Double-Struck Alphabet"
      },
      upint     = {
        feature = 'ss08',
        value   = 1,
        comment = "Upright Integrals"
      },
    }
  }
}
\stopsmalltyping

These can be activated (in math mode) with the \type {\mathalternate} command
like:

\starttyping
$\mathalternate{cal}Z$
\stoptyping

\stopsection

\startsection[title=Math parameters]

Another goodie related to math is the overload of some parameters (part of the
font itself) and variables (used in making virtual shapes).

\startsmalltyping
return {
  name = "lm-math",
  version = "1.00",
  comment = "Goodies that complement latin modern math.",
  author = "Hans Hagen",
  copyright = "ConTeXt development team",
  mathematics = {
    mapfiles = {
      "lm-math.map",
      "lm-rm.map",
      "mkiv-base.map",
    },
    virtuals = {
      ["lmroman5-math"]      = five,
      ["lmroman6-math"]      = six,
      ["lmroman7-math"]      = seven,
      ["lmroman8-math"]      = eight,
      ["lmroman9-math"]      = nine,
      ["lmroman10-math"]     = ten,
      ["lmroman10-boldmath"] = ten_bold,
      ["lmroman12-math"]     = twelve,
      ["lmroman17-math"]     = seventeen,
    },
    variables = {
      joinrelfactor = 3, -- default anyway
    },
    parameters = { -- test values
  --  FactorA = 123.456,
  --  FactorB = false,
  --  FactorC = function(value,target,original) return 7.89 * target.factor end,
  --  FactorD = "Hi There!",
    },
  }
}
\stopsmalltyping

In this example you see several virtuals defined which is due to the fact that
Latin Modern has design sizes. The values (like \type {twelve} are tables defined
before the return happens and are not shown here. The variables are rather
\CONTEXT\ specific, and the parameters are those that come with regular
\OPENTYPE\ math fonts (so the example names are invalid).

In the following example we show two wasy to change parameters. In this case we
have a regular \OPENTYPE\ math font. First we install a patch to the font itself.
That change will be cached. We could also have changed that parameter using the
goodies table. The first method is the oldest.

\startsmalltyping
local patches = fonts.handlers.otf.enhancers.patches

local function patch(data,filename,threshold)
  local m = data.metadata.math
  if m then
    local d = m.DisplayOperatorMinHeight or 0
    if d < threshold then
      patches.report("DisplayOperatorMinHeight(%s -> %s)",d,threshold)
      m.DisplayOperatorMinHeight = threshold
    end
  end
end

patches.register(
  "after",
  "check math parameters",
  "asana",
  function(data,filename)
    patch(data,filename,1350)
  end
)

local function less(value,target,original)
  return 0.25 * value
end

return {
  name = "asana-math",
  version = "1.00",
  comment = "Goodies that complement asana.",
  author = "Hans Hagen",
  copyright = "ConTeXt development team",
  mathematics = {
    parameters = {
      StackBottomDisplayStyleShiftDown = less,
      StackBottomShiftDown             = less,
      StackDisplayStyleGapMin          = less,
      StackGapMin                      = less,
      StackTopDisplayStyleShiftUp      = less,
      StackTopShiftUp                  = less,
      StretchStackBottomShiftDown      = less,
      StretchStackGapAboveMin          = less,
      StretchStackGapBelowMin          = less,
      StretchStackTopShiftUp           = less,
    }
  }
}
\stopsmalltyping

We use a function so that the scaling is taken into account as the values passed
are those resulting from the scaling of the font to the requested size.

\stopsection

\startsection[title=Unicoding]

We still have to deal with existing \TYPEONE\ fonts, and some of them have an
encoding that is hard to map onto \UNICODE\ without additional information. The
following goodie does that. The keys in the \type {unicodes} table are the glyph
names. Keep in mind that this only works with simple fonts. The \CONTEXT\ code
takes care of kerns but that's about it.

\startsmalltyping
return {
  name = "dingbats",
  version = "1.00",
  comment = "Goodies that complement dingbats (funny names).",
  author = "Hans Hagen",
  copyright = "ConTeXt development team",
  remapping = {
    tounicode = true,
    unicodes = {
      a1   = 0x2701,
      a10  = 0x2721,
      a100 = 0x275E,
      a101 = 0x2761,
      .............
      a98  = 0x275C,
      a99  = 0x275D,
    },
  },
}
\stopsmalltyping

The \type {tounicode} option makes sure that additional information ends ip in
the output so that cut|-|and|-|paste becomes more trustworthy.

\stopsection

\startsection[title=Typescripts]

Some font collections, like antykwa, come with so many variants that defining
them all in typescripts becomes somewhat of a nuisance. While a regular font has
a typescript of a few lines, antykwa needs way more lines. This is why we provide
a nother way as well, using goodies.

\startsmalltyping
return {
  name = "antykwapoltawskiego",
  version = "1.00",
  comment = "Goodies that complement Antykwa Poltawskiego",
  author = "Hans & Mojca",
  copyright = "ConTeXt development team",
  files = {
    name = "antykwapoltawskiego", -- shared
    list = {
      ["AntPoltLtCond-Regular.otf"] = {
     -- name   = "antykwapoltawskiego",
        weight = "light",
        style  = "regular",
        width  = "condensed",
      },
      ["AntPoltLtCond-Italic.otf"] = {
        weight = "light",
        style  = "italic",
        width  = "condensed",
      },
      ["AntPoltCond-Regular.otf"] = {
        weight = "normal",
        style  = "regular",
        width  = "condensed",
      },

      .......


      ["AntPoltExpd-BoldItalic.otf"] = {
        weight = "bold",
        style  = "italic",
        width  = "expanded",
      },
    },
  },
  typefaces = { -- for Mojca (experiment, names might change)
    ["antykwapoltawskiego-light"] = {
      shortcut     = "rm",
      shape        = "serif",
      fontname     = "antykwapoltawskiego",
      normalweight = "light",
      boldweight   = "medium",
      width        = "normal",
      size         = "default",
      features     = "default",
    },

    .......

  },
}
\stopsmalltyping

This is a typical example of when a goodies file is loaded directly:

\starttyping
\loadfontgoodies[antykwapoltawskiego]
\stoptyping

A bodyfont is now defined by choosing from the defined combinations:

\starttyping
\definetypeface
  [name=mojcasfavourite,
   preset=antykwapoltawskiego,
   normalweight=light,
   boldweight=bold,
   width=expanded]

\setupbodyfont
  [mojcasfavourite]
\stoptyping

This mechanism is a follow up on a discussion at a \CONTEXT\ conference, still
somewhat experimental, and a playground for Mojca.

\stopsection

\startsection[title=Font strategies]

This goodie is closely related to the Oriental \TEX\ project where a dedicated
paragraph optimizer can be used. A rather advanced font is used (husayni) and its
associated goodie file is rather extensive. It defines stylistic features,
implements a couple of feature sets, provides colorschemes and most of all,
defines some strategies for making paragraphs look better. Some of the goodie
file is shown here.

\startsmalltyping
local yes = "yes"

local basics = {
  analyze  = yes,
  mode     = "node",
  language = "dflt",
  script   = "arab",
}

local analysis = {
  ccmp = yes,
  init = yes, medi = yes, fina = yes,
}

local regular = {
  rlig = yes, calt = yes, salt = yes, anum = yes,
  ss01 = yes, ss03 = yes, ss07 = yes, ss10 = yes, ss12 = yes, ss15 = yes, ss16 = yes,
  ss19 = yes, ss24 = yes, ss25 = yes, ss26 = yes, ss27 = yes, ss31 = yes, ss34 = yes,
  ss35 = yes, ss36 = yes, ss37 = yes, ss38 = yes, ss41 = yes, ss42 = yes, ss43 = yes,
  js16 = yes,
}

local positioning = {
  kern = yes, curs = yes, mark = yes, mkmk = yes,
}

local minimal_stretching = {
  js11 = yes, js03 = yes,
}

local medium_stretching = {
  js12=yes, js05=yes,
}

local maximal_stretching= {
  js13 = yes, js05 = yes, js09 = yes,
}

local wide_all = {
  js11 = yes, js12 = yes, js13 = yes, js05 = yes, js09 = yes,
}

local shrink = {
  flts = yes, js17 = yes, ss05 = yes, ss11 = yes, ss06 = yes, ss09 = yes,
}

local default = {
  basics, analysis, regular, positioning, -- xxxx = yes, yyyy = 2,
}

return {
  name = "husayni",
  version = "1.00",
  comment = "Goodies that complement the Husayni font by Idris Samawi Hamid.",
  author = "Idris Samawi Hamid and Hans Hagen",
  featuresets = { -- here we don't have references to featuresets
    default = {
      default,
    },
    minimal_stretching = {
      default,
      js11 = yes, js03 = yes,
    },
    medium_stretching = {
      default,
      js12=yes, js05=yes,
    },
    maximal_stretching= {
      default,
      js13 = yes, js05 = yes, js09 = yes,
    },
    wide_all = {
      default,
      js11 = yes, js12 = yes, js13 = yes, js05 = yes, js09 = yes,
    },
    shrink = {
      default,
      flts = yes, js17 = yes, ss05 = yes, ss11 = yes, ss06 = yes, ss09 = yes,
    },
  },
  solutions = { -- here we have references to featuresets, so we use strings!
    experimental = {
      less = {
        "shrink"
      },
      more = {
        "minimal_stretching",
        "medium_stretching",
        "maximal_stretching",
        "wide_all"
      },
    },
  },
  stylistics = {
    ......
    ss03 = "level-1 stack over Jiim, initial entry only",
    ss04 = "level-1 stack over Jiim, initial/medial entry",
    ......
    ss54 = "chopped finals",
    ss55 = "idgham-tanwin",
    ......
    js11 = "level-1 stretching",
    js12 = "level-2 stretching",
    ......
    js21 = "Haa.final_alt2",
  },
  colorschemes = {
    default = {
      [1] = {
        "Onedotabove", "Onedotbelow", ...
      },
      [2] = {
        "Fathah", "Dammah", "Kasrah", ...
      },
      [3] = {
        "Ttaa.waqf", "SsLY.waqf", "QLY.waqf", ...
      },
      [4] = {
        "ZeroArabic.ayah", "OneArabic.ayah", "TwoArabic.ayah", ...
      },
      [5] = {
        "Ayah", "Ayah.alt1", "Ayah.alt2", ...
      }
    }
  }
}
\stopmalltyping

Discussion of these goodies is beyond this document and happens elsewhere.

\stopsection

\startsection[title=Composition]

The \type {compose} features extends a font with additional (virtual) shapes.
This is mostly used with \TYPEONE\ fonts that lack support for eastern european
languages. The type {compositions} subtable is used to control placement of
accents. This can be done per font.

\startmalltyping
local defaultunits = 193 - 30

-- local compose = {
--                DY = defaultunits,
--   [0x010C] = { DY = defaultunits }, -- Ccaron
--   [0x02C7] = { DY = defaultunits }, -- textcaron
-- }

-- fractions relative to delta(X_height - x_height)

local defaultfraction = 0.85

local compose = {
  DY = defaultfraction, -- uppercase compensation
}

return {
  name = "lucida-one",
  version = "1.00",
  comment = "Goodies that complement lucida.",
  author = "Hans and Mojca",
  copyright = "ConTeXt development team",
  compositions = {
    ["lbr"]  = compose,
    ["lbi"]  = compose,
    ["lbd"]  = compose,
    ["lbdi"] = compose,
  }
}
\stopsmalltyping

\stopsection

\startsection[title=Postprocessing]

You can hook postprocessors into the scaler. Future versions might provide more
control over where this happens.

\startsmalltyping
local function statistics(tfmdata)
    commands.showfontparameters(tfmdata)
end

local function squeeze(tfmdata)
  for k, v in next, tfmdata.characters do
    v.height = 0.75 * (v.height or 0)
    v.depth  = 0.75 * (v.depth  or 0)
  end
end

return {
  name = "demo",
  version = "1.00",
  comment = "An example of goodies.",
  author = "Hans Hagen",
  postprocessors = {
    statistics = statistics,
    squeeze    = squeeze,
  },
}
\stopsmalltyping

\stopsection

\stopchapter

\stopcomponent
