%% 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