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

\_codedecl \setfontsize {Font resizing macros <2022-11-08>} % preloaded in format

   \_doc -----------------------------
   \`\initunifonts` macro extends \LuaTeX's font capabilities,
   in order to be able to load Unicode fonts. Unfortunately, this part of
   \OpTeX/ depends on the `luaotfload` package, which adapts \ConTeXt's generic
   font loader for plain \TeX/ and \LaTeX. `luaotfload` uses Lua functions
   from \LaTeX's `luatexbase` namespace, we provide our own replacements.
   \^`\initunifonts` sets itself to relax because we don't want to do
   this work twice.
   \`\ufont` is a shortcut of \^`\initunifonts`~`\font`.
   \_cod -----------------------------

\_protected\_def \_initunifonts {%
   \_directlua{%
      require('luaotfload-main')
      luaotfload.main()
      optex.hook_into_luaotfload()
   }%
   \_glet \_fmodtt=\_unifmodtt  % use \_ttunifont for \tt
   \_glet \_initunifonts=\_relax % we need not to do this work twice
   \_glet \initunifonts=\_relax
}
\_protected\_def \_ufont {\_initunifonts \_font}

\_public \initunifonts \ufont ;

   \_doc -----------------------------
   The \`\setfontsize` `{<size spec>}` saves the `<size spec>` to the \`\_sizespec` macro.
   The \`\_optsize` value is calculated from the `<size spec>`.
   If the <size spec> is in the format `scaled<factor>` then
   `\_optsize` is set from \`\defaultoptsize`.
   If the `<size spec>` is in the `mag<number>` format then the contents of
   the `\_sizespec` macro is re-calculated to the `at<dimen>` format using
   previous `\_optsize` value.
   \par \goodbreak
   \_cod -----------------------------

\_newdimen \_optsize         \_optsize=10pt
\_newdimen \_defaultoptsize  \_defaultoptsize=10pt
\_newdimen\_lastmagsize

\_def\_setfontsize #1{%
   \_edef\_sizespec{#1}%
   \_ea \_setoptsize \_sizespec\_relax
}
\_def\_setoptsize {\_isnextchar a{\_setoptsizeA}
                                 {\_isnextchar m{\_setoptsizeC}{\_setoptsizeB}}}
\_def\_setoptsizeA at#1\_relax{\_optsize=#1\_relax\_lastmagsize=\_optsize}   % at<dimen>
\_def\_setoptsizeB scaled#1\_relax{\_optsize=\_defaultoptsize\_relax} % scaled<scalenum>
\_def\_setoptsizeC mag#1\_relax{%
   \_ifdim\_lastmagsize>\_zo \_optsize=\_lastmagsize \_else \_optsize=\_pdffontsize\_font \_fi
   \_optsize=#1\_optsize
   \_lastmagsize=\_optsize
   \_edef\_sizespec{at\_the\_optsize}%
}
\_public \setfontsize \defaultoptsize ;

   \_doc -----------------------------
   The `\fontname` primitive returns the <font file name> optionally
   followed by <size spec>. The \`\xfontname` macro expands to <font file name>
   without <size spec>. We need to remove the part `<space>at<dimen>` from
   `\fontname` output. The letters `at` have category 12 in the \`\_stringat`
   macro.
   \_cod -----------------------------

