%% This is part of the OpTeX project, see http://petr.olsak.net/optex

\_codedecl \fontfam {Fonts selection system <2023-06-16>} % preloaded in format

   \_doc -----------------------------
   The main principle of the Font Selection System is: run one or more
   modifiers followed by \^`\fontsel`. Modifiers save data and \^`\fontsel`
   selects the font considering saved data. Each basic variant selector
   \`\rm`, \`\bf`, \`\it`, \`\bi`, and \`\tt` runs internal variant modifier
   \`\_fmodrm`, \`\_fmodbf`, \`\_fmodit`, \`\_fmodbi` and \`\_fmodtt`.
   These modifiers save their data to the \`\_famv` macro which is
   `rm` or `bf` or `it` or `bi` or `tt`. The \`\currvar` selector
   is \^`\fontsel` by default, but variant selectors declared by
   \^`\famvardef` change it.
   \_cod -----------------------------

\_def\_famv{rm}  % default value
\_protected\_def \_fmodrm {\_def\_famv{rm}}
\_protected\_def \_fmodbf {\_def\_famv{bf}}
\_protected\_def \_fmodit {\_def\_famv{it}}
\_protected\_def \_fmodbi {\_def\_famv{bi}}
\_protected\_def \_fmodtt {\_def\_famv{tt}}

\_protected\_def \_rm {\_fmodrm \_fontsel \_marm}
\_protected\_def \_bf {\_fmodbf \_fontsel \_mabf}
\_protected\_def \_it {\_fmodit \_fontsel \_mait}
\_protected\_def \_bi {\_fmodbi \_fontsel \_mabi}
\_protected\_def \_tt {\_fmodtt \_fontsel \_matt}
\_protected\_def \_currvar {\_fontsel} \_protected\_def \currvar{\_currvar}
\_public \rm \bf \it \bi \tt ;

   \_doc -----------------------------
   The \`\fontsel` creates the <font switch> in the format `\_ten<famv>`
   and loads the font associated to the <font switch>.
   The loading is done by:
   \begitems \style a
   * `\letfont <font switch> = \savedswitch \_sizespec`
   * `\font <font switch> = \fontnamegen \_sizespec`
   \enditems
   The a) variant is used when \~`\_fontnamegen` isn't defined, i.e.\
   \^`\fontfam` wasn't used: only basic variant and \^`\_sizespec` is taken
   into account. The b) variant is processed when \^`\fontfam` was used:
   all data saved by all font modifiers are used during expansion of \^`\_fontnamegen`.\nl
   After the font is loaded, final job is done by \`\_fontselA``<font-switch>`.
   \_cod -----------------------------

\_protected\_def \_fontsel {%
   \_ifx\_fontnamegen\_undefined % \fontfam was not used
      \_ea\_let \_ea\_tmpf \_csname _ten\_famv\_endcsname
      \_ea\_fontlet \_csname _ten\_xfamv\_endcsname \_tmpf \_sizespec
   \_else % \fontfam is used
      \_ea\_font \_csname _ten\_xfamv\_endcsname {\_fontnamegen}\_sizespec
   \_fi \_relax
   \_ea \_fontselA \_csname _ten\_xfamv\_endcsname
}
\_def\_fontselA #1{%
   \_protected\_def \_currvar {\_fontsel}% default value of \_currvar
   \_logfont #1%    font selecting should be logged.
   \_setwsp  #1%    wordspace setting
   \_fontloaded #1% initial settings if font is loaded firstly
   #1% select the font
}
\_def \_logfont #1{}
\_def \_xfamv {\_famv}

