font-xtx.mkii / last modification: 2020-01-30 14:15
%D \module
%D   [       file=font-xtx,
%D        version=2004.09.11,
%D          title=\CONTEXT\ Font Macros,
%D       subtitle=\XETEX\ Hacks,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

\ifnum\texengine=\xetexengine
    \writestatus{loading}{ConTeXt Font Macros / XeTeX Hacks}
\else
    \endinput
\fi

\unprotect

%D Features:

% \definefontfeature[default]     [liga=yes,texligatures=yes,texquotes=yes]
% \definefontfeature[default-caps][liga=yes,texligatures=yes,texquotes=yes,smcp=yes,script=latn]
%
% \starttypescript [serif] [palatino-nova-regular] [name]
%     \definefontsynonym[Serif]    [palatinonova-regular][features=default]
%     \definefontsynonym[SerifCaps][palatinonova-regular][features=default-caps] % also sets Serif
% \stoptypescript
%
% \starttypescript [serif] [palatino-nova-regular] [name]
%     \definefontsynonym[Serif]          [palatinonova-regular*default]
%     \definefontsynonym[SerifCaps]      [palatinonova-regular*default-caps]
% \stoptypescript

% \definetypeface[mainface][rm][serif][palatino-nova-regular][default] \setupbodyfont[mainface]
%
% \starttext
%   ``Test'' -- --- ff fi fl \sc ``Test'' -- --- ff fi fl
% \stoptext

% \starttext
%     \definefont
%         [blabla]
%         [name:Latin Modern Something]
%     \definefont
%         [blabla]
%         [file:texnansi-lmr10]
%     \blabla test
%     \definefont
%         [blabla]
%         [texnansi-lmtt10]
%     \blabla test
% \stoptext

\def\definefontfeature
  {\dotripleargument\dodefinefontfeature}

\def\dododefinefontfeature#1%
  {\edef\!!stringa{\ifx\!!stringa\empty\else\!!stringa,\fi\executeifdefined{\??fa#1}\empty}}

\def\dodefinefontfeature[#1][#2][#3]%
  {\doifassignmentelse{#2}
     {\setevalue{\??fa#1}{#2}}
     {\let\!!stringa\empty
      \processcommalist[#2]\dododefinefontfeature
      \setevalue{\??fa#1}{\ifx\!!stringa\empty\else\!!stringa,\fi#3}}}

\definefontfeature
  [default]
  [liga=yes,kern=yes,tlig=yes,trep=yes] % texligatures=yes,texquotes=yes

\definefontfeature
  [smallcaps]
  [liga=yes,kern=yes,tlig=yes,trep=yes,smcp=yes] % texligatures=yes,texquotes=yes

\definefontfeature
  [oldstyle]
  [liga=yes,kern=yes,tlig=yes,trep=yes,onum=yes] % texligatures=yes,texquotes=yes

\definefontfeature % no calt
  [arabic]
  [language=dflt,script=arab,
   init=yes,medi=yes,fina=yes,isol=yes,
   liga=yes,dlig=yes,rlig=yes,clig=yes,
   mark=yes,mkmk=yes,kern=yes,curs=yes]

\definefontfeature
  [none]
  [features=no]

%D Overloaded:

\def\getfontfileparameters#1% can be simpler for mkii (no features)
  {\edef\@@truefontname{\truefontname{#1}}%
   \edef\currentfontfileencoding{\truefontdata\@@truefontname\s!encoding}%
   \edef\currentfontfilemapping {\truefontdata\@@truefontname\s!mapping }%
   \edef\currentfontfilehandling{\truefontdata\@@truefontname\s!handling}%
   \edef\currentfontfilefeatures{\truefontdata\@@truefontname\s!features}}

\def\updatefontparameters
  {\edef\@@fontencoding{\truefontdata\fontfile    \s!encoding}%
   \edef\@@fontmapping {\truefontdata\fontfile    \s!mapping }%
   \edef\@@fonthandling{\truefontdata\somefontname\s!handling}%
   \edef\@@fontfeatures{\truefontdata\fontfile    \s!features}%
   \edef\@@fontskewchar{\truefontdata\fontfile    \s!skewchar}}

%D Loading:
%D
%D for some reason xetex does not support [filename] for tfm files and
%D quotes also behave kind of strange " vs ' vs [ vs ...
%D
%D \starttyping
%D \font\myfont =  msam7         % ok
%D \font\myfont = "msam7"        % also ok
%D \font\myfont = "msam7" at 8pt % error
%D \stoptyping

\newconditional\tracexetexfonts

%D Because \XETEX\ is not that fast on locating fonts we cache lookups so
%D that we minimize the test. It saves a little bit of runtime, depending
%D on the number of fonts loaded (which is normally not that much).

\def\doiffoundXTXfontelse#1#2%
  {\ifcsname xtx@fnt@#2\somefontspec\endcsname
     \ifconditional\tracexetexfonts
       \writestatus\m!fonts{already checked #1: #2\somefontspec\space (state: \number\csname xtx@fnt@#2\somefontspec\endcsname)}%
     \fi
   \else
     \suppressfontnotfounderror\plusone
     \font\xetextempfont=#2\somefontspec\relax
     \suppressfontnotfounderror\zerocount
     \edef\xetextempfont{\fontname\xetextempfont}%
     \global\expandafter\chardef\csname xtx@fnt@#2\somefontspec\endcsname
     \ifx\xetextempfont\nullfontname
       \zerocount \ifconditional\tracexetexfonts
         \writestatus\m!fonts{not found #1: #2\somefontspec}%
       \fi
     \else
       \plusone \ifconditional\tracexetexfonts
         \writestatus\m!fonts{found #1: #2\somefontspec}%
       \fi
     \fi
   \fi
   \ifcase\csname xtx@fnt@#2\somefontspec\endcsname
     \expandafter\secondoftwoarguments
   \else
     \expandafter\firstoftwoarguments
   \fi}

\def\docheckfontfilenameprefix#1:#2:#3#4\relax
  {\edef\!!stringa{#1}%
   \edef\!!stringb{#2}%
   \ifx\!!stringb\empty
     % no prefix
     \let\checkedfontfile\!!stringa
     \doiffoundXTXfontelse{1a}{\checkedfontfile\checkedfontfeatures}
       {\edef\checkedfontfile{\checkedfontfile\checkedfontfeatures}}
       {\doiffoundXTXfontelse{1b}{"\checkedfontfile\checkedfontfeatures"}
          {\edef\checkedfontfile{"\checkedfontfile\checkedfontfeatures"}}
          {\doiffoundXTXfontelse{1c}{"[\checkedfontfile]\checkedfontfeatures"}
             {\edef\checkedfontfile{"[\checkedfontfile]\checkedfontfeatures"}}
             {}}}%
   \else\ifx\!!stringa\v!file
     % force file, only file check when no spaces
     \let\checkedfontfile\!!stringb
     \doiffoundXTXfontelse{2a}{"[\checkedfontfile]\checkedfontfeatures"}
       {\edef\checkedfontfile{"[\checkedfontfile]\checkedfontfeatures"}}
       {\doiffoundXTXfontelse{2b}{"\checkedfontfile\checkedfontfeatures"}
          {\edef\checkedfontfile{"\checkedfontfile\checkedfontfeatures"}}
          {}}%
   \else\ifx\!!stringa\v!name
     % force name, always lookup by xetex itself, "" forces otf/ttf/type1
     \edef\checkedfontfile{"\!!stringb\checkedfontfeatures"}%
     \ifconditional\tracexetexfonts
       \writestatus\m!fonts{no checking 3a: \checkedfontfile}%
     \fi
   \else
     % whatever, maybe even xetex spec, forget about features
     \edef\checkedfontfile{"\!!stringa\!!stringb"}%
     \ifconditional\tracexetexfonts
       \writestatus\m!fonts{no checking 3b: \checkedfontfile}%
     \fi
   \fi\fi\fi}

\newconditional\enabledfontfeatures

\def\checkfontfilename% -- todo: integrate so that we call do.. directly
  {\expandafter\docheckfontfilename\fontfile*\empty*\relax}

\def\docheckfontfilename#1*#2#3*#4\relax % class overrules file
  {\settrue\enabledfontfeatures
   \edef\checkedfontfeatures
     {\expandafter\ifx\csname\fontclass\s!features\endcsname\empty
        \ifx\@@fontfeatures\empty\ifx#2\empty\else#2#3\fi\else\@@fontfeatures\fi
      \else\expandafter\ifx\csname\fontclass\s!features\endcsname\relax % redundant, will go away
        \ifx\@@fontfeatures\empty\ifx#2\empty\else#2#3\fi\else\@@fontfeatures\fi
      \else
        \csname\fontclass\s!features\endcsname
      \fi\fi}%
   \ifx\checkedfontfeatures\empty
     % done
   \else
     \edef\checkedfontfeatures{\executeifdefined{\??fa\checkedfontfeatures}\empty}%
     \ifx\checkedfontfeatures\empty
       % done
     \else
       \let\convertedfontfeatures\empty
       \processcommacommand[\checkedfontfeatures]\doconvertfontfeatures % raw
       \ifx\convertedfontfeatures\empty
         \let\checkedfontfeatures\empty
       \else\ifconditional\enabledfontfeatures
         \edef\checkedfontfeatures{:\convertedfontfeatures}%
       \else
         \let\checkedfontfeatures\empty
       \fi\fi
     \fi
   \fi
   \docheckfontfilenameprefix#1:\empty:\empty\relax
   \doshowcheckedfontfeatures}

\edef\@@fontfeaturesareno {features\v!no}
\edef\@@fontfeaturesareoff{features\v!off}

\def\dodoconvertfontfeatures#1=#2#3=#4\relax
  {\ifx#2\empty
     % invalid feature
   \else\ifcsname @xtx@#1@#2#3\endcsname
     \expandafter\ifx\csname @xtx@#1@#2#3\endcsname\empty\else
       \edef\convertedfontfeatures{\convertedfontfeatures\csname @xtx@#1@#2#3\endcsname;}%
     \fi
   \else
     \edef\!!stringa{#1}%
     \edef\!!stringb{#2#3}%
     \edef\!!stringc{#1#2#3}%
     \ifx\!!stringc\@@fontfeaturesareoff
       \setfalse\enabledfontfeatures
     \else\ifx\!!stringc\@@fontfeaturesareno
       \setfalse\enabledfontfeatures
     \else
       \edef\convertedfontfeatures
         {\convertedfontfeatures
          \ifx\!!stringb\v!yes
            +\!!stringa
          \else\ifx\!!stringb\v!on
            +\!!stringa
          \else\ifx\!!stringb\v!no
            -\!!stringa
          \else\ifx\!!stringb\v!off
            -\!!stringa
          \else
            \!!stringa=\!!stringb
          \fi\fi\fi\fi;}%
     \fi\fi
   \fi\fi}

\def\doconvertfontfeatures#1%
  {\dodoconvertfontfeatures#1=\empty=\relax}

\def\remapfontfeature #1 #2 #3 {\setevalue{@xtx@#1@#2}{#3}}

% this may move to another file, maybe font-xtx

\remapfontfeature tlig          yes  mapping=tlig
%remapfontfeature tlig          no   mapping=
\remapfontfeature trep          yes  {}
\remapfontfeature trep          no   {}
\remapfontfeature texligatures  yes  mapping=tlig
%remapfontfeature texligatures  no   mapping=
%remapfontfeature texquotes     yes  mapping=tex-text
%remapfontfeature texquotes     no   mapping=

%D Variants:

\unexpanded\def\variant[#1]%
  {\dosetscaledfont
   \font\variantfont\truefontname{\fontstringA\fontstylesuffix\fontvariant\fontstringA{#1}} at \scaledfont
   \variantfont}

%D Possible optimizations:

% \def\updatefontparameters
%   {\edef\@@fontfeatures{\truefontdata\fontfile\s!features}%
%    \edef\@@fontskewchar{\truefontdata\fontfile\s!skewchar}}

% \def\setfontcharacteristics
%   {\updatefontparameters % redundant, will go away, faster too
%    \the\everyfont}

% \let\synchronizepatternswithfont\relax

%D Names:

% We need to move the feature into the filename else it may be
% overloaded by another reference. For instance the definition of
% a regular and caps variant can use the same font.

% We could use an indirect method ... store in 'array' and refer to
% slot.

\def\definefontsynonym[#1]#2[#3]%
  {\edef\@@fontname{#1}%
   \edef\@@fontfile{#3}%
   \doifnextoptionalelse\dodefinefontsynonym\nodefinefontsynonym}

\def\nodefinefontsynonym
  {\@EA\let\csname\??ff\fontclass\@@fontname\endcsname\@@fontfile
%    \@EA\let\csname\??ff\@@fontfile\s!features\endcsname\undefined
}

\def\dodefinefontsynonym[#1]%
  {\edef\@@fontdata{#1}%
   \ifx\@@fontdata\empty
     \nodefinefontsynonym
   \else
     \ifx\fontclass\empty
       \getfontparameters
     \else
       \getglobalfontparameters
     \fi
     \ifcsname\??ff\@@fontfile\s!features\endcsname
       \@EA\edef\csname\??ff\fontclass\@@fontname\endcsname{\@@fontfile*\csname\??ff\@@fontfile\s!features\endcsname}%
       \@EA\let\csname\??ff\@@fontfile\s!features\endcsname\undefined
     \else
       \nodefinefontsynonym
     \fi
   \fi}

\let\definefontfile\definefontsynonym % dedicated to Taco Hoekwater

% simple version
%
% \def\truefontname#1%
%   {\@EA\dotruefontname#1*\relax}
%
% \def\dotruefontname#1*#2\relax
%   {\ifcsname\??ff\fontclass#1\endcsname
%      \@EA\truefontname\csname\??ff\fontclass#1\endcsname
%    \else\ifcsname\??ff#1\endcsname
%      \@EA\truefontname\csname\??ff#1\endcsname
%    \else
%      #1%
%    \fi\fi}
%
% last counts
%
% \def\truefontname#1%
%   {\@EA\dotruefontname#1*\empty*\relax}
%
% \def\dotruefontname#1*#2#3*#4\relax
%   {\ifcsname\??ff\fontclass#1\endcsname
%      \ifx#2\empty
%        \@EA\truefontname\csname\??ff\fontclass#1\endcsname
%      \else
%        \@EA\truefontname\csname\??ff\fontclass#1\endcsname*#2#3%
%      \fi
%    \else\ifcsname\??ff#1\endcsname
%      \ifx#2\empty
%        \@EA\truefontname\csname\??ff#1\endcsname
%      \else
%        \@EA\truefontname\csname\??ff#1\endcsname*#2#3%
%      \fi
%    \else
%      \ifx#2\empty
%        #1%
%      \else
%        #1*#2#3%
%      \fi
%    \fi\fi}
%
% first counts

\def\truefontname#1%
  {\@EA\dotruefontname#1*\empty*\relax}

\def\dotruefontname#1*#2#3*#4\relax
  {\ifcsname\??ff\fontclass#1\endcsname
     \ifx#2\empty
       \@EA\truefontname\csname\??ff\fontclass#1\endcsname
     \else
       \@EA\redotruefontname\csname\??ff\fontclass#1\endcsname*#2#3%
     \fi
   \else\ifcsname\??ff#1\endcsname
     \ifx#2\empty
       \@EA\truefontname\csname\??ff#1\endcsname
     \else
       \@EA\redotruefontname\csname\??ff#1\endcsname*#2#3%
     \fi
   \else
     #1\ifx#2\empty\else*#2#3\fi
   \fi\fi}

\def\redotruefontname#1%
  {\@EA\dodotruefontname#1*\relax}

\def\dodotruefontname#1*#2\relax
  {\ifcsname\??ff\fontclass#1\endcsname
     \@EA\redotruefontname\csname\??ff\fontclass#1\endcsname
   \else\ifcsname\??ff#1\endcsname
     \@EA\redotruefontname\csname\??ff#1\endcsname
   \else
     #1%
   \fi\fi}

%D Default:

\def\defaultfontfile{file:lmmono10-regular}

%D Maybe:

% \def\updatefontparameters
%   {\edef\@@fontfeatures{\truefontdata\fontfile    \s!features}%
%    \edef\@@fontskewchar{\truefontdata\fontfile    \s!skewchar}}

% \def\setfontcharacteristics
%   {%\updatefontparameters % redundant, will go away, faster too
%    \the\everyfont
%    \synchronizepatternswithfont}

\protect \endinput

% \starttypescript[serif] [myzhfont]
%     \definefontsynonym [Serif]           [file:SimSun]
%     \definefontsynonym [SerifBold]       [file:SimSun]
%     \definefontsynonym [SerifItalic]     [file:SimSun]
%     \definefontsynonym [SerifBoldItalic] [file:SimSun]
% \stoptypescript
% \starttypescript[sans] [myzhfont]
%     \definefontsynonym [Sans]           [file:SimSun]
%     \definefontsynonym [SansBold]       [file:SimSun]
%     \definefontsynonym [SansItalic]     [file:SimSun]
%     \definefontsynonym [SansBoldItalic] [file:SimSun]
% \stoptypescript
% \starttypescript[mono] [myzhfont]
%     \definefontsynonym [Mono]           [file:SimSun]
%     \definefontsynonym [MonoBold]       [file:SimSun]
%     \definefontsynonym [MonoItalic]     [file:SimSun]
%     \definefontsynonym [MonoBoldItalic] [file:SimSun]
% \stoptypescript
% \definetypeface [myzhfont] [rm] [serif][myzhfont]   [default]
% \definetypeface [myzhfont] [ss] [sans] [myzhfont]   [default]
% \definetypeface [myzhfont] [tt] [mono] [myzhfont]   [default]

% \starttext
%     % on windows: make sure fonts.conf has no cache mentioned
%     %
%     % 64 sec xetex, 11 sec luatex (56 sec xetex when \nobigmath)
%     %
%       \setupbodyfont[myzhfont] \dorecurse{10000}{{hello {\switchtobodyfont[myzhfont] 你好}}\par}
%     %
%     % 67 sec xetex, 11.5 sec luatex
%     %
%     % \dorecurse{10000}{{hello {\switchtobodyfont[myzhfont] 你好}}\par}
%     %
%     % 5 sec xetex, 7 sec luatex
%     %
%     % \setupbodyfont[myzhfont]  \dorecurse{10000}{{hello {你好}}\par}
%     %
%     % 5 sec xetex, 7 sec luatex
%     %
%     % \setupbodyfont[myzhfont]  \dorecurse{10000}{{\bf hello {你好}}\par}
% \stoptext