\_edef\_stringat{\_string a\_string t}
\_edef\_xfontname#1{\_unexpanded{\_ea\_xfontnameA\_fontname}#1 \_stringat\_relax}
\_expanded{\_def\_noexpand\_xfontnameA#1 \_stringat#2\_relax}{#1}

   \_doc -----------------------------
   \`\fontlet` `<font switch A> <font switch B> <size spec>` does
   \begtt \catcode`\<=13
   \font <font switch A> = {<font file name>} <size spec>
   \endtt
   Note, that the `\_xfontname` output is converted due to optical size data using `\_optfn`.
   \_cod -----------------------------

\_protected\_def \_fontlet #1#2{\_ifx #2=\_ea\_fontlet \_ea#1\_else
   \_ea\_font \_ea#1\_expanded{{\_optfn{\_xfontname#2}}}\_fi}
\_public \xfontname \fontlet ;

   \_doc -----------------------------
   \`\newcurrfontsize` `<size spec>` does
   \^`\fontlet` `<saved switch>=\font <size spec>\_relax <saved switch>`.
   It changes the current font at the given <size spec>.
   \nl
   \`\resizethefont` is implemented by \^`\newcurrfontsize` using data from
   the \^`\_sizespec` macro.\nl
   \`\sfont` has the same syntax like `\font` primitive, but declares a
   macro which selects the font and sets its size properly dependent on the
   current size.
   \_cod -----------------------------

% \newcurrfontsize{at25pt}
\_def \_newcurrfontsize {\_ea\_newcurrfontsizeA \_csname \_ea\_csstring \_the\_font \_endcsname}
\_def \_newcurrfontsizeA #1#2{\_fontlet #1\_font #2\_relax \_fontloaded#1#1}
\_protected\_def \_resizethefont {\_newcurrfontsize\_sizespec}
\_protected\_def \_sfont #1{%
   \_protected\_edef #1{\_csname _sfont:\_csstring#1\_endcsname \_resizethefont}%
   \_initunifonts \_ea\_font \_csname _sfont:\_csstring#1\_endcsname
}
\_public \newcurrfontsize \resizethefont \sfont ;

   \_doc -----------------------------
   The \`\_regtfm` `<font id> <optical size data>`
   registers optical sizes data directly by the font file names.
   This can be used for `tfm` files or OpenType files without
   various font features. See also \^`\_regoptsizes` in section~\ref[optsizes].
   The `\_regtfm` command saves the <optical size data> concerned to the `<font id>`.
   The `<optical size data>` is in the form as shown below in the code where
   `\_regtfm` is used.
   \nl
   The \`\_optfn` `<fontname>` expands to the `<fontname>` or to the corrected
   `<fontname>` read from the `<optical size data>` registered by `\_regtfm`.
   It is used in the \^`\fontlet` macro.

   The implementation detail: The `\_reg:<font id>` is defined as the
   `<optical size data>` and all control sequences `\_reg:<fontname>`
   from this data line have the same meaning because of the
   \`\_reversetfm` macro. The `\_optfn` expands this data line and apply
   \`\_runoptfn`. This macro selects the right result from the data line
   by testing with the current `\_optsize` value.
   \_cod -----------------------------

\_def\_regtfm #1 0 #2 *{\_ea\_def \_csname _reg:#1\_endcsname{#2 16380 \_relax}%
  \_def\_tmpa{#1}\_reversetfm #2 * %
}
\_def\_reversetfm #1 #2 {% we need this data for \_setmathfamily
   \_ea\_let\_csname _reg:#1\_ea\_endcsname
   \_csname _reg:\_tmpa\_endcsname
   \_if*#2\_else \_ea\_reversetfm \_fi
}
\_def\_optfn #1{%
   \_ifcsname _reg:#1\_endcsname
      \_ea\_ea\_ea \_runoptfn
      \_csname _reg:#1\_ea\_endcsname
   \_else
      #1%
   \_fi
}
\_def\_runoptfn #1 #2 {%
   \_ifdim\_optsize<#2pt #1\_ea\_ignoretfm\_else \_ea\_runoptfn
\_fi
}
\_def\_ignoretfm #1\_relax{}

   \_doc -----------------------------
   Optical sizes data for preloaded 8bit Latin Modern fonts:
   \_cod -----------------------------

\_regtfm lmr  0 ec-lmr5 5.5 ec-lmr6 6.5 ec-lmr7 7.5 ec-lmr8 8.5 ec-lmr9 9.5
                         ec-lmr10 11.1 ec-lmr12 15 ec-lmr17 *
\_regtfm lmbx 0 ec-lmbx5 5.5 ec-lmbx6 6.5 ec-lmbx7 7.5 ec-lmbx8 8.5 ec-lmbx9 9.5
                         ec-lmbx10 11.1 ec-lmbx12 *
\_regtfm lmri 0 ec-lmri7 7.5 ec-lmri8 8.5 ec-lmri9 9.5 ec-lmri10 11.1 ec-lmri12 *
\_regtfm lmtt 0 ec-lmtt8 8.5 ec-lmtt9 9.5 ec-lmtt10 11.1 ec-lmtt12 *

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


\sec[fontprimitive] Using `\font` primitive directly
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