\_public \fontsel ;

   \_doc -----------------------------
   If a font is loaded by macros \^`\fontsel` or \^`\resizethefont` then the
   \`\_fontloaded``<font switch>` is called immediately after it. If the font
   is loaded first then its `\skewchar` is equal to $-1$. We run
   \`\_newfontloaded``<font switch>` and set `\skewchar=-2` in this case.
   A user can define a `\_newfontloaded` macro. We are sure that
   `\_newfontloaded` macro is called only once for each instance of the font
   given by its name, OTF features and size specification. The `\skewchar` value is
   globally saved to the font (like `\fontdimen`). If it is used in math
   typesetting then it is set to a positive value.\nl
   The `\_newfontloaded` should be defined for micro-typographic configuration of
   fonts, for example. The `mte.opm` package uses it. See also
   \ulink[http://petr.olsak.net/optex/optex-tricks.html\#fontexpand]{\OpTeX/ trick 0058}.
   \_cod -----------------------------

\_def\_fontloaded #1{\_ifnum\_skewchar#1=-1 \_skewchar#1=-2 \_newfontloaded#1\_fi}
\_def\_newfontloaded #1{}

   \_doc -----------------------------
   \`\_ttunifont` is default font for \^`\tt` variant when \^`\initunifonts` is declared.
   User can re-define it or use \^`\famvardef``\tt`.
   The \`\_unifmodtt` macro is used instead \^`\_fmodtt` after
   \^`\initunifonts`. It ignores the loading part of the following \^`\fontsel`
   and do loading itself.
   \_cod -----------------------------

\_def\_ttunifont{[lmmono10-regular]:\_fontfeatures-tlig;}
\_def\_unifmodtt\_fontsel{%  ignore following \_fontsel
   \_ea\_font \_csname _ten\_ttfamv\_endcsname {\_ttunifont}\_sizespec \_relax
   \_ea\_fontselA \_csname _ten\_ttfamv\_endcsname
   \_def \_currvar{\_tt}%
}
\_def\_ttfamv{tt}

   \_doc ----------------------------
   A large part of the Font Selection System was re-implemented in Feb. 2022.
   We want to keep backward compatibility:
   \_cod ----------------------------

\_def \_tryloadrm\_tenrm {\_fmodrm \_fontsel}
\_def \_tryloadbf\_tenbf {\_fmodbf \_fontsel}
\_def \_tryloadit\_tenit {\_fmodit \_fontsel}
\_def \_tryloadbi\_tenbi {\_fmodbi \_fontsel}
\_def \_tryloadtt\_tentt {\_fmodtt \_fontsel}
\_def \_reloading {}

   \_doc -----------------------------
   The \`\_famdecl` `[<Family Name>] \<Famselector> {<comment>} {<modifiers>} {<variants>} {<math>}`\nl
   `{<font for testing>} {\def`\^`\_fontnamegen``{<data>}}` runs \^`\initunifonts`, then
   checks if `\<Famselector>` is defined. If it is true, then closes the file by
   `\endinput`. Else it defines `\<Famselector>` and saves it to the
   internal `\_f:<currfamily>:main.fam` command.
   The macro \`\_initfontfamily` needs it. The \`\_currfamily` is set
   to the `<Famselector>` because the following \^`\moddef` commands need to
   be in the right font family context. The `\_currfamily` is set to the
   `<Famselector>` by the `\<Famselector>` too, because `\<Famselector>`
   must set the right font family context. The font family context is given by the current
   `\_currfamily` value and by the current meaning of the \^`\_fontnamegen` macro.
   The \`\_mathfaminfo` is saved for usage in the catalog.
   \_cod -----------------------------

\_def\_famdecl [#1]#2#3#4#5#6#7#8{%
   \_initunifonts \_unichars \_uniaccents
   \_unless\_ifcsname _f:\_csstring#2:main.fam\_endcsname
      \_isfont{#7}\_iffalse
         \_opwarning{Family [#1] skipped, font "#7" not found}\_endinput
         \_ifcsname _fams:\_famfile\_endcsname \_famsubstitute \_fi
      \_else
         \_edef\_currfamily {\_csstring #2}\_def\_mathfaminfo{#6}%
         \_wterm {FONT: [#1] -- \_string#2 \_detokenize{(#3)^^J mods:{#4} vars:{#5} math:{#6}}}%
         \_unless \_ifx #2\_undefined
            \_opwarning{\_string#2 is redefined by \_string\_famdecl\_space[#1]}\_fi
         \_protected\_edef#2{\_def\_noexpand\_currfamily{\_csstring #2}\_unexpanded{#8\_resetfam}}%
         \_ea \_let \_csname _f:\_currfamily:main.fam\_endcsname =#2%
      \_fi
   \_else \_csname _f:\_csstring#2:main.fam\_endcsname \_rm \_endinput \_empty\_fi
}
\_def\_initfontfamily{%
   \_csname _f:\_currfamily:main.fam\_endcsname \_rm
}

   \_doc -----------------------------
   \`\_fvars` `<rm-template> <bf-template> <it-template> <bi-template>`
   saves data for usage by the `\_currV` macro. If a template is only dot
   then previous template is used (it can be used if the font family doesn't
   dispose with all standard variants).
   \nl
   \`\_currV` expands to a template declared by `\_fvars` depending on the
   `<variant name>`. Usable only of standard four variants. Next variants
   can be declared by the \^`\famvardef` macro.
   \nl
   \`\_fsetV` `<key>=<value>,...,<key>=<value>` expands to
   `\def\_<key>V{<value>}` in the loop.
   \nl
   \`\_onlyif` `<key>=<value-a>,<value-b>...,<value-z>: {<what>}`
   runs <what> only if the `\_<key>V` is defined as `<value-a>` or
   `<value-b>` or ... or `<value-z>`.
   \nl
   \`\_prepcommalist` `ab,{},cd,\_fin,` expands to `ab,,cd,` (auxiliary macro
   used in `\_onlyif`).\nl
   \`\_ffonum` is a shortcut for oldstyle digits font features used in
   font family files. You can do `\let\_ffonum=\ignoreit` if you don't want
   to set old digits together with `\caps`.
   \_cod -----------------------------

\_def\_fvars #1 #2 #3 #4 {%
   \_sdef{_fvar:rm}{#1}%
   \_sdef{_fvar:bf}{#2}%
   \_ifx.#2\_slet{_fvar:bf}{_fvar:rm}\_fi
   \_sdef{_fvar:it}{#3}%
   \_ifx.#3\_slet{_fvar:it}{_fvar:rm}\_fi
   \_sdef{_fvar:bi}{#4}%
   \_ifx.#4\_slet{_fvar:bi}{_fvar:it}\_fi
}
\_def\_currV{\_trycs{_fvar:\_famv}{rm}}
\_def\_V{ }
\_def \_fsetV #1 {\_fsetVa #1,=,}
\_def \_fsetVa #1=#2,{\_isempty{#1}\_iffalse
   \_ifx,#1\_else\_sdef{_#1V}{#2}\_ea\_ea\_ea\_fsetVa\_fi\_fi
}
\_def \_onlyif #1=#2:#3{%
    \_edef\_act{\_noexpand\_isinlist{,\_prepcommalist #2,\_fin,}{,\_cs{_#1V},}}\_act
    \_iftrue #3\_fi
}
\_def\_prepcommalist#1,{\_ifx\_fin#1\_empty\_else #1,\_ea\_prepcommalist\_fi}
\_def\_ffonum {+onum;+pnum}

   \_doc -----------------------------
   The \`\moddef` `\<modifier> {<data>}` simply speaking does
   `\def\<modifier>{<data>}`, but we need to respect
   the family context. In fact, `\protected\def\_f:<current family>:<modifier>{<data>}` is
   performed and the `\<modifier>` is defined as
   \`\_famdepend``\<modifier>{_f:\_currfamily:<modifier>}`. It expands to
   `\_f:\_currfamily:<modifier>` value if it is defined or it prints
   the warning. When the `\_currfamily` value is
   changed then we can declare the same `\<modifier>` with a different meaning.

   \`\_setnewmeaning` `<cs-name>=\_tmpa <by-what>` does exactly `\_let <csname>=\_tmpa`
   but warning is printed if <cs-name> is defined already and it is not a variant
   selector or font modifier.

   \`\_addtomodlist` `<font modifier>` adds given modifier to \`\_modlist`
   macro. This list is used after \^`\resetmod` when a new family is selected by
   a family selector, see \`\_resetfam` macro.
   This allows reinitializing the same current modifiers in the font context
   after the family is changed.
   \_cod -----------------------------

\_def \_moddef #1#2{%
   \_edef\_tmp{\_csstring#1}%
   \_sdef{_f:\_currfamily:\_tmp}{\_addtomodlist#1#2}%
   \_protected \_edef \_tmpa{\_noexpand\_famdepend\_noexpand#1{_f:\_noexpand\_currfamily:\_tmp}}%
   \_setnewmeaning #1=\_tmpa \moddef
}
\_protected \_def\_resetmod {\_cs{_f:\_currfamily:resetmod}} % private variant of \resetmod
\_def \_resetfam{%
   \_def\_addtomodlist##1{}\_resetmod
   \_edef \_modlist{\_ea}\_modlist
   \_let\_addtomodlist=\_addtomodlistb
   \_ifcsname _f:\_currfamily:\_ea\_csstring \_currvar \_endcsname
   \_else \_ea\_ifx\_currvar\_tt \_else \_def\_currvar{\_fontsel}\_fi
   \_fi % corrected \_currvar in the new family
}
\_def \_currfamily{} % default current family is empty
\_def \_modlist{}    % list of currently used modifiers

\_def \_addtomodlist#1{\_addto\_modlist#1}
\_let \_addtomodlistb=\_addtomodlist

\_def\_famdepend#1#2{\_ifcsname#2\_endcsname \_csname#2\_ea\_endcsname \_else
   \_ifx\_addtomodlist\_addtomodlistb
      \_opwarning{\_string#1 is undeclared in family "\_currfamily", ignored}\_fi\_fi
}
\_def\_setnewmeaning #1=\_tmpa#2{%
   \_ifx #1\_undefined \_else \_ifx #1\_tmpa \_else
      \_opwarning{\_string#1 is redefined by \_string#2}%
   \_fi\_fi
   \_let#1=\_tmpa
}
\_public \moddef ;

   \_doc -----------------------------
   \`\fontdef` `<font-switch> {<data>}` does:
   \begtt \catcode`\<=13
   \begingroup <data> \ea\endgroup \ea\let \ea<font-switch> \the\font
   \endtt
   It means that font modifiers used in <data> are applied in the group and the
   resulting selected font (current at the end of the group) is set to the
   <font-switch>.
   We want to declare <font-switch> in its real name directly by `\font` primitive in
   order to save this name for reporting later (in overfull messages, for
   example). This is the reason why \`\_xfamv` and \`\_ttfamv` are re-defined locally here.
   They have precedence when \^`\fontsel` constructs the <font switch> name.
   \_cod -----------------------------

\_protected\_def \_fontdef #1#2{\_begingroup
   \_edef\_xfamv{\_csstring#1}\_let\_ttfamv\_xfamv #2%
   \_ea\_endgroup\_ea \_let\_ea #1\_the\_font
}
\_public \fontdef ;

   \_doc -----------------------------
   The \`\famvardef` `\xxx {<data>}` does, roughly speaking:
   \begtt \catcode`\<=13
   \def \xxx {{<data>\ea}\the\font \def\_currvar{\xxx}}
   \endtt
   but the macro `\xxx` is declared as family-dependent.
   It is analogically as in `\moddef`.
   The `\xxx` is defined as `\_famdepend\xxx{_f:\_currfamily:xxx}`
   and `\_f:<currfam>:xxx` is defined as mentioned.\nl
   `\famvardef\tt` behaves somewhat differently: it defines internal version
   `\_tt` (it is used in \^`\_ttfont` and \^`\_urlfont`) and set `\tt` to
   the same meaning.
   \_cod -----------------------------

\_protected\_def \_famvardef #1#2{%
   \_sdef{_f:\_currfamily:\_csstring#1}%
      {{\_edef\_xfamv{\_csstring#1}\_let\_ttfamv\_xfamv #2\_ea}\_the\_font \_def\_currvar{#1}}%
   \_protected\_edef\_tmpa {%
      \_noexpand\_famdepend\_noexpand#1{_f:\_noexpand\_currfamily:\_csstring#1}}%
   \_ifx #1\tt
      \_protected\_def\_tt{{\_def\_xfamv{tt}#2\_ea}\_the\_font \_def\_currvar{\_tt}}%
      \_let\tt=\_tt
   \_else \_setnewmeaning #1=\_tmpa \famvardef
   \_fi
}
\_public \famvardef ;

   \_doc -----------------------------
   The \`\fontfam` `[<Font Family>]` does:
   \begitems
   * Convert its parameter to lower case and without spaces, e.g.\ `<fontfamily>`.
   * If the file `f-<fontfamily>.opm` exists read it and finish.
   * Try to load user defined `fams-local.opm`.
   * If the `<fontfamily>` is declared in `fams-local.opm` or `fams-ini.opm`
     read relevant file and finish.
   * Print the list of declared families.
   \enditems
   The `fams-local.opm` is read by the \`\_tryloadfamslocal` macro. It sets
   itself to `\_relax` because we need not load this file twice.
   The \`\_listfamnames` macro prints registered font families to the
   terminal and to the log file.
   \_cod -----------------------------

\_protected\_def \_fontfam [#1]{%
   \_lowercase{\_edef\_famname{\_ea\_removespaces \_expanded{#1} {} }}%
   \_isfile {f-\_famname.opm}\_iftrue \_edef\_famfile{f-\_famname}\_opinput {f-\_famname.opm}%
   \_else
       \_tryloadfamslocal
       \_edef\_famfile{\_trycs{_famf:\_famname}{}}%
       \_ifx\_famfile\_empty
           \_ifcsname _fams:f-\_famname \_endcsname \_edef\_famfile{f-\_famname}\_famsubstitute
           \_else \_listfamnames
           \_fi
       \_else \_opinput {\_famfile.opm}%
   \_fi\_empty\_fi
}
\_def\_tryloadfamslocal{%
   \_isfile {fams-local.opm}\_iftrue
      \_opinput {fams-local.opm}\_famfrom={}\_famsrc={}%
   \_fi
   \_let \_tryloadfamslocal=\_relax  % need not to load fams-local.opm twice
}
\_def\_listfamnames {%
   \_wterm{===== List of font families ======}
   \_begingroup
       \_let\_famtext=\_wterm
       \_def\_faminfo [##1]##2##3##4{%
           \_wterm{ \_space\_noexpand\fontfam [##1] -- ##2}%
       \_let\_famalias=\_famaliasA}%
       \_opinput {fams-ini.opm}%
       \_isfile {fams-local.opm}\_iftrue \_opinput {fams-local.opm}\_fi
       \_message{^^J}%
   \_endgroup
}
\_def\_famaliasA{\_message{ \_space\_space\_space\_space -- alias:}
   \_def\_famalias[##1]{\_message{[##1]}}\_famalias
}
\_public \fontfam ;

   \_doc -----------------------------
   \`\fontfamsub` `[<Family>][<byFamily>]` declares automatic substitution of
   <Family> by <byFamily> which is done when <Family> is not installed. I.e.
   if there is no `f-<family>.opm` file or there is no regular font of the
   family installed.
   \`\_famsubstitute` is internal macro used in \^`\fontfam` and \^`\_famdecl` macros.
   It consumes the rest of the macro, runs \^`\nospacefuturelet` in order to
   do `\endinput` to the current `f-file` and runs \^`\fontfam` again.
   The table of such substutitions are saved in the macros `\_fams:<family-file>`.
   \_cod -----------------------------

\_def \_fontfamsub [#1]#2[#3]{\_tryloadfamslocal
   \_lowercase{\_edef\_tmp{\_removespaces #1 {} }}%
   \_sxdef{_fams:\_trycs{_famf:\_tmp}{f-\_tmp}}{#3}%
}
\_def\_famsubstitute #1\_empty\_fi{\_fi\_fi\_fi
   \_wterm {FONT-SUB: \_famfile\_space -> [\_cs{_fams:\_famfile}]}%
   \_nospacefuturelet\_tmp\_famsubstituteA  % we want to \endinput current f-file
}
\_def\_famsubstituteA{\_fontfam[\_cs{_fams:\_famfile}]}

\_public \fontfamsub ;

   \_doc -----------------------------
   When the `fams-ini.opm` or `fams-local.opm` files are read then we need
   to save only a mapping from family names or alias names to the font family file
   names. All other information is ignored in this case. But if these files
   are read by the `\_listfamnames` macro or when printing a catalog then more
   information is used and printed.\nl
   \`\_famtext` does nothing or prints the text on the terminal.
   \nl
   \`\_faminfo` `[<Family Name>] {<comments>} {<file-name>} {<mod-plus-vars>}`
   does\nl `\_def \_famf:<familyname> {<file-name>}` (only if <file-name> differs
   from `f-<familyname>`) or prints information on the terminal. The
   <mod-plus-vars> data are used when printing the font catalog.
   \nl
   \`\_famalias` `[<Family Alias>]` does `\def \_famf:<familyalias> {<file-name>}`
   where `<file-name>` is stored from the previous `\_faminfo` command. Or
   prints information on the terminal.
   \nl
   \`\_famfrom` declares type foundry or owner or designer of the font family.
   It can be used in `fams-ini.opm` or `fams-local.opm` and it is printed
   in the font catalog.
   \nl
   \`\_famsrc` declares the source, where is the font family from (used in `fams-ini.opm`
   and if the font isn't found when the fonts catalog is printed).
   \_cod -----------------------------

\_def\_famtext #1{}
\_def\_faminfo [#1]#2#3#4{%
   \_lowercase{\_edef\_tmp{\_ea\_removespaces #1 {} }}%
   \_edef\_tmpa{f-\_tmp}\_def\_famfile{#3}%
   \_unless\_ifx\_tmpa\_famfile \_sdef{_famf:\_tmp}{#3}\_fi
}
\_def\_famalias [#1]{%
   \_lowercase{\_edef\_tmpa{\_ea\_removespaces #1 {} }}%
   \_sdef{_famf:\_tmpa\_ea}\_ea{\_famfile}%
}
\_newtoks\_famfrom  \_newtoks\_famsrc
\_input fams-ini.opm
\_let\_famfile=\_undefined
\_famfrom={} \_famsrc={}

   \_doc -----------------------------
   When the \^`\fontfam``[catalog]` is used then the file
   `fonts-catalog.opm` is read. The macro \^`\_faminfo` is redefined here
   in order to print catalog samples of all declared modifiers/variant
   pairs. The user can declare different samples and different behavior of
   the catalog, see the end of catalog listing for more information.
   The default parameters
   \`\catalogsample`, \`\catalogmathsample`, \`\catalogonly`,
   \`\catalogexclude` and \`\catalognextfam` of the catalog are declared here.
   \_cod -----------------------------

\_newtoks \_catalogsample
\_newtoks \_catalogmathsample
\_newtoks \_catalogonly
\_newtoks \_catalogexclude
\_newtoks \_catalognextfam
\_catalogsample={ABCDabcd Qsty fi fl �������������� ������ ���������� ������ 0123456789}
\_catalognextfam={\_bigskip}

\_public \catalogonly \catalogexclude \catalogsample \catalogmathsample \catalognextfam ;

   \_doc -----------------------------
   The font features are managed in the \`\_fontfeatures` macro.
   It expands to
   \begitems
   * \`\_defaultfontfeatures` -- used for each font,
   * \`\_ffadded` -- features added by \^`\setff`,
   * \`\_ffcolor` -- features added by \^`\setfontcolor` (this is obsolette)
   * \`\_ffletterspace` -- features added by \^`\setletterspace`,
   * \`\_ffwordspace` -- features added by \^`\setwordspace`.
   \enditems
   The macros \^`\_ffadded`, \^`\_ffcolor`, \^`\_ffletterspace`,
   \^`\_ffwordspace` are empty by default.
   \_cod -----------------------------

\_def \_fontfeatures{\_defaultfontfeatures\_ffadded\_ffcolor\_ffletterspace\_ffwordspace}
\_def \_defaultfontfeatures {+tlig;}
\_def \_ffadded{}
\_def \_ffcolor{}
\_def \_ffletterspace{}
\_def \_ffwordspace{}

   \_doc -----------------------------
   The \`\setff` `{<features>}` adds next font features to \^`\_ffadded`.
   Usage \^`\setff{}` resets empty set of all \^`\_ffadded` features.
   \_cod -----------------------------

\_def \_setff #1{%
   \_ifx^#1^\_def\_ffadded{}\_else \_edef\_ffadded{\_ffadded #1;}\_fi
}
\_public \setff ;

   \_doc -----------------------------
   \`\setletterspace` is based on the
   special font features provided by `luaotfload` package.\nl
   The \`\setwordspace` recalculates the `\fontdimen2,3,4`
   of the font using the \`\setwsp` macro which is used by the
   \^`\_fontselA` macro. It activates a dummy font feature `+Ws` too in
   order the font is reloded by the `\font` primitive (with independent
   `\fontdimen` registers).
   If the \^`\setwordspace` is used again to the same font then we need to
   reset `\fondimen` registers first. It is done by `\_sws:<fontname>`
   macro which keeps the original values of the `\fontdimen`s.\nl
   \`\setfontcolor` is kept here only for backward compatibility but not
   recommended. Use real color switches and the \^`\transparency` instead.
   \_cod -----------------------------

\_def \_setfontcolor #1{%
   \_edef\_tmp{\_calculatefontcolor{#1}}%
   \_ifx\_tmp\_empty \_def\_ffcolor{}\_else \_edef\_ffcolor{color=\_tmp;}\_fi
}
\_def \_setletterspace #1{%
   \_if^#1^\_def\_ffletterspace{}\_else \_edef\_ffletterspace{letterspace=#1;}\_fi
}
\_def \_setwordspace #1{%
   \_if^#1^\_def\_setwsp##1{}\_def\_ffwordspace{}%
   \_else \_def\_setwsp{\_setwspA#1/}\_def\_ffwordspace{+Ws;}\_fi
}
\_def\_setwsp #1{}
\_def\_setwspA #1{\_ifx/#1\_ea\_setwspB \_else\_afterfi{\_setwspC#1}\_fi}
\_def\_setwspB #1/#2/#3/#4{%
   \_csname _sws:\_fontname#4\_endcsname \_relax
   \_ea\_xdef \_csname _sws:\_fontname#4\_endcsname
      {\_foreach 234\_do{\_fontdimen##1#4=\_the\_fontdimen##1#4}}%
   \_fontdimen2#4=#1\_fontdimen2#4%
   \_fontdimen3#4=#2\_fontdimen3#4\_fontdimen4#4=#3\_fontdimen4#4}
\_def\_setwspC #1/{\_setwspB #1/#1/#1/}

\_def\_calculatefontcolor#1{\_trycs{_fc:#1}{#1}} % you can define more smart macro ...
\_sdef{_fc:red}{FF0000FF}    \_sdef{_fc:green}{00FF00FF} \_sdef{_fc:blue}{0000FFFF}
\_sdef{_fc:yellow}{FFFF00FF} \_sdef{_fc:cyan}{00FFFFFF}  \_sdef{_fc:magenta}{FF00FFFF}
\_sdef{_fc:white}{FFFFFFFF}  \_sdef{_fc:grey}{00000080}  \_sdef{_fc:lgrey}{00000025}
\_sdef{_fc:black}{} % ... you can declare more colors...

\_public \setfontcolor \setletterspace \setwordspace ;

   \_doc -----------------------------
   \`\_regoptsizes` `<internal-template> <left-output>?<right-output> <resizing-data>`
   prepares data for using by the \`\_optname` `<internal-template>` macro.
   The data are saved to the `\_oz:<internal-template>` macro.
   When the `\_optname` is expanded then the data are scanned by the macro
   \`\_optnameA` `<left-output>?<right-output> <mid-output> `\code{<}`<size>`
   in the loop.\nl
   \`\_optfontalias` `{<template A>}{<template B>}` is defined as
   `\let\_oz:<templateA>=\_oz:<templateB>`.
   \_cod -----------------------------

\_def\_regoptsizes #1 #2?#3 #4*{\_sdef{_oz:#1}{#2?#3 #4* }}
\_def\_optname #1{\_ifcsname _oz:#1\_endcsname
   \_ea\_ea\_ea \_optnameA \_csname _oz:#1\_ea\_endcsname
   \_else \_failedoptname{#1}\_fi
}
\_def\_failedoptname #1{optname-fails:(#1)}
\_def\_optnameA #1?#2 #3 <#4 {\_ifx*#4#1#3#2\_else
   \_ifdim\_optsize<#4pt #1#3#2\_optnameC
   \_else \_afterfifi \_optnameA #1?#2 \_fi\_fi
}
\_def\_optnameC #1* {\_fi\_fi}
\_def\_afterfifi #1\_fi\_fi{\_fi\_fi #1}
\_def\_optfontalias #1#2{\_slet{_oz:#1}{_oz:#2}}

\_setfontsize {at10pt} % default font size

\_endcode %---------------------------------------------------


\sec[fontsystem] The Font Selection System
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

The basic principles of the Font Selection System used in \OpTeX/
was documented in the section~\ref[fontfam].

\secc Terminology

We distinguish between
\begitems
* {\em font switches}, they are declared by the `\font` primitive or by
  \^`\fontlet` or \~`\fontdef` macros, they select given font.
* {\em variant selectors}, there are four basic variant selectors
  \^`\rm`, \^`\bf`, \^`\it`, \^`\bi`, there is a special selector \^`\currvar`.
  More variant selectors can be declared by the \~`\famvardef` macro.
  They select the font depending on the given variant and on the {\em font context}
  (i.e.\ on current family and on more features given by font modifiers).
  In addition, \OpTeX/ defines \~`\tt` as variant selector
  independent of chosen font family. It selects typewriter-like font.
* {\em font modifiers} are declared in a family (`\cond`, `\caps`) or are
  \"built-in" (\^`\setfontsize``{<size spec>}`, \~`\setff{<features>}`).
  They do appropriate change in the {\em font context} but do not select
  the font.
* {\em family selectors} (for example `\Termes`, `\LMfonts`),
  they are declared typically in the {\em font family files}.
  They enable to switch between font families, they do appropriate
  change in the {\em font context} but do not select
  the font.
\enditems

These commands set their values locally. When the \TeX/ group is
left then the selected font and the {\em font context} are returned back to the values
used when the group was opened. They have the following features:

The {\em font context} is a set of macro values that will affect the
selection of real font when the variant selector is processed. It includes the
value of {\em current family}, current font size, and
more values stored by font modifiers.

The {\em family context} is the current family name stored in the font
context. The variant selectors declared by \~`\famvardef` and
font modifiers declared by \~`\moddef` are dependent on the {\em family context}.
They can have the same names but different behavior in different families.

The fonts registered in \OpTeX/ have their macros in the {\em font family files},
each family is declared in one font family file with the name `f-famname.opm`.
All families are collected in `fams-ini.opm` and users can give more
declarations in the file `fams-local.opm`.

\secc Font families, selecting fonts

The \^`\fontfam` `[<Font Family>]` opens the relevant font family file where
the `<Font Family>` is declared. The family selector is defined here by rules
described in the section~\ref[fontfamfiles]. Font modifiers and variant
selectors may be declared here.
The loaded family is set as current and `\rm` variant selector is processed.

When \^`\fontfam` `[<Font Family>]` is used and the given
family isn't found in the current \TeX/ system and
the <Font Family> is previously declared by
\^`\fontfamsub``[<Font Family>][<Other Family>]`
then \OpTeX/ does the given substitution and runs \^`\fontfam``[<Other Family>]`.

The available declared font modifiers and declared variant selectors are
listed in the log file when the font family is load. Or you can print
`\fontfam[catalog]` to show available font modifiers and variant selectors.

The font modifiers can be independent, like `\cond` and `\light`. They can
be arbitrarily combined (in arbitrary order) and if the font family disposes
of all such sub-variants then the desired font is selected (after variant
selector is used). On the other hand, there are font modifiers that negates
the previous font modifier, for example: `\cond`, `\extend`. You can reset
all modifiers to their initial value by the \^`\resetmod` command.

You can open more font families by more \^`\fontfam` commands. Then the
general method to selecting the individual font is:

\begtt \catcode`\<=13
<family selector> <font modifiers> <variant selector>
\endtt
For example:
\begtt
\fontfam [Heros]  % Heros family is active here, default \rm variant.
\fontfam [Termes] % Termes family is active here, default \rm variant.
{\Heros \caps \cond \it The caps+condensed italics in Heros family is here.}
The Termes roman is here.
\endtt

There is one special command \^`\currvar` which acts as a variant selector.
It keeps the current variant and the font of such variant is
reloaded with respect to the current font context by the previously given family
selector and font modifiers.

You can use the \^`\setfontsize` `{<size spec>}` command in the same sense as
other font modifiers. It saves information about font size to the font
context. See section~\ref[setfontsize]. Example:

\begtt
\rm default size \setfontsize{at14pt}\rm here is 14pt size \it italic is
in 14pt size too \bf bold too.
\endtt

A much more comfortable way to resize fonts is using OPmac-like commands
\~`\typosize` and \~`\typoscale`.
These commands prepare the right sizes for math
fonts too and they re-calculate many internal parameters like `\baselineskip`.
See section~\ref[opmac-fonts] for more information.


\secc Math Fonts
%---------------

Most font families are connected with a preferred Unicode-math font. This
Unicode-math is activated when the font family is loaded. If you don't prefer
this and you are satisfied with 8bit math CM+AMS fonts preloaded in the
\OpTeX/ format then you can use command \^`\noloadmath` before you load a first
font family.

If you want to use your specially selected Unicode-math font then use
\^`\loadmath` `{[<font file>]}` or \^`\loadmath` `{<font name>}` before first
`\fontfam` is used.


\secc[fontcommands] Declaring font commands
%----------------------------

Font commands can be font switches, variant selectors, font modifiers,
family selectors and defined font macros doing something with fonts.

\begitems
* Font switches can be decared by `\font` primitive (see
  section~\ref[fontprimitive]) or by \^`\fontlet` command (see
  section~\ref[fontlet]) or by \~`\fontdef` command (see
  sections~\ref[fontdef2]).
  When the font switches are used then they select the given font independently
  of the current font context. They can be used
  in `\output` routine (for example) because we need to set fixed fonts
  in headers and footers.
* Variant selectors are \^`\rm`, \^`\bf`, \^`\it`, \^`\bi`, \~`\tt` and \^`\currvar`. More
  variant selectors can be declared by \~`\famvardef` command. They select a
  font dependent on the current font context, see section~\ref[famvardef].
  The `\tt` selector is documented in section~\ref[tt].
* Font modifiers are \"built-in" or declared by \~`\moddef` command.
  They do modifications in the font context but don't select any font.
  \begitems
  * \"built-in" font modifiers are \^`\setfontsize` (see
    section~\ref[setfontsize]), \~`\setff` (see section~\ref[setff]),
    \~`\setletterspace` and \~`\setwordspace`
    (see section~\ref[specff]). They are independent of font family.
  * Font modifiers declared by \~`\moddef` depend on the font family and they
    are typically declared in font family files, see
    section~\ref[fontfamfiles].
  \enditems
* Family selectors set the given
  font family as current and re-set data used by the family-dependent font
  modifiers to initial values and to the currently used modifiers.
  They are declared in font family files
  by \~`\_famdecl` macro, see section~\ref[fontfamfiles].
* Font macros can be defined arbitrarily by `\def` primitive by users.
  See an example in section~\ref[fontmacros].
\enditems

All declaration commands mentioned here: `\font`, `\fontlet`, `\fontdef`, `\famvardef`,
`\moddef`, `\_famdecl` and `\def` make local assignment.

\secc[fontdef2] The `\fontdef` declarator in detail

You can declare `\<font-switch>` by the \^`\fontdef` command.
\begtt \catcode`\<=13
\fontdef\<font-switch> {\<family selector> <font modifiers> \<variant selector>}
\endtt
%
where `\<family selector>` and `<font modifiers>` are optional and
`\<variant selector>` is mandatory.

The resulting `\<font-switch>` declared by \~`\fontdef` is \"fixed font switch"
independent of the font context. More exactly, it is
a fixed font switch when it is {\em used}. But it can depend on the current font
modifiers and font family and given font modifiers when it is {\em declared}.

The \^`\fontdef` does the following steps.
It pushes the current font context to a stack, it does modifications of the font
context by given `\<family selector>` and/or `<font modifiers>` and it
finds the real font by `\<variant selector>`. This font is not selected but
it is assigned to the declared `\<font switch>` (like `\font` primitive does
it). Finally, `\fontdef` pops the font context stack, so the current
font context is the same as it was before `\fontdef` is used.


\secc[famvardef] The `\famvardef` declarator

You can declare a new variant selector by the \^`\famvardef` macro. This
macro has similar syntax as \^`\fontdef`:
\begtt \catcode`\<=13
\famvardef\<new variant selector> {\<family selector> <font modifiers> \<variant selector>}
\endtt
%
where `\<family selector>` and `<font modifiers>` are optional and
`\<variant selector>` is mandatory.
The `\<new variant selector>` declared by `\famvardef` should be used in the same
sense as `\rm`, `\bf` etc. It can be used as the final command in next
\^`\fontdef` or \^`\famvardef` declarators
too. When the `\<new variant selector>` is used in the normal text then it does
the following steps: pushes current font context to a stack, modifies font
context by declared `\<family selector>` and/or `<font modifiers>`,
runs following `\<variant selector>`.
This last one selects a real font. Then pops the font context stack.
The new font is selected but the font context has its original values.
This is main difference between `\famvardef\foo{...}` and `\def\foo{...}`.

Moreover, the \^`\famvardef` creates the `\<new variant selector>` family dependent.
When the selector is used in another family context than it is defined then a warning is
printed on the terminal \"<var selector> is undeclared in the current family"
and nothing happens. But you can declare the same variant selector by
\^`\famvardef` macro in the context of a new family. Then the same command
may do different work depending on the current font family.

Suppose that the selected font family provides the font modifier `\medium` for
mediate weight of fonts. Then you can declare:
\begtt
\famvardef \mf {\medium\rm}
\famvardef \mi {\medium\it}
\endtt
Now, you can use six independent variant selectors `\rm`, `\bf`, `\it`,
`\bi`, `\mf` and  `\mi` in the selected font family.

A `\<family selector>` can be written before `<font modifiers>` in the
`\famvardef` parameter. Then the `\<new variant selector>` is declared in
the current family but it can use fonts from another family represented by
the `\<family selector>`.

When you are mixing fonts from more families then you probably run
into a problem with incompatible ex-heights. This problem can be solved using
\^`\setfontsize` and \^`\famvardef` macros:
\begtt
\fontfam[Heros]  \fontfam[Termes]

\def\exhcorr{\setfontsize{mag.88}}
\famvardef\rmsans{\Heros\exhcorr\rm}
\famvardef\itsans{\Heros\exhcorr\it}

Compare ex-height of Termes \rmsans with Heros \rm and Termes.
\endtt

The variant selectors (declared by \~`\famvardef`) or font
modifiers (declared by \~`\moddef`) are (typically) control sequences in the public
namespace (`\mf`, `\caps`). They are most often declared in font family files and
they are loaded by \^`\fontfam`. A conflict with such names in
the public namespace can be here. For example: if `\mf` is defined by a user and then
`\fontfam[Roboto]` is used then `\famvardef\mf` is performed for Roboto
family and the original meaning of `\mf` is lost. But \OpTeX/ prints warning
about it. There are two cases:

\begtt
\def\mf{Metafont}
\fontfam[Roboto]  % warning: "The \mf is redefined by \famvardef" is printed
  or
\fontfam[Roboto]
\def\mf{Metafont} % \mf variant selector redefined by user, we suppose that \mf
                  % is used only in the meaning of "Metafont" in the document.
\endtt

\secc[tt] The `\tt` variant selector

\^`\tt` is an additional special variant selector which is defined as \"select typewriter
font independently of the current font family". By default, the typewriter font-face
from LatinModern font family is used.

The \^`\tt` variant selector is used in \OpTeX/ internal macros
\^`\_ttfont` (verbatim texts) and \^`\_urlfont` (printing URL's).

The behavior of \^`\tt` can be re-defined by \^`\famvardef`. For example:

\begtt
\fontfam[Cursor]
\fontfam[Heros]
\fontfam[Termes]
\famvardef\tt{\Cursor\setff{-liga;-tlig}\rm}

Test in Termes: {\tt text}. {\Heros\rm Test in Heros: {\tt text}}.
Test in URL \url{http://something.org}.
\endtt
%
You can see that \^`\tt` stay family independent. This is a special feature only
for \^`\tt` selector. New definitions of \^`\_ttfont` and \^`\_urlfont` are done too.
It is recommended to use `\setff{-liga;-tlig}` to suppress the
ligatures in typewriter fonts.

If Unicode math font is loaded then the `\tt` macro selects typewriter
font-face in math mode too. This face
is selected from used Unicode math font and it is independent of
`\famvardef\tt` declaration.


\secc[fontmacros] Font commands defined by `\def`

Such font commands can be used as fonts selectors for titles, footnotes,
citations, etc. Users can define them.

The following example shows how to define a \"title-font selector".
Titles are not only bigger but they are typically in the bold variant. When a user puts
`{\it...}` into the title text then he/she expects bold italic here, no normal
italic. You can remember the great song by John Lennon \"Let It Be" and
define:

\begtt
\def\titlefont{\setfontsize{at14pt}\bf \let\it\bi}
...
{\titlefont Title in bold 14pt font and {\it bold 14pt italics} too}
\endtt

\OpTeX/ defines similar internal commands \^`\_titfont`, \^`\_chapfont`, \^`\_secfont` and
\^`\_seccfont`, see section~\ref[sections]. The commands \^`\typosize` and
\^`\boldify` are used in these macros. They set the math fonts to given size too and they
are defined in section~\ref[opmac-fonts].


\secc[setff] Modifying font features
%----------------------------

Each OTF font provides \"font features". You can list these font features
by `otfinfo -f font.otf`. For example, LinLibertine fonts provide `frac` font
feature. If it is active then fractions like 1/2 are printed in a special
form.

The font features are part of the font context data.
The macro \^`\setff` `{<feature>}` acts like family independent font modifier and
prepares a new <feature>. You must use a variant selector in order to
reinitialize the font with the new font feature. For example
\^`\setff``{+frac}\rm` or \^`\setff``{+frac}`\^`\currvar`. You can declare a new variant
selector too:

\begtt
\fontfam[LinLibertine]
\famvardef \fraclig {\setff{+frac}\currvar}
Compare 1/2 or 1/10 \fraclig to 1/2 or 1/10.
\endtt

If the used font does not support the given font feature then the font is reloaded
without warning nor error, silently. The font feature is not activated.

The `onum` font feature (old-style digits) is connected to `\caps` macro for
Caps+SmallCaps variant in \OpTeX/ font family files. So you need not
create a new modifier, just use `{\caps`\^`\currvar`` 012345}`.


\secc[specff] Special font modifiers
%---------------------------

Despite the font modifiers declared in the font family file (and dependent on
the font family), we have following font modifiers (independent of font
family):

\begtt \catcode`\<=13
\setfontsize{<size spec>}   % sets the font size
\setff{<font feature>}       % adds the font feature
\setletterspace{<number>} % sets letter spacing
\setwordspace{<scaling>}    % modifies word spacing
\endtt

The \^`\setfontsize` command is described in the section \ref[setfontsize].
The \^`\setff` command was described in previous subsection.

\^`\setletterspace` `{<number>}` specifies the letter spacing of the font. The
`<number>` is a decimal number without unit. The unit is supposed as 1/100 of
the font size. I.e. `2.5` means 0.25 pt when the font is at 10 pt size. The
empty parameter `<number>` means no letter spacing which is the default.

\^`\setwordspace` `{<scaling>}` scales the default interword space (defined in the
font) and its stretching and shrinking parameters by given `<scaling>`
factor. For example `\setwordspace{2.5}` multiplies interword space by 2.5.
\^`\setwordspace` can use different multiplication factors if its parameter is in the
format `{/<default>/<stretching>/<shrinking>}`. For example,
`\setwordspace{/1/2.5/1}` enlarges only stretching 2.5~times.

You can use `\setff` with other font features provided by Lua\TeX/ and `luaotfload` package
(see documentation of `loaotfload` package for more information):

\begtt
\setff{embolden=1.5}\rm  % font is bolder because outline has nonzero width
\setff{slant=0.2}\rm     % font is slanted by a linear transformation
\setff{extend=1.2}\rm    % font is extended by a linear transformation.
\setff{colr=yes}\rm      % if the font includes colored characters, use colors
\setff{upper}\rm         % to uppercase (lower=lowecase) conversion at font level
\setff{fallback=name}\rm % use fonts from a list given by name if missing chars
\endtt

Use font transformations `embolden`, `slant`, `extend` and \^`\setletterspace`,
\^`\setwordspace` with care. The best setting of these values is the default
setting in every font, of course. If you really need to set a different
letter spacing then it is strongly recommended to add `\setff{-liga}`
to disable ligatures. And setting a positive letter spacing probably
needs to scale interword spacing too.

All mentioned font modifiers (except for `\setfontsize`) work only
with Unicode fonts loaded by \^`\fontfam`.

\secc[fontfamfiles] How to create the font family file
%------------------------------------------------------

\printdoctail f-heros.opm

\printdoctail f-lmfonts.opm

\secc How to register the font family in the Font Selection System
%---------------------------------------------------------------

\printdoctail fams-ini.opm

\endinput

2023-06-16  \fontfamsub improved.
2023-05-30  \catalognextfam introduced.
2023-04-22  \setwordspace: \fontdimens reset, bug fixed.
2023-03-09  \_famsrc, \fontfamsub introduced
2022-12-01  \faminfo saves f-<filename> to the format only when needed
2022-11-08  \protected: \fontdef, \famvardef, \fontfam
2022-02-22  Font Selection System reimplemented, \fontsel introduced
2021-09-24  \_unichars used in \initunifonts
2021-07-16  \initunifonts: optex_hook_into_luaotfload added.
2021-05-23  concept of \_fontfeatures macro re-implemented
2021-05-02  simpler \_resizefont, better concept of doc, moving parts from fonts-resize
2021-04-22  \_ffonum introduced
2021-04-19  \setwordspace: parameter format {/A/B/C} implemented.
2021-02-25  \_ttunifont introduced
2021-01-27  lua hack (print function) removed because luaotfload 3.17 removes bug.
2020-12-12  \_modlist added, doc improved
2020-04-18  \_tryloadfamslocal introduced
            \_fontdecl -> \_famdecl with different concept
2020-03-18  released