You can declare a new {\em font switch} by `\font` primitive:
\begtt \catcode`\<=13
\font \<font switch> = <font file name> <size spec>
% for example:
\font \tipa = tipa10 at12pt % the font tipa10 at 12pt is loaded
% usage:
{\tipa TEXT}  % the TEXT is printed in the loaded font.
\endtt
The <size spec> can be empty or `at<dimen>` or `scaled<scale factor>`. The
<font file name> must be terminated by space or surrounded in the braces.

\OpTeX/ starts with `\font` primitive which is able to read only `tfm` files.
i.e.\ the `<font file name>.tfm` (and additional data for glyphs)
must be correctly installed in your system. If you want to load
OpenType `otf` or `ttf` font files, use the declarator \^`\initunifonts`
before first `\font` primitive.
This command adds additional features to the `\font` primitive which
gives the extended syntax:
\begtt \catcode`\<=13
\font \<font switch> = {[<font file name>]:<font features>} <size spec>
% or
\font \<font switch> = {<font name>:<font features>} <size spec>
\endtt
where <font file name> is name of the OpenType font file with the extension
`.otf` or `.ttf` or without it. The braces in the syntax
are optional, use them when the <font file name> or <font name> includes spaces.
The original syntax for `tfm` files is also available. Example:
\begtt
\initunifonts
\font\crimson=[Crimson-Roman] at11pt % the font Crimson-Regular.otf is loaded
\font\crimsonff=[Crimson-Roman]:+smcp;+onum at11pt % The same font is re-loaded
                                                   % with font features
{\crimson Text 12345}   % normal text in Crimson-Regular
{\crimsonff Text 12345} % Crimson-Regular with small capitals and old digits
\endtt
\^`\initunifonts` loads the implementation of the `\font`
primitive from `luaotfload` package. More information is available
in the `luaotfload-latex.pdf` file.

You can use \^`\ufont` macro which runs \^`\initunifonts` followed by `\font`
primitive. And \^`\fontfam` does (among other things) \^`\initunifonts`
too. You need not to specify \^`\initunifonts` if \^`\fontfam` or \^`\ufont` is used.

When \^`\initunifonts` is declared then the `\font` primitive is ready to read
Type1 fonts too. If you have `file.afm` and `file.pfb` then you can
declare `\font\f=file.afm` and use `\f`. It means that you needn't to create
`tfm` files nor `vf` files, you can use Type1 fonts directly.
They behave as Unicode fonts if the `afm` metrics are implemented correctly
(with correct names of all included glyphs). But we must to say that Type1
font format is old technology, the loading of Type1 fonts is not optimized.
Use OpenType fonts (`otf` of `ttf`) if it is possible.

Let's sum it up.  Suppose that \^`\initunifonts` was used.
The `\font` primitive is able to load OpenType
fonts (`otf` or `ttf`), Type1 fonts (`afm` and `pfb`) or classical `tfm` fonts.
We strongly recommend to prefer OpenType format over Type1 format
over `tfm` format. The last one doesn't support Unicode. If there is nothing
else left and you must to use `tfm`, then you must to implement re-encoding from
Unicode to the `tfm` encoding at macro level, see the
\ulink[http://petr.olsak.net/optex/optex-tricks.html\#nonunicode]{\OpTeX/ trick 0018}
for example.


\secc[setfontsize] The `\setfontsize` macro

It seems that you must decide about final size of the font before it is
loaded by the `\font` primitive. It is not exactly true; \OpTeX/ offers
powerful possibility to resize the font already loaded on demand.

The \^`\setfontsize` `{<size spec>}`
saves the information about `<size spec>`. This information is taken into
account when a variant selector (for example `\rm`, `\bf`, `\it`, `\bi`)
or `\resizethefont` is used. The `<size spec>` can be:
\begitems
* `at<dimen>`, for example `\setfontsize{at12pt}`. It gives the desired font size directly.
* `scaled<scale factor>`, for example `\setfontsize{scaled1200}`. The font is
  scaled in respect to its native size (which is typically 10\,pt). It
  behaves like `\font\... scaled<number>`.
* `mag<decimal number>`, for example `\setfontsize{mag1.2}`. The font is
  scaled in respect to the current size of the fonts given by the previous
  \^`\setfontsize` command.
\enditems
The initial value in \OpTeX/ is given by `\setfontsize{at10pt}`.

The \^`\resizethefont` resizes the currently selected font to the size given by previous
\^`\setfontsize`. For example

\begtt
                     The 10 pt text is here,
\setfontsize{at12pt} the 10 pt text is here unchanged...
\resizethefont       and the 12 pt text is here.
\endtt
%
The \^`\setfontsize` command acts like {\em font modifier}. It means that it
saves information about fonts but does not change the font actually until
variant selector or \^`\resizethefont` is used.

The following example demonstrates the `mag` format of \^`\setfontsize`
parameter. It is only a curious example probably not used in practical
typography.

\begtt
\def\smaller{\setfontsize{mag.9}\resizethefont}
Text \smaller text \smaller text \smaller text.
\endtt

The \^`\resizethefont` works with arbitrary current font, for example with the
font loaded directly by `\font` primitive.  For example:

\begtt
\ufont\tencrimson=[Crimson-Roman]:+onum % font Crimson-Regular at 10 pt is loaded
\def\crimson{\tencrimson\resizethefont} % \crimson uses the font size on demand

\crimson The 10 pt text is here.
\setfontsize{at12pt}
\crimson The 12 pt text is here.
\endtt
This is not only an academical example. The `\csrimson` command defined here
behaves like variant selector in the Font Selection System (section~\ref[fontsystem]).
It takes only information about size from the font context, but it is
sufficient. You can use it in titles, footnotes, etc. The font size
depending on surrounding size is automatically selected.
There is a shortcut \^`\sfont` with the same syntax like `\font` primitive,
it declares a macro which selects the font and does resizing depending on
the current size. So, the example above can be realized by
`\sfont\crimson=[Crimson-Roman]:+onum`.

\secc The `\font`-like commands summary

\begitems
* `\font` is \TeX/ primitive. When \OpTeX/ starts, then it accepts only
  classical \TeX/ syntax and doesn't allow to load Unicode fonts.
  Once \^`\initunifonts` (or \^`\fontfam`) is used, the `\font` primitive is
  re-initialized: now it accepts extended syntax and it is able to load Unicode
  OpenType fonts.
* \^`\ufont` is a shortcut of `\initunifonts \font`. I.e.\ it behaves like
  `\font` and accepts extended syntax immediately.
* \^`\sfont` has syntax like extended `\font`. It declares a macro which
  selects the given font and resizes it to the current size (given by
  \^`\setfontsize`). In various part of document (text, footnotes, titles), the
  size of this font is selected by the declared macro properly.
\enditems


\secc[fontlet] The \code{\\fontlet} declarator

We have another command for scaling: \^`\fontlet` which can resize
arbitrary font given by its font switch.
\begtt \catcode`\<=13
  \fontlet \<new font switch> = \<given font switch> <size spec>
  example:
  \fontlet \bigfont = \_tenbf at15pt
\endtt
The `\<given font switch>` must be declared previously by `\font` or
\^`\fontlet` or \~`\fontdef`. The `\<new font switch>` is declared as the
same font at given <size spec>. The equal sign in the syntax is optional.
You can declare `\<new font switch>` as the scaled current font by
\begtt \catcode`\<=13
\fontlet \<new font switch> = \font <size spec>
\endtt


\secc Optical sizes

There are font families with more font files where almost the same font is
implemented in various design sizes: `cmr5`, `cmr6`, `cmr7`, `cmr8`, `cmr9`,
`cmr10`, `cmr12`, `cmr17` for example. This feature is called \"optical
sizes". Each design size is implemented in its individual font file and \OpTeX/ is
able to choose right file if various optical sizes and corresponding file
names are declared for the font by \^`\_regtfm` or \^`\_regoptsizes` command.
The command \^`\setfontsize` sets the internal requirements for
optical size if the parameter is in the format `at<dimen>` or `mag<factor>`.
Then the command \^`\resizethefont` or \^`\fontlet` or variant selectors try to choose
the font suitable for the required optical size. For example
\begtt
\fontfam[lm]
      The text is printed in font [lmroman10-regular] at 10 pt.
\setfontsize{at13pt}\rm
      Now, the text is printed in [lmroman12-regular] at 13 pt.
\endtt
See also section~\ref[optsizes].


\secc Font rendering

If \^`\initunifonts` isn't declared then \OpTeX/ uses classical font
renderer (like in `pdftex`). The extended font renderer implemented in the
Luaotfload package is started after \^`\initunifonts`.

The \OpTeX/ format uses `luahbtex` engine by default (from 2025).
It means that the harfbuzz library is
ready to use for font rendering as an alternative to built-in font renderer
from Luaotfload. The harfbuzz library gives more features for rendering
Indic and Arabic scripts. But it is not used as default, you need to specify
`mode=harf` in the fontfeatures field when `\font` is used. Moreover, when
`mode=harf` is used, then you must specify `script` too. For example

\begtt
\font\devafont=[NotoSansDevanagari-Regular]:mode=harf;script=dev2
\endtt
%
If the `luahbtex` engine is not used then `mode=harf` is ignored. See
Luaotfload documentation for more information.

\_endinput

2022-11-08 \sfont introduced, \protected: \initunifont, \ufont, \fontlet
2022-11-07 \fontlet \a\a: bug fixed
2022-10-14 \ufont introduced
2022-02-22 Font Selection System reimplemented, \fontsel introduced
2021-05-02 better concept of doc, moving parts to fonts-select
2021-04-17 \_fontloaded, \_newfontloaded introduced
2020-04-17 \resizethefont introduced
2020-03-17 released
