% \iffalse ---!!! FIRST META-COMMENT !!!--- % % % This file is mathfont-code.dtx from version 3.0 of the % free and open-source LaTeX package "mathfont," released % January 2026, to be used with the XeTeX or LuaTeX engines. % % Running Plain TeX on mathfont-code.dtx will produce the % following files: % % (1) the package file mathfont.sty; % % (2) the derived files mathfont-symbol-list.tex, % mathfont-user-guide.tex, and four files called % mathfont-example-.tex, which can be % used to typeset further documentation for % mathfont; % % (3) the stand-alone derived files mathfont-doc-patch.tex, % mathfont-equations.tex, and mathfont-heading.tex, % which are used to produce documentation; % % and % % (4) a number of other derived files. % % Running LaTeX on mathfont-code.dtx will produce the files % listed above as well as the following: % % (5) the pdf documentation file mathfont-code.pdf; % % and % % (6) a number of other derived files. % % To install mathfont on your computer, run this file through % Plain TeX or LaTeX and move mathfont.sty into a directory % searchable by TeX. See the associated README.txt file for % installation information. % % % \fi % \iffalse ---!!! SECOND META-COMMENT !!!--- % % % This file is from version 3.0 of the free and open-source % LaTeX package "mathfont," released January 2026, to be used % with the XeTeX or LuaTeX engines. (As of version 2.0, LuaTeX % is recommended.) % % Copyright 2018, 2019, 2021-2023, 2025, 2026 Conrad Kosowsky % % This Work may be used, distributed, and modified under the % terms of the LaTeX Public Project License, version 1.3c or % any later version. The most recent version of this license % is available online at % % https://www.latex-project.org/lppl/. % % This Work has the LPPL status "maintained," and the current % maintainer is the package author, Conrad Kosowsky. He can % be reached at kosowsky.latex@gmail.com. The Work consists % of the following items: % % (1) the base file: % mathfont-code.dtx % % (2) the package file: % mathfont.sty % % (3) the derived files: % mathfont-doc_patch.tex % mathfont-equations.tex % mathfont-example-cormorant.tex % mathfont-example-kelvinch.tex % mathfont-example-roboto.tex % mathfont-example-typey.tex % mathfont-heading.tex % mathfont-symbol-list.tex % mathfont-user-guide.tex % % (4) the pdf documentation files: % mathfont-code.pdf, % mathfont-example-cormorant.pdf % mathfont-example-kelvinch.pdf % mathfont-example-roboto.pdf % mathfont-example-typey.pdf % mathfont-symbol-list.pdf % mathfont-user-guide.pdf % % (5) all other files created through the configuration % process % % and % % (6) the associated README.txt file % % The Work does not include any fonts, and the installation % does not contain any font files. The fonts Bona Nova, % Cormorant, Crimson, Kelvinch, Overpass, STIXGeneral, and % Typey McTypeface have been released under the SIL Open % Font License and are used pursuant to that license. The % font Roboto has been released under the Apache License % and is used pursuant to that license. % % PLEASE KNOW THAT THIS FREE SOFTWARE IS PROVIDED WITHOUT % ANY WARRANTY. SPECIFICALLY, THE "NO WARRANTY" SECTION OF % THE LATEX PROJECT PUBLIC LICENSE STATES THE FOLLOWING: % % THERE IS NO WARRANTY FOR THE WORK. EXCEPT WHEN OTHERWISE % STATED IN WRITING, THE COPYRIGHT HOLDER PROVIDES THE WORK % `AS IS’, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED % OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED % WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR % PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE % OF THE WORK IS WITH YOU. SHOULD THE WORK PROVE DEFECTIVE, % YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR % CORRECTION. % % IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED % TO IN WRITING WILL THE COPYRIGHT HOLDER, OR ANY AUTHOR % NAMED IN THE COMPONENTS OF THE WORK, OR ANY OTHER PARTY % WHO MAY DISTRIBUTE AND/OR MODIFY THE WORK AS PERMITTED % ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, % SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT % OF ANY USE OF THE WORK OR OUT OF INABILITY TO USE THE WORK % (INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA, DATA BEING % RENDERED INACCURATE, OR LOSSES SUSTAINED BY ANYONE AS A % RESULT OF ANY FAILURE OF THE WORK TO OPERATE WITH ANY % OTHER PROGRAMS), EVEN IF THE COPYRIGHT HOLDER OR SAID % AUTHOR OR SAID OTHER PARTY HAS BEEN ADVISED OF THE % POSSIBILITY OF SUCH DAMAGES. % % For more information, see the Latex Project Public License. % Derivative works based on this package may come with their % own license or terms of use, and the package author is not % responsible for any third-party software. % % Happy TeXing! % % % \fi % \iffalse % % The installation and driver files are incorporated into % mathfont-code.dtx, so we do not need to generate them % separately. The and tags are for % reference. % %<*batchfile> \begingroup \input docstrip.tex \keepsilent \askforoverwritefalse \preamble This file is from version 3.0 of the free and open-source LaTeX package "mathfont," released January 2026, to be used with the XeTeX or LuaTeX engines. (As of version 2.0, LuaTeX is recommended.) Copyright 2018, 2019, 2021-2023, 2025, 2026 Conrad Kosowsky This Work may be used, distributed, and modified under the terms of the LaTeX Public Project License, version 1.3c or any later version. The most recent version of this license is available online at https://www.latex-project.org/lppl/. This Work has the LPPL status "maintained," and the current maintainer is the package author, Conrad Kosowsky. He can be reached at kosowsky.latex@gmail.com. PLEASE KNOW THAT THIS FREE SOFTWARE IS PROVIDED WITHOUT ANY WARRANTY. SPECIFICALLY, THE "NO WARRANTY" SECTION OF THE LATEX PROJECT PUBLIC LICENSE STATES THE FOLLOWING: THERE IS NO WARRANTY FOR THE WORK. EXCEPT WHEN OTHERWISE STATED IN WRITING, THE COPYRIGHT HOLDER PROVIDES THE WORK `AS IS’, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE WORK IS WITH YOU. SHOULD THE WORK PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR, OR CORRECTION. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL THE COPYRIGHT HOLDER, OR ANY AUTHOR NAMED IN THE COMPONENTS OF THE WORK, OR ANY OTHER PARTY WHO MAY DISTRIBUTE AND/OR MODIFY THE WORK AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE WORK OR OUT OF INABILITY TO USE THE WORK (INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA, DATA BEING RENDERED INACCURATE, OR LOSSES SUSTAINED BY ANYONE AS A RESULT OF ANY FAILURE OF THE WORK TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF THE COPYRIGHT HOLDER OR SAID AUTHOR OR SAID OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. For more information, see the LaTeX Project Public License. Derivative works based on this package may come with their own license or terms of use, and the package author is not responsible for any third-party software. For more information, see mathfont-code.dtx. Happy TeXing! \endpreamble \generate{ \file{mathfont.sty}{\from{mathfont-code.dtx}{package}} \file{mathfont-symbol-list.tex}{\from{mathfont-code.dtx}{chars}} \file{mathfont-user-guide.tex}{\from{mathfont-code.dtx}{user}} \file{mathfont-heading.tex}{\from{mathfont-code.dtx}{heading}} \file{mathfont-doc-patch.tex}{\from{mathfont-code.dtx}{doc}} \file{mathfont-equations.tex}{\from{mathfont-code.dtx}{equations}} \file{mathfont-example-cormorant.tex}{\from{mathfont-code.dtx}{cormorant}} \file{mathfont-example-kelvinch.tex}{\from{mathfont-code.dtx}{kelvinch}} \file{mathfont-example-roboto.tex}{\from{mathfont-code.dtx}{roboto}} \file{mathfont-example-typey.tex}{\from{mathfont-code.dtx}{typey}}} \catcode`\ =12\relax \immediate\write0{^^J% ***************************************************^^J% * Step 1 of the mathfont installation complete! *^^J% ***************************************************^^J^^J% ***************************************************^^J% * To finish the installation, move mathfont.sty *^^J% * to a directory searchable by TeX once *^^J% * mathfont-code.dtx is done typesetting *^^J% ***************************************************^^J^^J} \endgroup \ifx\LaTeX\undefined \immediate\write0{Plain TeX format used; quitting now.} \immediate\write0{To create mathfont-code.pdf, run^^J% mathfont-code.dtx through LaTeX.^^J^^J} \expandafter\end \fi % %<*driver> \documentclass[12pt,doc2,letterpaper,oneside]{ltxdoc} \makeatletter \flushbottom \usepackage[margin=1.5in]{geometry} \usepackage[factor=700,stretch=14,shrink=14,step=1]{microtype} \usepackage{graphicx} \usepackage{tabularx} \usepackage{booktabs} \usepackage{multirow} \usepackage{enumitem} \usepackage{soul} \usepackage{amsmath} \setlist{itemsep=\smallskipamount,topsep=\smallskipamount, parsep=\z@,partopsep=\z@} \hyphenation{OpenType} \hyphenation{mathfont} \c@IndexColumns=2 \c@topnumber\@ne \columnsep=20pt \MacroIndent=1.5em \AtBeginDocument{% \baselineskip=\the\baselineskip plus 0.3pt minus 0.3pt\relax} \let\index@prologue\relax \EnableCrossrefs\CodelineIndex \begin{document} \def\documentname{Implementation} \def\showabstract{1} \input mathfont-doc-patch.tex \input mathfont-heading.tex \DocInput{mathfont-code.dtx} \vfil\eject \immediate\closeout\@indexfile \ifx\directlua\@undefined \immediate\write18{makeindex -s gind.ist mathfont-code.idx} \else \directlua{os.execute("makeindex -s gind.ist mathfont-code.idx")} \fi \section*{Index} Entries refer to lines in the code. Bold means a definition. \hfuzz=20pt %\medskip \input mathfont-code.ind \end{document} % %<*package> % % \fi % % % \CheckSum{7307} % \init@checksum % % % \makeatother\CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z % Digits \0\1\2\3\4\5\6\7\8\9 % Exclamation \! Double quote \" Hash (number) \# % Dollar \$ Percent \% Ampersand \& % Acute accent \' Left paren \( Right paren \) % Asterisk \* Plus \+ Comma \, % Minus \- Point \. Solidus \/ % Colon \: Semicolon \; Less than \< % Equals \= Greater than \> Question mark \? % Commercial at \@ Left bracket \[ Backslash \\ % Right bracket \] Circumflex \^ Underscore \_ % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} % \makeatletter % % % \DoNotIndex{\NeedsTeXFormat,\ProvidesPackage,\DeclareOption, % \ProcessOptions,\def,\edef,\global,\let,\csname,\endcsname, % \expandafter,\relax,\advance,\newcount,\newif,\z@,\@ne,\m@ne, % \ifx,\ifcat,\ifnum,\ifeof,\ifmmode,\else,\fi,\PackageInfo, % \PackageWarning,\PackageError,\message,\@undefined, % \space,\MessageBreak,\string,\M@count,\count@,\noexpand, % \@empty,\@tempa,\@tempb,\@tempc,\@temp@opt,\@temp@sub,\@i, % \@j,\@k,\count,\tw@,\do,\the,\mathalpha,\mathord,\multiply, % \mathop,\mathbin,\mathrel,\mathopen,\mathclose,\mathpunct, % \mathinner,\DeclareRobustCommand,\joinrel,\smash,\newtoks, % \if,\\,\@nil,\leavevmode,\begingroup,\endgroup,\+,\active, % \@gobbletwo,\GenericError,\catcode,\wlog,\typeout, % \E@sterEggUpd@te,\show,\@temperror,\xdef,\@for,\@tfor, % \@ifundefined,\@ifpackageloaded,\@nnil,\@onlypreamble, % \AtBeginDocument,\AtEndOfPackage,\AtVeryVeryEnd,\bgroup, % \CurrentOption,\egroup,\escapechar,\ifM@upper,\ifM@lower, % \ifM@diacritics,\ifM@greekupper,\ifM@greeklower, % \ifM@agreekupper,\ifM@agreeklower,\ifM@cyrillicupper, % \ifM@cyrilliclower,\ifM@hebrew,\ifM@digits,\ifM@operator, % \ifM@symbols,\ifM@extsymbols,\ifM@delimiters,\ifM@arrows, % \ifM@bigops,\ifM@extbigops,\ifM@bb,\ifM@cal,\ifM@frak, % \ifM@bcal,\M@font@loadedtrue,\ifM@bfrak,\if@optionpresent, % \if@suboptionpresent,\mathgroup,\nolimits,\on@line, % \PackageWarningNoLine,\RequirePackage,\thr@@, % \inputlineno,\mathchar@type,\DeclareMathAccent, % \ifM@EasterEgg@declare,\M@EasterEgg@declaretrue, % \M@EasterEgg@declarefalse,\IfFileExists,\E@sterEggHook, % \@gobblefour,\@gobble@brackets,\protected,\@eha,\@cclv, % \new@mathgroup,\new@symbolfont,\@latex@error,\ifcase,\or, % \thr@@,\gdef,\rmdefault,\openin,\closein,\immediate,\itdefault, % \shapedefault,\mddefault,\bfdefault,\E@sterEggDecl@redtrue, % \detokenize,\scdefault,\@next,\@suboptionpresenttrue, % \@suboptionpresentfalse,\@break@tfor,\M@adjust@fonttrue, % \M@adjust@fontfalse,\next,\@tempcntb,\ifdim, % \M@arg@goodtrue,\M@arg@goodfalse,\M@Noluaotfloadtrue, % \M@Noluaotfloadfalse,\M@XeTeXLuaTeXtrue,\ifcsname,\ifdefined, % \TU,\",\@@DeclareSymbolFont,\@@set@mathaccent,\@@set@mathchar, % \@@set@mathsymbol,\@expandedtwoargs,\@spaces,\@tempswatrue, % \@tempswafalse,\@iftempswa,\copy,\e@mathgroup@top,\endlinechar, % \everyeof,\globaldefs,\m@th,\newbox,\newread,\newmuskip,\number, % \zap@space,\setbox,\clap,\hss,\ht,\wd,\dp, % \raise,\M@arrows@id,\M@delimiters@id,\M@extbigops@id, % \M@extsymbols@id,\M@symbols@id,\M@greekupper@id, % \M@greeklower@id,\M@agreekupper@id,\M@agreeklower@id, % \M@bigops@id,\M@upper@id,\M@lower@id,\M@radical@id, % \M@diacritics@id,\M@cyrillicupper@id,\M@digits@id, % \M@cyrilliclower@id,\M@hebrew@id,\Umathcode,\EasterEggUpdate, % \@firstofone,\if@arg@good,\M@f@ntn@me,\M@f@ntn@meb@se, % \dimen@,\math@E@sterEggUpd@te,\@DMA,\M@sym@,\@tempwarning, % \@mathfontinfo,\everymath,\Udelcode,\Udelimiter,\@@set@mathchar, % \@@set@mathsymbol,\@@set@mathaccent,\set@mathchar,\set@mathsymbol, % \set@mathaccent,\Umathcode,\Umathchardef,\Umathaccent, % \@easter@egg@,\@expandtwoargs,\afterassignment,\aftergroup, % \AtEndDocument,\DeclareSymbolFont@m@dropped,\directlua,\ifodd, % \edef@nospace,\hb@xt@,\hbox,\hfil,\if@operator@s, % \ifE@sterEggDecl@red,\ifin@,in@,\llap,\mathpalette,\mathsm@sh, % \meaning,\numexpr,\scantokens,\scantextokens,\strip@prefix, % \vphantom,\XeTeXrevision,\symMupright,\ProcessE@sterEgg, % \@ifnextchar,\@testopt,\endinput,\Umathcharnumdef,\Umathcodes, % \Umathcodenum,\seriesdefault,\@@DeclareSymbolFont@m@dropped, % \ifM@radical,\@backslashchar,\@tempbase,\@tempboxa, % \@tempfeatures,\@secondoftwo,\unexpanded,\long, % \@tempseries,\@tempshape,\displaystyle,\textstyle,\scriptstyle, % \scriptscriptstyle,\f@family,\getanddefine@fonts,\if@tempswa, % \@tempswatrue,\@tempswafalse,\M@acc@,\M@addtab@count@tempa, % \M@addto@localfonts,\M@addto@symbolfonts, % \M@delimiters@num,\M@localfonts,\M@symbolfonts, % \M@robust@def,\M@base@false,\M@base@true,\toks@,\Uchar, % \@nomath,\@whilenum,\@notprerr,\@optionpresenttrue, % \@optionpresentfalse,\@@mathchar@type,\luafunction, % \newluafunction,\remove@to@nnil,\showtokens} % % % \DoNotIndex{\cyrA,\cyrBe,\cyrVe,\cyrGhe,\cyrDe,% % \cyrIe,\cyrZhe,\cyrZe,\cyrI,\cyrKa,\cyrEl,% % \cyrEm,\cyrEn,\cyrO,\cyrPe,\cyrEr,\cyrEs,% % \cyrTe,\cyrU,\cyrEf,\cyrHa,\cyrTse,\cyrChe,% % \cyrSha,\cyrShcha,\cyrHard,\cyrYeru,\cyrSoft,% % \cyrE,\cyrYu,\cyrYa,\cyrvarI,\cyra,\cyrbe,% % \cyrve,\cyrghe,\cyrde,\cyrie,\cyrzhe,\cyrze,% % \cyri,\cyrka,\cyrel,\cyrem,\cyren,\cyro,% % \cyrpe,\cyrer,\cyres,\cyrte,\cyru,\cyref,% % \cyrha,\cyrtse,\cyrche,\cyrsha,\cyrshcha,% % \cyrhard,\cyryeru,\cyrsoft,\cyre,\cyryu,% % \cyrya,\cyrvari} % % % \DoNotIndexMain{\colon,\mathellipsis,\angle,\sqsubset,\sqsupset, % \bowtie,\doteq,\neq,\ng,\clubsuit,\spadesuit,\diamondsuit,% % \heartsuit,\cong,\uparrow,\Uparrow,\downarrow,\Downarrow,% % \updownarrow,\Updownarrow,\longrightarrow,\longleftarrow,$ % \longleftrightarrow,\hookrightarrow,\hookleftarrow,% % \Longrightarrow,\Longleftarrow,\Longleftrightarrow,% % \rightleftharpoons,\to,\mapsto,\mapsto,\longmapsto,% % \from,\mapsfrom,\longmapsfrom,\lightningboltarrow,\sum,% % \prod,\coprod,\bigvee,\bigwedge,\bigcup,\bigcap,% % \bigoplus,\bigotimes,\bigodot,\bigsqcup,\iint,\iiint,% % \oint,\oiint,\oiiint,\lbrace,\rbrace,\lguil,\rguil,% % \backslash,\mathbackslash,\textng,\simeq,\vert,\llguil,% % \rrguil,\fakelangle,\fakerangle,\fakellangle,\fakerrangle,% % \bigtimes,\@@relbar,\@@Relbar,\hbar,\mathsterling} % % \noindent This file documents the code for the \textsf{mathfont} package. It is not a user guide! If you are looking for instructions on how to use \textsf{mathfont} in your document, see |mathfont-user-guide.pdf|, which is included with the \textsf{mathfont} installation and is available on \textsc{ctan}. See also the other |pdf| documentation files for \textsf{mathfont}. Section~1 of this document begins with the implementation basics, including package declaration and package options. Section~2 provides package default settings, and section~3 deals with errors and messaging. Section~4 contains the fontloader, and section~5 contains the optional-argument parser for |\mathfont|. Section 6 documents the code for the |\mathfont| command itself. Section~7 contains the code for local font changes. Section~8 contains miscellaneous material. Sections~9--11 contain the Lua code to modify font objects at loading, and section~12 lists the Unicode hex values used in symbol declaration. Version history and code index appear at the end of the document. % % At high level, the package works as follows: the font-loader |\M@newfont| is a wrapper around \textsc{nfss} macros to declare fonts---namely |\DeclareFontFamily| and |\DeclareFontShape|---or, if the user requested to use \textsf{fontspec} as a backend, the macro |\fontspec_set_family:Nnn|. All font-setting macros in the package will call |\M@newfont|. The primary font-setting command |\mathfont| is a wrapper around |\DeclareSymbolFont| and calls various |\M@|\meta{keyword}|@set| commands. Each |\M@|\meta{keyword}|@set| macro is a wrapper around a number of |\Umathcode| declarations that do the actual work of setting default font(s). The local font-change commands are wrappers around |\DeclareMathAlphabet|, and the Lua font adjustments alter the font table through the |luaotfload.patch_font| callback when \TeX\ loads the font. Specifically, we change the top-level flag |nomath| to false, alter character-level entries in the table to make the font more suitable for math typesetting, and add a MathConstants table based on font dimensions. % % % % \section{Setup} % % % First, the package should declare itself. The first 61 lines of |mathfont.sty| are comments. \c@CodelineNo=61\relax % \begin{macrocode} \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{mathfont}[2026/01/22 v. 3.0] % \end{macrocode} % Informational message. % \begin{macrocode} \def\@mathfontinfo#1{\wlog{Package mathfont Info: #1}} % \end{macrocode} % We specify conditionals and one count variable that we use later in handling options and setup. % \begin{macrocode} \newif\ifM@XeTeXLuaTeX % is engine one of xetex or luatex? \newif\ifM@Noluaotfload % cannot find luaotfload.sty? \newif\ifM@adjust@font % should adjust fonts with lua script? \newif\ifM@font@loaded % load mathfont with font specified? \newif\ifE@sterEggDecl@red % already did easter egg? \newcount\M@loader % specifies which font-loader to use % \end{macrocode} % We disable the twenty user-level commands. If \textsf{mathfont} runs normally, it will overwrite these ``bad'' definitions later, but if it throws one of its two fatal errors, it will |\endinput| while the user-level commands are error messages. That way the commands don't do anything in the user's document, and the user gets information on why not. The bad definitions gobble their original arguments to avoid a ``missing |\begin{document}|'' error. To streamline the process, we metacode most of the error messages, namely the macros that |\@gobble| their argument and the macros that |\@gobbletwo| their argument. % \begin{macrocode} \long\def\@gobble@brackets[#1]{} \def\M@NoMathfontError#1{\PackageError{mathfont} {\MessageBreak Invalid command\MessageBreak \string#1 on line \the\inputlineno} {Your command was ignored. I couldn't\MessageBreak load mathfont, so I never defined this\MessageBreak control sequence.}} % \end{macrocode} % The macro |\M@robust@def| is an engine-dependent command to define robust control sequences. We want this part of the package to work regardless of the engine, so we need an approach that doesn't depend on $\epsilon$-\TeX\ support. However, I don't want to use |\DeclareRobustCommand| with \XeTeX\ or Lua\TeX\ because that will leave useless macros like \verb*.\mathfont . defined when we fill in the proper definitions of the user-level commands later. % \begin{macrocode} \ifx\protected\@undefined \let\M@robust@def\DeclareRobustCommand \else \def\M@robust@def{\protected\def} \fi % \end{macrocode} % First the commands that normally accept a single argument---the ``bad'' versions |\@gobble| the argument. To keep the syntax straightforward, we expand the definition using |\edef|. (We can't use |\expanded| because that's \XeTeX/Lua\TeX\ only.) We need to do this because the macro name is stored in |\@i|, and otherwise, we would end up with a mess of |\expandafter|s to expand all instances of |\@i|. % \begin{macrocode} \@tfor\@i:=\setfont \RuleThicknessFactor \IntegralItalicFactor \SurdVerticalFactor \SurdHorizontalFactor \charmline \charmfile \CharmLine \CharmFile \CharmInfo \CharmType\do{% \edef\@tempa{\noexpand\M@robust@def\expandafter\noexpand\@i{% \noexpand\M@NoMathfontError\expandafter\noexpand\@i \noexpand\@gobble}} \@tempa} % \end{macrocode} % Now for the macros that |\@gobbletwo| their argument. The code is essentially the same. % \begin{macrocode} \@tfor\@i:=\newmathrm \newmathit \newmathbf \newmathbfit \newmathsc \newmathscit \newmathbfsc \newmathbfscit\do{% \edef\@tempa{\noexpand\M@robust@def\expandafter\noexpand\@i{% \noexpand\M@NoMathfontError\expandafter\noexpand\@i \noexpand\@gobbletwo}} \@tempa} % \end{macrocode} % The two commands with weird ``arguments'': |\charminfo| and |\charmtype| scan and remove the next integer, so we assign a count value instead of gobbling stuff. % \begin{macrocode} \M@robust@def\charminfo{\M@NoMathfontError\charminfo \begingroup \afterassignment\endgroup \count@} \M@robust@def\charmtype{\M@NoMathfontError\charmtype \begingroup \afterassignment\endgroup \count@} % \end{macrocode} % For the optional argument, we check if the following character is a |[|. If yes, we gobble first the brackets and then the mandatory argument. If not, we gobble the single mandatory argument. % \begin{macrocode} \@tfor\@i:=\documentfont \mathfont \mainfont \mathfontshapes \mathconstantsfont\do{% \edef\@tempa{\noexpand\M@robust@def\expandafter\noexpand\@i{% \noexpand\M@NoMathfontError\expandafter\noexpand\@i \noexpand\@ifnextchar[% {\noexpand\expandafter\noexpand\@gobble \noexpand\@gobble@brackets} {\noexpand\@gobble}}} \@tempa} % \end{macrocode} % We code |\newmathfontcommand| by hand because it is the only command with four arguments. % \begin{macrocode} \M@robust@def\newmathfontcommand{% \M@NoMathfontError\newmathfontcommand\@gobblefour} % \end{macrocode} % Check that the engine is \XeTeX\ or Lua\TeX. If yes, set |\ifM@XeTeXLuaTeX| to true. (Otherwise the conditional will be false by default.) % \begin{macrocode} \ifx\directlua\@undefined \else \M@XeTeXLuaTeXtrue \fi \ifx\XeTeXrevision\@undefined \else \M@XeTeXLuaTeXtrue \fi % \end{macrocode} % The package can raise two fatal errors: one if the engine is not \XeTeX\ or Lua\TeX\ (and cannot load OpenType fonts) and one if \TeX\ cannot find the \textsf{luaotfload} package. In both cases, the package will stop loading, so we want a particularly conspicuous error message. For each message, we check the appropriate conditional to determine if we need to raise the error. If yes, we change space to catcode 12 inside a group. We define a |\GenericError| inside a macro and then call the macro for a cleaner error context line. The |\@gobbletwo| eats the extra period and return that \LaTeX\ adds to the error message. Notice that we expand the error before the |\endgroup|\textemdash this is because we need to switch |\M@XeTeXLuaTeXError| with its replacement text while it is still defined before we leave the group. At the same time, we want |\AtBeginDocument| and |\endinput| outside the group. The second |\expandafter| means that we expand the final |\fi| before |\endinput|, which balances the original conditional. % \begin{macrocode} \ifM@XeTeXLuaTeX\else \begingroup \catcode`\ =12\relax \def\M@XeTeXLuaTeXError{\GenericError{}% {\MessageBreak\MessageBreak Package mathfont error:% \MessageBreak\MessageBreak *************************\MessageBreak * *\MessageBreak * UNABLE TO *\MessageBreak * LOAD MATHFONT *\MessageBreak * *\MessageBreak * Missing XeTeX *\MessageBreak * or LuaTeX *\MessageBreak * *\MessageBreak *************************\MessageBreak\@gobbletwo}% {See the mathfont package documentation for explanation.}% {I need XeTeX or LuaTeX to use mathfont. It\MessageBreak looks like the current engine is something\MessageBreak else, so I'm going to stop reading in the\MessageBreak package file now. (You won't be able to use\MessageBreak commands from mathfont in your document.) To\MessageBreak load mathfont correctly, please retypeset your\MessageBreak document with one of those two engines.^^J}}% \expandafter\endgroup \M@XeTeXLuaTeXError \AtEndOfPackage{% \typeout{:: mathfont :: Failed to load\on@line.}} \expandafter\endinput % we \endinput with a balanced conditional \fi % \end{macrocode} % Now do the same thing in checking for \textsf{luaotfload}. If the engine is Lua\TeX, we tell \textsf{mathfont} to implement Lua-based font adjustments by default. The conditional |\ifM@Noluaotfload| will keep track of whether \TeX\ could find |luaotfload.sty|. If the engine is \XeTeX, issue a warning. % \begin{macrocode} \ifdefined\directlua \M@adjust@fonttrue % if engine is LuaTeX, adjust font by default \IfFileExists{luaotfload.sty} {\M@Noluaotfloadfalse\RequirePackage{luaotfload}} {\M@Noluaotfloadtrue} \else \AtEndOfPackage{\PackageWarningNoLine{mathfont}{% The current engine is XeTeX, but as\MessageBreak of mathfont version 2.0, LuaTeX is\MessageBreak recommended. Consider compiling with\MessageBreak LuaLaTeX. Certain features will not\MessageBreak work with XeTeX}} \fi % \end{macrocode} % If the engine is Lua\TeX, we must have \textsf{luaotfload} because Lua\TeX\ needs this package to load OpenType fonts. Before anything else, \TeX\ should check whether it can find |luaotfload.sty| and stop reading in \textsf{mathfont} if it cannot. Same command structure as before. Newer \LaTeX\ versions load \textsf{luaotfload} as part of the format, but it never hurts to double check. % \begin{macrocode} \ifM@Noluaotfload % true if LuaTeX AND no luaotfload.sty \begingroup \catcode`\ =12\relax \def\M@NoluaotfloadError{\GenericError{}% {\MessageBreak\MessageBreak Package mathfont error:% \MessageBreak\MessageBreak *************************\MessageBreak * *\MessageBreak * UNABLE TO *\MessageBreak * LOAD MATHFONT *\MessageBreak * *\MessageBreak * Cannot find the *\MessageBreak * file luaotfload.sty *\MessageBreak * *\MessageBreak *************************\MessageBreak\@gobbletwo}% {You are likely seeing this message because you haven't^^J% installed luaotfload. Check your TeX distribution for a^^J% list of the packages on your system.^^J^^J% See the mathfont documentation for further explanation.}% {You're in trouble here. It looks like the current\MessageBreak engine is LuaTeX, so I need the luaotfload package\MessageBreak to make mathfont work correctly. However, I can't\MessageBreak find luaotfload, which likely means something is\MessageBreak wrong with your TeX installation. I'm going to stop\MessageBreak reading in the mathfont package file. (You won't be\MessageBreak able to use commands from mathfont in your document.)\MessageBreak To load mathfont properly, make sure you installed\MessageBreak luaotfload.sty in a directory searchable by TeX or\MessageBreak compile with XeLaTeX.^^J}}% \expandafter\endgroup \M@NoluaotfloadError \AtEndOfPackage{% \typeout{:: mathfont :: Failed to load\on@line.}} \expandafter\endinput % we \endinput with a balanced conditional \fi % \end{macrocode} % Easter egg!! % \begin{macrocode} \DeclareOption{easter-egg}{% \ifE@sterEggDecl@red\else \E@sterEggDecl@redtrue \newcount\@easter@egg@ \protected\def\EasterEggUpdate{% \ProcessE@sterEgg\showtokens\expandafter{\E@sterEggUpd@te}} \let\ProcessE@sterEgg\relax % \end{macrocode} % Two status updates during package loading. % \begin{macrocode} \edef\E@sterEggUpd@te{Easter Egg Status:^^J^^J% Okay, opening your Easter egg.^^J% Type \string\EasterEggUpdate\space in your^^J% document to see the status.^^J^^J} \EasterEggUpdate \def\E@sterEggUpd@te{Easter Egg Status:^^J^^J% Uh oh. It looks like your Easter^^J% egg flew out the window. I don't^^J% I don't suppose you know the best^^J% kind of bait to lure an egg?^^J^^J} \EasterEggUpdate % \end{macrocode} % Possible updates if the user types |\EasterEggUpdate|. We define the status update with |\ProcessE@sterEgg|, which stores the current message in |\E@sterEggUpd@te| and changes the message as the user calls |\EasterEggUpdate|. The count |\@easter@egg@| keeps track of how many times the user has requested a status update. % \begin{macrocode} \def\ProcessE@sterEgg{% \edef\E@sterEggUpd@te{Easter Egg Status:^^J^^J% \ifodd\@easter@egg@ \ifcase\numexpr(\@easter@egg@ - 1) / 2\relax An Easter bunny must be related to a^^J% platypus, no? Some sort of monotreme...% \or Don't count your chickens before they hatch^^J% out of Easter eggs! But we don't have any^^J% chickens right now because there are no eggs,^^J% and the supply chain is sad.% \or Sorry, I'm late to a meeting. Can't talk right now.% \or Sunday, Monday, Tuesday, Wednesday, also^^J% known as hump day, as in camel humps, which^^J% I must say look distinctly egg-like if you^^J% squint.% \or I'm calling Eggs Anonymous!% \or Sorry, I'm on the phone. Can't talk right now.% \or Still haven't found your Easter egg. I know^^J% it's floating around here somewhere. Like an^^J% asteroid in space, hopefully without the^^J% massive extinction event.% \or Did you know eggs are used to make certain^^J% types of vaccines? PSA: get your flu shot^^J% and your covid shot!% \or Three large eggs.^^J% Three large eggs.^^J% See how they crack.^^J% See how they crack.^^J% Their broken shells are so pearly white.^^J% In simmering water they catch the light.^^J% Did you ever see such a sight in your life^^J% As three poached eggs?% \or Do gnus eat eggs? Surely they must.% \or Okay, I have a fishing rod, some twine, and^^J% a hook, but I still haven't caught your Easter^^J% egg. Apparently it's harder to catch an egg^^J% than a fish.% \or Sorry, I'm out fishing. Can't talk right now.% \or Is ghoti really an acceptable phonetic^^J% spelling of fish? I am skeptical.% \or Perhaps an Easter bunny is actually a species^^J% of fish. A rabbit fish.% \else Sorry, I'm all out of witty things to say.^^J% Check back later.% \fi \else Still wrangling. Check back later.% \fi^^J^^J}% \global\advance\@easter@egg@\@ne} % \end{macrocode} % One status update |\AtBeginDocument|. % \begin{macrocode} \AtBeginDocument{\bgroup \let\ProcessE@sterEgg\relax \def\E@sterEggUpd@te{Easter Egg Status:^^J^^J% If we have zero eggs^^J% and zero bunnies, how^^J% many gnats does it take^^J% to change a lightbulb??^^J^^J} \EasterEggUpdate \egroup} % \end{macrocode} % One update at the first instance of math mode, assuming another package doesn't overwrite the contents of |\everymath| first. % \begin{macrocode} \def\math@E@sterEggUpd@te{\begingroup \let\ProcessE@sterEgg\relax \def\E@sterEggUpd@te{Easter Egg Status:^^J^^J% Scrambled, poached, or sunny side up?^^J^^J}% \EasterEggUpdate \endgroup \global\let\math@E@sterEggUpd@te\relax} \everymath\expandafter{\the\everymath\math@E@sterEggUpd@te} % \end{macrocode} % Two status updates |\AtEndDocument|, including the egg itself. First, we disable |\ProcessE@sterEgg| since we don't need it anymore. Then inside a group, we make the control symbols |\*|, |\/|, and |\=| expand to their own names and do some extreme catcode sports. We convert |+| to active and make it expand to a space. Because everything has already been tokenized inside |\DeclareOption|, we have to retokenize the definition of |+| inside |\scantokens|, and we set |\everyeof| to |\noexpand| to avoid an end-of-file error. % \begin{macrocode} \AtEndDocument{\let\ProcessE@sterEgg\relax \begingroup \edef\*{\@backslashchar*} \edef\/{\@backslashchar/} \edef\={\@backslashchar=} \catcode`\+=\active \everyeof{\noexpand} \scantokens{\def+{ }} % \end{macrocode} % At this point we are ready to make the egg message Again, we have to retokenize everything with |\scantokens| because it was previously tokenized. However, if we write |^^J| directly inside |\scantokens|, that primitive will convert the newline to a blank space, so instead we store |^^J| in |\@tempb|. After the |\edef| expands |\scantokens|, it also expands each |\@tempb|, so |\@tempa| has the line breaks we want. % \begin{macrocode} \def\@tempb{^^J} \edef\@tempa{\scantokens{Easter Egg Status:\@tempb\@tempb The egg has been retrieved. What\@tempb pinnacle of pulchritude!\@tempb\@tempb +++++++++++++******\@tempb ++++++++++************\@tempb +++++++******************\@tempb +++++----------------------\@tempb +++**************************\@tempb ++****/\****/\****/\****/\****\@tempb +*****\/****\/****\/****\/*****\@tempb +******************************\@tempb ********************************\@tempb ***/\****/\****/\****/\****/\***\@tempb ***\/****\/****\/****\/****\/***\@tempb ********************************\@tempb ********************************\@tempb ******/\****/\****/\****/\******\@tempb +*****\/****\/****\/****\/*****\@tempb ++****************************\@tempb +++--------------------------\@tempb +++++**********************\@tempb +++++++******************\@tempb +++++++++\============/\@tempb +++++++++++\========/\@tempb ++++++++++++\======/\@tempb +++++++++++++|====|\@tempb ++++++++++++/======\@backslashchar\@tempb +++++++++++(________)\@tempb}} % \end{macrocode} % Then end the group and store the message in |\E@sterEggUpd@te|. % \begin{macrocode} \expandafter\endgroup\expandafter \def\expandafter\E@sterEggUpd@te\expandafter{\@tempa} \EasterEggUpdate \def\E@sterEggUpd@te{Easter Egg Status:^^J^^J% Happy, happy day! Happy,^^J% happy day! Clap your hands,^^J% and be glad your hovercraft^^J% isn't full of eels!^^J^^J} \EasterEggUpdate \let\E@sterEggUpd@te\relax \let\EasterEggUpdate\relax} \fi}% my easter egg :) % \end{macrocode} % The five real package options. The |default-loader| and |fontspec-loader| tell \textsf{mathfont} what to use as a backend for loading fonts. % \begin{macrocode} \DeclareOption{default-loader}{\M@loader\z@} \DeclareOption{fontspec-loader}{\M@loader\@ne} % \end{macrocode} % The options |adjust| and |no-adjust| determine whether \textsf{mathfont} applies Lua-based font adjustments to fonts loaded in the future. % \begin{macrocode} \DeclareOption{adjust}{\M@adjust@fonttrue} \DeclareOption{no-adjust}{\M@adjust@fontfalse} % \end{macrocode} % Interpret an unknown option as a font name and save it for loading. In this case, the package sets |\ifM@font@loaded| to true and stores the font name in |\M@font@load|. % \begin{macrocode} \DeclareOption*{\M@font@loadedtrue \edef\M@font@load{\CurrentOption}} \ProcessOptions* % \end{macrocode} % For the font-loader, we have a bit of processing to do. First print an informational message in the |log| file. The default loader is easy, but if the user requests \textsf{fontspec}, we have to make sure to load everything properly. % \begin{macrocode} \ifcase\M@loader \@mathfontinfo{Default font-loader was requested for font loading.} \or \@mathfontinfo{Package fontspec was requested for font loading.} % \end{macrocode} % If \textsf{fontspec} was already loaded, check whether |\g__fontspec_math_bool| is true or not. If it is, change it to false. % \begin{macrocode} \@ifpackageloaded{fontspec} {\@mathfontinfo{Package fontspec detected.} \csname bool_if:NTF\expandafter\endcsname \csname g__fontspec_math_bool\endcsname {\@mathfontinfo{Setting \string\g__fontspec_math_bool to false.} \csname bool_set_false:N\expandafter\endcsname \csname g__fontspec_math_bool\endcsname}{\relax}} % \end{macrocode} % If \textsf{fontspec} was not loaded, check that the package file exists. % \begin{macrocode} {\@mathfontinfo{Package fontspec not detected.} \IfFileExists{fontspec.sty} {\@mathfontinfo{File fontspec.sty was found.} \@mathfontinfo{Loading fontspec.} \RequirePackage[no-math]{fontspec}} {\PackageError{mathfont} {Missing package fontspec;^^J% using default font-loader instead} {You requested fontspec as the font-loader\MessageBreak for mathfont. However, I can't find the\MessageBreak package file for fontspec, so I'm going to\MessageBreak use mathfont's built-in font-loader. (This\MessageBreak likely means that something is wrong with\MessageBreak your TeX installation.) Check your TeX\MessageBreak distribution for a list of the packages\MessageBreak installed on your system. To resolve this\MessageBreak error, make sure fontspec is installed in\MessageBreak a directory searchable by TeX or load\MessageBreak mathfont with the default-loader option.^^J} \M@loader\z@}} \fi % \end{macrocode} % We print an informational message specifying the font-loader in use. We store default OpenType features in |\M@otf@features|. The contents depend on the font-loader because we use \XeTeX/\textsf{luaotfload} syntax versus \textsf{fontspec} syntax. By default, \textsf{mathfont} loads fonts with Latin script, default language, \TeX\ and common ligatures, and lining numbers. % \begin{macrocode} \ifcase\M@loader \@mathfontinfo{Using default font-loader.} \AtEndOfPackage{% \typeout{:: mathfont :: Using default font-loader.}} \def\M@otf@features{language=DFLT;+tlig;+liga;+lnum} \or \@mathfontinfo{Using fontspec as font-loader.} \AtEndOfPackage{% \typeout{:: mathfont :: Using fontspec as font-loader.}} \def\M@otf@features{Language=Default, Ligatures={TeX,Common}, Numbers=Lining} \fi % \end{macrocode} % We print an informational message depending on whether the user enabled Lua-based font adjustments. If |\directlua| is defined, that means we are using Lua\TeX, so we print a message depending on |\ifM@adjust@font|. % \begin{macrocode} \ifdefined\directlua \ifM@adjust@font \@mathfontinfo{Enabling Lua-based font adjustments.} \AtEndOfPackage{% \typeout{:: mathfont :: Lua-based font adjustments enabled.}} \else \@mathfontinfo{Disabling Lua-based font adjustments.} \AtEndOfPackage{% \typeout{:: mathfont :: Lua-based font adjustments disabled.}} \fi \else % \end{macrocode} % If |\directlua| is undefined, we make sure Lua-based font adjustments are disabled, and we issue an error if the user tried to manually enable them. % \begin{macrocode} \ifM@adjust@font \PackageError{mathfont}{Option^^J"adjust" ignored with XeTeX} {Your package option "adjust" was ignored.\MessageBreak This option works only with LuaTeX, and it\MessageBreak looks like the current engine is XeTeX. To\MessageBreak enable Lua-based font adjustments, typeset\MessageBreak with LuaLaTeX.^^J} \M@adjust@fontfalse \fi \@mathfontinfo{Disabling Lua-based font adjustments.} \AtEndOfPackage{% \typeout{:: mathfont :: Lua-based font adjustments disabled.}} \fi % \end{macrocode} % % % % \section{Default Settings} % % We save four macros from the \LaTeX\ kernel for safe-keeping, and then we change their definitions. As of version 3.0 of \textsf{mathfont}, the new definitions for |\set@mathchar|, etc.\ are not necessary for implementing \textsf{mathfont}, but we keep them in the package to make |\DeclareMathSymbol| and friends compatible with Unicode. For these three control sequences, we convert the hexadecimal digits in |\count0| and |\count2| back to decimal and change the |\math| primitive to |\Umath|. % \begin{macrocode} \let\@@set@mathchar\set@mathchar \let\@@set@mathsymbol\set@mathsymbol \let\@@set@mathaccent\set@mathaccent \let\@@DeclareSymbolFont\DeclareSymbolFont \let\@@DeclareSymbolFont@m@dropped\DeclareSymbolFont@m@dropped \@onlypreamble\@@set@mathchar \@onlypreamble\@@set@mathsymbol \@onlypreamble\@@set@mathaccent \@onlypreamble\@@DeclareSymbolFont \@onlypreamble\@@DeclareSymbolFont@m@dropped \@mathfontinfo{Adapting \noexpand\set@mathchar for Unicode.} \@mathfontinfo{Adapting \noexpand\set@mathsymbol for Unicode.} \@mathfontinfo{Adapting \noexpand\set@mathaccent for Unicode.} \@mathfontinfo{Increasing upper bound on \noexpand\DeclareSymbolFont to 256.} % \end{macrocode} % Kernel command to set math characters from keystrokes. % \begin{macrocode} \def\set@mathchar#1#2#3#4{% \multiply\count\z@ by 16\relax \advance\count\z@\count\tw@ \global\Umathcode`#2=\mathchar@type#3+#1+\count\z@\relax} % \end{macrocode} % Kernel command to set math characters from control sequences. % \begin{macrocode} \def\set@mathsymbol#1#2#3#4{% \multiply\count\z@ by 16\relax \advance\count\z@\count\tw@ \global\Umathchardef#2=\mathchar@type#3+#1+\count\z@\relax} % \end{macrocode} % Kernel command to set accents. % \begin{macrocode} \def\set@mathaccent#1#2#3#4{% \multiply\count\z@ by 16\relax \advance\count\z@\count\tw@ \protected\xdef#2{% \Umathaccent\mathchar@type#3+\number#1+\the\count\z@\relax}} % \end{macrocode} % We increase the upper bound on the number of symbol fonts to be 256. Lua\TeX\ and \XeTeX\ allow up to 256 math families, but the \LaTeX\ kernel keeps the old upper bound of 16 symbol fonts under these two engines. We patch |\DeclareSymbolFont| to change the |\count18<15| to |\count18|\penalty0|<\e@mathgroup@top|, where |\e@mathgroup@top| is the number of math families, which is 256 in \XeTeX\ and Lua\TeX. We get a sanitized definition with |\meaning| and |\strip@prefix|, implement the patch by expanding |\M@p@tch@decl@re|, and retokenize the whole thing. A simpler approach, such as calling |\M@p@tch@decl@re| directly on the expansion of |\DeclareSymbolFont|, won't work because of how \TeX\ stores and expands parameter symbols inside macros. % % As of November 2022, the \LaTeX\ team renamed |\DeclareSymbolFont| to |\DeclareSymbolFont@m@dropped|, and now |\DeclareSymbolFont| is a wrapper around the old version of itself. This was done for error checking purposes to remove extra |m|'s from certain \textsc{nfss} family names. This means that if |\DeclareSymbolFont@m@dropped| is defined, we should patch that macro, and otherwise, we should patch |\DeclareSymbolFont|. % \begin{macrocode} \ifx\DeclareSymbolFont@m@dropped\@undefined \edef\@tempa{\expandafter \strip@prefix\meaning\DeclareSymbolFont} \def\@tempb{\def\DeclareSymbolFont##1##2##3##4##5} \else \edef\@tempa{\expandafter \strip@prefix\meaning\DeclareSymbolFont@m@dropped} \def\@tempb{\def\DeclareSymbolFont@m@dropped##1##2##3##4##5} \fi \def\M@p@tch@decl@re#1<15#2\@nil{#1<\e@mathgroup@top#2} \edef\M@DecSymDef{\expandafter\M@p@tch@decl@re\@tempa\@nil} % \end{macrocode} % Now |\M@DecSymDef| contains the patched text of our new |\DeclareSymbolFont|, all with catcode 12. In order to make it useable, we have to retokenize it. If this package was Lua\TeX\ only, we could use |\scantextokens|, which is nicely behaved and does what we expect. However, to make it compatible with \XeTeX, we use |\scantokens|. Unfortunately, while |\scantextokens| is straightforward, |\scantokens| is a menace. The problem is that when it expands, the primitive inserts an end-of-file token (because |\scantokens| mimics writing to a file and |\input|ing what it just wrote) after the retokenized code, and as a result, |\scantokens| can produce an end-of-file error. The trick (realized after much trial and error) is that if we scan the entire definition statement including |\def| and the macro definition, the end-of-file token doesn't end up in the macro definition, and we avoid the ``file ended'' error message. % \begin{macrocode} \scantokens\expandafter{% \expandafter\@tempb\expandafter{\M@DecSymDef}} % \end{macrocode} % We need to keep track of the number of times we have loaded fonts, and |\M@count| fulfills this role. The |\toks| will record a message that displays in the |log| file when the user calls |\mathfont|. The |\newread| is for Lua-based font adjustments. % \begin{macrocode} \newbox\surdbox \newcount\M@count \newcount\M@num@localfonts \newcount\rulethicknessfactor \newcount\hsurdfactor \newcount\vsurdfactor \newmuskip\radicandoffset \newread\M@Charm \M@count\z@ \rulethicknessfactor\@m \hsurdfactor\@m \vsurdfactor\@m \radicandoffset=1mu\relax % \end{macrocode} % Necessary booleans and default math font shapes. % \begin{macrocode} \newif\ifM@upper \newif\ifM@lower \newif\ifM@diacritics \newif\ifM@greekupper \newif\ifM@greeklower \newif\ifM@agreekupper \newif\ifM@agreeklower \newif\ifM@cyrillicupper \newif\ifM@cyrilliclower \newif\ifM@hebrew \newif\ifM@digits \newif\ifM@operator \newif\ifM@symbols \newif\ifM@extsymbols \newif\ifM@delimiters \newif\ifM@radical \newif\ifM@arrows \newif\ifM@bigops \newif\ifM@extbigops \newif\ifM@bb \newif\ifM@cal \newif\ifM@frak \newif\ifM@bcal \newif\ifM@bfrak \newif\if@optionpresent \newif\if@suboptionpresent \newif\ifM@arg@good \newif\ifM@mode@ % \end{macrocode} % Default shapes. % ^^A temporarily disable writing % ^^A macros in the margin % ^^A otherwise it looks weird % \let\@@marginmacro\marginmacro % \def\marginmacro#1\@nil{} % \begin{macrocode} \def\upperdefault{italic} % latin upper \def\lowerdefault{italic} % latin lower \def\diacriticsdefault{upright} % diacritics \def\greekupperdefault{upright} % greek upper \def\greeklowerdefault{italic} % greek lower \def\agreekupperdefault{upright} % ancient greek upper \def\agreeklowerdefault{italic} % ancient greek lower \def\cyrillicupperdefault{upright} % cyrillic upper \def\cyrilliclowerdefault{italic} % cyrillic lower \def\hebrewdefault{upright} % hebrew \def\digitsdefault{upright} % numerals \def\operatordefault{upright*} % operator font \def\delimitersdefault{upright} % delimiters \def\radicaldefault{upright} % surd \def\bigopsdefault{upright} % big operators \def\extbigopsdefault{upright} % extended big operators \def\symbolsdefault{upright} % basic symbols \def\extsymbolsdefault{upright} % extended symbols \def\arrowsdefault{upright} % arrows \def\bbdefault{upright} % blackboard bold \def\caldefault{upright} % caligraphic \def\frakdefault{upright} % fraktur \def\bcaldefault{upright} % bold caligraphic \def\bfrakdefault{upright} % bold fraktur % \end{macrocode} % \let\marginmacro\@@marginmacro % The |\M@keys| list stores all the possible keyword options, and |\M@defaultkeys| stores the character classes that |\mathfont| acts on by default. % \begin{macrocode} \def\M@keys{upper,lower,diacritics,greekupper,% greeklower,agreekupper,agreeklower,cyrillicupper,% cyrilliclower,hebrew,digits,operator,delimiters,% radical,bigops,extbigops,symbols,extsymbols,arrows,% bb,cal,frak,bcal,bfrak} \def\M@defaultkeys{upper,lower,diacritics,greekupper,% greeklower,digits,operator,symbols} % \end{macrocode} % If the user enabled Lua-based font adjustments, the |\M@defaultkeys| list also includes delimiters, surd, and big operator symbols. % \begin{macrocode} \ifM@adjust@font \edef\M@defaultkeys{\M@defaultkeys,delimiters,radical,bigops} \fi % \end{macrocode} % A few macros that we use for assembling lists of font information and printing messages |\AtBeginDocument|. % \begin{macrocode} \let\M@localfonts\@empty \let\M@symbolfonts\@empty \let\M@families\@empty % \end{macrocode} % And now the macros to add to those three control sequences. First is a helper macro that accepts two arguments and stores information about declaration of local font changes. The macro successively adds comma-separated pairs of control sequence and font name information to |\M@localfonts|. It also keeps track of the number of distinct font names in |\M@localfonts| with the count variable |\M@num@localfonts|. The |#1| argument is a control sequence (with all characters having catcode 12 from |\string|), and the |#2| argument is a font name. We have two different approaches depending on whether |\M@localfonts| is empty, i.e.\ if it's the first time calling |\M@addto@localfonts|. If |\M@localfonts| is |\@empty|, that means we haven't added any fonts to the list yet, so we increase |\M@num@localfonts|. Otherwise we loop through |\M@localfonts|, and we increase |\M@num@localfonts| only if none of the entries in |\M@localfonts| use the |#2| font. After incrementing (or not) the count, we append |#1| and |#2| to |\M@localfonts|. % \begin{macrocode} \def\M@addto@localfonts#1#2#3#4{% \begingroup \@tempswatrue % increase by default \def\@tempa##1##2##3##4{##2}% \@for\@j:=\M@localfonts\do{% \edef\@tempb{\expandafter\@tempa\@j}% \ifx\@tempbase\@tempb \@tempswafalse % if \@tempbase is in list, don't add \fi}% \expandafter \endgroup \if@tempswa \advance\M@num@localfonts\@ne \fi \ifx\M@localfonts\@empty \else \edef\M@localfonts{\M@localfonts,}% \fi \edef\M@localfonts{\M@localfonts{#1}{#2}{#3}{#4}}} % \end{macrocode} % Same thing for symbol fonts. % \begin{macrocode} \def\M@addto@symbolfonts#1#2#3#4{% \ifx\M@symbolfonts\@empty \else \edef\M@symbolfonts{\M@symbolfonts,}% \fi \edef\M@symbolfonts{\M@symbolfonts{#1}{#2}{#3}{#4}}} % \end{macrocode} % And font families. % \begin{macrocode} \def\M@addto@families#1{% \ifx\M@families\@empty \else \edef\M@families{\M@families,}% \fi \xdef\M@families{\M@families#1}} % \end{macrocode} % % % \section{Messages and Errors} % \suppressfloats[t] % % % % \begin{figure}[t] % \def\vrb#1{\texttt{\string#1}} % \centerline{\bfseries Table 1: Package Messages and Errors and Their Uses\strut} % \begin{tabularx}\textwidth{lX<{\raggedright\arraybackslash}} % \toprule % Command & Use\\\midrule % \vrb\@mathfontinfo & General informational macro\\ % \vrb\M@FontChangeInfo & When using a new symbol font\\ % \vrb\M@FontFamilyInfo & Declaring new font shape in the \textsc{nfss}\\ % \vrb\M@NewFontCommandInfo & New local font-change command\\ % \vrb\M@SymbolFontInfo & Declare new symbol font\\\midrule % \vrb\M@FamilyTypeError & Error if bad argument for \vrb\mainfont\\ % \vrb\M@NFSSShapesWarning & Warning if font is missing shapes\\ % \vrb\M@NoBaseModeError & Error if no base-mode version of a font\\\midrule % \vrb\M@InvalidOptionError & Bad keyword for font-change command\\ % \vrb\M@InvalidSupoptionError & Bad suboption for font-change command\\ % \vrb\M@MissingOptionError & Missing keyword for font-change command\\ % \vrb\M@MissingSuboptionError & Missing suboption for font-change command\\\midrule % \vrb\M@FontShapesError & Tried to add font shapes after preamble\\ % \vrb\M@LuaTeXOnlyWarning & User called Lua\TeX-only macro in \XeTeX\\\midrule % \vrb\M@HModeError & Font-change command used outside math\\ % \vrb\M@MissingCSError & No macro for font-change command\\\midrule % \vrb\M@BadIntegerError & Non-integer value for font adjustment\\ % \vrb\M@NoCharmFileError & Bad file name for \vrb\charmfile\\ % \vrb\M@NoFontAdjustError & Macro used without Lua font adjustments\\ % \bottomrule % \end{tabularx} % \end{figure} % % % % Some error and informational messages. Table~1 lists all macros defined in this section along with a brief description of their use. We begin with general informational messages. % \begin{macrocode} \def\M@FontChangeInfo#1#2{\@mathfontinfo{Setting #1 chars to #2!}} \def\M@FontFamilyInfo#1{\@mathfontinfo{Adding #1 to the nfss.}} \def\M@SymbolFontInfo#1#2#3{% \@mathfontinfo{New symbol font uses TU/#1/#2/#3.}} \def\M@NewFontCommandInfo#1#2#3#4{% \@mathfontinfo{New \string#1 uses TU/#2/#3/#4.}} % \end{macrocode} % Warnings and errors related to font declaration. % \begin{macrocode} \def\M@NFSSShapesWarning#1#2{% \PackageWarningNoLine{mathfont} {The nfss family "#1"\MessageBreak from line \the\inputlineno\space is missing shapes.\MessageBreak You may see some substitutions\MessageBreak or errors. See the log file for\MessageBreak details} \@mathfontinfo{Shapes missing: #2.}} \def\M@NoBaseModeError#1{% \PackageError{mathfont} {Missing base-mode^^J% version of font family "#1"} {With LuaTeX, when you tell mathfont to\MessageBreak use a font family from the nfss, I try to\MessageBreak find aversion of that font in the nfss\MessageBreak that uses base mode. I couldn't do that\MessageBreak here, so you may see some problems with\MessageBreak your math. To resolve this error, either\MessageBreak use XeTeX, or make sure the nfss contains\MessageBreak a version of your font in base mode, and\MessageBreak define \string\-base to be the nfss\MessageBreak name for your base-mode family.^^J}} \def\M@FamilyTypeError#1{% \PackageError{mathfont} {Invalid family type/^^J% optional argument "#1" for \string\mainfont} {The optional argument of \string\mainfont\space should\MessageBreak be one of rm, sf, or tt. You used something\MessageBreak else, so I'm changing it to rm.^^J}} % \end{macrocode} % Error and warning messages for keywords and shape identifiers. % \begin{macrocode} \def\M@InvalidOptionError#1{% \PackageError{mathfont} {Invalid^^Jkeyword "#1" on line \the\inputlineno} {You used a character keyword that I'm\MessageBreak not familiar with. Check that you spelled\MessageBreak everything correctly. To resolve this\MessageBreak error, make sure you use keywords that\MessageBreak are listed in the documentation.^^J\@gobble}} \def\M@InvalidSuboptionError#1{% \PackageError{mathfont} {Invalid^^Jshape identifer "#1" on line \the\inputlineno} {You used a suboption/shape identifier\MessageBreak that I'm not familiar with. Check that\MessageBreak you spelled everything correctly. To\MessageBreak resolve this error, make sure you use\MessageBreak shape identifiers that are listed in\MessageBreak the documentation.^^J}} \def\M@MissingOptionError{% \PackageError{mathfont} {Missing keyword on line \the\inputlineno} {I didn't see a character keyword\MessageBreak where I was expecting to. This can\MessageBreak happen if you type ,, or ,= by\MessageBreak mistake. To resolve this error,\MessageBreak make sure you provided a comma-\MessageBreak separated list of keywords.^^J}} \def\M@MissingSuboptionError{% \PackageError{mathfont} {Missing suboption/^^Jshape identifier on line \the\inputlineno} {I didn't see a suboption/shape identifier\MessageBreak where I was expecting to. This can happen\MessageBreak if you type ,, or =, or == by mistake. To\MessageBreak resolve this error, make sure that every\MessageBreak = sign comes before a suboption or that you\MessageBreak provided a comma-separated list of shape\MessageBreak identifiers, depending on the context.^^J}} % \end{macrocode} % Error messages regarding arguments previously fed to |\mathfont| and friends. % \begin{macrocode} \def\M@FontShapesError{% \PackageError{mathfont} {^^JCan't declare new font shapes after \string\begin{document}} {This error means that you (1) requested\MessageBreak to use a family/series/shape combination\MessageBreak for a font-change command in this package\MessageBreak (2) after your document preamble (3) that\MessageBreak does not match any font you used for this\MessageBreak package in the preamble. To resolve this\MessageBreak error, try declaring more font shapes in\MessageBreak your preamble with \string\mathfontshapes.^^J}} \def\M@LuaTeXOnlyWarning#1{% \PackageWarningNoLine{mathfont} {Your \string#1\space on line \the\inputlineno\MessageBreak is mainly for use in LuaTeX with font\MessageBreak adjustments enabled. In the current\MessageBreak situation, it is probably not doing\MessageBreak anything}} % \end{macrocode} % Error messages for the |\newmathrm|, etc.\ commands. % \begin{macrocode} \def\M@MissingCSError#1#2{% \PackageError{mathfont} {Missing control sequence^^J% for\string#1\space on line \the\inputlineno} {Your command was ignored. Instead of\MessageBreak "#2,"\MessageBreak I was expecting a single control\MessageBreak sequence. To resolve this error,\MessageBreak please use one control sequence instead.^^J}} \def\M@HModeError#1{% \PackageError{mathfont} {Missing \string$ inserted^^J% on line \the\inputlineno} {I raised an error because you used\MessageBreak \string#1\space outside of math mode,\MessageBreak which isn't allowed. I inserted a \string$\MessageBreak before your control sequence, so we\MessageBreak should be all good now.^^J}} % \end{macrocode} % We need error messages related to Lua-based font adjustments. % \begin{macrocode} \def\M@NoFontAdjustError#1{% \PackageError{mathfont} {\string#1^^J% is invalid without Lua-based font adjustments} {Your control sequence won't do anything\MessageBreak without Lua-based font adjustments, but\MessageBreak you didn't enable them. To resolve this\MessageBreak error, load mathfont with LuaTeX and the\MessageBreak package option "adjust" or remove your\MessageBreak control sequence.^^J}} \def\M@BadIntegerError#1#2{% \PackageError{mathfont} {Bad argument^^J% "#2" for \string#1 on line \the\inputlineno} {Your command was ignored. Please make sure\MessageBreak that your argument for \string#1\MessageBreak is a nonnegative integer.^^J}} \def\M@NoCharmFileError#1{% \PackageError{mathfont}{Missing Charm File} {You requested to read the file\MessageBreak "#1"\MessageBreak with \string\charmfile. I can't find that file,\MessageBreak so I'm ignoring your command. To resolve\MessageBreak this error, make sure the filename is\MessageBreak correct, and double check that the file\MessageBreak is in a directory searchable by TeX.^^J}} % \end{macrocode} % % % % \section{Font Declaration} % % We come to the fontloader. The main font declaration macro is |\M@newfont|, and it accepts one argument that is a combination of font name and optional OpenType feature information separated by a colon. The macro accomplishes four tasks: (1) it separates the font name and features and stores them in |\@tempbase| and |\@tempfeatures|; (2) it checks whether tbe argument is present as a font name in the \textsc{nfss}; (3) if not, it declares the font in the \textsc{nfss}, either with the built-in font loader or using \textsf{fontspec}; and (4) it stores the \textsc{nfss} family name(s) in |\M@f@ntn@me| and |\M@f@ntn@meb@se|. If |\M@newfont| reaches step~3 after |\begin{document}|, it raises a ``can't declare new font shapes'' error. % % Checking the \textsc{nfss} happens in two steps. First, |\M@newfont| removes the spaces from its argument and checks whether the result matches a previous call to |\M@newfont|, and if yes, |\M@newfont| uses the family name from the previous call. If no, the macro checks whether the argument with spaces removed appears in the \textsc{nfss}. (Properly declared \textsc{nfss} font families shouldn't have spaces in their names because \LaTeX\ ignores spaces when scanning a font family declaration.) If |\M@newfont| finds an \textsc{nfss} family, it looks at the font shapes associated with that family using the helper macro |\M@check@nfss@shapes|. This command prints a warning if the \textsc{nfss} is missing any standard series/shape combinations (|m|/|n|, |m|/|it|, |b|/|n|, and |b|/|it|) for the font family. The package does not add any font shapes to the \textsc{nfss} at this point in the font-loading process. % % If both checks of the \textsc{nfss} fail, \textsf{mathfont} assumes the \textsc{nfss} does not contain the user's desired font and proceeds to declare it in the \textsc{nfss}. For the built-in font loader, font declaration uses the helper macros |\M@fill@nfss@shapes| and |\M@declare@shape|. The first of these two macros loops through series/shape pairs and feeds them to the second macro, which acts as a wrapper around |\DeclareFontShape|. If the user requested to use \textsf{fontspec} for the font loader, |\M@newfont| feeds the font name and requested features to |\fontspec_set_family:Nnn|, which modifies the \textsc{nfss} accordingly. Advanced users should keep in mind the difference between font declaration and font loading in \LaTeX. Font declaration, the subject of this section, means adding font information to the \textsc{nfss} through |\DeclareFontFamily| and |\DeclareFontShape|, and font loading is when \TeX\ reads a font file into memory via the |\font| primitive. \LaTeX\ handles font loading automatically at a |\selectfont| command or upon entering math mode, so a call to |\M@newfont| will not actually load any fonts into memory, just prepare \LaTeX\ to do so at a later time. % % In Lua\TeX, users can load fonts in one of three modes, namely |node| (the default), |base|, or |harf|. Node mode works well for text, but it has more limited capabilities for math. Harf mode uses the HarfBuzz renderer and is appropriate for more complicated scripts. Accordingly, when the engine is Lua\TeX, \textsf{mathfont} loads fonts once in base mode for math and once in unspecified (so likely node) mode for text. If the user specifies a font family already in the \textsc{nfss}, |\M@newfont| tries to find a base-mode version of the font family and raises an error if it cannot. When |\M@newfont| declares the font, it does so twice, once in unspecified mode and once in base mode. This is why we have two control sequences for font family names: |\M@f@ntn@me| is the font family, and |\M@f@nt@n@me@base| contains the \textsc{nfss} family name of the base-mode version of the font. In \XeTeX, these control sequences will be identical because \textsf{mathfont} does not load a font multiple times in that case. % % During font declaration, \textsf{mathfont} links several pieces of information as follows: % \begin{itemize} % \item Given an \meta{argument} with spaces removed, |\M@newfont| stores the corresponding \textsc{nfss} family name in |\M@fontfamily@|\meta{argument} % \item The \textsc{nfss} family name for the base-mode version of the font goes in |\M@fontfamily@base@|\meta{argument} % \item Given a \meta{family name}, |\M@newfont| stores the corresponding base-mode font family name in the control sequence |\|\meta{family name}|-base|. Users who want to declare their own fonts in the \textsc{nfss} prior to using them with \textsf{mathfont} should manually define this control sequence so that \textsf{mathfont} knows where your base-mode font lives. % \item Each \textsc{nfss} font family is assigned a unique value of |\M@count| that is stored in |\M@fontid@|\meta{family}. % \end{itemize} % These macro assignments are global. The difference relative to |\M@f@ntn@me| and |\M@f@ntn@meb@se| is that |\M@f@ntn@me| and |\M@f@ntn@meb@se| are temporary and always hold the font family from the most recent call to |\M@newfont|. % % The |\M@check@nfss@shapes| macro checks if a font family has shapes declared in upright, italic, bold, and bold italic. If any of those shapes are missing, we issue a warning. We store the missing series/shape pairs in |\@tempb| to print them as part of the warning message. % \begin{macrocode} \def\M@check@nfss@shapes#1{% \let\@tempb\@empty \let\@tempwarning\@gobble \@for\@i:=\mddefault/\shapedefault,% \mddefault/\itdefault,% \bfdefault/\shapedefault,% \bfdefault/\itdefault\do{% \expandafter\ifx\csname TU/#1/\@i\endcsname\relax \def\@tempwarning{\M@NFSSShapesWarning{#1}}% \edef\@tempb{\@tempb, \@i}% \fi}% % \end{macrocode} % We use a small hack to get everything to print correctly. If all shapes are present, then |\@tempwarning| is |\@gobble|, and the argument disappears. Otherwise, the argument becomes part of the warning message. The |\@gobble| eats the (unnecessary) first comma inside |\@tempb|. % \begin{macrocode} \@tempwarning{\expandafter\@gobble\@tempb}} % \end{macrocode} % Next we have commands to add series and shape information to the \textsc{nfss} for a given font family. The |\M@declare@shape| macro takes several arguments. It checks whether the series/shape pair exists in the \textsc{nfss}, and if not, it adds it using |\DeclareFontShape|. The argument structure is % \begin{itemize} % \item |#1|---\textsc{nfss} font family name % \item |#2|---optional |/B| or |/I| (or |/BI|) suffix on the font name % \item |#3|---a list of (default) OpenType feature tags % \item |#4|---a list of (the user's) OpenType feature tags % \item |#5|---\textsc{nfss} series identifier % \item |#6|---\textsc{nfss} shape identifier % \end{itemize} % We assume that the font file reference has already been stored in |\@tempbase|. % \begin{macrocode} \def\M@declare@shape#1#2#3#4#5#6{% \ifcsname TU/#1/#5/#6\endcsname \else \DeclareFontShape{TU}{#1}{#5}{#6}{<->"\@tempbase#2:#3;#4"}{}% \fi} % \end{macrocode} % The |\M@fill@nfss@shapes| command does the work of populating the \textsc{nfss} with the correct shape information. The argument structure is: % \begin{itemize} % \item |#1|---\textsc{nfss} font family name % \item |#2|---a list of (default) OpenType feature tags % \item |#3|---a list of (the user's) OpenType feature tags % \end{itemize} % We call |\M@declare@shape| for each combination of medium/bold series and upright/italic shape, and the result is an entry in the \textsc{nfss} for each combination. We have separate declarations for regular and small caps because they have different shape identifiers in the \textsc{nfss}. We manually set |smcp| to be |true| or |false| accordingly. % \begin{macrocode} \def\M@fill@nfss@shapes#1#2#3{% \@for\@i:={#1}{}{#2;-smcp}{#3}{\mddefault}{\shapedefault},% {#1}{/I}{#2;-smcp}{#3}{\mddefault}{\itdefault},% {#1}{/B}{#2;-smcp}{#3}{\bfdefault}{\shapedefault},% {#1}{/BI}{#2;-smcp}{#3}{\bfdefault}{\itdefault},% % \end{macrocode} % And do small caps. If a small caps font face is separate from the main font file, \TeX\ won't be able to find it automatically. In that case, you will have to write your own |fd| file or |\DeclareFontShape| commands. % \begin{macrocode} {#1}{}{#2;+smcp}{#3}{\mddefault}{\scdefault},% {#1}{/I}{#2;+smcp}{#3}{\mddefault}{\scdefault\itdefault},% {#1}{/B}{#2;+smcp}{#3}{\bfdefault}{\scdefault},% {#1}{/BI}{#2;+smcp}{#3}{\bfdefault}{\scdefault\itdefault}% \do{\expandafter\M@declare@shape\@i}} % \end{macrocode} % We use |\M@split@colon| and |\M@strip@colon| for parsing the argument of |\mathfont|. If the user calls |\mathfont{|\meta{name}|:|\meta{features}|}|, we store the name in |\@tempbase| and the features in |\@tempfeatures|. If the user specifies a name only, then |\@tempfeatures| will be empty. Syntactically, we use |\M@strip@colon| to remove a final |:| the same way we remove a final |=| when we parse the optional argument in the next section. % \begin{macrocode} \def\M@split@colon#1:#2\@nil{% \def\@tempbase{#1}% \def\@tempfeatures{#2}} \def\M@strip@colon#1:{#1} % \end{macrocode} % The main font-loading macro. It takes a single argument, which should look like either \meta{\textup{\textsc{nfss}} family} or \meta{font name}|:|\meta{optional features}. The first thing |\M@newfont| does is split the font name and OpenType features and store each portion in |\@tempbase| and |\@tempfeatures|. If |\@tempfeatures| is not empty, it has an extra colon at the end, so we remove it. % \begin{macrocode} \def\M@newfont#1{% \expandafter\M@split@colon\expanded{#1}:\@nil \ifx\@tempfeatures\@empty\else \edef\@tempfeatures{\expandafter\M@strip@colon\@tempfeatures}% \fi % \end{macrocode} % Then we find the font family name. We remove spaces from the argument, store it in |\@tempa|, and check whether the result matches a previous call to |\M@newfont|. If yes, we retrieve the font family and base-mode family names and store them in the appropriate control sequences. % \begin{macrocode} \edef@nospace\@tempa{#1}% \ifcsname M@fontfamily@\@tempa\endcsname \edef\M@f@ntn@me {\csname M@fontfamily@\@tempa\endcsname}% \edef\M@f@ntn@meb@se {\csname M@fontfamily@base@\@tempa\endcsname}% \else % \end{macrocode} % Next check whether |\@tempa| appears as a font family in the \textsc{nfss}. % \begin{macrocode} \ifcsname TU+\@tempa\endcsname% is #1 font family in the nfss? \let\M@f@ntn@me\@tempa % \end{macrocode} % Check that the \textsc{nfss} contains some font shapes. If any are missing, we issue a warning but do not fill them. % \begin{macrocode} \M@check@nfss@shapes\M@f@ntn@me % \end{macrocode} % With Lua\TeX, we want a proper base-mode version of the font. In this situation, \textsf{mathfont} expects to find a second font family whose \textsc{nfss} identifier is stored in |\|\meta{font family}|-base|, and we assume this second font was loaded with |mode=base|. If that information exists, we use it for the base-mode version. % \begin{macrocode} \ifdefined\directlua % if LuaTeX? \ifcsname\M@f@ntn@me-base\endcsname % if base-mode version \edef\M@f@ntn@meb@se {\csname\M@f@ntn@me-base\endcsname}% % \end{macrocode} % If the package found a base-mode font, again check that it contains some font shapes, and issue a warning if not. % \begin{macrocode} \M@check@nfss@shapes\M@f@ntn@meb@se \else % \end{macrocode} % Raise an error if we can't find a base-mode font family, and use the regular font instead. % \begin{macrocode} \M@NoBaseModeError\M@f@ntn@me \expandafter\xdef \csname\M@f@ntn@me-base\endcsname{\M@f@ntn@me}% \let\M@f@ntn@meb@se\M@f@ntn@me \fi % \end{macrocode} % Base mode is a Lua\TeX-only feature version of a font, so we link the base-mode identifier to the same font. % \begin{macrocode} \else % if XeTeX? \expandafter\xdef \csname\M@f@ntn@me-base\endcsname{\M@f@ntn@me}% \let\M@f@ntn@meb@se\M@f@ntn@me \fi % \end{macrocode} % Now save the font families for reference later. % \begin{macrocode} \expandafter\xdef \csname M@fontfamily@\@tempa\endcsname {\M@f@ntn@me}% \expandafter\xdef \csname M@fontfamily@base@\@tempa\endcsname {\M@f@ntn@meb@se}% \else % if #1 is not in nfss % \end{macrocode} % If the argument does not match a known font family, we have to load it ourselves. First, we check that we are still in the document preamble, and if not, we issue an error. % \begin{macrocode} \ifx\@onlypreamble\@notprerr % if after \begin{document} \M@FontShapesError \else % if in preamble % \end{macrocode} % If we are in the document preamble, we can still add information to the \textsc{nfss}. We store the font family name in |\M@f@ntn@me| and print messages in the |log| file. Then we declare the font family and call |\M@fill@nfss@shapes| to declare all the shapes. % \begin{macrocode} \ifcase\M@loader % are we using default font-loader? \let\M@f@ntn@me\@tempa \M@FontFamilyInfo\M@f@ntn@me \DeclareFontFamily{TU}{\M@f@ntn@me}{}% \M@fill@nfss@shapes{\M@f@ntn@me}{\M@otf@features} {\@tempfeatures}% % \end{macrocode} % If the engine is Lua\TeX, we load a separate version of the font with |mode=base| and |script=math|. We need to set the |script| because \textsf{luaotfload} processes math information only for fonts with the script set to |math|, and we definitely want that information loaded if present. Then we link the base-mode and regular versions. % \begin{macrocode} \ifdefined\directlua \edef\M@f@ntn@meb@se{\M@f@ntn@me-base}% \M@FontFamilyInfo\M@f@ntn@meb@se \DeclareFontFamily{TU}{\M@f@ntn@meb@se}{}% \M@fill@nfss@shapes{\M@f@ntn@meb@se}{\M@otf@features} {\@tempfeatures;mode=base;script=math}% \else \let\M@f@ntn@meb@se\M@f@ntn@me \fi \or % are we using fontspec as font-loader? % \end{macrocode} % If the user requested \textsf{fontspec} as the font-loader, we pass the font name and features to |\fontspec_set_family:Nnn| for loading and store the \textsc{nfss} family name in |\M@f@ntn@me|. In Lua\TeX, we request a separate base-mode version by specifying |Renderer=Base| and |Script=Math|. % \begin{macrocode} \@mathfontinfo{Passing \@tempbase\space to fontspec for handling!}% \csname fontspec_set_family:Nnn\endcsname\M@f@ntn@me {\M@otf@features,\@tempfeatures}{\@tempbase}% \ifdefined\directlua \@mathfontinfo{Passing \@tempbase\space with Renderer=Base to fontspec for handling!}% \csname fontspec_set_family:Nnn\endcsname \M@f@ntn@meb@se {\M@otf@features,\@tempfeatures,% Renderer=Base,Script=Math} {\@tempbase}% \else \edef\M@f@ntn@meb@se{\M@f@ntn@me}% \fi \fi % \end{macrocode} % Now link the base-mode family name and store the family names for future reference. % \begin{macrocode} \expandafter\xdef\csname\M@f@ntn@me-base\endcsname {\M@f@ntn@meb@se}% \expandafter\xdef\csname M@fontfamily@\@tempa\endcsname {\M@f@ntn@me}% \expandafter\xdef \csname M@fontfamily@base@\@tempa\endcsname {\M@f@ntn@meb@se}% \fi \fi \fi % \end{macrocode} % Finally, assign |\M@count| values to the font family(ies) if needed and save their names in |\M@families|. % \begin{macrocode} \ifcsname M@fontid@\M@f@ntn@me\endcsname % need new \M@count? \else \expandafter\xdef \csname M@fontid@\M@f@ntn@me\endcsname{\the\M@count}% \global\advance\M@count\@ne \M@addto@families{\M@f@ntn@me}% \fi % \end{macrocode} % Same thing with the base-mode version of the font. % \begin{macrocode} \ifcsname M@fontid@\M@f@ntn@meb@se\endcsname \else \expandafter\xdef \csname M@fontid@\M@f@ntn@meb@se\endcsname{\the\M@count}% \global\advance\M@count\@ne \M@addto@families{\M@f@ntn@meb@se}% \fi} % \end{macrocode} % The font-loading commands should appear only in the preamble. % \begin{macrocode} \@onlypreamble\M@declare@shape \@onlypreamble\M@fill@nfss@shapes % \end{macrocode} % % % \section{Parse Input} % % This section provides the macros to parse the optional argument of |\mathfont|. We have two parts to this section: error checking and parsing. For parsing, we extract option and suboption information, and for error checking, we make sure that both are valid. The command |\M@check@opt| accepts a macro containing (what is hopefully) the text of a keyword-option. The macro defines |\@temperror| to be an invalid option error and loops through all possible options. If the argument matches one of the correct possibilities, \textsf{mathfont} changes |\@temperror| to |\relax|. The macro ends by calling |\@temperror| and issuing an error if and only if the argument is invalid. If |\M@check@opt| finds a valid keyword-option, it changes |\if@optionpresent| to true. % \begin{macrocode} \def\M@check@opt#1{% \@optionpresentfalse % set switch to false by default \ifx#1\@empty \M@MissingOptionError \else \let\@temperror\M@InvalidOptionError % error by default \@for\@j:=\M@keys\do{% \ifx\@j#1% \let\@temperror\@gobble % eliminate error \@optionpresenttrue % set switch to true \fi}% \@temperror{#1}% \fi} % \end{macrocode} % Now we have to parse the optional argument of |\mathfont|. The macro |\M@parse@option| carries out the following tasks: % \begin{enumerate} % \item Store the keyword in |\@temp@opt| and the suboption (if present) in |\@temp@sub|. Set the boolean corresponding to the presence of a suboption. % \item Check that |\@temp@opt| is actually a keyword and set the corresponding boolean. % \item Convert |\@temp@sub| into \textsc{nfss} series and shape keywords. % \end{enumerate} % We want to allow the user to specify options using an \textsf{xkeyval}-type syntax. However, we do not need the full package; a slim few lines of code will suffice. When |\mathfont| reads one segment of \textit{text} from its optional argument, it calls |\M@parse@option|\meta{text}|=\@nil|. The |\M@parse@option| macro splits the option and suboption by looking for the first |=|. % \begin{macrocode} \def\M@strip@equals#1={#1} \def\M@parse@option#1=#2\@nil{% \def\@temp@opt{#1}% % store option \def\@temp@sub{#2}% % store suboption % \end{macrocode} % After storing the option and suboption, check for errors. If the user specified a suboption, |\@temp@sub| contains \meta{suboption}|=|, and we use |\M@strip@equals| to get rid of the extra |=|. If the user does not specify a suboption, |\@temp@sub| will be empty. After |\M@parse@sub|, the \textsc{nfss} series and shape codes for the suboption (if provided) will be stored in |\@tempseries| and |\@tempshape|. % \begin{macrocode} \M@check@opt\@temp@opt % \end{macrocode} % At this point, we have three possibilities for |\@temp@sub|: % \begin{enumerate} % \item |\@temp@sub| is |=|, which means the user wrote something like |,|\meta{keyword}|=,| and indicates a missing suboption. % \item |\@temp@sub| is empty, which indicates the user didn't provide a suboption, and we should use the default setting. % \item Otherwise, we try to extract series and shape information from |\@temp@sub|. % \end{enumerate} % We process |\@temp@sub| in that order. In case 3, we expect |\@temp@sub| to look like \meta{shape identifier}|=|, so we have to strip the final |=| before processing. % \begin{macrocode} \begingroup \def\@tempa{=}% \expandafter \endgroup \@suboptionpresentfalse % set switch to false by default \ifx\@temp@sub\@tempa % if missing suboption \M@MissingSuboptionError \else \ifx\@temp@sub\@empty % if no suboption provided \else % if suboption provided, parse it \@suboptionpresenttrue % set switch to true \edef\@temp@sub{\expandafter\M@strip@equals\@temp@sub}% \M@parse@sub\@temp@sub \fi \fi} % \end{macrocode} % Now a macro to convert a shape identifier into \textsc{nfss} series and shape codes. Here the |#1| argument is a control sequence such as |\@temp@sub|. The first thing we do is check whether |#1| ends in an asterisk and set |\M@base@| accordingly. This boolean is true if we use base mode (if no asterisk) and false otherwise (if asterisk). Note that |\M@parse@sub| should always be called when |\@suboptionpresent| is set to true. If we encounter a bad shape identifier in |#1|, we change |\@suboptionpresent| to false. (So it may be more accurate to name the conditional something like |\@suboptioncheck|, but I'm keeping the name as is to match |\@optionpresent|.) % \begin{macrocode} \def\M@parse@sub#1{% \expanded{\noexpand\in@*{#1}}% % \end{macrocode} % If |#1| contains an asterisk, we check that it is the final character in |#1| and strip it. % \begin{macrocode} \ifin@ \begingroup \expandafter\M@split@star#1\@nil \ifx\@tempb\@empty \expanded{\endgroup % first branch \endgroup \def\noexpand#1{\@tempa}}% \M@mode@true % \end{macrocode} % If the asterisk is not the final character, that probably means something went wrong. (But we'll catch the problem later.) % \begin{macrocode} \else \endgroup % second branch \endgroup \M@mode@false \fi \else \M@mode@false \fi % \end{macrocode} % If the shape identifier contains a |/|, we interpret it as \textsc{nfss} identifiers and do not check further, and otherwise, we check that the argument is one of |upright|, |italic|, |bold|, or |bolditalic|. We also accept |roman| for backwards compatibility. We store \textsc{nfss} information in |\@tempseries| and |\@tempshape|. % \begin{macrocode} \expanded{\noexpand\in@/{#1}}% \ifin@ \expandafter\M@split@slash#1\@nil \else % \end{macrocode} % If the user wrote out a shape identifier, we have a bit more checking to do: we have to check whether |#1| is one of |roman|, |upright|, |italic|, |bold|, or |bolditalic|. We let |\@tempa| be equal to different strings inside a group, and for each possibility, if |#1| is that string, we set |\@tempseries| and |\@tempshape| to the correct definitions. We have multiple |\endgroup|s for the same |\begingroup| because they occur on different branches of the compound conditional. % \begin{macrocode} \begingroup \def\@tempa{roman}% \ifx#1\@tempa \endgroup % first branch \endgroup % \end{macrocode} % If |\@temp@sub| is |roman|, we change it to |upright|. % \begin{macrocode} \def#1{upright}% \let\@tempseries\mddefault \let\@tempshape\shapedefault \else \def\@tempa{upright}% \ifx#1\@tempa \endgroup % second branch \endgroup \let\@tempseries\mddefault \let\@tempshape\shapedefault \else \def\@tempa{italic}% \ifx#1\@tempa \endgroup % third branch \endgroup \let\@tempseries\mddefault \let\@tempshape\itdefault \else \def\@tempa{bold}% \ifx#1\@tempa \endgroup % fourth branch \endgroup \let\@tempseries\bfdefault \let\@tempshape\shapedefault \else \def\@tempa{bolditalic}% \ifx#1\@tempa \endgroup % fifth branch \endgroup \let\@tempseries\bfdefault \let\@tempshape\itdefault \else % \end{macrocode} % Otherwise, the user specified a bad suboption. % \begin{macrocode} \endgroup % sixth branch \endgroup \@suboptionpresentfalse \M@InvalidSuboptionError{#1}% \fi \fi \fi \fi \fi % no \fi at this level of indentation \fi} % \end{macrocode} % Helper macro to parse the shape identifier if it contains a |/| character. % \begin{macrocode} \def\M@split@slash#1/#2\@nil{% \def\@tempseries{#1}% \def\@tempshape{#2}} % \end{macrocode} % Helper macros for processing asterisks in the shape identifier. The first macro here should be called inside a group since it uses |\@tempa| and |\@tempb| and therefore will mess with temporary assignments otherwise. % \begin{macrocode} \def\M@split@star#1*#2\@nil{% \def\@tempa{#1}% \def\@tempb{#2}} \def\M@strip@star#1*{#1} % \end{macrocode} % We code a general-purpose definition macro that defines its first argument to be the second argument fully expanded and with spaces removed. % \begin{macrocode} \long\def\edef@nospace#1#2{% \edef#1{\expandafter\zap@space\expanded{#2} \@empty}} % \end{macrocode} % Perhaps something that sets spaces to |\catcode9| and then retokenizes |#2| would be better, but I don't think it matters very much. % % % \section{Default Font Changes} % % This section documents default font changes. We have three main user-level commands in this section: |\mathfont|, which makes changes for math mode; |\mainfont|, which makes changes for horizontal mode; and |\documentfont|, which calls both |\mathfont| and |\mainfont|. The |\mainfont| command is straightforward: set |\rmdefault| to be the font family corresponding to the user's argument and, when necessary, call |\selectfont| to change the font family in use. (So unlike |\mathfont|, |\mainfont| can result in font loading rather than just font declaration.) % % The |\mathfont| command serves as the primary font-changing command for this package and is more complicated than |\mainfont|. This command is a wrapper around |\@mathfont|, the internal command that does the actual font changing, and when a user calls |\mathfont|, the |\@mathfont| macro carries out the following tasks: % \begin{enumerate} % \item Call |\M@newfont| on the mandatory argument of |\mathfont|, and store |\M@count| values. % \item Loop through the optional argument of |\mathfont| and determine \textsc{nfss} series and shape codes from any suboptions using macros from the previous section. % \item On each iteration, check whether \textsf{mathfont} added a symbol font to the \textsc{nfss} that uses the series and shape corresponding to the current suboption (or the default series and shape if there is no suboption). If not, call |\DeclareSymbolFont| to add the symbol font or raise a ``Can't declare new font shapes after |\begin{document}|'' error. % \item Call |\M@|\meta{keyword}|@set| to actually change the font. % \end{enumerate} % Each |\M@|\meta{keyword}|@set| macro is a wrapper around |\Umathcode| declarations and is defined in the last section of this document. % % For a given \meta{keyword}, |\M@fontinfo@|\meta{keyword} stores the human-readable name of the new default font for \meta{keyword} as well as the \textsc{nfss} series and shape identifiers. (This is the name in |\@tempbase|, not |\M@f@ntn@me|.) We use this information for writing messages to the user. Additionally, |\M@|\meta{keyword}|shape| holds the series and shape pair for \meta{keyword}. If the user specified a suboption, the contents of this macro come from the suboption via |\M@parse@sub|, and if the user did not specify a suboption, the information comes from |\|\meta{keyword}|default|. % % For a combination of \meta{font family}, \meta{series}, and \meta{shape} identifiers, \textsf{mathfont} calls the associated symbol font |M|\meta{count}|-|\meta{series}|/|\meta{shape}, where \meta{count} is the |\M@count| value associated to the \meta{font family}, i.e.\ the contents of |\M@fontid@|\meta{font family}. The \meta{series} and \meta{shape} values should be entries in the \textsc{nfss}. For example, calls to |\mathfont| will often result symbol font names like |M0-m/n|. Including a count value in the symbol font name serves two purposes. First, it enables consistent formatting of symbol font names regardless of underlying \textsc{nfss} family names. In particular, using the built-in fontloader vs.\ \textsf{fontspec} will result in different family names for the same font face with the same OpenType features, but the symbol font names will still match. Second, it simplifies the symbol font names and makes them human readable regardless of the underlying \textsc{nfss} family names, which may be complicated. % % The last two user-level commands in this section are |\mathconstantsfont| and |\mathfontshapes|. The first of these two commands only works in Lua\TeX\ and makes \TeX\ use the math parameters from a given font when formatting equations. Traditional \TeX\ expects to see extra parameters in the font(s) in |\|\meta{math style}|font2| and |\|\meta{math style}|font3|, and it uses those parameters to format equations. Lua\TeX\ can pull these extra parameters from the fonts in any math family, and |\mathconstantsfont| tells Lua\TeX\ to do so for a given font family. The command |\mathfontshapes| declares extra font shapes for the \textsc{nfss} as well as extra symbol fonts. The purpose of this command is to allow the user to declare symbol fonts in the document preamble for use after |\begin{document}|. % % We begin by coding |\mainfont|. This command is a wrapper around |\@mainfont|. % \begin{macrocode} \protected\def\mainfont{\@testopt{\@mainfont}{rm}} % \end{macrocode} % Now the internal |\@mainfont| command. This command doesn't do anything in math mode, so we include |\@nomath|. We check whether |#1| is one of |rm|, |sf|, |tt|, or empty. If not, we issue an error and change |\@tempa| to |rm|. We use |\@tempswa| to check whether we are storing the font family name in |\|\meta{type}|default| macros. % \begin{macrocode} \def\@mainfont[#1]#2{% \@nomath\mainfont \M@newfont{#2}% \edef@nospace\@tempa{#1}% \@tempswatrue \def\@tempb{rm}% \ifx\@tempa\@tempb \else \def\@tempb{sf}% \ifx\@tempa\@tempb \else \def\@tempb{tt}% \ifx\@tempa\@tempb \else \ifx\@tempa\@empty \@tempswafalse \else \M@FamilyTypeError\@tempa \def\@tempa{rm}% \fi \fi \fi \fi % \end{macrocode} % Now close the group and save the font family in |\|\meta{\upshape\ttfamily\string#1}|default| and change the default family to |#1|. % \begin{macrocode} \if@tempswa \expandafter\let\csname\@tempa default\endcsname\M@f@ntn@me \edef\familydefault{\expandafter\noexpand \csname\@tempa default\endcsname} \fi % \end{macrocode} % If the current font is not |\nullfont| or |\M@f@ntn@me|, select |\M@f@ntn@me| as the font family. % \begin{macrocode} \expandafter\ifx\the\font\nullfont \else \ifx\f@family\M@f@ntn@me \else \fontfamily\M@f@ntn@me\selectfont \fi \fi} % \end{macrocode} % Now we come to |\mathfont|. This macro is a wrapper around |\@mathfont| that we use to check for an optional argument. The default argument is |\M@defaultkeys|. % \begin{macrocode} \protected\def\mathfont{\@testopt{\@mathfont}{\M@defaultkeys}} % \end{macrocode} % The internal font-changing command. We call |\M@newfont| on the mandatory argument of |\mathfont|, which stores the \textsc{nfss} family name(s) in |\M@f@ntn@me| and |\M@f@ntn@meb@se|. We check whether each family name corresponds to a value of |\M@newcount|, and if not, we define it. Throughout the definition of |\mathfont|, |\@tempa| stores the value of |\M@count| that corresponds to the |#1| font, and |\@tempb| stores the value of |\M@count| that corresponds to the |#1| font in base mode. % \begin{macrocode} \def\@mathfont[#1]#2{% \wlog{}% \M@newfont{#2}% % \end{macrocode} % Temporarily store values of |\M@count|. % \begin{macrocode} \edef\@tempa{\csname M@fontid@\M@f@ntn@me\endcsname}% \edef\@tempb{\csname M@fontid@\M@f@ntn@meb@se\endcsname}% % \end{macrocode} % Expand, zap spaces from, and store the optional argument in |\@tempc|, and then perform the loop. (At that point, we do not need |\@tempc| anymore.) We store the current keyword-suboption pair in |\@i| and feed it to |\M@parse@option|. % \begin{macrocode} \edef@nospace\@tempc{#1}% \@for\@i:=\@tempc\do{% \expandafter\M@parse@option\@i=\@nil \if@optionpresent % \end{macrocode} % If the user did not specify a suboption, parse the default option, and use that instead. We set |\@suboptionpresent| to true before calling |\M@parse@sub| so that we can check whether the default shape identifier is valid. If |\@suboptionpresent| is false after |\M@parse@sub|, we use |m/n| as the series/shape pair. % \begin{macrocode} \if@suboptionpresent \else \@suboptionpresenttrue \expandafter\M@parse@sub \csname\@temp@opt default\endcsname \if@suboptionpresent \else \let\@tempseries\mddefault \let\@tempshape\shapedefault \fi \fi % \end{macrocode} % Now store the series and shape in |\M@|\meta{option}|shape|. % \begin{macrocode} \expandafter\edef\csname M@\@temp@opt shape\endcsname{% \@tempseries/\@tempshape}% % \end{macrocode} % At this point we have the information we need to declare the symbol font, namely the \textsc{nfss} family (|\M@f@ntn@me| or |\M@f@ntn@meb@se|), series (|\@tempseries|), and shape (|\@tempshape|). We check if the symbol font we want to use is defined, and if not, we define it. We have two cases to consider: if |\M@base@| is true, we use the base-mode version of the font (corresponding to information in |\@tempb| and |\M@f@ntn@meb@se|), and if |\M@base@| is false, we use the default-mode version of the font (corresponding to information in |\@tempa| and |\M@f@ntn@me|). We let |\@tempc| be the count value in use for the current iteration of the loop. % \begin{macrocode} \ifM@mode@ % if default/node mode \let\@tempc\@tempa \ifcsname symM\@tempa-\@tempseries/\@tempshape\endcsname % \end{macrocode} % If the symbol font has not been declared, check that we are still in the preamble. If no, issue an error message. % \begin{macrocode} \else \ifx\@onlypreamble\@notprerr \M@FontShapesError % \end{macrocode} % Otherwise, we declare the symbol font. % \begin{macrocode} \else \M@SymbolFontInfo{\M@f@ntn@me} {\@tempseries}{\@tempshape}% \M@addto@symbolfonts {M\@tempa-\@tempseries/\@tempshape} {\@tempbase}{\@tempseries}{\@tempshape}% \DeclareSymbolFont {M\@tempa-\@tempseries/\@tempshape}{TU} {\M@f@ntn@me}{\@tempseries}{\@tempshape}% \fi \fi % \end{macrocode} % Now do the same thing for default (node) mode. % \begin{macrocode} \else % if default/node mode \let\@tempc\@tempb \ifcsname symM\@tempb-\@tempseries/\@tempshape\endcsname \else \ifx\@onlypreamble\@notprerr \M@FontShapesError % \end{macrocode} % The only difference is we use different font family and symbol font names. % \begin{macrocode} \else \M@SymbolFontInfo{\M@f@ntn@meb@se} {\@tempseries}{\@tempshape}% \M@addto@symbolfonts {M\@tempb-\@tempseries/\@tempshape} {\@tempbase(base)}{\@tempseries} {\@tempshape}% \DeclareSymbolFont {M\@tempb-\@tempseries/\@tempshape}{TU} {\M@f@ntn@meb@se}{\@tempseries}{\@tempshape}% \fi \fi \fi % \end{macrocode} % We store the new font information so we can write it to the |log| file |\AtBeginDocument| and send an informational message to the user. % \begin{macrocode} \expandafter\edef \csname M@fontinfo@\@temp@opt\endcsname{% {\@tempbase}{\@tempseries}{\@tempshape}}% \M@FontChangeInfo{\@temp@opt}{\@tempbase}% % \end{macrocode} % We have extra information to keep track of when |\@temp@opt| is |bb|, |cal|, |frak|, |bcal|, or |bfrak| because then \textsf{mathfont} effectively creates a new local font-change command. We make sure that information gets added to |\M@localfonts| (a macro that tracks the font names used for local font changes). % \begin{macrocode} \@tfor\@j:={bb}{cal}{frak}{bcal}{bfrak}\do{% \ifx\@temp@opt\@j \M@addto@localfonts{\expandafter\string \csname math\@temp@opt\endcsname} {\@tempbase}{\@tempseries}{\@tempshape}% \@break@tfor \fi}% % \end{macrocode} % And now the magic happens! % \bgroup % \advance\c@CodelineNo\@ne % \SpecialIndex{\M@upper@set} % \SpecialIndex{\M@lower@set} % \SpecialIndex{\M@diacritics@set} % \SpecialIndex{\M@greekupper@set} % \SpecialIndex{\M@greeklower@set} % \SpecialIndex{\M@agreekupper@set} % \SpecialIndex{\M@agreeklower@set} % \SpecialIndex{\M@cyrillicupper@set} % \SpecialIndex{\M@cyrilliclower@set} % \SpecialIndex{\M@hebrew@set} % \SpecialIndex{\M@digits@set} % \SpecialIndex{\M@operator@set} % \SpecialIndex{\M@delimiters@set} % \SpecialIndex{\M@radical@set} % \SpecialIndex{\M@bigops@set} % \SpecialIndex{\M@extbigops@set} % \SpecialIndex{\M@symbols@set} % \SpecialIndex{\M@extsymbols@set} % \SpecialIndex{\M@arrows@set} % \SpecialIndex{\M@bb@set} % \SpecialIndex{\M@cal@set} % \SpecialIndex{\M@frak@set} % \SpecialIndex{\M@bcal@set} % \SpecialIndex{\M@bfrak@set} % \egroup % \begin{macrocode} \csname M@\@temp@opt @set\endcsname % set default font \csname M@\@temp@opt true\endcsname % set switch to true \fi}% % \end{macrocode} % Display concluding messages for the user. % \begin{macrocode} \ifx\@tempa\@empty \wlog{The \string\mathfont\space command on line \the\inputlineno\space did not change the font for any characters!}% \else \typeout{:: mathfont :: Using font \@tempbase\space on line \the\inputlineno.}% \fi \wlog{}} % \end{macrocode} % Using |\documentfont| calls |\mainfont|, |\mathfont|, and |\mathconstantsfont|. It also calls |\mathfontcommands| if the user is still in the preamble. The optional argument gets fed directly to |\@mainfont|. % \begin{macrocode} \protected\def\documentfont{\@testopt{\@documentfont}{rm}} % \end{macrocode} % The internal command. % \begin{macrocode} \def\@documentfont[#1]#2{% \@mainfont[#1]{#2}% \mathfont{#2}% \ifdefined\directlua \mathconstantsfont{#2}% \fi \ifx\@onlypreamble\@notprerr \else \mathfontcommands{#2}% \fi} % \end{macrocode} % For backwards compatibility, we make |\setfont| expand to |\documentfont| (plus a warning message). % \begin{macrocode} \protected\def\setfont{% \PackageWarningNoLine{mathfont} {Using \string\setfont\space is deprecated; I\MessageBreak replaced it with \string\documentfont}% \documentfont} % \end{macrocode} % The macro |\mathconstantsfont| chooses a font for setting math parameters. It is intended for Lua\TeX\ when \textsf{mathfont} can adjust text fonts and add a MathConstants table. It issues a warning if called without font adjustments enabled. First, we check for an optional argument, which should be a shape identifier. % \begin{macrocode} \let\M@SetMathConstants\relax \protected\def\mathconstantsfont{% \@testopt{\@mathconstantsfont}{upright}} % \end{macrocode} % The internal command that does the processing. We begin by feeding the |#2| argument to |\M@newfont| and parsing the |#1| argument. % \begin{macrocode} \def\@mathconstantsfont[#1]#2{% \M@newfont{#2}% \edef@nospace\@tempa{#1}% \M@parse@sub\@tempa % \end{macrocode} % Store the family, series, and shape information. Because it doesn't make sense to use a font that is loaded with node mode, we force use of the base-mode version of the font regardless of the value of |\ifM@mode@|. % \begin{macrocode} \let\m@th@const@nts@f@mily\M@f@ntn@meb@se \let\m@th@const@nts@series\@tempseries \let\m@th@const@nts@sh@pe\@tempshape % \end{macrocode} % Temporarily store the value of |\M@count|. % \begin{macrocode} \edef\@tempa{\csname M@fontid@\m@th@const@nts@f@mily\endcsname}% % \end{macrocode} % Now check whether the desired symbol font has been declared. If no, we declare it or issue an error. % \begin{macrocode} \ifcsname symM\@tempa-\@tempseries/\@tempshape\endcsname \else \ifx\@onlypreamble\@notprerr \M@FontShapesError \else % \end{macrocode} % Declare the symbol font. % \begin{macrocode} \M@SymbolFontInfo{\m@th@const@nts@f@mily} {\@tempseries}{\@tempshape}% \M@addto@symbolfonts {M\@tempb-\@tempseries/\@tempshape} {\@tempbase(base)}{\@tempseries}{\@tempshape}% \DeclareSymbolFont {M\@tempa-\@tempseries/\@tempshape}{TU} {\m@th@const@nts@f@mily}{\@tempseries}{\@tempshape}% \fi \fi % \end{macrocode} % We come to the tricky problem of making sure to use the correct MathConstants table. Lua\TeX\ automatically initializes all math parameters based on the most recent |\textfont|, etc.\ assignment, so we want to tell \LaTeX\ to reassign whatever font we're using to the correct math family right after we finish assigning other math fonts. This is possible, but the implementation is super hacky. When \LaTeX\ enters math mode, it checks whether it needs to redo any math family assignments, typically because of a change in font size, and if so, it calls |\getanddefine@fonts| repeatedly to append |\textfont|, etc.\ assignments onto the macro |\math@fonts|. Usually |\math@fonts| is empty because this process always happens inside a group, so we can hook into the code by defining |\math@font| to be |\aftergroup|\meta{extra code}. In this case, the \textit{extra code} will be another call to |\getanddefine@fonts|. % % We initialize |\M@SetMathConstants| to be |\relax|, and we define it the first time the user calls |\mathconstantsfont|. When that happens, \textsf{mathfont} begins by calling |\getanddefine@fonts| inside a group and uses as arguments the upright face of the font corresponding to |#1|. That puts the |\textfont|, |\scriptfont|, and |\scriptscriptfont| assignments corresponding to |#1| inside |\math@fonts|. Then we call |\math@fonts|, and to avoid an infinite loop, we gobble the |\aftergroup||\M@SetMathConstants| macros that \textsf{mathfont} has inserted at the start of |\math@fonts|. Setting |\globaldefs| to 1 makes the |\textfont|, etc.\ assignments from |\getanddefine@fonts| global when we call |\math@fonts|. % \begin{macrocode} \ifx\M@SetMathConstants\relax \protected\def\M@SetMathConstants{% \begingroup \escapechar\m@ne \expandafter\getanddefine@fonts \csname symM% \csname M@fontid@\m@th@const@nts@f@mily\endcsname -\m@th@const@nts@series/\m@th@const@nts@sh@pe \expandafter \endcsname % expands to e.g. \symM0-m/n \csname TU/\m@th@const@nts@f@mily /\m@th@const@nts@series /\m@th@const@nts@sh@pe \endcsname % expands to \TU/// \globaldefs\@ne \expandafter\@gobbletwo\math@fonts % avoid infinite loop \endgroup}% \fi \ifM@adjust@font \else \M@LuaTeXOnlyWarning\mathconstantsfont \fi} \def\math@fonts{\aftergroup\M@SetMathConstants} % \end{macrocode} % Now |\mathfontshapes|. This macro adds extra font shapes to the \textsc{nfss} and defines symbol fonts. Its purpose is to allow the user to easily declare symbol fonts in the preamble without using them right away. The user-level command is a wrapper around |\@mathfontshapes|. % \begin{macrocode} \protected\def\mathfontshapes{\@testopt{\@mathfontshapes} {upright,upright*,italic,bold}} % \end{macrocode} % For the internal command, we feed the font name to |\M@newfont| and then loop through the optional argument. For each shape identifier in the optional argument, we parse it and then use it to declare a symbol font. This macro is very similar to parts of |\@mathfont|. % \begin{macrocode} \protected\def\@mathfontshapes[#1]#2{% \wlog{}% \M@newfont{#2}% % \end{macrocode} % As in |\@mathfont|, we temporarily store values of |\M@count|. % \begin{macrocode} \edef\@tempa{\csname M@fontid@\M@f@ntn@me\endcsname}% \edef\@tempb{\csname M@fontid@\M@f@ntn@meb@se\endcsname}% % \end{macrocode} % Expand, zap spaces, and loop through the optional argument. % \begin{macrocode} \edef@nospace\@tempc{#1}% \@for\@i:=\@tempc\do{% \@suboptionpresenttrue \M@parse@sub\@i % \end{macrocode} % Then check whether the symbol font exists and if not, declare it. We start with default/node mode. We print a message in the log file, add the information to |\M@symbolfonts|, and call |\DeclareSymbolFont|. % \begin{macrocode} \if@suboptionpresent \ifM@mode@ % if default/node mode \ifcsname symM\@tempa-\@tempseries/\@tempshape\endcsname \else \M@SymbolFontInfo{\M@f@ntn@me} {\@tempseries}{\@tempshape}% \M@addto@symbolfonts {M\@tempa-\@tempseries/\@tempshape} {\@tempbase}{\@tempseries}{\@tempshape}% \DeclareSymbolFont {M\@tempa-\@tempseries/\@tempshape}{TU} {\M@f@ntn@me}{\@tempseries}{\@tempshape}% \fi % \end{macrocode} % And do the same thing for base mode. % \begin{macrocode} \else % if base mode \ifcsname symM\@tempb-\@tempseries/\@tempshape\endcsname \else \M@SymbolFontInfo{\M@f@ntn@meb@se} {\@tempseries}{\@tempshape}% \M@addto@symbolfonts {M\@tempb-\@tempseries/\@tempshape} {\@tempbase(base)}{\@tempseries}{\@tempshape}% \DeclareSymbolFont {M\@tempb-\@tempseries/\@tempshape}{TU} {\M@f@ntn@meb@se}{\@tempseries}{\@tempshape}% \fi \fi \fi}} \@onlypreamble\mathfontshapes \@onlypreamble\@mathfontshapes % \end{macrocode} % % % % \section{Local Font Changes} % % This section deals with local font changes. The main user-level macro in this section is |\newmathfontcommand|, which creates macros that change the font for math alphabet characters and is basically a wrapper around |\DeclareMathAlphabet|. Other user-level commands are a special case of this one. % % We begin with two helper macros. First is |\M@check@csarg|, which accepts two arguments and handles some error checking. The |#1| argument is a user-level command that we use in error messaging, and |#2| should be a single control sequence. The way |\M@check@csarg| scans the following tokens is a bit tricky: (1) check the length of the argument (number of tokens) by seeing if |\@gobble| eats it completely; and (2) check that the argument is a control sequence. If the user specifies an argument of the form |{..}|, i.e.\ extra text inside braces, the |\ifcat| will catch it and issue an error. If |\M@check@csarg| likes the input, it sets |\ifM@arg@good| to true, and otherwise, it sets |\ifM@arg@good| to false. % \begin{macrocode} \def\M@check@csarg#1#2{% \expandafter\ifx\expandafter\@nnil\@gobble#2\@nnil % good \ifcat\relax\noexpand#2 % good \M@arg@goodtrue \else % if #2 not a control sequence \M@MissingCSError#1{\detokenize{#2}} \M@arg@goodfalse \fi \else % if #2 is multiple tokens \M@MissingCSError#1{\detokenize{#2}} \M@arg@goodfalse \fi} % \end{macrocode} % The macro |\M@checkspecials| accepts a control sequence as its |#1| argument and a font name as its |#2| argument, and it checks whether |#1| is |\mathbb| or a related command. If yes, we assume that the user is using some variant of |\newmathrm| instead of, for example, |\mathfont[bb]|, so we do some processing analogous to what happens inside |\@mathfont|. % \begin{macrocode} \def\M@checkspecials#1#2{% \in@#1{\mathbb\mathcal\mathfrak\mathbcal\mathbfrak} \ifin@ % \end{macrocode} % We set |\escapechar| to $-1$ and use |\@gobblefour| to remove the |\math| from the start of |#1|. The string of |\expandafter|s hits the |\string| inside |\@tempa|, and then the |\edef| expands the |\@gobblefour|. We are left with just the keyword inside |\@tempa|. % \begin{macrocode} \begingroup \escapechar\m@ne \expandafter \endgroup \expandafter\edef\expandafter\@tempa\expandafter{% \expandafter\@gobblefour\string#1}% % \end{macrocode} % Then write a message to the |log| file and set the corresponding boolean to true. % \begin{macrocode} \@mathfontinfo{Interpreting your new macro \string#1\space as \@tempa\space chars.}% \@mathfontinfo{Setting \expandafter\string \csname ifM@\@tempa\endcsname\space to true.}% \csname M@\@tempa true\endcsname % \end{macrocode} % And store the information to write to the |log| file |\AtBeginDocument|. % \begin{macrocode} \expandafter\edef\csname M@fontinfo@\@tempa\endcsname{% {\@tempbase}{\@tempseries}{\@tempshape}}% \expandafter\edef\csname M@\@tempa shape\endcsname {\@tempseries/\@tempshape}% \fi} % \end{macrocode} % Now declare the math alphabet. This macro first checks that its |#1| argument is a control sequence using |\M@check@csarg|. If yes, load the |#2| argument with |\M@newfont|, call |\DeclareMathAlphabet|, and check whether |#1| is |\mathbb| or a related command. Finally, add |#1| and |#2| to the list of local font-change commands. % \begin{macrocode} \protected\def\newmathfontcommand#1#2#3#4{% \M@check@csarg\newmathfontcommand{#1}% \ifM@arg@good \M@newfont{#2} \M@NewFontCommandInfo{#1}{\M@f@ntn@meb@se}{#3}{#4} \DeclareMathAlphabet{#1}{TU}{\M@f@ntn@meb@se}{#3}{#4} \M@checkspecials{#1}{\@tempbase} \M@addto@localfonts{\string#1}{\@tempbase}{#3}{#4} \fi} \@onlypreamble\newmathfontcommand % \end{macrocode} % Then define macros that create local font-changing commands with default series and shape information. Because they're all similar, we metacode them. We define the commands themselves with |\define@newmath@cmd|. The argument structure is: % \begin{itemize} % \item |#1|---|\newmath|\meta{key} macro name % \item |#2|---font series % \item |#3|---font shape % \item |##1|---the user's control sequence % \item |##2|---the user's font information (family name) % \end{itemize} % We feed |##1|, |##2|, |#2|, and |#3| to |\newmathfontcommand|, and we load |##2| with |\M@newfont|. Each |\newmath|\meta{key} macro will check its first argument using |\M@check@csarg| and then call |\newmathfontcommand| on both of its two arguments. We store the list of |\newmath|\meta{key} commands that we want to define with their series and shape information in |\M@default@newmath@cmds|, and we loop through it with |\@for|. % \begin{macrocode} \def\M@define@newmath@cmd#1#2#3{% \protected\def#1##1##2{% \M@check@csarg{#1}{##1} \newmathfontcommand{##1}{##2}{#2}{#3}}} \def\M@default@newmath@cmds{% \newmathrm{\mddefault}{\shapedefault},% \newmathit{\mddefault}{\itdefault},% \newmathbf{\bfdefault}{\shapedefault},% \newmathbfit{\bfdefault}{\itdefault},% \newmathsc{\mddefault}{\scdefault},% \newmathscit{\mddefault}{\scdefault\itdefault},% \newmathbfsc{\bfdefault}{\scdefault},% \newmathbfscit{\bfdefault}{\scdefault\itdefault}} \@for\@i:=\M@default@newmath@cmds\do{% \expandafter\M@define@newmath@cmd\@i} \@onlypreamble\newmathrm \@onlypreamble\newmathit \@onlypreamble\newmathbf \@onlypreamble\newmathbfit \@onlypreamble\newmathsc \@onlypreamble\newmathscit \@onlypreamble\newmathbfsc \@onlypreamble\newmathbfscit \@onlypreamble\M@define@newmath@cmd \let\M@default@newmath@cmds\@undefined % \end{macrocode} % The command |\mathfontcommands| sets all the default local font-change commands at once. % \begin{macrocode} \protected\def\mathfontcommands#1{% \newmathrm\mathrm{#1} \newmathit\mathit{#1} \newmathbf\mathbf{#1} \newmathbfit\mathbfit{#1} \newmathsc\mathsc{#1} \newmathscit\mathscit{#1} \newmathbfsc\mathbfsc{#1} \newmathbfscit\mathbfscit{#1}} \@onlypreamble\mathfontcommands % \end{macrocode} % % % \section{Miscellaneous} % % % We begin this section with the user-level macros that provide information for Lua-based font adjustments. We define a macro |\M@check@int| to determine if |#1| is a nonnegative integer and set the switch |\M@arg@good| accordingly. Checking happens in three stages inside a group. Immediately after the group, we will check whether |\@tempb| is |\@empty|, so to force the switch to be false, we sometimes set |\@tempb| to |\@nnil| inside the group. The first stage is a check whether |#1| is empty. % \begin{macrocode} \ifM@adjust@font \def\M@check@int#1{% \begingroup \def\@tempa{#1}% \ifx\@tempa\@empty \let\@tempb\@nnil % \end{macrocode} % If |#1| is not empty, we check whether it is a nonnegative integer. If |#1| is a nonnegative integer, the entirety of |0#1| becomes the value of |\count@|, and |\@tempb| will end up empty. Otherwise, |\@tempb| will be nonempty. The use of |\afterassignment| here is inspired by |\@defaultunits| from the kernel. % \begin{macrocode} \else \def\@tempa##1\relax\@nil{\def\@tempb{##1}}% \afterassignment\@tempa \count@=0#1\relax\@nil % \end{macrocode} % If |\@tempb| is nonempty, we handle the case where |#1| is an octal or hexadecimal integer. We use |\if| to check whether the first character of |#1| is |'| or |"|, and if yes, we replace it with |'0| or |"0| and repeat the same check with |\@tempb|. The |\relax| prevents |\if| from scanning past |#1| if |#1| expands to something empty. The |\remove@to@nnil| gobbles everything in |#1| (except the |'| or |"|, which is eaten by |\if|) when the test is successful, and it gobbles the |\@nnil| after the |\else| when the test is unsuccessful. % \begin{macrocode} \ifx\@tempb\@empty \else \expandafter\remove@to@nnil\if'#1\relax \@nnil \afterassignment\@tempa \count@'0\expandafter\@gobble \expanded{#1}\relax\@nil \else \@nnil \expandafter\remove@to@nnil\if"#1\relax \@nnil \afterassignment\@tempa \count@"0\expandafter\@gobble \expanded{#1}\relax\@nil % \end{macrocode} % If |#1| is neither octal nor hexadecimal, we check whether it starts with |\numexpr|. This case is good, so we set |\@tempb| to |\@empty|. % \begin{macrocode} \else \@nnil \expandafter\remove@to@nnil\ifx\numexpr#1\@nnil \let\@tempb\@empty % \end{macrocode} % The last possibility is if |#1| has the form |`|\meta{character}. To allow for the possibility of, for example, |`\%|, we check whether |#1| begins with |`| and contains two tokens. This is not foolproof, and sufficiently bad input, such as |`\relax|, will break this macro. (So don't do that.) Checking the catcode of the second token in |#1| doesn't seem worth the effort. If |#1| is a single |`| character, then |\@gobbletwo| will eat |#1| and |\@nnil|, so the |\ifx| will compare |\@nnil| and |\relax|. % \begin{macrocode} \else \@nnil \expandafter\remove@to@nnil\if`#1\relax \@nnil \expandafter\ifx\expandafter\@nnil \@gobbletwo#1\@nnil\relax \let\@tempb\@empty \else \let\@tempb\@nnil \fi \else \@nnil \let\@tempb\@nnil \fi \fi \fi \fi \fi \fi \expandafter \endgroup \ifx\@tempb\@empty \M@arg@goodtrue \else \M@arg@goodfalse \fi} % \end{macrocode} % Making the |\rulethicknessfactor|, etc.\ counts accessible to the user means that we don't need |\RuleThicknessFactor| and friends anymore, but we keep them for backwards compatibility and convenience. Each of these commands uses |\M@check@int| to check its argument, then calls the appropriate other commands. % \begin{macrocode} \protected\def\RuleThicknessFactor#1{% \M@check@int{#1}% \ifM@arg@good \rulethicknessfactor=#1\relax \else \M@BadIntegerError\RuleThicknessFactor{\detokenize{#1}}% \fi} \protected\def\SurdHorizontalFactor#1{% \M@check@int{#1}% \ifM@arg@good \hsurdfactor=#1\relax \else \M@BadIntegerError\SurdHorizontalFactor{\detokenize{#1}}% \fi} \protected\def\SurdVerticalFactor#1{% \M@check@int{#1}% \ifM@arg@good \vsurdfactor=#1\relax \else \M@BadIntegerError\SurdVerticalFactor{\detokenize{#1}}% \fi} % \end{macrocode} % For the integral italic factor, we input the information to |\charmline| % \begin{macrocode} \protected\def\IntegralItalicFactor#1{% \M@check@int{#1}% \ifM@arg@good \charmline{0x222B * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * #1}% \else \M@BadIntegerError\IntegralItalicFactor{\detokenize{#1}}% \fi} % \end{macrocode} % If automatic font adjustments are disabled, we should also disable the related user-level commands. In this case, each of the font-adjustment macros expands to raise an |\M@NoFontAdjustError| and gobble its argument. % \begin{macrocode} \else \@tfor\@i:=\RuleThicknessFactor\IntegralItalicFactor \SurdHorizontalFactor\SurdVerticalFactor\charmline \charmfile\CharmLine\CharmFile\CharmInfo\CharmType \do{% \protected\expandafter\edef\@i{% \noexpand\M@NoFontAdjustError\expandafter\noexpand\@i \noexpand\@gobble}} \protected\def\charminfo{\M@NoFontAdjustError\charminfo \begingroup \afterassignment\endgroup \count@} \protected\def\charmtype{\M@NoFontAdjustError\charmtype \begingroup \afterassignment\endgroup \count@} \fi % \end{macrocode} % These commands should appear in the preamble only. % \begin{macrocode} \@onlypreamble\charmline \@onlypreamble\charmfile \@onlypreamble\CharmLine \@onlypreamble\CharmFile \@onlypreamble\RuleThicknessFactor \@onlypreamble\IntegralItalicFactor \@onlypreamble\SurdHorizontalFactor \@onlypreamble\SurdVerticalFactor % \end{macrocode} % We use the next three macros in defining |\simeq| and |\cong|. The construction is clunky and needs the intermediate macro |\st@ck@fl@trel| because |\mathchoice| is a bit of an odd macro. It feels like it should be expandable, but it isn't. Instead, it fully typesets each of its four arguments and then takes the one corresponding to the correct style. This is due to fundamental aspects of how \TeX\ processes math-mode material. % \begin{macrocode} \protected\gdef\clap#1{\hb@xt@\z@{\hss#1\hss}} \protected\def\stack@flatrel#1#2{\expandafter \st@ck@fl@trel\expandafter#1\@firstofone#2} \protected\def\st@ck@fl@trel#1#2#3{% {\setbox0\hbox{$#1#2\m@th$}% contains \mathrel symbol \setbox1\hbox{$#1#3\m@th$}% gets raised over \box0 \if\wd0>\wd1\relax \hb@xt@\wd0{% \hfil \clap{\raise0.7\ht0\box1}% \clap{\box0}\hfil}% \else \hb@xt@\wd1{% \hfil \clap{\raise0.7\ht0\box1}% \clap{\box0}\hfil}% \fi}} % \end{macrocode} % Some fonts do not contain characters that \textsf{mathfont} can declare as math symbols. We want to make sure that if this happens, \TeX\ prints a message in the |log| file and terminal. % \begin{macrocode} \ifnum\tracinglostchars<\tw@ \tracinglostchars\tw@ \fi % \end{macrocode} % We |\typeout| a message about local font-change commands. % \begin{macrocode} \AtBeginDocument{% \ifcase\M@num@localfonts \or \def\@tempa#1#2#3\@nil{#2} \wlog{} \typeout{:: mathfont :: Using \expandafter\@tempa\M@localfonts\@nil\space for local font changes.} \else \wlog{} \typeout{:: mathfont :: Using \the\M@num@localfonts\space fonts for local font changes.} \fi} % \end{macrocode} % A helper macro for printing messages |\AtBeginDocument|. This macro adds characters from |#1| into |\@tempa| until the length of |\@tempa|, as measured by |\count@| becomes $|#2|-2$. If |\@tempa| has too many characters to fit, |\M@addtab@count@tempa| instead ends |\@tempa| with an ellipsis. Then the macro appends spaces to the end of |\@tempa| until it is |#2| characters long, again measured using |\count@|. % \begin{macrocode} \def\M@addtab@count@tempa#1#2{% \let\@tempb\@empty \@tempcntb\z@ \@tfor\@i:=#1\do{% \ifnum\count@=\numexpr#2 - 5\relax \edef\@tempb{\@tempb\@i} \advance\@tempcntb\@ne \else \edef\@tempa{\@tempa\@i} \advance\count@\@ne \fi} \ifnum\@tempcntb<4\relax \edef\@tempa{\@tempa\@tempb} \advance\count@\@tempcntb \else \edef\@tempa{\@tempa...} \advance\count@\thr@@ \fi \@whilenum\count@<#2\do{% \edef\@tempa{\@tempa\space} \advance\count@\@ne}} % \end{macrocode} % Write to the |log| file |\AtBeginDocument| all font changes carried out by \textsf{mathfont}. The command |\M@fontinfo@begin| accepts accepts a keyword as its |#1| argument and prints a message on the log file showing whether \textsf{mathfont} set a default font for that keyword and, if yes, the name, series, and shape for that font. % \begin{macrocode} \def\M@fontinfo@begin#1{% \expandafter\ifx % next lines are two cs to be compared \csname ifM@#1\expandafter\endcsname \csname iftrue\endcsname \expanded{\noexpand\M@fontinfo@begin@{#1} \csname M@fontinfo@#1\endcsname} \else \bgroup \let\@tempa\@empty \count@\z@ \M@addtab@count@tempa{#1}{35} \M@addtab@count@tempa{No\space change}{78} \wlog{\@tempa} \egroup \fi} % \end{macrocode} % Helper macro that handles printing the message. The four arguments appear sequentially on the same line in the log file: |#1| is the keyword, |#2| is the font name, |#3| is the series, and |#4| is the shape. We allocate 18, 30, 15, and 15 characters respectively, for a total of 78 characters. The default width of the log file is 80 characters, so we should fit everything on one line that way. % \begin{macrocode} \def\M@fontinfo@begin@#1#2#3#4{% \bgroup \let\@tempa\@empty \count@\z@ \M@addtab@count@tempa{#1}{18} \M@addtab@count@tempa{font:\space#2}{48} \M@addtab@count@tempa{series:\space#3}{63} \M@addtab@count@tempa{shape:\space#4}{78} % \end{macrocode} % And print the message. % \begin{macrocode} \wlog{\@tempa} \egroup} % \end{macrocode} % The macro |\M@localfonts@begin| does the same thing except for the local font-change commands. % \begin{macrocode} \let\M@localfonts@begin\M@fontinfo@begin@ % \end{macrocode} % And for symbol fonts declared. % \begin{macrocode} \let\M@symbolfonts@begin\M@fontinfo@begin@ % \end{macrocode} % The command for font families is different because we only have two pieces of information to display. % \begin{macrocode} \def\M@families@begin#1{% \bgroup \let\@tempa\@empty \count@\z@ \expanded{% \noexpand\M@addtab@count@tempa {\csname M@fontid@#1\endcsname}{5} \noexpand\M@addtab@count@tempa{#1}{78}} \wlog{\@tempa} \egroup} % \end{macrocode} % Now print the messages. We start with the font families that \textsf{mathfont} uses. We don't need to store a list of font families in |\M@families| because we can simply increment the |fontid| count until we reach a value that is large enough to not have a corresponding font. % \begin{macrocode} \AtBeginDocument{% \wlog{^^J------------------ Changes made by mathfont in the preamble ------------------} \wlog{} \wlog{**********************^^J% * Font families used *^^J% **********************} \ifx\M@families\@empty \wlog{No font families declared by mathfont.} \else \@for\@i:=\M@families\do{% \expandafter\M@families@begin\expandafter{\@i}} \fi \wlog{} % \end{macrocode} % Same thing for symbol fonts. % \begin{macrocode} \wlog{*************************^^J% * Symbol fonts declared *^^J% *************************} \ifx\M@symbolfonts\@empty \wlog{No symbol fonts declared by mathfont.} \else \@for\@i:=\M@symbolfonts\do{% \expandafter\M@symbolfonts@begin\@i} \fi \wlog{} % \end{macrocode} % Character keywords. % \begin{macrocode} \wlog{************^^J% * Keywords *^^J% ************} \@for\@i:=\M@keys\do{% \expandafter\M@fontinfo@begin\expandafter{\@i}} \wlog{} % \end{macrocode} % And information in the |log| file about local font-change commands. % \begin{macrocode} \wlog{******************************^^J% * Local font-change commands *^^J% ******************************} \ifnum\M@num@localfonts=\z@ \wlog{No local font change commands declared.} \else \@for\@j:=\M@localfonts\do{% \expandafter\M@localfonts@begin\@j} \fi \wlog{} \wlog{------------------------------- End of changes -------------------------------} \wlog{}} % \end{macrocode} % Warn the user about possible problems with a multi-word optional package argument in \XeTeX. % \begin{macrocode} \ifdefined\XeTeXrevision \ifM@font@loaded \AtEndOfPackage{% \PackageWarningNoLine{mathfont} {It looks like you specified a font\MessageBreak when you loaded mathfont. If you run\MessageBreak into problems with a font whose name\MessageBreak is multiple words, try using LuaLaTeX\MessageBreak or call \string\documentfont\space or \string\mathfont\MessageBreak manually}} \fi \fi % \end{macrocode} % If the user passed a font name to \textsf{mathfont}, we set it as the default |\AtEndOfPackage|. % \begin{macrocode} \ifM@font@loaded \AtEndOfPackage{\documentfont\M@font@load} \fi % \end{macrocode} % % % \section{Adjust Fonts: Setup} % % \suppressfloats[t] % % The next three sections implement Lua-based font adjustments and apply only if the user has enabled font adjustment. Most of the implementation happens through Lua code, but we need some \TeX\ code in case the user wants to adjust character metric information. Here is a rough outline of what happens in the next three sections: % \begin{enumerate}\itemsep\smallskipamount % \item Initialize a Lua table that contains new metrics for certain characters specific to math mode, such as letters with wider bounding boxes and large operator symbols. % \item Provide an interface for the user to change this metric information. % \item Write functions that accept a fontdata object and (a) change top-level math specs to indicate that we have a math function; (b) alter characters according to our Lua table of new metric information; and (c) populate a MathConstants table for the font. % \item Create callbacks that call these functions. Put a wrapper around them, and insert the wrapper-function into |luaotfload.patch_font|. % \end{enumerate} % Step 2 happens on the \TeX\ side of things and is documented next, and everything else happens inside |\directlua|. On the Lua side of things, we store all the functions and character metric information in the table |mathfont|. With the exception of a handful of integers used to track encoding slots, every entry in |mathfont| is either a function or a subtable indexed by an \meta{integer}. The \textit{integer} is a Unicode encoding number and indicates which Unicode character the subtable corresponds to. See tables~2 and 3 for a list of the functions in |mathfont| and the fields in character subtables. See section~10 for discussion of the callbacks for editing fontdata objects. % % % \begin{figure}[tb] % \centerline{\bfseries Table 2: Fields of Character Subtables in |mathfont|\strut} % \begin{tabularx}\textwidth{llllX<{\raggedright\arraybackslash}}\toprule % Field & Type & In |a| & In |e| & Used For\\\midrule % |type| & string & Yes & Yes & Type is |a| or |e|\\ % |data_rm| & table & Yes & Yes & Information for upright font shapes\\ % |data_it| & table & Yes & Yes & Information for italic font shapes\\ % |num_variants| & integer & No & Yes & Number of large variants\\ % |smash| & integer & No & Yes & Encoding slot for smashed character\\ % |next| & table & No & Yes & Encoding slots for large variants\\ % \bottomrule % \end{tabularx} % \end{figure} % % % \begin{figure}[t] % \centerline{\bfseries Table 3: Functions in |mathfont|\strut} % \begin{tabularx}\textwidth{lp{1.35in}X<{\raggedright\arraybackslash}}\toprule % Function & Argument(s) & Used For\\\midrule % |strint| & number & Format number as a string\\\midrule % |new_type_a| & |index|, data & Add type |a| entry to |mathfont|\\ % |new_type_e| & |index|, data & Add type |e| entry to |mathfont|\\\midrule % |add_to_charm| & string of charm info & Add charm info to |mathfont|\\ % |parse_charm| & string of charm info & Split string, validate inputs\\ % |parse_num| & numeric string & Parse numeric value\\\midrule % |empty| & none & Does nothing\\ % |glyph_info| & character subtable & Get height, width, depth, italic\\ % |make_a_commands| & |index|, offset & Return virtual font commands\\ % |make_a_table| & |index|, charm data, fontdata & Make new subtable for type |a| character\\ % |make_e_commands| & |index|, scale factors & Return virtual font commands\\ % |make_e_table| & |index|, charm data, fontdata & Make new subtable for type |e| character\\ % |smash_glyph| & |index|, fontdata & Make table for smashed char\\ % |utf_16BE| & integer & Return UTF-16BE format\\\midrule % |adjust_font| & fontdata & Call callbacks\\ % |apply_charm_info| & fontdata & Change character metrics in font\\ % |math_constants| & fontdata & Create MathConstants table\\ % |set_nomath_false| & fontdata & Set |nomath| (top-level flag in the font) to |false|\\\midrule % |get_font_name| & fontdata & Return font name\\ % |info| & string & Write message in the |log| file\\ % \bottomrule % \end{tabularx} % \end{figure} % % Changing the top-level |nomath| flag in a font object is easy. Creating a MathConstants table is complicated but largely self-contained. We take a few parameters that the user has set, define traditional \TeX\ math parameters based on the essential parameters of the font, and assign their values to the corresponding entries in a MathConstants table. However, editing character metrics during font loading is convoluted with many moving parts. For every glyph that we want modify, we store character metric information for that glyph as a subtable in |mathfont|. The entries of the subtable describe how to scale the bounding box, scale the glyph itself, or determine math accent placement. For characters of type |a| (``alphabet''), we specify information to stretch the bounding box (not the glyph) horizontally, so we equivalently add extra space around the character. For type |e| (``extensible''), we stretch the bounding box and glyph, so we create an ensemble of scaled versions, which we use as a family of large variants. % % Here's how to think about the dynamics of our approach. We use character metric information at three different times: pre-processing, interim processing, and post-processing. In pre-processing, which we implement in this section, we assemble initial character metric information into entries in |mathfont|. In other words, pre-processing means creating the initial |mathfont| subtables and happens during package loading. Interim processing means the user altering entries in |mathfont| and happens through |\charmline| and |\charmfile|. This can occur at any point in the pramble. In post-processing, which we implement in the next section, \textsf{mathfont} extracts information from the current state of the |mathfont| table and uses it to alter a fontdata object. Post-processing happens through the |luaotfload.patch_font| callback and occurs once at the point when \TeX\ loads the font file. As a rule, \LaTeX\ does not like to load fonts before it uses them, so post-processing typically happens |\AtBeginDocument| in the case of the main text font or whenever the user calls a |\text|\meta{font keyword} command or enters math mode. This is also why you cannot adjust fonts that \TeX\ loaded before \textsf{mathfont}. % % % We set |mathnolimitsmode| to 4 to make integral signs look nice. Or at least nicer than they would otherwise. % \begin{macrocode} \ifM@adjust@font \mathnolimitsmode=4\relax % \end{macrocode} % We need some error messages. We change the catcode of \expandafter|\textbackslash| to 12 in order to use it freely as a Lua escape character. We change |~| to catcode 0 to define the macros. % \begin{macrocode} \bgroup \catcode`\~=0 ~catcode`~\=12 ~@firstofone{% ~egroup ~let~@tempa~% ~let~%~@percentchar ~def~M@empty@ssert{"\n\n% Package mathfont error: Empty charm information.\n\n% Your argument for \\charmline is empty, or a\n% line in your \\charmfile is blank. Make sure\n% your calls to \\charmline and all lines in\n% your \\charmfile contain integers, floats,\n% and asterisks separated by commas or spaces.\n"} ~def~M@missing@ssert{"\n\n% Package mathfont error: Missing charm entries.\n\n% I'm having trouble with a character metric.\n% Your \\charmline or \\charmfile contains\n% \"".. temp_string .. ",\"\n% which looks to me like you provided an index\n% without any commas or spaces to specify the\n% numbers for charm values. Make sure that you\n% use commas or spaces to separate each entry\n% in your charm information.\n"} ~def~M@number@ssert{"\n\n% Package mathfont error: Nonnumeric charm value.\n\n% I'm having trouble with a character metric.\n% Your \\charmline or \\charmfile contains \"" .. s .. ",\"\n% which is not a number. Make sure that your\n% charm information is all integers, floats,\n% and asterisks separated by commas or spaces.\n"} ~def~M@index@ssert{"\n\n% Package mathfont error: Invalid Unicode index.\n\n% The Unicode index \"" .. temp_string .. "\" is invalid. Make sure\n% that the first entry in your \\charmline and in each\n% line of your \\charmfile is an integer between 0 and\n% 1,114,111 (0x10FFFF), possibly with an exclamation\n% point or question mark.\n"} ~def~M@bound@ssert{"\n\n% Package mathfont error: Exceeded Unicode table.\n\n% You asked me to do something with an encoding slot\n% number that exceeds the number of slots in the\n% Unicode table. You are probably seeing this error\n% because you declared too many type e characters.\n"} % \end{macrocode} % We previously defined |\%| to contain a single |%| with catcode 12, so when we put |\%| in an |\edef|, it becomes easy to get |%|'s inside the definition of our next two macros. This is important because it lets us use |string.format| to create informative error and warning messages using straightforward syntax. To insert the Unicode character in the messages, we use |utf8.char| function, which is the Lua code for producing arbitrary Unicode characters. % \begin{macrocode} ~edef~M@entries@ssert{string.format("\n\n% Package mathfont error: Charm values too short.\n\n% Your charm information for U+~%X ~%s (index ~%d)\n% needs more entries. Right now you have ~%d\n% entries (besides the index), but you need at\n% least ~%d. If you aren't sure what to do, try\n% adding asterisks to your \\charmline or line in\n% your \\charmfile. See the user guide for more\n% information.\n", index, utf8.char(index), index, number_of_entries, entries_needed)} ~edef~M@entries@warning{string.format("\n\n% Package mathfont warning: Charm values too long.\n\n% Your charm information for U+~%X ~%s (index ~%d)\n% has more entries than it needs. Right now you\n% have ~%d entries (besides the index), but you\n% only need ~%d. This isn't a problem per se\n% because I can easily ignore the extra numbers,\n% but it may indicate confusion about Unicode\n% characters and charm values. See the user\n% guide for more information.\n\n", index, utf8.char(index), index, number_of_entries, entries_needed)} % \end{macrocode} % Error message if the user tries to adjust the left side of the bounding box on a virtual character. % \begin{macrocode} ~edef~M@virtual@ssert{string.format("\n\n% Package mathfont error: Can't adjust left side\n% of the bounding box on a virtual character.\n\n% Your charm information for U+~%X ~%s (index ~%d)\n% instructs me to change the left side of the bounding\n% box around this character. However, in the font\n% ~%s,\n% that character is a virtual character, and I'm not\n% programmed to change the left side of the bounding\n% box on a virtual character. To resolve this error,\n% try including\n% \\charmline{~%d 0 * * *}\n% at the end of your document preamble.\n\n", index, utf8.char(index), index, mathfont.get_font_name(fontdata), index)}} \let\%\@tempa % \end{macrocode} % The user inputs charm information at the \TeX\ level. We define the macros |\charmline| that interfaces with |mathfont:add_to_charm| directly and |\charmfile| that reads lines from a file and individually feeds them to |\charmline|. The macros |\charminfo| and |\charmtype| print information from |mathfont| about the charm information currently in memory for certain characters. % \begin{macrocode} \newluafunction\addtocharm@ \newluafunction\charminfo@ \newluafunction\charmtype@ \directlua{% local t = lua.get_functions_table() t[\number\addtocharm@] = function() mathfont:add_to_charm(token.scan_string()) end % \end{macrocode} % We also define the Lua function |\charminfo@| for use in |\charminfo|. This function scans the following integer and prints the charm information for the Unicode character whose index is that integer. % \begin{macrocode} t[\number\charminfo@] = function() local temp = token.scan_int() temp = mathfont[temp] % \end{macrocode} % If |mathfont| contains an entry for index |temp|, gather the charm information from that entry. We will print to \TeX\ a string in the same format as the argument of |\charmline|. We loop through |data_rm|, and on each iteration, we add that entry to a temporary string and then add italic charm information if it is different. % \begin{macrocode} if temp then local temp_str = "" local temp_rm = {} local temp_it = {} % \end{macrocode} % We have to possibilities depending on the type of the input. For type |a| characters, all entries in |data_rm| and |data_it| are integers, and we can loop the list without issue. For type |e| characters, |data_rm| and |data_it| contain 15 two-entry subtables and three integers, so we have to flatten the list before we use it. % \begin{macrocode} for k,v in pairs(temp.data_rm) do if type(v) == "number" then temp_rm[k] = v * 1000 temp_it[k] = temp.data_it[k] * 1000 elseif type(v) == "table" then temp_rm[2*k-1] = v[1] * 1000 temp_rm[2*k] = v[2] * 1000 temp_it[2*k-1] = temp.data_it[k][1] * 1000 temp_it[2*k] = temp.data_it[k][2] * 1000 end end % \end{macrocode} % Now we loop through |temp_rm| and add the contents to |temp_str|. % \begin{macrocode} for k,v in pairs(temp_rm) do if temp_str \noexpand~= "" then temp_str = temp_str .. " " end temp_str = temp_str .. mathfont.strint(v) % \end{macrocode} % Now check the corresponding charm entry for italic fonts and add that if different from |v|. % \begin{macrocode} if temp_it[k] \noexpand~= v then temp_str = temp_str .. "/" .. mathfont.strint(temp_it[k]) end end % \end{macrocode} % Now print the result. % \begin{macrocode} tex.print(temp_str) else tex.print("none") end end % \end{macrocode} % Same thing for |\charmtype@|. % \begin{macrocode} t[\number\charmtype@] = function() local temp = token.scan_int() temp = mathfont[temp] if temp then tex.print(temp.type) else tex.print("none") end end} \protected\def\charmline{\luafunction\addtocharm@} % \end{macrocode} % The argument of |\charmfile| should be a valid filename, and we open it in |\M@Charm|. The macro processes each line of the file as a piece of charm information. % \begin{macrocode} \protected\def\charmfile#1{% \IfFileExists{#1}{% \begingroup \endlinechar\m@ne \immediate\openin\M@Charm{#1} % \end{macrocode} % The macro |\next| reads a line into |#1|, feeds it to |\charmline|, and calls itself if the file has more lines. \TeX\ adds an extra line to the end of files it reads (why??), so we check whether the current line is empty before feeding it to |\charmline|. (The last line of the file is empty because we set |\endlinechar| to $-1$. Otherwise, the file would have a spurious |\par| at the end.) % \begin{macrocode} \def\next{% \read\M@Charm to \@tempa \ifx\@tempa\@empty \else \charmline\@tempa \fi \ifeof\M@Charm\else % if file has more lines? \expandafter\next \fi} % \end{macrocode} % Call |\next|, close the file, and end the group. % \begin{macrocode} \next \immediate\closein\M@Charm \endgroup} % \end{macrocode} % If the file does not exist, raise an error. % \begin{macrocode} {\M@NoCharmFileError{\detokenize{#1}}}} % \end{macrocode} % Alternative names. % \begin{macrocode} \let\CharmLine\charmline \let\CharmFile\charmfile % \end{macrocode} % Now the macros |\charminfo| and |\charmtype|. The structure is a bit different because we want them to be fully expandable. The macros don't have an argument. Instead, they call the appropriate |\luafunction|, which scans the next integer and processes it. % \begin{macrocode} \def\charminfo{\luafunction\charminfo@} \def\charmtype{\luafunction\charmtype@} % \end{macrocode} % The wrapped versions are more user-friendly. For |\CharmInfo|, we first check whether |mathfont| contains an entry with index |#1|. % \begin{macrocode} \protected\def\CharmInfo#1{% \M@check@int{#1}% \ifM@arg@good \begingroup % \begingroup \edef\@tempa{\charminfo#1}% \def\@tempb{none}% \edef\@tempc{\number#1}% % \end{macrocode} % Now the actual check. If there is no entry, we print a message saying so. % \begin{macrocode} \ifx\@tempa\@tempb \expandafter\endgroup % first branch \endgroup \expanded{\showtokens{no charm info assigned to index \@tempc}}% % \end{macrocode} % If yes, we print the charm information to the terminal. % \begin{macrocode} \else \expandafter\endgroup % second branch \endgroup \expanded{\showtokens{index \@tempc\space has charm info: \@tempa}}% \fi \else \M@BadIntegerError\CharmInfo{\detokenize{#1}}% \fi} % \end{macrocode} % Now for |\CharmType|. % \begin{macrocode} \protected\def\CharmType#1{% \M@check@int{#1}% \ifM@arg@good \begingroup \edef\@tempa{\number#1}% \expandafter\endgroup \expanded{\showtokens{index \@tempa\space has type \charmtype\numexpr\@tempa\relax}}% \else \M@BadIntegerError\CharmType{\detokenize{#1}}% \fi} % \end{macrocode} % This concludes the \TeX-based portion of font adjustments. The rest of this section and the next two sections are the Lua code that adapts a text font for math mode. First, we create the |mathfont| table. We use |mathfont.encoding_slot| in |new_type_e| to keep track of the encoding slots where we will artificially add large versions of type |e| characters during loading. % \begin{macrocode} \directlua{ mathfont = {} mathfont.extra_chars = 0xFA000 mathfont.encoding_slot = 0xFA010 mathfont.fakel = mathfont.extra_chars + 4 mathfont.faker = mathfont.extra_chars + 5 mathfont.fakell = mathfont.extra_chars + 6 mathfont.fakerr = mathfont.extra_chars + 7 % \end{macrocode} % Helper function for use in |\charminfo@|. % \begin{macrocode} function mathfont.strint(i) if i == (i // 1) then return string.format("\@percentchar d", i) else return tostring(i) end end % \end{macrocode} % Each character whose metrics we want to change will have one of two types: |a| for alphabet or |e| for extensible. We begin with type |a|. The |index| is the base-10 Unicode encoding value of the character that we will later modify. The |data| arguments are tables with 4 entries that store sizing information and information regarding accent placement. We divide the information by 1000 as is standard in \TeX. % \begin{macrocode} function mathfont:new_type_a(index, data_rm, data_it) self[index] = {} self[index].type = "a" self[index].data_rm = {} self[index].data_it = {} for i = 1, 4, 1 do self[index].data_rm[i] = data_rm[i] / 1000 self[index].data_it[i] = data_it[i] / 1000 end end % \end{macrocode} % Initializing type |e| characters is more complicated. The |index| and |data| arguments are the same as in the type |a| case, and we process them similarly. The entries in |mathfont| for type |e| characters contain additional information. The |smash| value is a Unicode slot where we store a smashed version of the glyph with no height, depth, or width, which we need to scale the glyph correctly. The |num_variants| attribute is the number of slots in |next|, which we shorten to |v| for notational convenience. % \begin{macrocode} function mathfont:new_type_e(index, data_rm, data_it) self[index] = {} self[index].type = "e" self[index].smash = self.encoding_slot local v = (\string# data_rm - 3) / 2 self[index].num_variants = v % \end{macrocode} % Check that the user hasn't exhausted the Unicode table. (Unlikely, but you never know.) % \begin{macrocode} if self.encoding_slot + v + 1 > 0x10FFFF then error(\M@bound@ssert) end % \end{macrocode} % Now make lists that store encoding slots and scale factors. We have the following lists: % \begin{itemize}[nosep] % \item |next|: list of encoding slots % \item |data_rm|: scale factors for upright font shapes % \item |data_it|: scale factors for italic font shapes % \end{itemize} % Start with making blank lists in the subtable in |mathfont|. % \begin{macrocode} self[index].next = {} self[index].data_rm = {} self[index].data_it = {} % \end{macrocode} % We assemble these lists in a single loop, and they all have |v| elements. For |next|, we append consecutive integers to the list. For the scale factors, we expect |data_rm| and |data_it| to have $2|v|+3$ entries, which we consider in pairs. The $i$th pair (i.e.\ entries $2i-1$ and $2i$ of |data_rm| or |data_it|) encodes the horizontal and vertical scale factors for the $i$th large variant, and we add those scale factors as two-element sublists to the new lists on the $i$th iteration. % \begin{macrocode} for i = 1, v, 1 do self[index].next[i] = self.encoding_slot + i self[index].data_rm[i] = {data_rm[2*i-1] / 1000, data_rm[2*i] / 1000} self[index].data_it[i] = {data_it[2*i-1] / 1000, data_it[2*i] / 1000} end % \end{macrocode} % The final entries of |data_rm| and |data_it| contain information about accent placement and italic correction. We add those values to the subtable as well. % \begin{macrocode} for i = 1, 3, 1 do self[index].data_rm[2*v+i] = data_rm[2*v+i] / 1000 self[index].data_it[2*v+i] = data_it[2*v+i] / 1000 end % \end{macrocode} % Finally, update the |encoding_slot|. % \begin{macrocode} self.encoding_slot = self.encoding_slot + v + 1 end % \end{macrocode} % Interim processing. We let the user edit resizing and accent information for the characters in |mathfont|. The main editing function is |mathfont:add_to_charm|, which incorporates the user's information into the tables already in |mathfont|. It expects a single string of integers, floats, or asterisks separated by spaces or commas, and it immediately passes the argument to |parse_charm|, which processes it into tables that we incorporate into subtables of |mathfont|. We begin with a helper function to parse a (numeric) string. If this function returns a number, the number is properly scaled (divided by 1000). % \begin{macrocode} function mathfont.parse_num(s) if s == "*" then return s else local temp = tonumber(s) if temp then return temp / 1000 else error(\M@number@ssert) end end end % \end{macrocode} % Now |parse_charm|. We begin by setting up tables to store the parsed string contents. We store the Unicode index value in |index|. % \begin{macrocode} function mathfont.parse_charm(charm_input) local index = 0 local charm_string = charm_input local temp_string = "" % \end{macrocode} % Some preprocessing before we parse the string. Specifically, we % \begin{enumerate} % \item Get rid of any duplicate spaces % \item Remove any leading or trailing space, if present % \item Remove any spaces around slashes or commas % \item Replace any remaining spaces with commas % \end{enumerate} % After completion of the replacements, we should have a new string with same numeric/override information as the original |charm_input| except without any spaces and all (pairs of) entries separated by commas. Step 1: duplicate spaces. % \begin{macrocode} while string.find(charm_string, "\space\space") do charm_string = string.gsub(charm_string, "\space\space", " ") end % \end{macrocode} % Step 2: leading/trailing spaces. % \begin{macrocode} if string.sub(charm_string, 1, 1) == " " then charm_string = string.sub(charm_string, 2) end if string.sub(charm_string, -1) == " " then charm_string = string.sub(charm_string, 1, -2) end % \end{macrocode} % Step 3: space around punctuation. We don't replace \verb*.! . or \verb*.? . because the space in those cases could be separating two charm entries. % \begin{macrocode} charm_string = string.gsub(charm_string, ", ", ",") charm_string = string.gsub(charm_string, " ,", ",") charm_string = string.gsub(charm_string, "/ ", "/") charm_string = string.gsub(charm_string, " /", "/") % \end{macrocode} % Step 4: add commas. % \begin{macrocode} charm_string = string.gsub(charm_string, " ", ",") % \end{macrocode} % Check that |charm_string| is not empty. % \begin{macrocode} if charm_string == "" then error(\M@empty@ssert) end % \end{macrocode} % Check that |charm_string| contains at least one comma. If it does not, we raise an error. % \begin{macrocode} if not string.find(charm_string, ",") then temp_string = charm_input error(\M@missing@ssert) end % \end{macrocode} % We're ready to parse the entries. We remove the first entry manually since it is the index and has different formatting possibilities from the other entries. % \begin{macrocode} local sep = string.find(charm_string, ",") temp_string = string.sub(charm_string, 1, sep-1) % \end{macrocode} % Now check that the index is a (valid) number. Handle the case of possible asterisk at the end of |temp_string|. % \begin{macrocode} local exc if string.sub(temp_string, -1, -1) == "!" then index = tonumber(string.sub(temp_string, 1, -2)) exc = 1 elseif string.sub(temp_string, -1, -1) == "?" then index = tonumber(string.sub(temp_string, 1, -2)) exc = 2 else index = tonumber(temp_string) exc = 0 end if index then assert(index == index // 1 and index >= 0 and index <= 1114111, \M@index@ssert) else error(\M@index@ssert) end charm_string = string.sub(charm_string, sep+1) % \end{macrocode} % Create the lists that we will use to store the information from |charm_string|. % \begin{macrocode} local split_string_rm = {} local split_string_it = {} % \end{macrocode} % We loop through |charm_string| as long as it contains characters. At each iteration, we store the location of the first comma in |sep|. We remove the portion of |charm_string| preceding the first comma and store it in |temp_string|, and we save the remaining portion of |charm_string| for processing on the next iteration of the loop. We use |i| as a dummy variable to track loop iterations. % \begin{macrocode} local i = 1 while charm_string do sep = string.find(charm_string, ",") if sep then temp_string = string.sub(charm_string, 1, sep-1) charm_string = string.sub(charm_string, sep+1) % \end{macrocode} % If the current value of |charm_string| does not contain a comma, then it must be the last portion, and we set |charm_string| to |nil|. % \begin{macrocode} else temp_string = charm_string charm_string = nil end % \end{macrocode} % First check whether |temp_string| contains a |/| character. If yes, we have two values to process, and if not, we have one. % \begin{macrocode} sep = string.find(temp_string, "/") if sep then % \end{macrocode} % The information for upright font shapes comes from the first portion of |temp_string|. % \begin{macrocode} split_string_rm[i] = mathfont.parse_num( string.sub(temp_string, 1, sep-1)) % \end{macrocode} % Information for italic shapes comes from the latter portion of |temp_string|. % \begin{macrocode} split_string_it[i] = mathfont.parse_num( string.sub(temp_string, sep+1)) % \end{macrocode} % For the case without a |/|, the same information goes in both sets of lists. % \begin{macrocode} else local temp = mathfont.parse_num(temp_string) split_string_rm[i] = temp split_string_it[i] = temp end % \end{macrocode} % Increment |i|, end the loop, and return the charm information. % \begin{macrocode} i = i + 1 end return {index, exc, split_string_rm, split_string_it} end % \end{macrocode} % We feed the user's charm information directly to |mathfont:add_to_charm|, which processes the information and stores it in |mathfont|. It first calls |parse_charm| to parse the input and then modifies |mathfont| accordingly. After being parsed, the user's input lives in |charm_rm| and |charm_it|. The |index| is the Unicode value of the character whose information we want to modify, and the |number_of_entries| is the length of |charm_metrics|. % \begin{macrocode} function mathfont:add_to_charm(charm_string) local temp = self.parse_charm(charm_string) local index = temp[1] local force_type = temp[2] local data_rm = temp[3] local data_it = temp[4] local number_of_entries = \string# data_rm % \end{macrocode} % If |mathfont| does not already have an entry for the Unicode character |index|, we create an entry with type |a| or |e| depending on the value of |force_type|. % \begin{macrocode} if not self[index] then mathfont.info(string.format("Setting up charm entries for U+\@percentchar X \@percentchar s (index \@percentchar d)", index, utf8.char(index), index)) if force_type == 1 then temp = {} for i = 1, 30, 1 do temp[i] = 1000 end for i = 31, 33, 1 do temp[i] = 0 end self:new_type_e(index, temp, temp) else self:new_type_a(index, {0, 0, 0, 0}, {0, 0, 0, 0}) end else % \end{macrocode} % If |mathfont| does already have an entry for the character and |force_type| is positive, check whether the type of the entry in |mathfont| matches the value of |force_type|. If not, change the type by resetting the entry in |mathfont|. First, the case where the character has type |a|, and we want to change it to type |e|. We save the top and bottom accent values to use in setting up the new charm information. % \begin{macrocode} if (self[index].type == "a") and (force_type == 1) then local temp_rm = {} local temp_it = {} for i = 1, 30, 1 do temp_rm[i] = 1000 temp_it[i] = 1000 end temp_rm[31] = self[index].data_rm[3] temp_rm[32] = self[index].data_rm[4] temp_rm[33] = 0 temp_it[31] = self[index].data_it[3] temp_it[32] = self[index].data_it[4] temp_it[33] = 0 self:new_type_e(index, temp_rm, temp_it) % \end{macrocode} % The process to convert to type |a| is simpler but fairly similar. % \begin{macrocode} elseif (self[index].type == "e") and (force_type == 2) then self:new_type_a(index, {0, 0, self[index].data_rm[31], self[index].data_rm[32]}, {0, 0, self[index].data_it[31], self[index].data_it[32]}) end end % \end{macrocode} % Handling the user's input depends on the type of entry |index|. The basic procedure is to first check the number of inputs, and if the user provided enough entries, we update each entries in the |mathfont| subtable. For every asterisk, we leave the corresponding subtable entries unaltered. For type |a|, we need four entries besides the |index|. The first two determine the left and right offset, and the last two determine accent placement. % \begin{macrocode} if self[index].type == "a" then local entries_needed = 4 % \end{macrocode} % Check number of entries. If it is too small, we issue an error, and if it is too large, we print a warning. % \begin{macrocode} if number_of_entries < entries_needed then error(\M@entries@ssert) elseif number_of_entries > entries_needed then texio.write_nl(\M@entries@warning) end % \end{macrocode} % Now update the table entries. The data outputs from |parse_charm| have been properly scaled (divided by 1000), so we don't have to worry about rescaling in this function. % \begin{macrocode} for i = 1, 4, 1 do if data_rm[i] \noexpand~= "*" then self[index].data_rm[i] = data_rm[i] end if data_it[i] \noexpand~= "*" then self[index].data_it[i] = data_it[i] end end % \end{macrocode} % Now do type |e|. The number of entries in the |data| lists must be at least $2*|tot_variants|+3$. We loop through the information and, for each $i$th pair of charm values, set those numbers to be the horizontal and vertical stretch information for the $i$th variant. % \begin{macrocode} elseif self[index].type == "e" then local tot_variants = self[index].num_variants local entries_needed = 2 * tot_variants + 3 % \end{macrocode} % Again check number of entries. % \begin{macrocode} if number_of_entries < entries_needed then error(\M@entries@ssert) elseif number_of_entries > entries_needed then texio.write_nl(\M@entries@warning) end % \end{macrocode} % Now store the charm information. Again, we scaled the |data_rm| and |data_it| values in |parse_charm|, so we don't have to divide by 1000 here. % \begin{macrocode} for i = 1, tot_variants, 1 do if data_rm[2*i-1] \noexpand~= "*" then self[index].data_rm[i][1] = data_rm[2*i-1] end if data_rm[2*i] \noexpand~= "*" then self[index].data_rm[i][2] = data_rm[2*i] end if data_it[2*i-1] \noexpand~= "*" then self[index].data_it[i][1] = data_it[2*i-1] end if data_it[2*i] \noexpand~= "*" then self[index].data_it[i][2] = data_it[2*i] end end % \end{macrocode} % The final entries for type |e| are the accent and italic correction information. % \begin{macrocode} for i = tot_variants + 1, tot_variants + 3, 1 do if data_rm[i] \noexpand~= "*" then self[index].data_rm[i] = data_rm[i] end if data_it[i] \noexpand~= "*" then self[index].data_it[i] = data_it[i] end end end end % \end{macrocode} % We end this section with three general-purpose Lua functions. The first function, |utf_16BE|, accepts a nonnegative integer and returns its representation in UTF-16 big-endian format. Let $x$ be a nonnegative integer at most 0x10FFFF. Here are the steps to convert $x$ to its big-endian representation: % \begin{enumerate} % \item If $x\leq\hbox{0xFFFF}$, keep $x$ as is. Its representation is a single four-digit hexadecimal number. % \item If $x\geq\hbox{0x10000}$, we represent $x$ as two four-digit hexadecimal numbers. First, subtract 0x10000 from $x$, and the result $y$ is a number between 0 and 0xFFFFF. % \item Equivalently, we can think of $y$ as a twenty-digit binary number. (Five hexadecimal digits store the same information as twenty binary digits.) % \item Take the 10 left-most digits of $y$ (integer divide by $2^{10}=1024$), and add them to 0xD800. The result $z_1$ is the first hexadecimal number. % \item Take the 10 right-most digits of $y$ (remainder after dividing by $2^{10}=1024$), and add them to 0xDC00. The result $z_2$ is the second hexadecimal number. % \item The big-endian representation of $x$ is the string $z_1z_2$. % \end{enumerate} % The purpose of big-endian representation is to encode Unicode characters beyond U+FFFF while still using four-digit hexadecimal numbers. % \begin{macrocode} function mathfont.utf_16BE(integer) if integer > 0x10FFFF then error(\M@bound@ssert) end local temp = string.format("\@percentchar X", integer) if \string# temp <= 4 then while \string# temp < 4 do temp = "0" .. temp end else temp = integer - 0x10000 local left_bits = 0xD800 + temp // 1024 local right_bits = 0xDC00 + temp \@percentchar 1024 temp = string.format("\@percentchar X\@percentchar X", left_bits, right_bits) end return temp end % \end{macrocode} % The |glyph_info| function does exactly what it sounds like. It accepts a character table from a font and returns the width, height, depth, and italic correction values. % \begin{macrocode} function mathfont.glyph_info(char) local glyph_width = char.width or 0 local glyph_height = char.height or 0 local glyph_depth = char.depth or 0 local glyph_italic = char.italic or 0 return glyph_width, glyph_height, glyph_depth, glyph_italic end % \end{macrocode} % The |smash_glyph| function returns a character table that will produce a smashed version of the Unicode character with value |index|. The character has no width, height, or depth, and we typeset the glyph virtually using a |char| command. % \begin{macrocode} function mathfont.smash_glyph(index) local smash_table = {} smash_table.width = 0 smash_table.height = 0 smash_table.depth = 0 smash_table.commands = {{"char", index}} return smash_table end % \end{macrocode} % An empty function that does nothing. Used later for creating callbacks. % \begin{macrocode} function mathfont.empty(arg) end % \end{macrocode} % % % % \section{Adjust Fonts: Changes} % \suppressfloats[t] % % % % This section contains the Lua functions that actually modify the font during loading. The three functions |set_nomath_false|, |math_constants|, and |apply_charm_info| do most of the heavy lifting, and we set them as the default behavior for three callbacks. In total, \textsf{mathfont} defines seven different callbacks and calls them inside the function |adjust_font|---see table~4 for a list. Each callback accepts a fontdata object as an argument and returns nothing. You can use these callbacks to change \textsf{mathfont}'s default modifications or to modify a fontdata object before or after \textsf{mathfont} looks at it. Be aware that if you add a function to any of the |disable_nomath|, |add_math_constants|, or |fix_character_metrics| callbacks, Lua\TeX\ will not call the default |mathfont| function associated with the callback anymore. In other words, do not mess with these three callbacks unless you are duplicating the functionality of the corresponding ``Default Behavior'' function from table~4. % % \begin{figure}[bt] % \centerline{\bfseries Table 4: Callbacks Created by \textsf{mathfont}\strut} % \begin{tabularx}\textwidth{lX}\toprule % Callback Name & Default Behavior\\\midrule % |"mathfont.inspect_font"| & None\\\midrule % |"mathfont.pre_adjust"| & None\\ % |"mathfont.disable_nomath"| & |mathfont.set_nomath_false|\\ % |"mathfont.add_math_constants"| & |mathfont.math_constants|\\ % |"mathfont.fix_character_metrics"|& |mathfont.apply_charm_info|\\ % |"mathfont.post_adjust"| & None\\\midrule % |"mathfont.finishing_touches"| & None\\\bottomrule % \end{tabularx} % \end{figure} % % % % We begin with the functions that create new character subtables for inclusion in a font object, and we think of these new subtables as modified versions of characters already present in a given font. The functions for assembling character tables take three arguments. The |index| argument is the Unicode index of the modified character. The |charm_data| argument is the subtable in |mathfont| of charm information that corresponds to |index|, and the |fontdata| argument is a font object. For type |a|, we change the width of the bounding box and horizontal glyph positioning, and for type |e|, we scale the glyph to create large variants and change the italic correction. For both types, we modify accent placement. We add five categories of information into our new character tables: glyph dimensions, Unicode encoding bits, (possible) virtual font commands, accent placement dimensions, and math kerning. % % The |:make_a_table| returns a character table for type |a| characters. We build up the subtable in the variable |a_table|, and we eventually return |a_table| at the end of the function. We let |char| be a shorthand for the subtable at |index| in |fontdata|, and |slant| is the font's |slant| parameter. In upright fonts, |slant| is generally 0, and in italic fonts, |slant| is generally positive. % \begin{macrocode} function mathfont:make_a_table(index, charm_data, fontdata) local a_table = {} local char = fontdata.characters[index] or {} local ex = fontdata.parameters.x_height or 0 local slant = (fontdata.parameters.slant or 0)/ 65536 % \end{macrocode} % Get the dimensions of the character. We determine the new bounding box dimensions, horizontal glyph placement, and accent placement in terms of the character's original width (plus italic correction). % \begin{macrocode} local width, height, depth, italic = self.glyph_info(char) % \end{macrocode} % Incorporate the italic correction into the character width. % \begin{macrocode} width = width + italic % \end{macrocode} % We extract charm information from |charm_data| depending on whether the font is slanted or not. % \begin{macrocode} local left_stretch local right_stretch local top_accent local bot_accent if slant == 0 then left_stretch = charm_data.data_rm[1] right_stretch = charm_data.data_rm[2] top_accent = charm_data.data_rm[3] bot_accent = charm_data.data_rm[4] else left_stretch = charm_data.data_it[1] right_stretch = charm_data.data_it[2] top_accent = charm_data.data_it[3] bot_accent = charm_data.data_it[4] end % \end{macrocode} % The new width is $1+|left_stretch|+|right_stretch|$ times the original width. The horizontal offset that appears in the commands is the |left_stretch| portion of the new width. % \begin{macrocode} local offset = width * left_stretch a_table.width = width * (1 + left_stretch + right_stretch) a_table.height = height a_table.depth = depth a_table.italic = 0 % \end{macrocode} % Unicode information attached to the character. % \begin{macrocode} a_table.unicode = index a_table.tounicode = self.utf_16BE(index) a_table.index = char.index % \end{macrocode} % If |left_stretch| is nonzero, we have to turn the character into a virtual character that typesets the glyph through a |char| command---that is the only way to add space on the left of the glyph. (A nonzero |right_stretch| is easier because we only have to extend the bounding box.) % \begin{macrocode} if offset \noexpand~= 0 then if char.commands then error(\M@virtual@ssert) else a_table.commands = {{"right", offset}, {"char", index}} end end % \end{macrocode} % We calculate accent placement in two steps. The first step is to calculate a ``base'' accent position from character and font properties, and then we modify the base position according to charm information. If the font contains a |top_accent| value for the character, we take that value as our base accent position. % \begin{macrocode} local top_base if char.top_accent then top_base = char.top_accent % \end{macrocode} % If the font does not contain a |top_accent| value, which for text fonts is the more likely possibility, we have to create the base accent position ourselves. We use an approach similar to how \TeX\ positions accents in text mode. If the character is less than 1ex tall, the base accent position is halfway across the character's bounding box, i.e.\ any horizontal offset plus half the original width and half the italic correction. If the character is taller than 1ex, we move the base accent position right by the font's |slant| value times the character's height above 1ex. The base accent position in this approach does not change when the user changes the |left_stretch| or |right_stretch| values in the charm information. % \begin{macrocode} else top_base = offset + 0.5 * width if height > ex then top_base = top_base + slant * (height - ex) end end % \end{macrocode} % We take a similar approach for the bottom accent. For the base accent position, we subtract the |slant| times 1ex. % \begin{macrocode} local bot_base if char.bot_accent then bot_base = char.bot_accent else bot_base = offset + 0.5 * width - slant * ex end % \end{macrocode} % Now add the accent information to the font. % \begin{macrocode} a_table.top_accent = top_base + top_accent * width a_table.bot_accent = bot_base + bot_accent * width % \end{macrocode} % \TeX\ shifts superscripts (but not subscripts) right by the italic correction. We added italic correction to the character's width. Effectively, that shifts any superscript right relative to the character's original bounding box, so our changes to the character result in superscripts that behave the way we expect. However, the larger bounding box also affects subscripts, which we don't want, so we implement a mathkern table that moves any subscripts left by the italic correction. A mathkern table contains up to four subtables, one for each corner of the character. Within each subtable, we store pairs of |height| and |kern| values, where |height| means to apply |kern| to exponents at that height. In this case, we have a |kern| value of minus italic correction in the lower right corner. % \begin{macrocode} a_table.mathkern = {} a_table.mathkern.top_right = {{height = 0, kern = 0}} a_table.mathkern.bottom_right = {{height = 0, kern = -italic}} a_table.mathkern.top_left = {{height = 0, kern = 0}} a_table.mathkern.bottom_left = {{height = 0, kern = 0}} return a_table end % \end{macrocode} % For type |e| characters, we add several virtual characters to the font, and we use |make_e_commands| to produce their commands tables. The commands tables from this function produces a scaled version of the glyph in slot |index|. The |pdf| command sends code directly to the pdf backend that handles the transformation. The |q| specification induces a linear transformation of the output, which in this case is a dilation by |h_stretch| and |v_stretch| factors. The |Q| command restores the original coordinate system. % \begin{macrocode} function mathfont.make_e_commands(index, h_stretch, v_stretch) local c_1 = {"pdf", "origin", string.format("q \@percentchar s 0 0 \@percentchar s 0 0 cm", h_stretch, v_stretch)} local c_2 = {"char", index} local c_3 = {"pdf", "origin", "Q"} return {c_1, c_2, c_3} end % \end{macrocode} % The function for type |e| characters returns a list of character subtables because we need to create multiple characters at once. Specifically, the function returns a new subtable for the original character plus one subtable for each larger variant. The structure is similar to |:make_type_a|, except that we scale the glyph instead of enlarging the bounding box. % \begin{macrocode} function mathfont:make_e_table(index, charm_data, fontdata) local e_table = {} local char = fontdata.characters[index] or {} local ex = fontdata.parameters.x_height or 0 local slant = (fontdata.parameters.slant or 0) / 65536 local width, height, depth, italic = self.glyph_info(char) % \end{macrocode} % Extract the charm information other than scale factors. Here |_sc| is short for scale. % \begin{macrocode} local v = charm_data.num_variants local smash = charm_data.smash local next = charm_data.next local top_accent_sc local bot_accent_sc local italic_sc if slant == 0 then top_accent_sc = charm_data.data_rm[2*v+1] bot_accent_sc = charm_data.data_rm[2*v+2] italic_sc = charm_data.data_rm[2*v+3] else top_accent_sc = charm_data.data_it[2*v+1] bot_accent_sc = charm_data.data_it[2*v+2] italic_sc = charm_data.data_it[2*v+3] end % \end{macrocode} % Calculate accent placement for the original glyph, and rescale the italic correction. We calculate accent placement similarly to type |a|, and we change the italic correction afterwards to ensure that accent placement is independent of |italic_scale|. Unlike with type |a|, we do not enlarge the bounding box on the left side of the character, so the base accent placement does not contain |offset|. % \begin{macrocode} local top_base if char.top_accent then top_base = char.top_accent else top_base = 0.5 * width if height > ex then top_base = top_base + slant * (height - ex) end end local bot_base = char.bot_accent or (0.5 * width - slant * ex) local top_accent = top_base + top_accent_sc * (width + italic) local bot_accent = bot_base + bot_accent_sc * (width + italic) italic = italic + italic_sc * (width + italic) % \end{macrocode} % Store the Unicode encoding slot for reference later % \begin{macrocode} local tounicode = self.utf_16BE(index) % \end{macrocode} % We create a number of entries in |e_table| equal to one plus the number of variants we want, which is stored in |charm_data.num_variants|. We begin with the first entry. This isn't a full character subtable because for the small version of the big operator, we won't replace the subtable already in |fontdata| but rather will add the information here into that subtable. % \begin{macrocode} e_table[1] = {} e_table[1].italic = italic e_table[1].unicode = index e_table[1].tounicode = self.utf_16BE(index) e_table[1].top_accent = top_accent e_table[1].bot_accent = bot_accent e_table[1].next = next[1] % \end{macrocode} % Now loop through the large variants, and add each one to |e_table|. We begin by extracting the scale factors for the particular large variant. % \begin{macrocode} local h_stretch local v_stretch for i = 2, v + 1, 1 do if slant == 0 then h_stretch = charm_data.data_rm[i-1][1] v_stretch = charm_data.data_rm[i-1][2] else h_stretch = charm_data.data_it[i-1][1] v_stretch = charm_data.data_it[i-1][2] end % \end{macrocode} % Now add the entries for the subtable. % \begin{macrocode} e_table[i] = {} e_table[i].width = width * h_stretch e_table[i].height = height * v_stretch e_table[i].depth = depth * v_stretch e_table[i].italic = italic * h_stretch % \end{macrocode} % Add the Unicode information. % \begin{macrocode} e_table[i].unicode = index e_table[i].tounicode = tounicode % \end{macrocode} % Accent placement. % \begin{macrocode} e_table[i].top_accent = top_accent * h_stretch e_table[i].bot_accent = bot_accent * h_stretch % \end{macrocode} % Add the commands. % \begin{macrocode} e_table[i].commands = self.make_e_commands(smash, h_stretch, v_stretch) % \end{macrocode} % If we aren't dealing with the last entry in the table, we need to add the character's |next| field. The next larger variant after the |i|th character will the the ${|i|}+1$st character, and we can extract the index from the |charm_information|. % \begin{macrocode} if i <= v then e_table[i].next = charm_data.next[i] end end return e_table end % \end{macrocode} % Before we get to the main font-changing functions, we code |make_fake_angle|, which returns a character table for the fake angle brackets. The idea is to transform a guillement such that the top 90\% of the original bounding box lines up with the full bounding box (height plus depth) of the left parenthesis (U+28). We make the fake angle brackets as follows: % \begin{enumerate} % \item Take a (single or double) guillemet, and let $h$ be its height. We assume the guillemet has no depth. % \item Let $h_p$ and $d_p$ be the height and depth respectively of the left parenthesis. % \item Our transformation of the guillement will involve a translation and a dilation. The translation should lower the basepoint of the guillemet such that if $p$ is the proportion of the guillemet that is below the baseline after translation, then $(p-0.1\sigma)h=d_p$, where $\sigma$ is the scale factor, assuming we apply the translation before the dilation. (The dilation fixes the current position within the virtual character regardless of its relation to the baseline.) This means $ph=d_p+0.1h\sigma$. % \item The scale factor for the dilation is % \[ % \sigma=\frac{h_p+d_p}{0.9h}, % \] % so 90\% of the guillemet height becomes equal to the size of the parenthesis. % \end{enumerate} % The function accepts the index of a guillemet as |index| and the index of the smashed guillemet as |smash|. The |slot| argument is the encoding slot of the angle bracket. First, extract relevant character and font dimensions. % \begin{macrocode} function mathfont:make_fake_angle(index, smash, slot, fontdata) local fab_table = {} % fab for fake angle bracket local chars = fontdata.characters local lp = chars[40] or {} % lp for left parenthesis local lp_width, lp_height, lp_depth, lp_italic = self.glyph_info(lp) local g = chars[index] or {} % g for guillemet local g_width, g_height, g_depth, g_italic = self.glyph_info(g) local ex = fontdata.parameters.x_height or 0 local slant = (fontdata.parameters.slant or 0) / 65536 % \end{macrocode} % We compute the dimensions of our fake angle bracket. % \begin{macrocode} local factor if g_height \noexpand~= 0 then factor = (lp_height + lp_depth) / (0.9 * g_height) else factor = 1 end local shift = lp_depth + 0.1 * factor * g_height % \end{macrocode} % Now populate |fab_table|. % \begin{macrocode} fab_table.height = lp_height fab_table.depth = lp_depth fab_table.width = g_width fab_table.italic = g_italic % \end{macrocode} % Unicode information. % \begin{macrocode} fab_table.unicode = slot fab_table.tounicode = self.utf_16BE(slot) % \end{macrocode} % We calculate accent placement information the same way as we have been doing for type |a| and type |e| characters. % \begin{macrocode} if g.top_accent then fab_table.top_accent = g.top_accent else if g_height > ex then fab_table.top_accent = 0.5 * g_width + slant * (g_height - ex) else fab_table.top_accent = 0.5 * g_width end end fab_table.bot_accent = g.bot_accent or (0.5 * g_width - slant * ex) % \end{macrocode} % Commands. % \begin{macrocode} fab_table.commands = { {"down", shift}, {"pdf", "origin", string.format("q 1 0 0 \@percentchar s 0 0 cm", factor)}, {"char", smash}, {"pdf", "origin", "Q"}, {"down", -shift}} return fab_table end % \end{macrocode} % Similar function that returns the character subtable for a nabla (inverted increment symbol/capital Delta). Again, |index| is the encoding slot for an increment symbol, and |smash| is the encoding slot for a smashed version of an increment. % \begin{macrocode} function mathfont:make_nabla(index, smash, slot, fontdata) local n_table = {} % n for nabla local i = fontdata.characters[index] % i for increment local i_width, i_height, i_depth, i_italic = self.glyph_info(i) % \end{macrocode} % Now populate |n_table|. % \begin{macrocode} n_table.width = i_width n_table.height = i_height n_table.depth = i_depth n_table.italic = i_italic % \end{macrocode} % Unicode information. % \begin{macrocode} n_table.unicode = slot n_table.tounicode = self.utf_16BE(slot) % \end{macrocode} % Take accent placement values from the increment symbol if they exist. % \begin{macrocode} if i.top_accent then n_table.bot_accent = i_width - i.top_accent end if i.bot_accent then n_table.top_accent = i_width - i.bot_accent end % \end{macrocode} % Commands. We reflect the increment glyph horizontally and vertically. % \begin{macrocode} n_table.commands = { {"down", -i_height}, {"right", i_width}, {"pdf", "origin", "q -1 0 0 -1 0 0 cm"}, {"char", smash}, {"pdf", "origin", "Q"}, {"right", -i_width}, {"down", i_height}} return n_table end % \end{macrocode} % We come to the functions that modify the font. We need to accomplish three tasks, and we define separate functions for each one. First, we set the font's |nomath| entry to |false|. Second, we incorporate the modifications based on charm information into the font, i.e.\ set the font's character subtables using the previous functions from this section. Third, we need to add a MathConstants table. The first task is very easy. % \begin{macrocode} function mathfont.set_nomath_false(fontdata) fontdata.nomath = false fontdata.oldmath = false end % \end{macrocode} % The second task is more involved. The basic idea is to loop through |mathfont|, and whenever we find an entry that is a subtable, we treat it as charm information that we use to modify the font object. We begin by storing the character information from the font in |chars| for easier reference later. % \begin{macrocode} function mathfont.apply_charm_info(fontdata) local chars = fontdata.characters or {} % \end{macrocode} % Before we loop through the charm data, we need to make a few changes to the font, namely add fake angle brackets, add nabla, and trim the bounding box on the surd. First, we add fake angle brackets. We use |mathfont.extra_chars| to track where we put the extra (virtual) characters in the font. % \begin{macrocode} local temp = mathfont.extra_chars chars[temp] = mathfont.smash_glyph(0x2039) % smashed \lguil chars[temp+1] = mathfont.smash_glyph(0x203A) % smashed \rguil chars[temp+2] = mathfont.smash_glyph(0xAB) % smashed \llguil chars[temp+3] = mathfont.smash_glyph(0xBB) % smashed \rrguil % \end{macrocode} % Now add the characters to the font. % \begin{macrocode} chars[mathfont.fakel] = mathfont:make_fake_angle( %\fakelangle 0x2039, temp, 0x27E8, fontdata) chars[mathfont.faker] = mathfont:make_fake_angle( %\fakerangle 0x203A, temp+1, 0x27E9, fontdata) chars[mathfont.fakell] = mathfont:make_fake_angle( %\fakellangle 0xAB, temp+2, 0x27EA, fontdata) chars[mathfont.fakerr] = mathfont:make_fake_angle( %\fakerrangle 0xBB, temp+3, 0x27EB, fontdata) % \end{macrocode} % If the function doesn't have an increment character, copy a capital Delta if it exists in the font. % \begin{macrocode} if chars[0x394] and (not chars[0x2206]) then chars[0x2206] = {} for k,v in pairs(chars[0x394]) do chars[0x2206][k] = v end chars[0x2206].commands = {{"char", 0x394}} end % \end{macrocode} % Add the nabla (inverted increment/capital Delta) character to the font if it is missing. % \begin{macrocode} if chars[0x2206] and (not chars[0x2207]) then chars[temp+8] = mathfont.smash_glyph(0x2206) chars[0x2207] = mathfont:make_nabla( 0x2206, temp+8, 0x2207, fontdata) end % \end{macrocode} % We trim the bounding box on the surd if the user requests it. Some text fonts extend the bounding box of the surd past the edge of the glyph, and we trim the edge of the box according to the values of |\vsurdfactor| and |\hsurdfactor|. % \begin{macrocode} if chars[0x221A] then local hsurd = tex.getcount("hsurdfactor") / 1000 local vsurd = tex.getcount("vsurdfactor") / 1000 chars[0x221A].width = hsurd * chars[0x221A].width chars[0x221A].height = vsurd * chars[0x221A].height end % \end{macrocode} % Perform the loop. We care about entries |info| whose index is a number because those entries are the charm information that determines how we modify the font object. We ignore charm information for any characters not present in the font. % \begin{macrocode} for index, info in pairs(mathfont) do if type(index) == "number" and chars[index] then % \end{macrocode} % One each iteration of the loop, we start by checking the |type| of the current entry because the handling of the font object varies based on the character type. For characters of type |a|, we insert our character subtable into the font object. % \begin{macrocode} if info.type == "a" then chars[index] = mathfont:make_a_table(index,info,fontdata) % \end{macrocode} % For type |e| we have to add entries to |chars[index]| and insert multiple character subtables into the font, namely one for the smashed version of the base glyph and others corresponding to the large variants. % \begin{macrocode} elseif info.type == "e" then local variants_table = mathfont:make_e_table(index, info, fontdata) % \end{macrocode} % First add entries to the subtable for the base glyph. % \begin{macrocode} for k,v in pairs(variants_table[1]) do chars[index][k] = v end % \end{macrocode} % Smashed version of the glyph. % \begin{macrocode} chars[info.smash] = mathfont.smash_glyph(index) % \end{macrocode} % Now add the large variants. % \begin{macrocode} for i = 1, info.num_variants, 1 do chars[info.next[i]] = variants_table[i+1] end end end end end % \end{macrocode} % The |populate_math_constants| function is even longer because we need to add a full MathConstants table to the font object, which has some fifty parameters that we need to set. (But the mechanics behind the function are simpler than |apply_charm_info|.) We set the font parameters in terms of traditional \TeX\ |\fontdimen| parameters. Besides the eight essential parameters found in all fonts, \TeX\ traditionally uses some fifteen extra parameters to typeset math formulas. To preserve whatever structure may already exist in the font object, we do not override any MathConstants that the font already contains. For brevity, we let |MC| be a shortcut for the MathConstants table. % \begin{macrocode} function mathfont.math_constants(fontdata) fontdata.MathConstants = fontdata.MathConstants or {} local MC = fontdata.MathConstants % \end{macrocode} % First evaluate the dimensions from the font object that we will use in determining other math parameter values. The |A_height| is the height of the capital ``A'' character, and the |y_depth| is the depth of the lower-case ``y'' character. Both will be 0 if the font does not have the correct character. % \begin{macrocode} local size = fontdata.size or 0 local ex = fontdata.parameters.x_height or 0 local em = fontdata.parameters.quad or 0 local A_height = 0 local y_depth = 0 if fontdata.characters[65] then A_height = fontdata.characters[65].height or 0 % A end if fontdata.characters[121] then y_depth = fontdata.characters[121].depth or 0 % y end % \end{macrocode} % We begin by setting the axis height and default rule thickness. We need to start with these parameters because we will use them to calculate other constants. We set both values to 0 initially and then change them. % \begin{macrocode} local axis = 0 local rule_thickness = 0 % \end{macrocode} % Set the default rule thickness. If the font already has a value set for the parameter |FractionRuleThickness|, we take that as the default rule thickness, and otherwise we set it to be 1/18 of the font size times the adjustment factor from |\rulethicknessfactor|. % \begin{macrocode} if MC.FractionRuleThickness then rule_thickness = MC.FractionRuleThickness else local temp = tex.getcount("rulethicknessfactor") / 1000 rule_thickness = (size / 18) * temp MC.FractionRuleThickness = rule_thickness end % \end{macrocode} % If the font has an |AxisHeight|, we take that value as the |axis|. If the font does not have |AxisHeight| already set, we set the axis to be the height of a minus sign, which has position U+2212 (8722 in decimal). As a fallback, we set the axis to 0.8ex if the font does not have a character in slot U+2212. % \begin{macrocode} if MC.AxisHeight then axis = MC.AxisHeight else if fontdata.characters[8722] then axis = fontdata.characters[8722].height - rule_thickness / 2 else axis = 0.8 * ex end MC.AxisHeight = axis end % \end{macrocode} % Apart from the axis height and rule thickness, we can group the traditional mathematics |\fontdimen| parameters into three categories: four for large operators, five for fractions, and six for superscripts and subscripts. (OpenType math does not use the fifth large-operator parameter $\xi_{13}$ and the seventh script parameter $\sigma_{14}$.) We define variables with the same names as their traditional references from Appendix G in the \textit{\TeX Book}. I have taken the design approach of using twice the rule height as a standard minimum clearance, and I am assuming that script styles are roughly 70\% as large as text and display styles. We begin with the parameters for large operators. % % The parameter $\xi_9$ is the minimum clearance between the top of a large operator and the limit above it, and we set it to be twice the rule thickness. Before ensuring that the bottom of the upper limit is at least $\xi_9$ away from the operator character, \TeX\ attempts to position the baseline of the limit at $\xi_{10}$ distance above the operator character, and we set $\xi_{10}$ to be slightly larger than $\xi_9$. If the upper limit has no decender, \TeX\ will raise its baseline by $\xi_{10}$, and if it has a descener, \TeX\ will position the bottom of the descender to be $\xi_9$ above the operator, which in practice means it will be higher than limits without descenders. This approach balances the desire for consistency in whitespace with the desire for consistency in baseline height. Similarly, we set the minimum clearance $\xi_{11}$ for the lower limit to be equal to the attempted clearance for the upper limit, and the attempted clearance $\xi_{12}$ for the lower limit will be the minimum clearance plus the average of the |\scriptfont| x-height and |\scriptfont| A-height. % \begin{macrocode} local xi_9 = 2 * rule_thickness % top limit min clearance local xi_10 = xi_9 + 0.35 * y_depth % bottom limit try placement local xi_11 = xi_10 % top limit min clearance local xi_12 = xi_10 + 0.35 * (A_height + ex) % bottom attempt % \end{macrocode} % Our general approach for |\displaystyle| fractions is to place the baseline of the numerator numerator at a distance above the fraction rule of 1.5 times the rule height plus descender depth plus a small extra space. The minimum clearance will be the rule height, so we expect the numerator to strictly exceed the minimum clearance in most situations. Doing so produces consistent baselines of numerators and gives our value for $\sigma_8$, the attempted height of the numerator in |\displaystyle| fractions. For smaller styles, we use a single rule height as clearance, so we add $0.5*|rule_thickness|+|y_depth|$ scaled down by 0.7 to the rule thickness. The minimum clearance for numerator and denominator are separate OpenType parameters, and we set them later. The extra 0.1 A-height in the attempted clearance relative to the minimum clearance appears because we measure attempted clearance from the axis, whereas we measure minimum clearance from the top or bottom of the fraction rule. % \begin{macrocode} local sigma_8 = axis + 1.5 * rule_thickness + y_depth + 0.1 * A_height local sigma_9 = axis + 1.35 * rule_thickness + 0.7 * y_depth + 0.07 * A_height local sigma_10 = sigma_9 % \end{macrocode} % Our approach in the denominators is the same except that we add half the descender depth to the minimum clearance. This creates extra space below the fraction rule so that the typographical color above the rule matches that below the rule when the numerator contains descenders. % \begin{macrocode} local sigma_11 = -axis + 1.5 * rule_thickness + 0.5 * y_depth + 1.1 * A_height local sigma_12 = -axis + 1.35 * rule_thickness + 0.35 * y_depth + 0.77 * A_height % \end{macrocode} % For superscripts we think in terms of the top of the superscript. We raise the baseline of the superscript by the desired height of the superscript top minus the |\scriptfont| A-height. Choosing $1.3*|A_height|$ for regular styles and $1.2*|A_height|$ for cramped styles was a design choice that worked well. The attempted drop for subscripts is one-fifth the A-height or slightly more than the y-depth, whichever is greater. This way the subscript baseline is slightly lower than any descenders, and for fonts without descenders, we still clearly lower the subscript. Setting $\sigma_{18}$ and $\sigma_{19}$ was another design choice that worked well. % \begin{macrocode} local sigma_13 = 0.6 * A_height % attempted superscript height local sigma_15 = 0.5 * A_height % attempt for cramped scripts local sigma_16 = 1.1 * y_depth % attempted subscript lower if sigma_16 < 0.2 * A_height then sigma_16 = 0.2 * A_height end local sigma_17 = sigma_16 % sigma_16 when superscript local sigma_18 = 0.5 * A_height % superscript lower for boxed local sigma_19 = 0.1 * A_height % subscript lower for boxed % \end{macrocode} % The MathConstants themselves come from the Unicode equivalents of the traditional \TeX\ |\fontdimen| parameters where appropriate. Where not appropriate, I made design choices as indicated. Setting the next three parameters was purely a design choice. % \begin{macrocode} if not MC.DisplayOperatorMinHeight then MC.DisplayOperatorMinHeight = 1.8 * A_height end if not MC.FractionDelimiterDisplayStyleSize then MC.FractionDelimiterDisplayStyleSize = 2 * size end if not MC.FractionDelimiterSize then MC.FractionDelimiterSize = 1.3 * size end if not MC.FractionDenominatorDisplayStyleShiftDown then MC.FractionDenominatorDisplayStyleShiftDown = sigma_11 end if not MC.FractionDenominatorShiftDown then MC.FractionDenominatorShiftDown = sigma_12 end % \end{macrocode} % We set the minium clearance for the numerator to be twice the rule height in |\displaystyle| and the rule height in other styles. Our approach in setting the attempted height of the numerator ($\sigma_8$ and $\sigma_9$) was to add the minimum clearance plus the descender depth plus a small extra space, so in general, we do not expect the numerator to run into the minimum clearance. For the denominator, we do the same thing except add half the descender depth to the clearance, which balances the amount of color above and below the fraction rule and is similar to what we did for the lower limits on big operators when we set $\xi_{11}$ larger than $\xi_9$. % \begin{macrocode} if not MC.FractionDenominatorDisplayStyleGapMin then MC.FractionDenominatorDisplayStyleGapMin = rule_thickness + 0.5 * y_depth end % that MathConstants entry has a long name lol if not MC.FractionDenominatorGapMin then MC.FractionDenominatorGapMin = rule_thickness + 0.35 * y_depth end if not MC.FractionNumeratorDisplayStyleShiftUp then MC.FractionNumeratorDisplayStyleShiftUp = sigma_8 end if not MC.FractionNumeratorShiftUp then MC.FractionNumeratorShiftUp = sigma_9 end if not MC.FractionNumeratorDisplayStyleGapMin then MC.FractionNumeratorDisplayStyleGapMin = rule_thickness end if not MC.FractionNumeratorGapMin then MC.FractionNumeratorGapMin = rule_thickness end % \end{macrocode} % The |SkewedFractionHorizontalGap| and |SkewedFractionVerticalGap| take the values that Lua\TeX would set for a traditional \TeX\ font. % \begin{macrocode} if not MC.SkewedFractionHorizontalGap then MC.SkewedFractionHorizontalGap = 0.5 * em end if not MC.SkewedFractionVerticalGap then MC.SkewedFractionVerticalGap = ex end % \end{macrocode} % The |UpperLimit| and |LowerLimit| dimensions correspond exactly to traditional \TeX\ math |\fontdimen| parameters. % \begin{macrocode} if not MC.UpperLimitBaselineRiseMin then MC.UpperLimitBaselineRiseMin = xi_11 end if not MC.UpperLimitGapMin then MC.UpperLimitGapMin = xi_9 end if not MC.LowerLimitBaselineDropMin then MC.LowerLimitBaselineDropMin = xi_12 end if not MC.LowerLimitGapMin then MC.LowerLimitGapMin = xi_10 end % \end{macrocode} % Traditional \TeX\ doesn't have stack objects, but they are meant to be similar to large operators, so we set the same parameters. % \begin{macrocode} if not MC.StretchStackGapBelowMin then MC.StretchStackGapBelowMin = xi_10 end if not MC.StretchStackTopShiftUp then MC.StretchStackTopShiftUp = xi_11 end if not MC.StretchStackGapAboveMin then MC.StretchStackGapAboveMin = xi_9 end if not MC.StretchStackBottomShiftDown then MC.StretchStackBottomShiftDown = xi_12 end % \end{macrocode} % For the three |Overbar| parameters, we take the approach that the bar itself should be as thick as the rule height. The gap will be twice the rule height, and the extra clearance will be a single rule height. % \begin{macrocode} if not MC.OverbarExtraAscender then MC.OverbarExtraAscender = rule_thickness end if not MC.OverbarRuleThickness then MC.OverbarRuleThickness = rule_thickness end if not MC.OverbarVerticalGap then MC.OverbarVerticalGap = 2 * rule_thickness end % \end{macrocode} % For the radical sign, we take the same approach as with the |Overbar| parameters. We insert one rule thickness of extra space above the radical symbol and two rule thickness of extra space under it. For |\textstyle| and smaller, we reduce the space to a single rule height. % \begin{macrocode} if not MC.RadicalExtraAscender then MC.RadicalExtraAscender = rule_thickness end if not MC.RadicalRuleThickness then MC.RadicalRuleThickness = rule_thickness end if not MC.RadicalDisplayStyleVerticalGap then MC.RadicalDisplayStyleVerticalGap = 2 * rule_thickness end if not MC.RadicalVerticalGap then MC.RadicalVerticalGap = rule_thickness end % \end{macrocode} % The final three |Radical| parameters aren't used if we handle degree placement at the macro level rather than at the font level. We set them to the default values that Lua\TeX\ uses for traditional tfm fonts. % \begin{macrocode} if not MC.RadicalKernBeforeDegree then MC.RadicalKernBeforeDegree = (5/18) * em end if not MC.RadicalKernAfterDegree then MC.RadicalKernAfterDegree = (10/18) * em end if not MC.RadicalDegreeBottomRaisePercent then MC.RadicalDegreeBottomRaisePercent = 60 end % \end{macrocode} % The |SpaceAfterScript| is a design choice. Somewhat arbitrary. % \begin{macrocode} if not MC.SpaceAfterScript then MC.SpaceAfterScript = 0.1 * em end % \end{macrocode} % The |Stack| parameters come from their traditional |\fontdimen| analogues. % \begin{macrocode} if not MC.StackBottomDisplayStyleShiftDown then MC.StackBottomDisplayStyleShiftDown = sigma_11 end if not MC.StackBottomShiftDown then MC.StackBottomShiftDown = sigma_12 end if not MC.StackTopDisplayStyleShiftUp then MC.StackTopDisplayStyleShiftUp = sigma_8 end if not MC.StackTopShiftUp then MC.StackTopShiftUp = sigma_10 end % \end{macrocode} % Traditionally \TeX\ uses an internal method rather than a parameter to determine the minimum distance between two boxes in an |\atop| stack. We set the minimum distance to be one rule thickness plus the combined minimum clearance for numerators and denominators in fractions. For |\displaystyle|, that gives us % \[ % |rule_thickness|+(2*|rule_thickness|)+(2*|rule_thickness|+0.5*|y_depth|) % \] % For smaller styles, we use single rule height values and scale down the |y_depth| by 0.7. % \begin{macrocode} if not MC.StackDisplayStyleGapMin then MC.StackDisplayStyleGapMin = 5 * rule_thickness + 0.5 * y_depth end if not MC.StackGapMin then MC.StackGapMin = 3 * rule_thickness + 0.35 * y_depth end % \end{macrocode} % With three exceptions, superscript and subscript parameters come from traditional \TeX\ dimensions. % \begin{macrocode} if not MC.SubscriptShiftDown then MC.SubscriptShiftDown = sigma_16 end if not MC.SubscriptBaselineDropMin then MC.SubscriptBaselineDropMin = sigma_19 end if not MC.SubscriptShiftDownWithSuperscript then MC.SubscriptShiftDownWithSuperscript = sigma_17 end % \end{macrocode} % The top of a subscript should be less than half the A-height. This is a somewhat arbitrary design choice. % \begin{macrocode} if not MC.SubscriptTopMax then MC.SubscriptTopMax = 0.5 * A_height end % \end{macrocode} % The minimum gap between superscripts and subscripts will be the height of the rule. This is less space than \TeX\ traditionally allocates. % \begin{macrocode} if not MC.SubSuperscriptGapMin then MC.SubSuperscriptGapMin = rule_thickness end % \end{macrocode} % We set the minimum height for the bottom of a subscript to be the height of a superscript in cramped styles minus the depth of a possible descender. Theoretically this is the lowest that any portion of a superscript should ever be if it contains only text. % \begin{macrocode} if not MC.SuperscriptBottomMin then MC.SuperscriptBottomMin = sigma_15 - 0.7 * y_depth end if not MC.SuperscriptBaselineDropMax then MC.SuperscriptBaselineDropMax = sigma_18 end if not MC.SuperscriptShiftUp then MC.SuperscriptShiftUp = sigma_13 end if not MC.SuperscriptShiftUpCramped then MC.SuperscriptShiftUpCramped = sigma_15 end % \end{macrocode} % If the superscript and subscript overlap, we choose the new position such that the baselines of subscripts are roughly consistent across subformulas. In this case, the bottom of the superscript box will rise at most to the point such that a subscript containing only text at 70\% of the next-larger style will align with all similar subscripts. The top of the subscript will have approximate height $-\sigma_{16}+0.7*|A_height|$ above the baseline, so to find our desired position for the bottom of the superscript, we add the minimum clearance of a single rule thickness. Putting this parameter in terms of the subscript sizing is necessary because we don't know how large the descender will be in a given subscript. % \begin{macrocode} if not MC.SuperscriptBottomMaxWithSubscript then MC.SuperscriptBottomMaxWithSubscript = -sigma_16 + 0.7 * A_height + rule_thickness end % \end{macrocode} % As with the |Overbar| parameters, we set the extra clearance to be the rule height and the gap to be twice the rule height. % \begin{macrocode} if not MC.UnderbarExtraDescender then MC.UnderbarExtraDescender = rule_thickness end if not MC.UnderbarRuleThickness then MC.UnderbarRuleThickness = rule_thickness end if not MC.UnderbarVerticalGap then MC.UnderbarVerticalGap = 2 * rule_thickness end % \end{macrocode} % No reason not to set |MinConnectorOverlap| to 0. It doesn't matter for our purposes because \textsf{mathfont} doesn't use extensibles. % \begin{macrocode} if not MC.MinConnectorOverlap then MC.MinConnectorOverlap = 0 end end % \end{macrocode} % Time for callbacks! We create seven of them. % \begin{macrocode} luatexbase.create_callback("mathfont.inspect_font", "simple", mathfont.empty) luatexbase.create_callback("mathfont.pre_adjust", "simple", mathfont.empty) luatexbase.create_callback("mathfont.disable_nomath", "simple", mathfont.set_nomath_false) luatexbase.create_callback("mathfont.add_math_constants", "simple", mathfont.math_constants) luatexbase.create_callback("mathfont.fix_character_metrics", "simple", mathfont.apply_charm_info) luatexbase.create_callback("mathfont.post_adjust", "simple", mathfont.empty) luatexbase.create_callback("mathfont.finishing_touches", "simple", mathfont.empty) % \end{macrocode} % The functions |mathfont.info| and |mathfont.get_font_name| are used for informational messaging. The first prints a message in the |log| file, and the second returns a font name. % \begin{macrocode} function mathfont.info(msg) texio.write_nl("log", "Package mathfont Info: " .. msg) end function mathfont.get_font_name(fontdata) return fontdata.psname or fontdata.fullname or fontdata.name or "" end % \end{macrocode} % The |adjust_font| function is what actually goes in |luaotfload.patch_font|. This function calls the six callbacks at appropriate times and writes informational messages in the |log| file. We adjust the font object when |nomath| is |false| and the font is loaded in |base| mode. I am assuming that the user will usually load text-only fonts in |node| or |harf| mode, and then \textsf{mathfont} does not need to (and probably should not) alter that particular font. Unfortunately, there does not appear to be a better way to notate that we will use a font for text versus math when declaring it with |\DeclareFontSize|. I would ideally set |script=math| with the rest of the OpenType font features, but \textsf{luaotfload} ignores |script| declarations that aren't built into the font. % \begin{macrocode} function mathfont.adjust_font(fontdata) luatexbase.call_callback("mathfont.inspect_font", fontdata) local the_font = mathfont.get_font_name(fontdata) if fontdata.nomath and fontdata.properties and fontdata.properties.mode and fontdata.properties.mode == "base" then luatexbase.call_callback("mathfont.pre_adjust", fontdata) luatexbase.call_callback("mathfont.disable_nomath", fontdata) luatexbase.call_callback("mathfont.add_math_constants", fontdata) luatexbase.call_callback("mathfont.fix_character_metrics", fontdata) luatexbase.call_callback("mathfont.post_adjust", fontdata) end luatexbase.call_callback("mathfont.finishing_touches", fontdata) end % \end{macrocode} % Finally, add the processing function to \textsf{luaotfload}'s |patch_font| callback. % \begin{macrocode} luatexbase.add_to_callback("luaotfload.patch_font", mathfont.adjust_font, "mathfont.adjust_font") % \end{macrocode} % % % % \section{Adjust Fonts: Metrics} % % % % This section contains the default charm information for the characters that \textsf{mathfont} adjusts upon loading a font. We start with uppercase Latin letters. The first set of numbers applies to upright fonts, and the second set applies to italic/slanted fonts. % \begin{macrocode} mathfont:new_type_a(0x41, {0,0,0,0}, {50,0,150,0}) %A mathfont:new_type_a(0x42, {0,0,0,0}, {0,0,0,0}) %B mathfont:new_type_a(0x43, {0,0,50,0}, {0,0,50,0}) %C mathfont:new_type_a(0x44, {0,0,0,0}, {50,0,0,0}) %D mathfont:new_type_a(0x45, {0,0,0,0}, {50,0,0,0}) %E mathfont:new_type_a(0x46, {0,0,0,0}, {50,0,0,0}) %F mathfont:new_type_a(0x47, {0,0,0,0}, {0,0,0,0}) %G mathfont:new_type_a(0x48, {0,0,0,0}, {50,0,0,0}) %H mathfont:new_type_a(0x49, {0,0,0,0}, {50,0,50,0}) %I mathfont:new_type_a(0x4A, {0,0,100,0}, {50,0,100,0}) %J mathfont:new_type_a(0x4B, {0,0,0,0}, {50,0,0,0}) %K mathfont:new_type_a(0x4C, {0,0,-200,0}, {50,0,-100,0}) %L mathfont:new_type_a(0x4D, {0,0,0,0}, {50,0,0,0}) %M mathfont:new_type_a(0x4E, {0,0,0,0}, {50,0,0,0}) %N mathfont:new_type_a(0x4F, {0,0,0,0}, {0,0,50,0}) %O mathfont:new_type_a(0x50, {0,0,0,0}, {50,0,0,0}) %P mathfont:new_type_a(0x51, {0,0,0,0}, {0,0,50,0}) %Q mathfont:new_type_a(0x52, {0,0,0,0}, {50,0,0,0}) %R mathfont:new_type_a(0x53, {0,0,0,0}, {0,0,0,0}) %S mathfont:new_type_a(0x54, {0,0,0,0}, {0,0,0,0}) %T mathfont:new_type_a(0x55, {0,0,0,0}, {0,0,0,0}) %U mathfont:new_type_a(0x56, {0,0,0,0}, {0,0,0,0}) %V mathfont:new_type_a(0x57, {0,0,0,0}, {0,0,0,0}) %W mathfont:new_type_a(0x58, {0,0,0,0}, {50,0,0,0}) %X mathfont:new_type_a(0x59, {0,0,0,0}, {0,0,0,0}) %Y mathfont:new_type_a(0x5A, {0,0,0,0}, {50,0,0,0}) %Z % \end{macrocode} % Lowercase Latin letters. % \begin{macrocode} mathfont:new_type_a(0x61, {0,0,0,0}, {0,0,0,0}) %a mathfont:new_type_a(0x62, {0,0,0,0}, {0,0,0,0}) %b mathfont:new_type_a(0x63, {0,0,0,0}, {0,0,100,0}) %c mathfont:new_type_a(0x64, {0,0,0,0}, {0,0,0,0}) %d mathfont:new_type_a(0x65, {0,0,0,0}, {0,0,100,0}) %e mathfont:new_type_a(0x66, {0,400,300,0}, {150,0,50,0}) %f mathfont:new_type_a(0x67, {0,0,0,0}, {0,0,0,0}) %g mathfont:new_type_a(0x68, {0,0,0,0}, {0,0,0,0}) %h mathfont:new_type_a(0x69, {0,0,0,0}, {0,0,0,0}) %i mathfont:new_type_a(0x6A, {100,0,0,0}, {200,0,0,0}) %j mathfont:new_type_a(0x6B, {0,0,0,0}, {0,0,0,0}) %k mathfont:new_type_a(0x6C, {0,0,0,0}, {0,0,0,0}) %l mathfont:new_type_a(0x6D, {0,0,0,0}, {0,0,50,0}) %m mathfont:new_type_a(0x6E, {0,0,0,0}, {0,0,50,0}) %n mathfont:new_type_a(0x6F, {0,0,0,0}, {0,0,100,0}) %o mathfont:new_type_a(0x70, {0,0,0,0}, {0,0,100,0}) %p mathfont:new_type_a(0x71, {0,0,0,0}, {0,0,0,0}) %q mathfont:new_type_a(0x72, {0,0,0,0}, {0,0,50,0}) %r mathfont:new_type_a(0x73, {0,0,0,0}, {0,0,0,0}) %s mathfont:new_type_a(0x74, {0,0,0,0}, {0,0,0,0}) %t mathfont:new_type_a(0x75, {0,0,0,0}, {0,0,0,0}) %u mathfont:new_type_a(0x76, {0,0,0,0}, {0,0,50,0}) %v mathfont:new_type_a(0x77, {0,0,0,0}, {0,0,50,0}) %w mathfont:new_type_a(0x78, {0,0,0,0}, {0,0,50,0}) %x mathfont:new_type_a(0x79, {0,0,0,0}, {0,0,50,0}) %y mathfont:new_type_a(0x7A, {0,0,0,0}, {0,0,0,0}) %z mathfont:new_type_a(0x131, {0,0,0,0}, {0,0,50,0}) %\imath mathfont:new_type_a(0x237, {0,0,0,0}, {200,0,50,0}) %\jmath % \end{macrocode} % Uppercase Greek characters. % \begin{macrocode} mathfont:new_type_a(0x391, {0,0,0,0}, {50,0,150,0}) %\Alpha mathfont:new_type_a(0x392, {0,0,0,0}, {50,0,0,0}) %\Beta mathfont:new_type_a(0x393, {0,0,0,0}, {50,0,0,0}) %\Gamma mathfont:new_type_a(0x394, {0,0,0,0}, {50,0,150,0}) %\Delta mathfont:new_type_a(0x395, {0,0,0,0}, {50,0,0,0}) %\Epsilon mathfont:new_type_a(0x396, {0,0,0,0}, {50,0,0,0}) %\Zeta mathfont:new_type_a(0x397, {0,0,0,0}, {50,0,0,0}) %\Eta mathfont:new_type_a(0x398, {0,0,0,0}, {0,0,50,0}) %\Theta mathfont:new_type_a(0x399, {0,0,0,0}, {50,0,0,0}) %\Iota mathfont:new_type_a(0x39A, {0,0,0,0}, {50,0,0,0}) %\Kappa mathfont:new_type_a(0x39B, {0,0,0,0}, {0,0,150,0}) %\Lambda mathfont:new_type_a(0x39C, {0,0,0,0}, {50,0,0,0}) %\Mu mathfont:new_type_a(0x39D, {0,0,0,0}, {50,0,0,0}) %\Nu mathfont:new_type_a(0x39E, {0,0,0,0}, {0,0,0,0}) %\Xi mathfont:new_type_a(0x39F, {0,0,0,0}, {0,0,50,0}) %\Omicron mathfont:new_type_a(0x3A0, {0,0,0,0}, {50,0,0,0}) %\Pi mathfont:new_type_a(0x3A1, {0,0,0,0}, {50,0,0,0}) %\Rho mathfont:new_type_a(0x3A3, {0,0,0,0}, {50,0,0,0}) %\Sigma mathfont:new_type_a(0x3A4, {0,0,0,0}, {0,0,0,0}) %\Tau mathfont:new_type_a(0x3A5, {0,0,0,0}, {0,0,0,0}) %\Upsilon mathfont:new_type_a(0x3A6, {0,0,0,0}, {0,0,50,0}) %\Phi mathfont:new_type_a(0x3A7, {0,0,0,0}, {50,0,0,0}) %\Chi mathfont:new_type_a(0x3A8, {0,0,0,0}, {0,0,0,0}) %\Psi mathfont:new_type_a(0x3A9, {0,0,0,0}, {0,0,50,0}) %\Omega mathfont:new_type_a(0x3F4, {0,0,0,0}, {0,0,50,0}) %\varTheta % \end{macrocode} % Lowercase Greek characters. % \begin{macrocode} mathfont:new_type_a(0x3B1, {0,0,0,0}, {0,0,0,0}) %\alpha mathfont:new_type_a(0x3B2, {0,0,0,0}, {0,0,0,0}) %\beta mathfont:new_type_a(0x3B3, {0,0,0,0}, {0,0,0,0}) %\gamma mathfont:new_type_a(0x3B4, {0,0,0,0}, {0,0,0,0}) %\delta mathfont:new_type_a(0x3B5, {0,0,50,0}, {0,0,50,0}) %\epsilon mathfont:new_type_a(0x3B6, {0,0,50,0}, {0,0,0,0}) %\zeta mathfont:new_type_a(0x3B7, {0,0,50,0}, {0,0,0,0}) %\eta mathfont:new_type_a(0x3B8, {0,0,0,0}, {0,0,100,0}) %\theta mathfont:new_type_a(0x3B9, {0,0,0,0}, {0,0,50,0}) %\iota mathfont:new_type_a(0x3BA, {0,0,0,0}, {0,0,0,0}) %\kappa mathfont:new_type_a(0x3BB, {0,0,-150,0}, {0,0,-100,0}) %\lambda mathfont:new_type_a(0x3BC, {0,0,0,0}, {0,0,100,0}) %\mu mathfont:new_type_a(0x3BD, {0,0,0,0}, {0,0,50,0}) %\nu mathfont:new_type_a(0x3BE, {0,0,0,0}, {0,0,50,0}) %\xi mathfont:new_type_a(0x3BF, {0,0,0,0}, {0,0,50,0}) %\omicron mathfont:new_type_a(0x3C0, {0,0,0,0}, {0,0,0,0}) %\pi mathfont:new_type_a(0x3C1, {0,0,0,0}, {0,0,50,0}) %\rho mathfont:new_type_a(0x3C3, {0,0,0,0}, {0,0,0,0}) %\sigma mathfont:new_type_a(0x3C4, {0,0,0,0}, {0,0,50,0}) %\tau mathfont:new_type_a(0x3C5, {0,0,0,0}, {0,0,0,0}) %\upsilon mathfont:new_type_a(0x3C6, {0,0,0,0}, {0,0,0,0}) %\phi mathfont:new_type_a(0x3C7, {0,0,0,0}, {50,0,50,0}) %\chi mathfont:new_type_a(0x3C8, {0,0,0,0}, {0,0,0,0}) %\psi mathfont:new_type_a(0x3C9, {0,0,0,0}, {0,0,50,0}) %\omega mathfont:new_type_a(0x3D0, {0,0,0,0}, {0,0,0,0}) %\varbeta mathfont:new_type_a(0x3F5, {0,0,0,0}, {0,0,50,0}) %\varepsilon mathfont:new_type_a(0x3D1, {0,0,150,0}, {0,0,100,0}) %\vartheta mathfont:new_type_a(0x3F1, {0,0,0,0}, {0,0,50,0}) %\varrho mathfont:new_type_a(0x3C2, {0,0,100,0}, {0,0,50,0}) %\varsigma mathfont:new_type_a(0x3D5, {0,0,0,0}, {0,0,100,0}) %\varphi % \end{macrocode} % We add the charm information for delimiters and other resizable characters. We divide the characters into four categories depending on how we want to magnify the base glyph to create large variants: delimiters, big operators, vertical characters, and the integral sign. We automate the process by putting charm information for each category of character into a separate table and feeding the whole thing to a wrapper around |:new_type_e|. % \begin{macrocode} local delim_glyphs = {40, % ( 41, % ) 47, % / 91, % [ 92, % backslash 93, % ] 123, % { 125, % } 8249, % \lguil 8250, % \rguil 171, % \llguil 187, % \rrguil mathfont.fakel, % \fakelangle mathfont.faker, % \fakerangle mathfont.fakell, % \fakellangle mathfont.fakerr} % \fakerrangle local big_op_glyphs = {33, % ! 35, % # 36, % $ 37, % % 38, % & 43, % + 63, % ? 64, % @ 167, % \S 215, % \times 247, % \div 8719, % \prod 8721, % \sum 8720, % \coprod 8897, % \bigvee 8896, % \bigwedge 8899, % \bigcup 8898, % \bigcap 10753, % \bigoplus 10754, % \bigotimes 10752, % \bigodot 10757, % \bigsqcap 10758} % \bigsqcup local vert_glyphs = {124, 8730} % | and \surd local int_glyphs = {8747, % \intop 8748, % \iint 8749, % \iiint 8750, % \oint 8751, % \oiint 8752} % \oiiint % \end{macrocode} % Each category of type |e| character will have its own table of charm information with different magnification values. each table is initially empty. % \begin{macrocode} local delim_scale = {} local big_op_scale = {} local vert_scale = {} local int_scale = {} % \end{macrocode} % Populate each table with magnification information. For every type |e| character we will create fifteen larger variants in the font. Delimiters stretch mostly vertically and some horzontally. Vertical characters stretch vertically only, so their horizontal scale factors are all constant. Big operators stretch the same in vertical and horizoontal directions. % \begin{macrocode} for i = 1, 15, 1 do delim_scale[2*i-1] = 1000 + 100*i % delimiters - horizontal delim_scale[2*i] = 1000 + 500*i % delimiters - vertical vert_scale[2*i-1] = 1000 vert_scale[2*i] = 1000 + 500*i % vertically scaled chars big_op_scale[2*i-1] = 1000 + 100*i % big operators - horizontal big_op_scale[2*i] = 1000 + 100*i % big operators - vertical % \end{macrocode} % The integral sign is different. Visually, we would like an integral symbol that is larger than the large operators, which means that the integral sign should have no variants between the font's value of |\Umathoperatorsize| and the desired larger size. Accordingly, I decided it would be easiest to have large variants of the integral sign jump by large enough scale factors that the smallest variant larger than the regular size is already significantly larger than the |\Umathoperatorsize| setting in |populate_math_constants|. Effectively this means that the user should take the size of the integral operator as fixed and should set |\Umathoperatorsize| to make all other big operators the desired size. % \begin{macrocode} int_scale[2*i-1] = 1000 + 500*i % integral sign - horizontal int_scale[2*i] = 1000 + 1500*i % integral sign - vertical end % \end{macrocode} % We do not modify accent placement or italic corrections. % \begin{macrocode} delim_scale[31] = 0 delim_scale[32] = 0 delim_scale[33] = 0 big_op_scale[31] = 0 big_op_scale[32] = 0 big_op_scale[33] = 0 vert_scale[31] = 0 vert_scale[32] = 0 vert_scale[33] = 0 int_scale[31] = 0 int_scale[32] = 0 int_scale[33] = 0 % \end{macrocode} % The wrapper for |:new_type_e|. We feed it a list of characters to create charm information for and a table of scaling information. % \begin{macrocode} function mathfont:add_extensible_variants(char_list, scale_list) local variants = (\string# scale_list - 3) / 2 for i = 1, \string# char_list, 1 do self:new_type_e(char_list[i], scale_list, scale_list) end end % \end{macrocode} % Add the charm information for the type |e| characters. % \begin{macrocode} mathfont:add_extensible_variants(delim_glyphs, delim_scale) mathfont:add_extensible_variants(big_op_glyphs, big_op_scale) mathfont:add_extensible_variants(vert_glyphs, vert_scale) mathfont:add_extensible_variants(int_glyphs, int_scale) % \end{macrocode} % Finally, end the call to |\directlua| and balance the preceeding conditional. % \begin{macrocode} } \fi % matches previous \ifM@adjust@font % \end{macrocode} % % % % % \section{Unicode Hex Values} % % For this section, we don't want any |\endlinechar|s present when \TeX\ scans things because we want to eliminate any extra spaces, so before anything else, we set |\endlinechar| to $-1$. % \begin{macrocode} \count@\endlinechar \endlinechar\m@ne % \end{macrocode} % We have to save |\mathchar@type| to use after |\begin{document}| because \LaTeX\ feeds it to |\@onlypreamble|. % \begin{macrocode} \let\@@mathchar@type\mathchar@type % \end{macrocode} % We define |\M@sym@|, which is a wrapper around |\Umathchardef| or |\Umathcode| and is \textsf{mathfont}'s version of |\DeclareMathSymbol|. Before version 3.0, \textsf{mathfont} used |\DeclareMathSymbol|, but we create our own version to support Unicode input. The command first checks whether |#1| is a control sequence. If yes, we define it using |\Umathchardef| and again using |\Umathcode|. Otherwise, we define it once with |\Umathcode|. % \begin{macrocode} \def\M@sym@#1#2#3#4{ \ifcat\relax\noexpand#1 % \end{macrocode} % Check if we're redefining a previously declared math symbol. We put |mathchar| in |\if@| so we don't have to check for |\mathchar| and |\Umathchar| separately. We use |\string| so that the letters in |mathchar| have catcode 12 when we check for their presence in |\meaning#1| with |\in@|. If |#1| is undefined, |\in@| will set |\ifin@| to false. % \begin{macrocode} \expandafter\in@\expanded {{\expandafter\@gobble\string\mathchar}{\meaning#1}} \ifin@ % \end{macrocode} % Now redeclare the symbol. % \begin{macrocode} \Umathchardef#1=+\@@mathchar@type#2 +\csname sym#3\endcsname+#4\relax % \end{macrocode} % The next two lines implement Unicode input. % \begin{macrocode} \Umathcode #4=+\@@mathchar@type#2 +\csname sym#3\endcsname+#4\relax % \end{macrocode} % If |#1| does not code for a math symbol, we check whether it is already defined. If no, we define it, and if yes, we issue an error. Again, we implement Unicode input. % \begin{macrocode} \else \ifx#1\@undefined \Umathchardef#1=+\@@mathchar@type#2 +\csname sym#3\endcsname+#4\relax \Umathcode #4=+\@@mathchar@type#2 +\csname sym#3\endcsname+#4\relax \else \@latex@error{Command "\string#1" already defined}\@eha \fi \fi % \end{macrocode} % Easy to deal with the case where |#1| is a single character. % \begin{macrocode} \else \Umathcode`#1=+\@@mathchar@type#2+\csname sym#3\endcsname +#4\relax \fi} % \end{macrocode} % Similar deal for accents; |\M@acc@| is our version of |\DeclareMathAccent|. Newer versions of the \LaTeX\ kernel define math accents as robust commands, so we have to incorporate a check for robustness as well. We let |\@tempswa| be true or false according to whether we can (re)define the control sequence |#1| as a math accent. % \begin{macrocode} \def\M@acc@#1#2#3#4{ \begingroup \@tempswatrue \ifdefined#1 \expandafter\in@\expanded{ {\expandafter\@gobble\string\mathaccent} {\meaning#1}} \ifin@ \else \begingroup \escapechar\m@ne \expandafter \endgroup \expandafter\in@\expanded{ {\string\mathaccent} {\expandafter\meaning\csname\string#1\space\endcsname}} \ifin@ \else \@tempswafalse \fi \fi \fi \expandafter \endgroup % \end{macrocode} % Now (re)define the command or issue an error. % \begin{macrocode} \if@tempswa \protected\edef#1{\Umathaccent+\@@mathchar@type#2 +\csname sym#3\endcsname+#4\relax} \else \@latex@error{Command "\string#1" already defined}\@eha \fi} % \end{macrocode} % Set upper-case Latin characters. We use an |\edef| for |\M@upper@id| because every expansion now will save \LaTeX\ twenty-six expansions later when it evaluates each |\DeclareMathSymbol|. If the user has enabled Lua font adjustments, we set the mathcodes to use encoding slots in the Math Alphanumeric Symbols block. % \begin{macrocode} \def\M@upper@set{ \edef\M@upper@id{M\@tempc-\M@uppershape} \M@sym@{A}{\mathalpha}{\M@upper@id}{`A} \M@sym@{B}{\mathalpha}{\M@upper@id}{`B} \M@sym@{C}{\mathalpha}{\M@upper@id}{`C} \M@sym@{D}{\mathalpha}{\M@upper@id}{`D} \M@sym@{E}{\mathalpha}{\M@upper@id}{`E} \M@sym@{F}{\mathalpha}{\M@upper@id}{`F} \M@sym@{G}{\mathalpha}{\M@upper@id}{`G} \M@sym@{H}{\mathalpha}{\M@upper@id}{`H} \M@sym@{I}{\mathalpha}{\M@upper@id}{`I} \M@sym@{J}{\mathalpha}{\M@upper@id}{`J} \M@sym@{K}{\mathalpha}{\M@upper@id}{`K} \M@sym@{L}{\mathalpha}{\M@upper@id}{`L} \M@sym@{M}{\mathalpha}{\M@upper@id}{`M} \M@sym@{N}{\mathalpha}{\M@upper@id}{`N} \M@sym@{O}{\mathalpha}{\M@upper@id}{`O} \M@sym@{P}{\mathalpha}{\M@upper@id}{`P} \M@sym@{Q}{\mathalpha}{\M@upper@id}{`Q} \M@sym@{R}{\mathalpha}{\M@upper@id}{`R} \M@sym@{S}{\mathalpha}{\M@upper@id}{`S} \M@sym@{T}{\mathalpha}{\M@upper@id}{`T} \M@sym@{U}{\mathalpha}{\M@upper@id}{`U} \M@sym@{V}{\mathalpha}{\M@upper@id}{`V} \M@sym@{W}{\mathalpha}{\M@upper@id}{`W} \M@sym@{X}{\mathalpha}{\M@upper@id}{`X} \M@sym@{Y}{\mathalpha}{\M@upper@id}{`Y} \M@sym@{Z}{\mathalpha}{\M@upper@id}{`Z}} % \end{macrocode} % Set lower-case Latin characters. % \begin{macrocode} \def\M@lower@set{ \edef\M@lower@id{M\@tempc-\M@lowershape} \M@sym@{a}{\mathalpha}{\M@lower@id}{`a} \M@sym@{b}{\mathalpha}{\M@lower@id}{`b} \M@sym@{c}{\mathalpha}{\M@lower@id}{`c} \M@sym@{d}{\mathalpha}{\M@lower@id}{`d} \M@sym@{e}{\mathalpha}{\M@lower@id}{`e} \M@sym@{f}{\mathalpha}{\M@lower@id}{`f} \M@sym@{g}{\mathalpha}{\M@lower@id}{`g} \M@sym@{h}{\mathalpha}{\M@lower@id}{`h} \M@sym@{i}{\mathalpha}{\M@lower@id}{`i} \M@sym@{j}{\mathalpha}{\M@lower@id}{`j} \M@sym@{k}{\mathalpha}{\M@lower@id}{`k} \M@sym@{l}{\mathalpha}{\M@lower@id}{`l} \M@sym@{m}{\mathalpha}{\M@lower@id}{`m} \M@sym@{n}{\mathalpha}{\M@lower@id}{`n} \M@sym@{o}{\mathalpha}{\M@lower@id}{`o} \M@sym@{p}{\mathalpha}{\M@lower@id}{`p} \M@sym@{q}{\mathalpha}{\M@lower@id}{`q} \M@sym@{r}{\mathalpha}{\M@lower@id}{`r} \M@sym@{s}{\mathalpha}{\M@lower@id}{`s} \M@sym@{t}{\mathalpha}{\M@lower@id}{`t} \M@sym@{u}{\mathalpha}{\M@lower@id}{`u} \M@sym@{v}{\mathalpha}{\M@lower@id}{`v} \M@sym@{w}{\mathalpha}{\M@lower@id}{`w} \M@sym@{x}{\mathalpha}{\M@lower@id}{`x} \M@sym@{y}{\mathalpha}{\M@lower@id}{`y} \M@sym@{z}{\mathalpha}{\M@lower@id}{`z} \M@sym@{\imath}{\mathalpha}{\M@lower@id}{"131} \M@sym@{\jmath}{\mathalpha}{\M@lower@id}{"237} \let\hbar\@undefined \M@sym@{\hbar}{\mathord}{\M@lower@id}{"127}} % \end{macrocode} % Set diacritics. % \begin{macrocode} \def\M@diacritics@set{ \edef\M@diacritics@id{M\@tempc-\M@diacriticsshape} \M@acc@{\acute} {\mathalpha}{\M@diacritics@id}{"B4} \M@acc@{\aacute} {\mathalpha}{\M@diacritics@id}{"2DD} \M@acc@{\dot} {\mathalpha}{\M@diacritics@id}{"2D9} \M@acc@{\ddot} {\mathalpha}{\M@diacritics@id}{"A8} \M@acc@{\grave} {\mathalpha}{\M@diacritics@id}{"60} \M@acc@{\breve} {\mathalpha}{\M@diacritics@id}{"2D8} \M@acc@{\hat} {\mathalpha}{\M@diacritics@id}{"2C6} \M@acc@{\check} {\mathalpha}{\M@diacritics@id}{"2C7} \M@acc@{\bar} {\mathalpha}{\M@diacritics@id}{"2C9} \M@acc@{\mathring}{\mathalpha}{\M@diacritics@id}{"2DA} \M@acc@{\tilde} {\mathalpha}{\M@diacritics@id}{"2DC}} % \end{macrocode} % Set capital Greek characters. % \begin{macrocode} \def\M@greekupper@set{ \edef\M@greekupper@id{M\@tempc-\M@greekuppershape} \M@sym@{\Alpha} {\mathalpha}{\M@greekupper@id}{"391} \M@sym@{\Beta} {\mathalpha}{\M@greekupper@id}{"392} \M@sym@{\Gamma} {\mathalpha}{\M@greekupper@id}{"393} \M@sym@{\Delta} {\mathalpha}{\M@greekupper@id}{"394} \M@sym@{\Epsilon} {\mathalpha}{\M@greekupper@id}{"395} \M@sym@{\Zeta} {\mathalpha}{\M@greekupper@id}{"396} \M@sym@{\Eta} {\mathalpha}{\M@greekupper@id}{"397} \M@sym@{\Theta} {\mathalpha}{\M@greekupper@id}{"398} \M@sym@{\Iota} {\mathalpha}{\M@greekupper@id}{"399} \M@sym@{\Kappa} {\mathalpha}{\M@greekupper@id}{"39A} \M@sym@{\Lambda} {\mathalpha}{\M@greekupper@id}{"39B} \M@sym@{\Mu} {\mathalpha}{\M@greekupper@id}{"39C} \M@sym@{\Nu} {\mathalpha}{\M@greekupper@id}{"39D} \M@sym@{\Xi} {\mathalpha}{\M@greekupper@id}{"39E} \M@sym@{\Omicron} {\mathalpha}{\M@greekupper@id}{"39F} \M@sym@{\Pi} {\mathalpha}{\M@greekupper@id}{"3A0} \M@sym@{\Rho} {\mathalpha}{\M@greekupper@id}{"3A1} \M@sym@{\Sigma} {\mathalpha}{\M@greekupper@id}{"3A3} \M@sym@{\Tau} {\mathalpha}{\M@greekupper@id}{"3A4} \M@sym@{\Upsilon} {\mathalpha}{\M@greekupper@id}{"3A5} \M@sym@{\Phi} {\mathalpha}{\M@greekupper@id}{"3A6} \M@sym@{\Chi} {\mathalpha}{\M@greekupper@id}{"3A7} \M@sym@{\Psi} {\mathalpha}{\M@greekupper@id}{"3A8} \M@sym@{\Omega} {\mathalpha}{\M@greekupper@id}{"3A9} \M@sym@{\varTheta}{\mathalpha}{\M@greekupper@id}{"3F4} % \end{macrocode} % Declare |\increment| and |\nabla| if they haven't already been declared in the |symbols| or |extsymbols| fonts. % \begin{macrocode} \ifM@adjust@font \ifM@symbols\else \M@sym@{\increment} {\mathord}{\M@greekupper@id}{"2206} \M@sym@{\nabla} {\mathord}{\M@greekupper@id}{"2207} \fi \else \ifM@symbols\else \M@sym@{\increment} {\mathord}{\M@greekupper@id}{"2206} \fi \ifM@extsymbols\else \M@sym@{\nabla} {\mathord}{\M@greekupper@id}{"2207} \fi \fi} % \end{macrocode} % Set minuscule Greek characters. % \begin{macrocode} \def\M@greeklower@set{ \edef\M@greeklower@id{M\@tempc-\M@greeklowershape} \M@sym@{\alpha} {\mathalpha}{\M@greeklower@id}{"3B1} \M@sym@{\beta} {\mathalpha}{\M@greeklower@id}{"3B2} \M@sym@{\gamma} {\mathalpha}{\M@greeklower@id}{"3B3} \M@sym@{\delta} {\mathalpha}{\M@greeklower@id}{"3B4} \M@sym@{\epsilon} {\mathalpha}{\M@greeklower@id}{"3B5} \M@sym@{\zeta} {\mathalpha}{\M@greeklower@id}{"3B6} \M@sym@{\eta} {\mathalpha}{\M@greeklower@id}{"3B7} \M@sym@{\theta} {\mathalpha}{\M@greeklower@id}{"3B8} \M@sym@{\iota} {\mathalpha}{\M@greeklower@id}{"3B9} \M@sym@{\kappa} {\mathalpha}{\M@greeklower@id}{"3BA} \M@sym@{\lambda} {\mathalpha}{\M@greeklower@id}{"3BB} \M@sym@{\mu} {\mathalpha}{\M@greeklower@id}{"3BC} \M@sym@{\nu} {\mathalpha}{\M@greeklower@id}{"3BD} \M@sym@{\xi} {\mathalpha}{\M@greeklower@id}{"3BE} \M@sym@{\omicron} {\mathalpha}{\M@greeklower@id}{"3BF} \M@sym@{\pi} {\mathalpha}{\M@greeklower@id}{"3C0} \M@sym@{\rho} {\mathalpha}{\M@greeklower@id}{"3C1} \M@sym@{\sigma} {\mathalpha}{\M@greeklower@id}{"3C3} \M@sym@{\tau} {\mathalpha}{\M@greeklower@id}{"3C4} \M@sym@{\upsilon} {\mathalpha}{\M@greeklower@id}{"3C5} \M@sym@{\phi} {\mathalpha}{\M@greeklower@id}{"3C6} \M@sym@{\chi} {\mathalpha}{\M@greeklower@id}{"3C7} \M@sym@{\psi} {\mathalpha}{\M@greeklower@id}{"3C8} \M@sym@{\omega} {\mathalpha}{\M@greeklower@id}{"3C9} \M@sym@{\varbeta} {\mathalpha}{\M@greeklower@id}{"3D0} \M@sym@{\varepsilon}{\mathalpha}{\M@greeklower@id}{"3F5} \M@sym@{\varkappa} {\mathalpha}{\M@greeklower@id}{"3F0} \M@sym@{\vartheta} {\mathalpha}{\M@greeklower@id}{"3D1} \M@sym@{\varrho} {\mathalpha}{\M@greeklower@id}{"3F1} \M@sym@{\varsigma} {\mathalpha}{\M@greeklower@id}{"3C2} \M@sym@{\varphi} {\mathalpha}{\M@greeklower@id}{"3D5}} % \end{macrocode} % Set capital ancient Greek characters. % \begin{macrocode} \def\M@agreekupper@set{ \edef\M@agreekupper@id{M\@tempc-\M@agreekuppershape} \M@sym@{\Heta} {\mathalpha}{\M@agreekupper@id}{"370} \M@sym@{\Sampi} {\mathalpha}{\M@agreekupper@id}{"3E0} \M@sym@{\Digamma} {\mathalpha}{\M@agreekupper@id}{"3DC} \M@sym@{\Koppa} {\mathalpha}{\M@agreekupper@id}{"3D8} \M@sym@{\Stigma} {\mathalpha}{\M@agreekupper@id}{"3DA} \M@sym@{\Sho} {\mathalpha}{\M@agreekupper@id}{"3F7} \M@sym@{\San} {\mathalpha}{\M@agreekupper@id}{"3FA} \M@sym@{\varSampi} {\mathalpha}{\M@agreekupper@id}{"372} \M@sym@{\varDigamma}{\mathalpha}{\M@agreekupper@id}{"376} \M@sym@{\varKoppa} {\mathalpha}{\M@agreekupper@id}{"3DE}} % \end{macrocode} % Set minuscule ancient Greek characters. % \begin{macrocode} \def\M@agreeklower@set{ \edef\M@agreeklower@id{M\@tempc-\M@agreeklowershape} \M@sym@{\heta} {\mathalpha}{\M@agreeklower@id}{"371} \M@sym@{\sampi} {\mathalpha}{\M@agreeklower@id}{"3E1} \M@sym@{\digamma} {\mathalpha}{\M@agreeklower@id}{"3DD} \M@sym@{\koppa} {\mathalpha}{\M@agreeklower@id}{"3D9} \M@sym@{\stigma} {\mathalpha}{\M@agreeklower@id}{"3DB} \M@sym@{\sho} {\mathalpha}{\M@agreeklower@id}{"3F8} \M@sym@{\san} {\mathalpha}{\M@agreeklower@id}{"3FB} \M@sym@{\varsampi} {\mathalpha}{\M@agreeklower@id}{"373} \M@sym@{\vardigamma}{\mathalpha}{\M@agreeklower@id}{"377} \M@sym@{\varkoppa} {\mathalpha}{\M@agreeklower@id}{"3DF}} % \end{macrocode} % Set capital Cyrillic characters. % \begin{macrocode} \def\M@cyrillicupper@set{ \edef\M@cyrillicupper@id{M\@tempc-\M@cyrillicuppershape} \M@sym@{\cyrA} {\mathalpha}{\M@cyrillicupper@id}{"410} \M@sym@{\cyrBe} {\mathalpha}{\M@cyrillicupper@id}{"411} \M@sym@{\cyrVe} {\mathalpha}{\M@cyrillicupper@id}{"412} \M@sym@{\cyrGhe} {\mathalpha}{\M@cyrillicupper@id}{"413} \M@sym@{\cyrDe} {\mathalpha}{\M@cyrillicupper@id}{"414} \M@sym@{\cyrIe} {\mathalpha}{\M@cyrillicupper@id}{"415} \M@sym@{\cyrZhe} {\mathalpha}{\M@cyrillicupper@id}{"416} \M@sym@{\cyrZe} {\mathalpha}{\M@cyrillicupper@id}{"417} \M@sym@{\cyrI} {\mathalpha}{\M@cyrillicupper@id}{"418} \M@sym@{\cyrKa} {\mathalpha}{\M@cyrillicupper@id}{"41A} \M@sym@{\cyrEl} {\mathalpha}{\M@cyrillicupper@id}{"41B} \M@sym@{\cyrEm} {\mathalpha}{\M@cyrillicupper@id}{"41C} \M@sym@{\cyrEn} {\mathalpha}{\M@cyrillicupper@id}{"41D} \M@sym@{\cyrO} {\mathalpha}{\M@cyrillicupper@id}{"41E} \M@sym@{\cyrPe} {\mathalpha}{\M@cyrillicupper@id}{"41F} \M@sym@{\cyrEr} {\mathalpha}{\M@cyrillicupper@id}{"420} \M@sym@{\cyrEs} {\mathalpha}{\M@cyrillicupper@id}{"421} \M@sym@{\cyrTe} {\mathalpha}{\M@cyrillicupper@id}{"422} \M@sym@{\cyrU} {\mathalpha}{\M@cyrillicupper@id}{"423} \M@sym@{\cyrEf} {\mathalpha}{\M@cyrillicupper@id}{"424} \M@sym@{\cyrHa} {\mathalpha}{\M@cyrillicupper@id}{"425} \M@sym@{\cyrTse} {\mathalpha}{\M@cyrillicupper@id}{"426} \M@sym@{\cyrChe} {\mathalpha}{\M@cyrillicupper@id}{"427} \M@sym@{\cyrSha} {\mathalpha}{\M@cyrillicupper@id}{"428} \M@sym@{\cyrShcha}{\mathalpha}{\M@cyrillicupper@id}{"429} \M@sym@{\cyrHard} {\mathalpha}{\M@cyrillicupper@id}{"42A} \M@sym@{\cyrYeru} {\mathalpha}{\M@cyrillicupper@id}{"42B} \M@sym@{\cyrSoft} {\mathalpha}{\M@cyrillicupper@id}{"42C} \M@sym@{\cyrE} {\mathalpha}{\M@cyrillicupper@id}{"42D} \M@sym@{\cyrYu} {\mathalpha}{\M@cyrillicupper@id}{"42E} \M@sym@{\cyrYa} {\mathalpha}{\M@cyrillicupper@id}{"42F} \M@sym@{\cyrvarI} {\mathalpha}{\M@cyrillicupper@id}{"419}} % \end{macrocode} % Set minuscule Cyrillic characters. % \begin{macrocode} \def\M@cyrilliclower@set{ \edef\M@cyrilliclower@id{M\@tempc-\M@cyrilliclowershape} \M@sym@{\cyra} {\mathalpha}{\M@cyrilliclower@id}{"430} \M@sym@{\cyrbe} {\mathalpha}{\M@cyrilliclower@id}{"431} \M@sym@{\cyrve} {\mathalpha}{\M@cyrilliclower@id}{"432} \M@sym@{\cyrghe} {\mathalpha}{\M@cyrilliclower@id}{"433} \M@sym@{\cyrde} {\mathalpha}{\M@cyrilliclower@id}{"434} \M@sym@{\cyrie} {\mathalpha}{\M@cyrilliclower@id}{"435} \M@sym@{\cyrzhe} {\mathalpha}{\M@cyrilliclower@id}{"436} \M@sym@{\cyrze} {\mathalpha}{\M@cyrilliclower@id}{"437} \M@sym@{\cyri} {\mathalpha}{\M@cyrilliclower@id}{"438} \M@sym@{\cyrka} {\mathalpha}{\M@cyrilliclower@id}{"43A} \M@sym@{\cyrel} {\mathalpha}{\M@cyrilliclower@id}{"43B} \M@sym@{\cyrem} {\mathalpha}{\M@cyrilliclower@id}{"43C} \M@sym@{\cyren} {\mathalpha}{\M@cyrilliclower@id}{"43D} \M@sym@{\cyro} {\mathalpha}{\M@cyrilliclower@id}{"43E} \M@sym@{\cyrpe} {\mathalpha}{\M@cyrilliclower@id}{"43F} \M@sym@{\cyrer} {\mathalpha}{\M@cyrilliclower@id}{"440} \M@sym@{\cyres} {\mathalpha}{\M@cyrilliclower@id}{"441} \M@sym@{\cyrte} {\mathalpha}{\M@cyrilliclower@id}{"442} \M@sym@{\cyru} {\mathalpha}{\M@cyrilliclower@id}{"443} \M@sym@{\cyref} {\mathalpha}{\M@cyrilliclower@id}{"444} \M@sym@{\cyrha} {\mathalpha}{\M@cyrilliclower@id}{"445} \M@sym@{\cyrtse} {\mathalpha}{\M@cyrilliclower@id}{"446} \M@sym@{\cyrche} {\mathalpha}{\M@cyrilliclower@id}{"447} \M@sym@{\cyrsha} {\mathalpha}{\M@cyrilliclower@id}{"448} \M@sym@{\cyrshcha}{\mathalpha}{\M@cyrilliclower@id}{"449} \M@sym@{\cyrhard} {\mathalpha}{\M@cyrilliclower@id}{"44A} \M@sym@{\cyryeru} {\mathalpha}{\M@cyrilliclower@id}{"44B} \M@sym@{\cyrsoft} {\mathalpha}{\M@cyrilliclower@id}{"44C} \M@sym@{\cyre} {\mathalpha}{\M@cyrilliclower@id}{"44D} \M@sym@{\cyryu} {\mathalpha}{\M@cyrilliclower@id}{"44E} \M@sym@{\cyrya} {\mathalpha}{\M@cyrilliclower@id}{"44F} \M@sym@{\cyrvari} {\mathalpha}{\M@cyrilliclower@id}{"439}} % \end{macrocode} % Set Hebrew characters. % \begin{macrocode} \def\M@hebrew@set{ \edef\M@hebrew@id{M\@tempc-\M@hebrewshape} \M@sym@{\aleph} {\mathalpha}{\M@hebrew@id}{"5D0} \M@sym@{\beth} {\mathalpha}{\M@hebrew@id}{"5D1} \M@sym@{\gimel} {\mathalpha}{\M@hebrew@id}{"5D2} \M@sym@{\daleth} {\mathalpha}{\M@hebrew@id}{"5D3} \M@sym@{\he} {\mathalpha}{\M@hebrew@id}{"5D4} \M@sym@{\vav} {\mathalpha}{\M@hebrew@id}{"5D5} \M@sym@{\zayin} {\mathalpha}{\M@hebrew@id}{"5D6} \M@sym@{\het} {\mathalpha}{\M@hebrew@id}{"5D7} \M@sym@{\tet} {\mathalpha}{\M@hebrew@id}{"5D8} \M@sym@{\yod} {\mathalpha}{\M@hebrew@id}{"5D9} \M@sym@{\kaf} {\mathalpha}{\M@hebrew@id}{"5DB} \M@sym@{\lamed} {\mathalpha}{\M@hebrew@id}{"5DC} \M@sym@{\mem} {\mathalpha}{\M@hebrew@id}{"5DE} \M@sym@{\nun} {\mathalpha}{\M@hebrew@id}{"5E0} \M@sym@{\samekh} {\mathalpha}{\M@hebrew@id}{"5E1} \M@sym@{\ayin} {\mathalpha}{\M@hebrew@id}{"5E2} \M@sym@{\pe} {\mathalpha}{\M@hebrew@id}{"5E4} \M@sym@{\tsadi} {\mathalpha}{\M@hebrew@id}{"5E6} \M@sym@{\qof} {\mathalpha}{\M@hebrew@id}{"5E7} \M@sym@{\resh} {\mathalpha}{\M@hebrew@id}{"5E8} \M@sym@{\shin} {\mathalpha}{\M@hebrew@id}{"5E9} \M@sym@{\tav} {\mathalpha}{\M@hebrew@id}{"5EA} \M@sym@{\varkaf} {\mathalpha}{\M@hebrew@id}{"5DA} \M@sym@{\varmem} {\mathalpha}{\M@hebrew@id}{"5DD} \M@sym@{\varnun} {\mathalpha}{\M@hebrew@id}{"5DF} \M@sym@{\varpe} {\mathalpha}{\M@hebrew@id}{"5E3} \M@sym@{\vartsadi}{\mathalpha}{\M@hebrew@id}{"5E5}} % \end{macrocode} % Set digits. % \begin{macrocode} \def\M@digits@set{ \edef\M@digits@id{M\@tempc-\M@digitsshape} \M@sym@{0}{\mathalpha}{\M@digits@id}{`0} \M@sym@{1}{\mathalpha}{\M@digits@id}{`1} \M@sym@{2}{\mathalpha}{\M@digits@id}{`2} \M@sym@{3}{\mathalpha}{\M@digits@id}{`3} \M@sym@{4}{\mathalpha}{\M@digits@id}{`4} \M@sym@{5}{\mathalpha}{\M@digits@id}{`5} \M@sym@{6}{\mathalpha}{\M@digits@id}{`6} \M@sym@{7}{\mathalpha}{\M@digits@id}{`7} \M@sym@{8}{\mathalpha}{\M@digits@id}{`8} \M@sym@{9}{\mathalpha}{\M@digits@id}{`9}} % \end{macrocode} % Set new operator font. % We change the |\fam| to the user's requested symbol font for math operators. % \begin{macrocode} \def\M@operator@set{ \edef\operator@font{\mathgroup \csname symM\@tempc-\M@operatorshape\endcsname}} % \end{macrocode} % Set delimiters. % \begin{macrocode} \ifM@adjust@font \def\M@delimiters@set{ \edef\M@delimiters@id{M\@tempc-\M@delimitersshape} \edef\M@delimiters@num{ \csname sym\M@delimiters@id\endcsname} \M@sym@{(} {\mathopen} {\M@delimiters@id}{"28} \M@sym@{)} {\mathclose}{\M@delimiters@id}{"29} \M@sym@{[} {\mathopen} {\M@delimiters@id}{"5B} \M@sym@{]} {\mathclose}{\M@delimiters@id}{"5D} \M@sym@{\leftbrace} {\mathopen} {\M@delimiters@id}{"7B} \M@sym@{\rightbrace}{\mathclose}{\M@delimiters@id}{"7D} % \end{macrocode} % Set |\Udelcode|s for delimiters that come from individual characters. % \begin{macrocode} \Udelcode"28+\M@delimiters@num+"28\relax % ( \Udelcode"29+\M@delimiters@num+"29\relax % ) \Udelcode"2F+\M@delimiters@num+"2F\relax % / \Udelcode"5B+\M@delimiters@num+"5B\relax % [ \Udelcode"5D+\M@delimiters@num+"5D\relax % ] \Udelcode"7C+\M@delimiters@num+"7C\relax % | \ifM@symbols\else \M@sym@{|}{\mathord}{\M@delimiters@id}{"7C} \fi \let\vert=| % \end{macrocode} % For the delimiters that come from control sequences, we use |\edef| and |\Udelimiter|. % \begin{macrocode} \protected\def\backslash{ \ifmmode\mathbackslash\else\textbackslash\fi} \protected\edef\mathbackslash{ \Udelimiter+2+\M@delimiters@num+92\relax} \protected\edef\lbrace{ \Udelimiter+4+\M@delimiters@num+123\relax} \protected\edef\rbrace{ \Udelimiter+5+\M@delimiters@num+125\relax} \protected\edef\lguil{ \Udelimiter+4+\M@delimiters@num+8249\relax} \protected\edef\rguil{ \Udelimiter+5+\M@delimiters@num+8250\relax} \protected\edef\llguil{ \Udelimiter+4+\M@delimiters@num+171\relax} \protected\edef\rrguil{ \Udelimiter+5+\M@delimiters@num+187\relax} \protected\edef\fakelangle{ \Udelimiter+4+\M@delimiters@num +\directlua{tex.print(mathfont.fakel)}\relax} \protected\edef\fakerangle{ \Udelimiter+5+\M@delimiters@num +\directlua{tex.print(mathfont.faker)}\relax} \protected\edef\fakellangle{ \Udelimiter+4+\M@delimiters@num +\directlua{tex.print(mathfont.fakell)}\relax} \protected\edef\fakerrangle{ \Udelimiter+5+\M@delimiters@num +\directlua{tex.print(mathfont.fakerr)}\relax}} \else \def\M@delimiters@set{ \edef\M@delimiters@id{M\@tempc-\M@delimitersshape} \M@sym@{(} {\mathopen} {\M@delimiters@id}{"28} \M@sym@{)} {\mathclose}{\M@delimiters@id}{"29} \M@sym@{[} {\mathopen} {\M@delimiters@id}{"5B} \M@sym@{]} {\mathclose}{\M@delimiters@id}{"5D} \M@sym@{\lguil} {\mathopen} {\M@delimiters@id}{"2039} \M@sym@{\rguil} {\mathclose}{\M@delimiters@id}{"203A} \M@sym@{\llguil} {\mathopen} {\M@delimiters@id}{"AB} \M@sym@{\rrguil} {\mathclose}{\M@delimiters@id}{"BB} \M@sym@{\leftbrace} {\mathopen} {\M@delimiters@id}{"7B} \M@sym@{\rightbrace}{\mathclose}{\M@delimiters@id}{"7D}} \fi % \end{macrocode} % Radicals. When we define |\surd| to typeset U+221A, |\M@sym@| sets the |\Umathcode| of \textsurd\ to be a surd symbol. However, if we modified the font, we know the surd character in the requested font can successfully make a square root expression, so we override the definition from |\M@sym@| to turn \textsurd\ to an active character in math mode. % \begin{macrocode} \ifM@adjust@font \def\M@radical@set{ \edef\M@radical@id{M\@tempc-\M@radicalshape} \let\surd\@undefined \M@sym@{\surd}{\mathord}{\M@radical@id}{"221A} % \end{macrocode} % Now set the |\mathcode| of \textsurd\ to 8000. This is probably me being paranoid, but I wanted to stick to ascii characters in the sty file. We use |\directlua| to print the surd character instead. This also has the advantage of printing an active character, so we don't have to scan any tokens. % \begin{macrocode} \expandafter\protected\expandafter\def\directlua{ tex.cprint(13, utf8.char(0x221A))} {\ifmmode\expandafter\sqrt\else\Uchar"221A\relax\fi} \mathcode"221A="8000\relax \edef\@sqrts@gn##1{\Uradical+\number \csname sym\M@radical@id\endcsname+"221A\relax{##1}} % \end{macrocode} % We redefine |\r@@t|, which typesets the degree symbol on an $n$th root. We set the placement so that right side of the box containing the degree lies 60\% of the horizontal distance across the surd symbol, and the baseline of the degree symbol is 60\% of the vertical distance up the surd. % \begin{macrocode} \def\r@@t##1##2{ \setbox\z@\hbox{$\m@th##1\sqrtsign{##2}$} \setbox\surdbox\hbox{$\m@th##1\@sqrts@gn{ \hbox{\vphantom{$\m@th##1##2$}}}$} \dimen@\ht\surdbox \advance\dimen@\dp\surdbox \dimen@=0.6\dimen@ \advance\dimen@-\dp\surdbox \ifdim\wd\rootbox<0.6\wd\surdbox \kern0.6\wd\surdbox \else \kern\wd\rootbox \fi \raise\dimen@\hbox{\llap{\copy\rootbox}} \kern-0.6\wd\surdbox \box\z@} \protected\def\sqrtsign##1{ \@sqrts@gn{\mkern\radicandoffset##1}}} \else \def\M@radical@set{ \edef\M@radical@id{M\@tempc-\M@radicalshape} \let\surd\@undefined \M@sym@{\surd}{\mathord}{\M@radical@id}{"221A}} \fi % \end{macrocode} % Big operators. % \begin{macrocode} \def\M@bigops@set{ \edef\M@bigops@id{M\@tempc-\M@bigopsshape} \let\sum\@undefined \let\prod\@undefined \M@sym@{\sum} {\mathop}{\M@bigops@id}{"2211} \M@sym@{\prod} {\mathop}{\M@bigops@id}{"220F} \M@sym@{\intop}{\mathop}{\M@bigops@id}{"222B}} % \end{macrocode} % Extended big operators. % \begin{macrocode} \def\M@extbigops@set{ \edef\M@extbigops@id{M\@tempc-\M@extbigopsshape} \let\coprod\@undefined \let\bigvee\@undefined \let\bigwedge\@undefined \let\bigcup\@undefined \let\bigcap\@undefined \let\bigoplus\@undefined \let\bigotimes\@undefined \let\bigodot\@undefined \let\bigsqcup\@undefined \M@sym@{\coprod} {\mathop}{\M@extbigops@id}{"2210} \M@sym@{\bigvee} {\mathop}{\M@extbigops@id}{"22C1} \M@sym@{\bigwedge} {\mathop}{\M@extbigops@id}{"22C0} \M@sym@{\bigcup} {\mathop}{\M@extbigops@id}{"22C3} \M@sym@{\bigcap} {\mathop}{\M@extbigops@id}{"22C2} \M@sym@{\iintop} {\mathop}{\M@extbigops@id}{"222C} \M@sym@{\iiintop} {\mathop}{\M@extbigops@id}{"222D} \M@sym@{\ointop} {\mathop}{\M@extbigops@id}{"222E} \M@sym@{\oiintop} {\mathop}{\M@extbigops@id}{"222F} \M@sym@{\oiiintop} {\mathop}{\M@extbigops@id}{"2230} \M@sym@{\bigoplus} {\mathop}{\M@extbigops@id}{"2A01} \M@sym@{\bigotimes}{\mathop}{\M@extbigops@id}{"2A02} \M@sym@{\bigodot} {\mathop}{\M@extbigops@id}{"2A00} \M@sym@{\bigsqcap} {\mathop}{\M@extbigops@id}{"2A05} \M@sym@{\bigsqcup} {\mathop}{\M@extbigops@id}{"2A06} \protected\def\iint{\iintop\nolimits} \protected\def\iiint{\iiintop\nolimits} \protected\def\oint{\ointop\nolimits} \protected\def\oiint{\oiintop\nolimits} \protected\def\oiiint{\oiiintop\nolimits}} % \end{macrocode} % Set symbols. % \begin{macrocode} \def\M@symbols@set{ \edef\M@symbols@id{M\@tempc-\M@symbolsshape} \let\colon\@undefined \let\mathellipsis\@undefined % \end{macrocode} % Before we start declaring symbols, specifically minus or equals signs, we have to address a minor clash with \textsf{amsmath}. That package defines |\relbar| and |\Relbar| as essentially a minus and equals sign respectively. However, those two control sequences are for making arrows, so they should come from the |arrows| font, not the |symbols| font. If the user already called |\mathfont| with the |arrows| keyword, we do nothing because |\M@arrows@set| defines |\relbar| and |\Relbar| correctly. If not, we make these two control sequences be the current minus and equals sign (before the font changes in |\M@symbols@set|) because that's as good a choice as any, and we prevent \textsf{amsmath} from changing them to the |symbols| font. Users or package authors who want to modify |\relbar| or |\Relbar| should change |\@relbar| or |\@Relbar| respectively. % \begin{macrocode} \ifM@arrows\else \Umathcharnumdef\@relbar=\Umathcodenum`\- \Umathcharnumdef\@Relbar=\Umathcodenum`\= \protected\def\relbar{\mathrel {\mathpalette\mathsm@sh\@relbar}} \protected\def\Relbar{\@Relbar} % \end{macrocode} % We redefine stuff if \textsf{amsmath} gets loaded after \textsf{mathfont}. % \begin{macrocode} \@ifpackageloaded{amsmath} {\relax}{ \let\@@relbar\relbar \let\@@Relbar\Relbar \AtBeginDocument{\ifM@arrows\else \@ifpackageloaded{amsmath}{ \let\relbar\@@relbar \let\Relbar\@@Relbar} {\relax} \fi}} \fi % \end{macrocode} % If the user enabled Lua-based font asjustments, we declare a few more big operators for fun. For brevity, we put the |adjust@font| conditional here rather than redefining |\M@symbols@set|. Apparently, \textsf{newtx} defines |\bigtimes|, so in case that package gets loaded ahead of \textsf{mathfont}, we should make sure to clear that definition. It's important to declare the big operators before the normal versions of these characters so that |\M@sym@| defines the correct |\Umathcode| for them. % \begin{macrocode} \ifM@adjust@font \let\bigtimes\@undefined \M@sym@{\bigat} {\mathop}{\M@symbols@id}{"40} \M@sym@{\bighash} {\mathop}{\M@symbols@id}{"23} \M@sym@{\bigdollar} {\mathop}{\M@symbols@id}{"24} \M@sym@{\bigpercent}{\mathop}{\M@symbols@id}{"25} \M@sym@{\bigand} {\mathop}{\M@symbols@id}{"26} \M@sym@{\bigplus} {\mathop}{\M@symbols@id}{"2B} \M@sym@{\bigp} {\mathop}{\M@symbols@id}{"21} \M@sym@{\bigq} {\mathop}{\M@symbols@id}{"3F} \M@sym@{\bigS} {\mathop}{\M@symbols@id}{"A7} \M@sym@{\bigtimes} {\mathop}{\M@symbols@id}{"D7} \M@sym@{\bigdiv} {\mathop}{\M@symbols@id}{"F7} % \end{macrocode} % Define |\nabla| here if we're adjusting the font. If we are not doing that, this declaration goes in |extsymbols|. % \begin{macrocode} \M@sym@{\nabla} {\mathord}{\M@symbols@id}{"2207} \fi % \end{macrocode} % The rest of the symbols. % \begin{macrocode} \M@sym@{.} {\mathord} {\M@symbols@id}{"2E} \M@sym@{@} {\mathord} {\M@symbols@id}{"40} \M@sym@{'} {\mathord} {\M@symbols@id}{"2032} \M@sym@{\prime} {\mathord} {\M@symbols@id}{"2032} \M@sym@{"} {\mathord} {\M@symbols@id}{"2033} \M@sym@{\mathhash} {\mathord} {\M@symbols@id}{"23} \M@sym@{\mathdollar} {\mathord} {\M@symbols@id}{"24} \M@sym@{\mathpercent} {\mathord} {\M@symbols@id}{"25} \M@sym@{\mathand} {\mathord} {\M@symbols@id}{"26} \M@sym@{\mathparagraph}{\mathord} {\M@symbols@id}{"B6} \M@sym@{\mathsection} {\mathord} {\M@symbols@id}{"A7} \let\mathsterling\@undefined \M@sym@{\mathsterling} {\mathord} {\M@symbols@id}{"A3} \M@sym@{\neg} {\mathord} {\M@symbols@id}{"AC} \M@sym@{\mid} {\mathrel} {\M@symbols@id}{"7C} \M@sym@{|} {\mathord} {\M@symbols@id}{"7C} \M@sym@{\infty} {\mathord} {\M@symbols@id}{"221E} \M@sym@{\partial} {\mathord} {\M@symbols@id}{"2202} \M@sym@{\degree} {\mathord} {\M@symbols@id}{"B0} \M@sym@{\increment} {\mathord} {\M@symbols@id}{"2206} \M@sym@{+} {\mathbin} {\M@symbols@id}{"2B} \M@sym@{-} {\mathbin} {\M@symbols@id}{"2212} \M@sym@{*} {\mathbin} {\M@symbols@id}{"2A} \M@sym@{\times} {\mathbin} {\M@symbols@id}{"D7} \M@sym@{/} {\mathord} {\M@symbols@id}{"2F} \M@sym@{\fractionslash}{\mathord} {\M@symbols@id}{"2215} \M@sym@{\div} {\mathbin} {\M@symbols@id}{"F7} \M@sym@{\pm} {\mathbin} {\M@symbols@id}{"B1} \M@sym@{\bullet} {\mathbin} {\M@symbols@id}{"2022} \M@sym@{\dagger} {\mathbin} {\M@symbols@id}{"2020} \M@sym@{\ddagger} {\mathbin} {\M@symbols@id}{"2021} \M@sym@{\cdot} {\mathbin} {\M@symbols@id}{"2219} \M@sym@{\setminus} {\mathbin} {\M@symbols@id}{"5C} \M@sym@{=} {\mathrel} {\M@symbols@id}{"3D} \M@sym@{<} {\mathrel} {\M@symbols@id}{"3C} \M@sym@{>} {\mathrel} {\M@symbols@id}{"3E} \M@sym@{\leq} {\mathrel} {\M@symbols@id}{"2264} \M@sym@{\geq} {\mathrel} {\M@symbols@id}{"2265} \M@sym@{\sim} {\mathrel} {\M@symbols@id}{"7E} \M@sym@{\approx} {\mathrel} {\M@symbols@id}{"2248} \M@sym@{\equiv} {\mathrel} {\M@symbols@id}{"2261} \M@sym@{\parallel} {\mathrel} {\M@symbols@id}{"2016} \M@sym@{\colon} {\mathpunct}{\M@symbols@id}{"3A} \M@sym@{:} {\mathrel} {\M@symbols@id}{"3A} \M@sym@{?} {\mathclose}{\M@symbols@id}{"3F} \M@sym@{!} {\mathclose}{\M@symbols@id}{"21} \M@sym@{\comma} {\mathord} {\M@symbols@id}{"2C} \M@sym@{,} {\mathpunct}{\M@symbols@id}{"2C} \M@sym@{;} {\mathpunct}{\M@symbols@id}{"3B} \M@sym@{\mathellipsis} {\mathinner}{\M@symbols@id}{"2026} % \end{macrocode} % Now a bit of housekeeping. We redefine |\#|, |\%|, and |\&| as |\protected| macros that expand to previously declared |\mathhash|, etc.\ commands in math mode and retain their standard |\char| definitions otherwise. Other commands that function in both math and horizontal modes such as |\S| or |\dag| also use this technique. Then we define macros |\cong| and |\simeq| if the user hasn't called |\mathfont| with |extsymbols|. % \begin{macrocode} \protected\def\#{\ifmmode\mathhash\else\char"23\relax\fi} \protected\def\%{\ifmmode\mathpercent\else\char"25\relax\fi} \protected\def\&{\ifmmode\mathand\else\char"26\relax\fi} \ifM@extsymbols\else \protected\def\simeq{ \mathrel{\mathpalette\stack@flatrel{{-}{\sim}}}} \protected\def\cong{ \mathrel{\mathpalette\stack@flatrel{{=}{\sim}}}} \fi \protected\def\models{\mathrel{|}\joinrel\mathrel{=}} % \end{macrocode} % New definition for |\not|. We define it to accept a |#1| argument, which we store in an |\hbox| in the appropriate style. Then we typeset a |/| halfway across the distance of the |\hbox| and the |\hbox| itself. This approach manually positions the |/| halfway across the |#1| subformula instead of using a character that appears to the right of a slim bounding box as in traditional \TeX. In case any users want to access the old |\not| definition, we save it as |\negslash|. % \begin{macrocode} \let\negslash\not \protected\def\not##1{\mathrel{\mathchoice {\setbox\@tempboxa\hbox{$\displaystyle##1\m@th$} \hbox{\hb@xt@\wd\@tempboxa{\hss$\displaystyle/\m@th$\hss} \llap{\box\@tempboxa}}} {\setbox\@tempboxa\hbox{$\textstyle##1\m@th$} \hbox{\hb@xt@\wd\@tempboxa{\hss$\textstyle/\m@th$\hss} \llap{\box\@tempboxa}}} {\setbox\@tempboxa\hbox{$\scriptstyle##1\m@th$} \hbox{\hb@xt@\wd\@tempboxa{\hss$\scriptstyle/\m@th$\hss} \llap{\box\@tempboxa}}} {\setbox\@tempboxa\hbox{$\scriptscriptstyle##1\m@th$} \hbox{\hb@xt@\wd\@tempboxa{\hss{$\scriptscriptstyle/ \m@th$\hss} \llap{\box\@tempboxa}}}}}}} % \end{macrocode} % Set extended symbols. % \begin{macrocode} \def\M@extsymbols@set{ \edef\M@extsymbols@id{M\@tempc-\M@extsymbolsshape} \let\angle\@undefined \let\simeq\@undefined \let\sqsubset\@undefined \let\sqsupset\@undefined \let\bowtie\@undefined \let\doteq\@undefined \let\neq\@undefined \M@sym@{\wp} {\mathord}{\M@extsymbols@id}{"2118} \M@sym@{\ell} {\mathord}{\M@extsymbols@id}{"2113} \M@sym@{\forall} {\mathord}{\M@extsymbols@id}{"2200} \M@sym@{\exists} {\mathord}{\M@extsymbols@id}{"2203} \M@sym@{\emptyset} {\mathord}{\M@extsymbols@id}{"2205} \M@sym@{\in} {\mathord}{\M@extsymbols@id}{"2208} \M@sym@{\ni} {\mathord}{\M@extsymbols@id}{"220B} \M@sym@{\mp} {\mathord}{\M@extsymbols@id}{"2213} \M@sym@{\angle} {\mathord}{\M@extsymbols@id}{"2220} \M@sym@{\top} {\mathord}{\M@extsymbols@id}{"22A4} \M@sym@{\bot} {\mathord}{\M@extsymbols@id}{"22A5} \M@sym@{\vdash} {\mathord}{\M@extsymbols@id}{"22A2} \M@sym@{\dashv} {\mathord}{\M@extsymbols@id}{"22A3} \M@sym@{\flat} {\mathord}{\M@extsymbols@id}{"266D} \M@sym@{\natural} {\mathord}{\M@extsymbols@id}{"266E} \M@sym@{\sharp} {\mathord}{\M@extsymbols@id}{"266F} \M@sym@{\fflat} {\mathord}{\M@extsymbols@id}{"1D12B} \M@sym@{\ssharp} {\mathord}{\M@extsymbols@id}{"1D12A} \M@sym@{\bclubsuit} {\mathord}{\M@extsymbols@id}{"2663} \M@sym@{\bdiamondsuit} {\mathord}{\M@extsymbols@id}{"2666} \M@sym@{\bheartsuit} {\mathord}{\M@extsymbols@id}{"2665} \M@sym@{\bspadesuit} {\mathord}{\M@extsymbols@id}{"2660} \M@sym@{\wclubsuit} {\mathord}{\M@extsymbols@id}{"2667} \M@sym@{\wdiamondsuit} {\mathord}{\M@extsymbols@id}{"2662} \M@sym@{\wheartsuit} {\mathord}{\M@extsymbols@id}{"2661} \M@sym@{\wspadesuit} {\mathord}{\M@extsymbols@id}{"2664} \let\spadesuit\bspadesuit \let\heartsuit\wheartsuit \let\diamondsuit\wdiamondsuit \let\clubsuit\bclubsuit \M@sym@{\wedge} {\mathbin}{\M@extsymbols@id}{"2227} \M@sym@{\vee} {\mathbin}{\M@extsymbols@id}{"2228} \M@sym@{\cap} {\mathord}{\M@extsymbols@id}{"2229} \M@sym@{\cup} {\mathbin}{\M@extsymbols@id}{"222A} \M@sym@{\sqcap} {\mathbin}{\M@extsymbols@id}{"2293} \M@sym@{\sqcup} {\mathbin}{\M@extsymbols@id}{"2294} \M@sym@{\amalg} {\mathbin}{\M@extsymbols@id}{"2A3F} \M@sym@{\wr} {\mathbin}{\M@extsymbols@id}{"2240} \M@sym@{\ast} {\mathbin}{\M@extsymbols@id}{"2217} \M@sym@{\star} {\mathbin}{\M@extsymbols@id}{"22C6} \M@sym@{\diamond} {\mathbin}{\M@extsymbols@id}{"22C4} \M@sym@{\varcdot} {\mathbin}{\M@extsymbols@id}{"22C5} \M@sym@{\varsetminus} {\mathbin}{\M@extsymbols@id}{"2216} \M@sym@{\oplus} {\mathbin}{\M@extsymbols@id}{"2295} \M@sym@{\otimes} {\mathbin}{\M@extsymbols@id}{"2297} \M@sym@{\ominus} {\mathbin}{\M@extsymbols@id}{"2296} \M@sym@{\odiv} {\mathbin}{\M@extsymbols@id}{"2A38} \M@sym@{\oslash} {\mathbin}{\M@extsymbols@id}{"2298} \M@sym@{\odot} {\mathbin}{\M@extsymbols@id}{"2299} \M@sym@{\sqplus} {\mathbin}{\M@extsymbols@id}{"229E} \M@sym@{\sqtimes} {\mathbin}{\M@extsymbols@id}{"22A0} \M@sym@{\sqminus} {\mathbin}{\M@extsymbols@id}{"229F} \M@sym@{\sqdot} {\mathbin}{\M@extsymbols@id}{"22A1} \M@sym@{\in} {\mathrel}{\M@extsymbols@id}{"2208} \M@sym@{\ni} {\mathrel}{\M@extsymbols@id}{"220B} \M@sym@{\subset} {\mathrel}{\M@extsymbols@id}{"2282} \M@sym@{\supset} {\mathrel}{\M@extsymbols@id}{"2283} \M@sym@{\subseteq} {\mathrel}{\M@extsymbols@id}{"2286} \M@sym@{\supseteq} {\mathrel}{\M@extsymbols@id}{"2287} \M@sym@{\sqsubset} {\mathrel}{\M@extsymbols@id}{"228F} \M@sym@{\sqsupset} {\mathrel}{\M@extsymbols@id}{"2290} \M@sym@{\sqsubseteq} {\mathrel}{\M@extsymbols@id}{"2291} \M@sym@{\sqsupseteq} {\mathrel}{\M@extsymbols@id}{"2292} \M@sym@{\triangleleft} {\mathrel}{\M@extsymbols@id}{"22B2} \M@sym@{\triangleright} {\mathrel}{\M@extsymbols@id}{"22B3} \M@sym@{\trianglelefteq} {\mathrel}{\M@extsymbols@id}{"22B4} \M@sym@{\trianglerighteq} {\mathrel}{\M@extsymbols@id}{"22B5} \M@sym@{\propto} {\mathrel}{\M@extsymbols@id}{"221D} \M@sym@{\bowtie} {\mathrel}{\M@extsymbols@id}{"22C8} \M@sym@{\hourglass} {\mathrel}{\M@extsymbols@id}{"29D6} \M@sym@{\therefore} {\mathrel}{\M@extsymbols@id}{"2234} \M@sym@{\because} {\mathrel}{\M@extsymbols@id}{"2235} \M@sym@{\ratio} {\mathrel}{\M@extsymbols@id}{"2236} \M@sym@{\proportion} {\mathrel}{\M@extsymbols@id}{"2237} \M@sym@{\ll} {\mathrel}{\M@extsymbols@id}{"226A} \M@sym@{\gg} {\mathrel}{\M@extsymbols@id}{"226B} \M@sym@{\lll} {\mathrel}{\M@extsymbols@id}{"22D8} \M@sym@{\ggg} {\mathrel}{\M@extsymbols@id}{"22D9} \M@sym@{\leqq} {\mathrel}{\M@extsymbols@id}{"2266} \M@sym@{\geqq} {\mathrel}{\M@extsymbols@id}{"2267} \M@sym@{\lapprox} {\mathrel}{\M@extsymbols@id}{"2A85} \M@sym@{\gapprox} {\mathrel}{\M@extsymbols@id}{"2A86} \M@sym@{\simeq} {\mathrel}{\M@extsymbols@id}{"2243} \M@sym@{\eqsim} {\mathrel}{\M@extsymbols@id}{"2242} \M@sym@{\simeqq} {\mathrel}{\M@extsymbols@id}{"2245} \let\cong\simeqq \M@sym@{\approxeq} {\mathrel}{\M@extsymbols@id}{"224A} \M@sym@{\sssim} {\mathrel}{\M@extsymbols@id}{"224B} \M@sym@{\seq} {\mathrel}{\M@extsymbols@id}{"224C} \M@sym@{\doteq} {\mathrel}{\M@extsymbols@id}{"2250} \M@sym@{\coloneq} {\mathrel}{\M@extsymbols@id}{"2254} \M@sym@{\eqcolon} {\mathrel}{\M@extsymbols@id}{"2255} \M@sym@{\ringeq} {\mathrel}{\M@extsymbols@id}{"2257} \M@sym@{\arceq} {\mathrel}{\M@extsymbols@id}{"2258} \M@sym@{\wedgeeq} {\mathrel}{\M@extsymbols@id}{"2259} \M@sym@{\veeeq} {\mathrel}{\M@extsymbols@id}{"225A} \M@sym@{\stareq} {\mathrel}{\M@extsymbols@id}{"225B} \M@sym@{\triangleeq} {\mathrel}{\M@extsymbols@id}{"225C} \M@sym@{\defeq} {\mathrel}{\M@extsymbols@id}{"225D} \M@sym@{\qeq} {\mathrel}{\M@extsymbols@id}{"225F} \M@sym@{\lsim} {\mathrel}{\M@extsymbols@id}{"2272} \M@sym@{\gsim} {\mathrel}{\M@extsymbols@id}{"2273} \M@sym@{\prec} {\mathrel}{\M@extsymbols@id}{"227A} \M@sym@{\succ} {\mathrel}{\M@extsymbols@id}{"227B} \M@sym@{\preceq} {\mathrel}{\M@extsymbols@id}{"227C} \M@sym@{\succeq} {\mathrel}{\M@extsymbols@id}{"227D} \M@sym@{\preceqq} {\mathrel}{\M@extsymbols@id}{"2AB3} \M@sym@{\succeqq} {\mathrel}{\M@extsymbols@id}{"2AB4} \M@sym@{\precsim} {\mathrel}{\M@extsymbols@id}{"227E} \M@sym@{\succsim} {\mathrel}{\M@extsymbols@id}{"227F} \M@sym@{\precapprox} {\mathrel}{\M@extsymbols@id}{"2AB7} \M@sym@{\succapprox} {\mathrel}{\M@extsymbols@id}{"2AB8} \M@sym@{\precprec} {\mathrel}{\M@extsymbols@id}{"2ABB} \M@sym@{\succsucc} {\mathrel}{\M@extsymbols@id}{"2ABC} \M@sym@{\asymp} {\mathrel}{\M@extsymbols@id}{"224D} \M@sym@{\nin} {\mathrel}{\M@extsymbols@id}{"2209} \M@sym@{\nni} {\mathrel}{\M@extsymbols@id}{"220C} \M@sym@{\nsubset} {\mathrel}{\M@extsymbols@id}{"2284} \M@sym@{\nsupset} {\mathrel}{\M@extsymbols@id}{"2285} \M@sym@{\nsubseteq} {\mathrel}{\M@extsymbols@id}{"2288} \M@sym@{\nsupseteq} {\mathrel}{\M@extsymbols@id}{"2289} \M@sym@{\subsetneq} {\mathrel}{\M@extsymbols@id}{"228A} \M@sym@{\supsetneq} {\mathrel}{\M@extsymbols@id}{"228B} \M@sym@{\nsqsubseteq} {\mathrel}{\M@extsymbols@id}{"22E2} \M@sym@{\nsqsupseteq} {\mathrel}{\M@extsymbols@id}{"22E3} \M@sym@{\sqsubsetneq} {\mathrel}{\M@extsymbols@id}{"22E4} \M@sym@{\sqsupsetneq} {\mathrel}{\M@extsymbols@id}{"22E5} \M@sym@{\neq} {\mathrel}{\M@extsymbols@id}{"2260} \M@sym@{\nl} {\mathrel}{\M@extsymbols@id}{"226E} \M@sym@{\nleq} {\mathrel}{\M@extsymbols@id}{"2270} \M@sym@{\ngeq} {\mathrel}{\M@extsymbols@id}{"2271} \M@sym@{\lneq} {\mathrel}{\M@extsymbols@id}{"2A87} \M@sym@{\gneq} {\mathrel}{\M@extsymbols@id}{"2A88} \M@sym@{\lneqq} {\mathrel}{\M@extsymbols@id}{"2268} \M@sym@{\gneqq} {\mathrel}{\M@extsymbols@id}{"2269} \M@sym@{\ntriangleleft} {\mathrel}{\M@extsymbols@id}{"22EA} \M@sym@{\ntriangleright} {\mathrel}{\M@extsymbols@id}{"22EB} \M@sym@{\ntrianglelefteq} {\mathrel}{\M@extsymbols@id}{"22EC} \M@sym@{\ntrianglerighteq}{\mathrel}{\M@extsymbols@id}{"22ED} \M@sym@{\nsim} {\mathrel}{\M@extsymbols@id}{"2241} \M@sym@{\napprox} {\mathrel}{\M@extsymbols@id}{"2249} \M@sym@{\nsimeq} {\mathrel}{\M@extsymbols@id}{"2244} \M@sym@{\nsimeqq} {\mathrel}{\M@extsymbols@id}{"2247} \M@sym@{\simneqq} {\mathrel}{\M@extsymbols@id}{"2246} \M@sym@{\nlsim} {\mathrel}{\M@extsymbols@id}{"2274} \M@sym@{\ngsim} {\mathrel}{\M@extsymbols@id}{"2275} \M@sym@{\lnsim} {\mathrel}{\M@extsymbols@id}{"22E6} \M@sym@{\gnsim} {\mathrel}{\M@extsymbols@id}{"22E7} \M@sym@{\lnapprox} {\mathrel}{\M@extsymbols@id}{"2A89} \M@sym@{\gnapprox} {\mathrel}{\M@extsymbols@id}{"2A8A} \M@sym@{\nprec} {\mathrel}{\M@extsymbols@id}{"2280} \M@sym@{\nsucc} {\mathrel}{\M@extsymbols@id}{"2281} \M@sym@{\npreceq} {\mathrel}{\M@extsymbols@id}{"22E0} \M@sym@{\nsucceq} {\mathrel}{\M@extsymbols@id}{"22E1} \M@sym@{\precneq} {\mathrel}{\M@extsymbols@id}{"2AB1} \M@sym@{\succneq} {\mathrel}{\M@extsymbols@id}{"2AB2} \M@sym@{\precneqq} {\mathrel}{\M@extsymbols@id}{"2AB5} \M@sym@{\succneqq} {\mathrel}{\M@extsymbols@id}{"2AB6} \M@sym@{\precnsim} {\mathrel}{\M@extsymbols@id}{"22E8} \M@sym@{\succnsim} {\mathrel}{\M@extsymbols@id}{"22E9} \M@sym@{\precnapprox} {\mathrel}{\M@extsymbols@id}{"2AB9} \M@sym@{\succnapprox} {\mathrel}{\M@extsymbols@id}{"2ABA} \M@sym@{\nequiv} {\mathrel}{\M@extsymbols@id}{"2262} % \end{macrocode} % The \textsf{math-operator} package renames |\Re| and |\Im| to |\varRe| and |\varIm|. To make \textsf{mathfont} compatible with that package, we test whether these macros contain |mathchar| in their definitions before redefining. First |\Re|. % \begin{macrocode} \expanded{\noexpand\in@{\expandafter\@gobble\string\mathchar} {\meaning\Re}} \ifin@ \M@sym@{\Re}{\mathord}{\M@extsymbols@id}{"211C} \else \expanded{\noexpand\in@{\expandafter\@gobble\string\mathchar} {\meaning\varRe}} \ifin@ \M@sym@{\varRe}{\mathord}{\M@extsymbols@id}{"211C} \fi \fi % \end{macrocode} % And |\Im|. % \begin{macrocode} \expanded{\noexpand\in@{\expandafter\@gobble\string\mathchar} {\meaning\Im}} \ifin@ \M@sym@{\Im}{\mathord}{\M@extsymbols@id}{"2111} \else \expanded{\noexpand\in@{\expandafter\@gobble\string\mathchar} {\meaning\varIm}} \ifin@ \M@sym@{\varIm}{\mathord}{\M@extsymbols@id}{"2111} \fi \fi % \end{macrocode} % We handle |\ng| specially. The \LaTeX\ kernel defines |\ng| as a text symbol, so we define |\mathng| like for |\$|, etc. % \begin{macrocode} \let\textng\ng \M@sym@{\mathng}{\mathrel}{\M@extsymbols@id}{"226F} \protected\def\ng{\ifmmode\mathng\else\textng\fi} % \end{macrocode} % If we're not adjusting the font, we declare |\nabla| here. % \begin{macrocode} \ifM@adjust@font\else \M@sym@{\nabla}{\mathord}{\M@extsymbols@id}{"2207} \fi} % \end{macrocode} % Set arrows. % \begin{macrocode} \def\M@arrows@set{ \edef\M@arrows@id{M\@tempc-\M@arrowsshape} \let\uparrow\@undefined \let\Uparrow\@undefined \let\downarrow\@undefined \let\Downarrow\@undefined \let\updownarrow\@undefined \let\Updownarrow\@undefined \let\longrightarrow\@undefined \let\longleftarrow\@undefined \let\longleftrightarrow\@undefined \let\hookrightarrow\@undefined \let\hookleftarrow\@undefined \let\Longrightarrow\@undefined \let\Longleftarrow\@undefined \let\Longleftrightarrow\@undefined \let\rightleftharpoons\@undefined \M@sym@{\rightarrow} {\mathrel}{\M@arrows@id}{"2192} \let\to\rightarrow \M@sym@{\nrightarrow} {\mathrel}{\M@arrows@id}{"219B} \M@sym@{\Rightarrow} {\mathrel}{\M@arrows@id}{"21D2} \M@sym@{\nRightarrow} {\mathrel}{\M@arrows@id}{"21CF} \M@sym@{\Rrightarrow} {\mathrel}{\M@arrows@id}{"21DB} \M@sym@{\longrightarrow} {\mathrel}{\M@arrows@id}{"27F6} \M@sym@{\Longrightarrow} {\mathrel}{\M@arrows@id}{"27F9} \M@sym@{\rightbararrow} {\mathrel}{\M@arrows@id}{"21A6} \let\mapsto\rightbararrow \M@sym@{\Rightbararrow} {\mathrel}{\M@arrows@id}{"2907} \M@sym@{\longrightbararrow} {\mathrel}{\M@arrows@id}{"27FC} \let\longmapsto\longrightbararrow \M@sym@{\Longrightbararrow} {\mathrel}{\M@arrows@id}{"27FE} \M@sym@{\hookrightarrow} {\mathrel}{\M@arrows@id}{"21AA} \M@sym@{\rightdasharrow} {\mathrel}{\M@arrows@id}{"21E2} \M@sym@{\rightharpoonup} {\mathrel}{\M@arrows@id}{"21C0} \M@sym@{\rightharpoondown} {\mathrel}{\M@arrows@id}{"21C1} \M@sym@{\rightarrowtail} {\mathrel}{\M@arrows@id}{"21A3} \M@sym@{\rightoplusarrow} {\mathrel}{\M@arrows@id}{"27F4} \M@sym@{\rightwavearrow} {\mathrel}{\M@arrows@id}{"219D} \M@sym@{\rightsquigarrow} {\mathrel}{\M@arrows@id}{"21DD} \M@sym@{\longrightsquigarrow} {\mathrel}{\M@arrows@id}{"27FF} \M@sym@{\looparrowright} {\mathrel}{\M@arrows@id}{"21AC} \M@sym@{\curvearrowright} {\mathrel}{\M@arrows@id}{"293B} \M@sym@{\circlearrowright} {\mathrel}{\M@arrows@id}{"21BB} \M@sym@{\twoheadrightarrow} {\mathrel}{\M@arrows@id}{"21A0} \M@sym@{\rightarrowtobar} {\mathrel}{\M@arrows@id}{"21E5} \M@sym@{\rightwhitearrow} {\mathrel}{\M@arrows@id}{"21E8} \M@sym@{\rightrightarrows} {\mathrel}{\M@arrows@id}{"21C9} \M@sym@{\rightrightrightarrows}{\mathrel}{\M@arrows@id}{"21F6} \M@sym@{\leftarrow} {\mathrel}{\M@arrows@id}{"2190} \let\from\leftarrow \M@sym@{\nleftarrow} {\mathrel}{\M@arrows@id}{"219A} \M@sym@{\Leftarrow} {\mathrel}{\M@arrows@id}{"21D0} \M@sym@{\nLeftarrow} {\mathrel}{\M@arrows@id}{"21CD} \M@sym@{\Lleftarrow} {\mathrel}{\M@arrows@id}{"21DA} \M@sym@{\longleftarrow} {\mathrel}{\M@arrows@id}{"27F5} \M@sym@{\Longleftarrow} {\mathrel}{\M@arrows@id}{"27F8} \M@sym@{\leftbararrow} {\mathrel}{\M@arrows@id}{"21A4} \let\mapsfrom\leftbararrow \M@sym@{\Leftbararrow} {\mathrel}{\M@arrows@id}{"2906} \M@sym@{\longleftbararrow} {\mathrel}{\M@arrows@id}{"27FB} \let\longmapsfrom\longleftbararrow \M@sym@{\Longleftbararrow} {\mathrel}{\M@arrows@id}{"27FD} \M@sym@{\hookleftarrow} {\mathrel}{\M@arrows@id}{"21A9} \M@sym@{\leftdasharrow} {\mathrel}{\M@arrows@id}{"21E0} \M@sym@{\leftharpoonup} {\mathrel}{\M@arrows@id}{"21BC} \M@sym@{\leftharpoondown} {\mathrel}{\M@arrows@id}{"21BD} \M@sym@{\leftarrowtail} {\mathrel}{\M@arrows@id}{"21A2} \M@sym@{\leftoplusarrow} {\mathrel}{\M@arrows@id}{"2B32} \M@sym@{\leftwavearrow} {\mathrel}{\M@arrows@id}{"219C} \M@sym@{\leftsquigarrow} {\mathrel}{\M@arrows@id}{"21DC} \M@sym@{\longleftsquigarrow} {\mathrel}{\M@arrows@id}{"2B33} \M@sym@{\looparrowleft} {\mathrel}{\M@arrows@id}{"21AB} \M@sym@{\curvearrowleft} {\mathrel}{\M@arrows@id}{"293A} \M@sym@{\circlearrowleft} {\mathrel}{\M@arrows@id}{"21BA} \M@sym@{\twoheadleftarrow} {\mathrel}{\M@arrows@id}{"219E} \M@sym@{\leftarrowtobar} {\mathrel}{\M@arrows@id}{"21E4} \M@sym@{\leftwhitearrow} {\mathrel}{\M@arrows@id}{"21E6} \M@sym@{\leftleftarrows} {\mathrel}{\M@arrows@id}{"21C7} \M@sym@{\leftleftleftarrows} {\mathrel}{\M@arrows@id}{"2B31} \M@sym@{\leftrightarrow} {\mathrel}{\M@arrows@id}{"2194} \M@sym@{\Leftrightarrow} {\mathrel}{\M@arrows@id}{"21D4} \M@sym@{\nLeftrightarrow} {\mathrel}{\M@arrows@id}{"21CE} \M@sym@{\longleftrightarrow} {\mathrel}{\M@arrows@id}{"27F7} \M@sym@{\Longleftrightarrow} {\mathrel}{\M@arrows@id}{"27FA} \M@sym@{\leftrightwavearrow} {\mathrel}{\M@arrows@id}{"21AD} \M@sym@{\leftrightarrows} {\mathrel}{\M@arrows@id}{"21C6} \M@sym@{\leftrightharpoons} {\mathrel}{\M@arrows@id}{"21CB} \M@sym@{\leftrightarrowstobar} {\mathrel}{\M@arrows@id}{"21B9} \M@sym@{\rightleftarrows} {\mathrel}{\M@arrows@id}{"21C4} \M@sym@{\rightleftharpoons} {\mathrel}{\M@arrows@id}{"21CC} \M@sym@{\uparrow} {\mathrel}{\M@arrows@id}{"2191} \M@sym@{\Uparrow} {\mathrel}{\M@arrows@id}{"21D1} \M@sym@{\Uuparrow} {\mathrel}{\M@arrows@id}{"290A} \M@sym@{\upbararrow} {\mathrel}{\M@arrows@id}{"21A5} \M@sym@{\updasharrow} {\mathrel}{\M@arrows@id}{"21E1} \M@sym@{\upharpoonleft} {\mathrel}{\M@arrows@id}{"21BF} \M@sym@{\upharpoonright} {\mathrel}{\M@arrows@id}{"21BE} \M@sym@{\twoheaduparrow} {\mathrel}{\M@arrows@id}{"219F} \M@sym@{\uparrowtobar} {\mathrel}{\M@arrows@id}{"2912} \M@sym@{\upwhitearrow} {\mathrel}{\M@arrows@id}{"21E7} \M@sym@{\upwhitebararrow} {\mathrel}{\M@arrows@id}{"21EA} \M@sym@{\upuparrows} {\mathrel}{\M@arrows@id}{"21C8} \M@sym@{\downarrow} {\mathrel}{\M@arrows@id}{"2193} \M@sym@{\Downarrow} {\mathrel}{\M@arrows@id}{"21D3} \M@sym@{\Ddownarrow} {\mathrel}{\M@arrows@id}{"290B} \M@sym@{\downbararrow} {\mathrel}{\M@arrows@id}{"21A7} \M@sym@{\downdasharrow} {\mathrel}{\M@arrows@id}{"21E3} \M@sym@{\zigzagarrow} {\mathrel}{\M@arrows@id}{"21AF} \let\lightningboltarrow\zigzagarrow \M@sym@{\downharpoonleft} {\mathrel}{\M@arrows@id}{"21C3} \M@sym@{\downharpoonright} {\mathrel}{\M@arrows@id}{"21C2} \M@sym@{\twoheaddownarrow} {\mathrel}{\M@arrows@id}{"21A1} \M@sym@{\downarrowtobar} {\mathrel}{\M@arrows@id}{"2913} \M@sym@{\downwhitearrow} {\mathrel}{\M@arrows@id}{"21E9} \M@sym@{\downdownarrows} {\mathrel}{\M@arrows@id}{"21CA} \M@sym@{\updownarrow} {\mathrel}{\M@arrows@id}{"2195} \M@sym@{\Updownarrow} {\mathrel}{\M@arrows@id}{"21D5} \M@sym@{\updownarrows} {\mathrel}{\M@arrows@id}{"21C5} \M@sym@{\downuparrows} {\mathrel}{\M@arrows@id}{"21F5} \M@sym@{\updownharpoons} {\mathrel}{\M@arrows@id}{"296E} \M@sym@{\downupharpoons} {\mathrel}{\M@arrows@id}{"296F} \M@sym@{\nearrow} {\mathrel}{\M@arrows@id}{"2197} \M@sym@{\Nearrow} {\mathrel}{\M@arrows@id}{"21D7} \M@sym@{\nwarrow} {\mathrel}{\M@arrows@id}{"2196} \M@sym@{\Nwarrow} {\mathrel}{\M@arrows@id}{"21D6} \M@sym@{\searrow} {\mathrel}{\M@arrows@id}{"2198} \M@sym@{\Searrow} {\mathrel}{\M@arrows@id}{"21D8} \M@sym@{\swarrow} {\mathrel}{\M@arrows@id}{"2199} \M@sym@{\Swarrow} {\mathrel}{\M@arrows@id}{"21D9} \M@sym@{\nwsearrow} {\mathrel}{\M@arrows@id}{"2921} \M@sym@{\neswarrow} {\mathrel}{\M@arrows@id}{"2922} \M@sym@{\lcirclearrow} {\mathrel}{\M@arrows@id}{"27F2} \M@sym@{\rcirclearrow} {\mathrel}{\M@arrows@id}{"27F3} % \end{macrocode} % The commands |\relbar| and |\Relbar| produce a smashed minus and an equals sign respectively. They are helper control sequences that \LaTeX\ uses to create other arrows. We have a small issue with \textsf{amsmath} because in \XeTeX\ and Lua\TeX, \textsf{amsmath} defines |\relbar| and |\Relbar| in terms of the |\Umathcodes| of the minus and equals signs respectively. That is a good approach in general, but it doesn't work when a package like \textsf{mathfont} allows users to pick different fonts for symbols and arrows. We really want |\relbar| and |\Relbar| to come from the |arrows| font, so our approach is to define the control sequences now and then redefine |\AtBeginDocument| if needed. % \begin{macrocode} \let\@relbar\@undefined \let\@Relbar\@undefined \M@sym@{\@relbar}{\mathbin}{\M@arrows@id}{"2212} \M@sym@{\@Relbar}{\mathrel}{\M@arrows@id}{"3D} \protected\def\relbar{\mathrel{\mathpalette\mathsm@sh\@relbar}} \protected\def\Relbar{\@Relbar} % \end{macrocode} % We redefine stuff if \textsf{amsmath} gets loaded after \textsf{mathfont}. % \begin{macrocode} \@ifpackageloaded{amsmath} {\relax}{ \let\@@relbar\relbar \let\@@Relbar\Relbar \AtBeginDocument{\@ifpackageloaded{amsmath}{ \let\relbar\@@relbar \let\Relbar\@@Relbar} {\relax}}}} % \end{macrocode} % Set blackboard bold letters and numbers. The alphanumeric keywords work a bit differently from the other font-setting commands. We define |\mathbb| here, which takes a single argument and is essentially a wrapper around |\M@bb@mathcodes|. That command changes the |\Umathcode|s of letters to the Unicode hex values of corresponding blackboard-bold characters, and throughout, |\M@bb@num| stores the family number of the sumbol font for the |bb| character class. In the definition of |\mathbb|, we use |\begingroup| and |\endgroup| to avoid creating unexpected atoms. The other alphanumeric keywords work similarly. % \begin{macrocode} \def\M@bb@set{ \protected\def\mathbb##1{\relax \ifmmode\else \M@HModeError\mathbb $ \fi \begingroup \M@bb@mathcodes ##1 \endgroup} \edef\M@bb@num{\number \csname symM\@tempc-\M@bbshape\endcsname} \protected\edef\M@bb@mathcodes{ \Umathcode`A=0+\M@bb@num"1D538\relax \Umathcode`B=0+\M@bb@num"1D539\relax \Umathcode`C=0+\M@bb@num"2102\relax \Umathcode`D=0+\M@bb@num"1D53B\relax \Umathcode`E=0+\M@bb@num"1D53C\relax \Umathcode`F=0+\M@bb@num"1D53D\relax \Umathcode`G=0+\M@bb@num"1D53E\relax \Umathcode`H=0+\M@bb@num"210D\relax \Umathcode`I=0+\M@bb@num"1D540\relax \Umathcode`J=0+\M@bb@num"1D541\relax \Umathcode`K=0+\M@bb@num"1D542\relax \Umathcode`L=0+\M@bb@num"1D543\relax \Umathcode`M=0+\M@bb@num"1D544\relax \Umathcode`N=0+\M@bb@num"2115\relax \Umathcode`O=0+\M@bb@num"1D546\relax \Umathcode`P=0+\M@bb@num"2119\relax \Umathcode`Q=0+\M@bb@num"211A\relax \Umathcode`R=0+\M@bb@num"211D\relax \Umathcode`S=0+\M@bb@num"1D54A\relax \Umathcode`T=0+\M@bb@num"1D54B\relax \Umathcode`U=0+\M@bb@num"1D54C\relax \Umathcode`V=0+\M@bb@num"1D54D\relax \Umathcode`W=0+\M@bb@num"1D54E\relax \Umathcode`X=0+\M@bb@num"1D54F\relax \Umathcode`Y=0+\M@bb@num"1D550\relax \Umathcode`Z=0+\M@bb@num"2124\relax \Umathcode`a=0+\M@bb@num"1D552\relax \Umathcode`b=0+\M@bb@num"1D553\relax \Umathcode`c=0+\M@bb@num"1D554\relax \Umathcode`d=0+\M@bb@num"1D555\relax \Umathcode`e=0+\M@bb@num"1D556\relax \Umathcode`f=0+\M@bb@num"1D557\relax \Umathcode`g=0+\M@bb@num"1D558\relax \Umathcode`h=0+\M@bb@num"1D559\relax \Umathcode`i=0+\M@bb@num"1D55A\relax \Umathcode`j=0+\M@bb@num"1D55B\relax \Umathcode`k=0+\M@bb@num"1D55C\relax \Umathcode`l=0+\M@bb@num"1D55D\relax \Umathcode`m=0+\M@bb@num"1D55E\relax \Umathcode`n=0+\M@bb@num"1D55F\relax \Umathcode`o=0+\M@bb@num"1D560\relax \Umathcode`p=0+\M@bb@num"1D561\relax \Umathcode`q=0+\M@bb@num"1D562\relax \Umathcode`r=0+\M@bb@num"1D563\relax \Umathcode`s=0+\M@bb@num"1D564\relax \Umathcode`t=0+\M@bb@num"1D565\relax \Umathcode`u=0+\M@bb@num"1D566\relax \Umathcode`v=0+\M@bb@num"1D567\relax \Umathcode`w=0+\M@bb@num"1D568\relax \Umathcode`x=0+\M@bb@num"1D569\relax \Umathcode`y=0+\M@bb@num"1D56A\relax \Umathcode`z=0+\M@bb@num"1D56B\relax \Umathcode`0=0+\M@bb@num"1D7D8\relax \Umathcode`1=0+\M@bb@num"1D7D9\relax \Umathcode`2=0+\M@bb@num"1D7DA\relax \Umathcode`3=0+\M@bb@num"1D7DB\relax \Umathcode`4=0+\M@bb@num"1D7DC\relax \Umathcode`5=0+\M@bb@num"1D7DD\relax \Umathcode`6=0+\M@bb@num"1D7DE\relax \Umathcode`7=0+\M@bb@num"1D7DF\relax \Umathcode`8=0+\M@bb@num"1D7E0\relax \Umathcode`9=0+\M@bb@num"1D7E1\relax}} % \end{macrocode} % Set caligraphic letters. % \begin{macrocode} \def\M@cal@set{ \protected\def\mathcal##1{\relax \ifmmode\else \M@HModeError\mathcal $ \fi \begingroup \M@cal@mathcodes ##1 \endgroup} \edef\M@cal@num{\number \csname symM\@tempc-\M@calshape\endcsname} \protected\edef\M@cal@mathcodes{ \Umathcode`A=0+\M@cal@num"1D49C\relax \Umathcode`B=0+\M@cal@num"212C\relax \Umathcode`C=0+\M@cal@num"1D49E\relax \Umathcode`D=0+\M@cal@num"1D49F\relax \Umathcode`E=0+\M@cal@num"2130\relax \Umathcode`F=0+\M@cal@num"2131\relax \Umathcode`G=0+\M@cal@num"1D4A2\relax \Umathcode`H=0+\M@cal@num"210B\relax \Umathcode`I=0+\M@cal@num"2110\relax \Umathcode`J=0+\M@cal@num"1D4A5\relax \Umathcode`K=0+\M@cal@num"1D4A6\relax \Umathcode`L=0+\M@cal@num"2112\relax \Umathcode`M=0+\M@cal@num"2133\relax \Umathcode`N=0+\M@cal@num"1D4A9\relax \Umathcode`O=0+\M@cal@num"1D4AA\relax \Umathcode`P=0+\M@cal@num"1D4AB\relax \Umathcode`Q=0+\M@cal@num"1D4AC\relax \Umathcode`R=0+\M@cal@num"211B\relax \Umathcode`S=0+\M@cal@num"1D4AE\relax \Umathcode`T=0+\M@cal@num"1D4AF\relax \Umathcode`U=0+\M@cal@num"1D4B0\relax \Umathcode`V=0+\M@cal@num"1D4B1\relax \Umathcode`W=0+\M@cal@num"1D4B2\relax \Umathcode`X=0+\M@cal@num"1D4B3\relax \Umathcode`Y=0+\M@cal@num"1D4B4\relax \Umathcode`Z=0+\M@cal@num"1D4B5\relax \Umathcode`a=0+\M@cal@num"1D4B6\relax \Umathcode`b=0+\M@cal@num"1D4B7\relax \Umathcode`c=0+\M@cal@num"1D4B8\relax \Umathcode`d=0+\M@cal@num"1D4B9\relax \Umathcode`e=0+\M@cal@num"212F\relax \Umathcode`f=0+\M@cal@num"1D4BB\relax \Umathcode`g=0+\M@cal@num"210A\relax \Umathcode`h=0+\M@cal@num"1D4BD\relax \Umathcode`i=0+\M@cal@num"1D4BE\relax \Umathcode`j=0+\M@cal@num"1D4BF\relax \Umathcode`k=0+\M@cal@num"1D4C0\relax \Umathcode`l=0+\M@cal@num"1D4C1\relax \Umathcode`m=0+\M@cal@num"1D4C2\relax \Umathcode`n=0+\M@cal@num"1D4C3\relax \Umathcode`o=0+\M@cal@num"2134\relax \Umathcode`p=0+\M@cal@num"1D4C5\relax \Umathcode`q=0+\M@cal@num"1D4C6\relax \Umathcode`r=0+\M@cal@num"1D4C7\relax \Umathcode`s=0+\M@cal@num"1D4C8\relax \Umathcode`t=0+\M@cal@num"1D4C9\relax \Umathcode`u=0+\M@cal@num"1D4CA\relax \Umathcode`v=0+\M@cal@num"1D4CB\relax \Umathcode`w=0+\M@cal@num"1D4CC\relax \Umathcode`x=0+\M@cal@num"1D4CD\relax \Umathcode`y=0+\M@cal@num"1D4CE\relax \Umathcode`z=0+\M@cal@num"1D4CF\relax}} % \end{macrocode} % Set fraktur letters. % \begin{macrocode} \def\M@frak@set{ \protected\def\mathfrak##1{\relax \ifmmode\else \M@HModeError\mathfrak $ \fi \begingroup \M@frak@mathcodes ##1 \endgroup} \edef\M@frak@num{\number \csname symM\@tempc-\M@frakshape\endcsname} \protected\edef\M@frak@mathcodes{ \Umathcode`A=0+\M@frak@num"1D504\relax \Umathcode`B=0+\M@frak@num"1D505\relax \Umathcode`C=0+\M@frak@num"212D\relax \Umathcode`D=0+\M@frak@num"1D507\relax \Umathcode`E=0+\M@frak@num"1D508\relax \Umathcode`F=0+\M@frak@num"1D509\relax \Umathcode`G=0+\M@frak@num"1D50A\relax \Umathcode`H=0+\M@frak@num"210C\relax \Umathcode`I=0+\M@frak@num"2111\relax \Umathcode`J=0+\M@frak@num"1D50D\relax \Umathcode`K=0+\M@frak@num"1D50E\relax \Umathcode`L=0+\M@frak@num"1D50F\relax \Umathcode`M=0+\M@frak@num"1D510\relax \Umathcode`N=0+\M@frak@num"1D511\relax \Umathcode`O=0+\M@frak@num"1D512\relax \Umathcode`P=0+\M@frak@num"1D513\relax \Umathcode`Q=0+\M@frak@num"1D514\relax \Umathcode`R=0+\M@frak@num"211C\relax \Umathcode`S=0+\M@frak@num"1D516\relax \Umathcode`T=0+\M@frak@num"1D517\relax \Umathcode`U=0+\M@frak@num"1D518\relax \Umathcode`V=0+\M@frak@num"1D519\relax \Umathcode`W=0+\M@frak@num"1D51A\relax \Umathcode`X=0+\M@frak@num"1D51B\relax \Umathcode`Y=0+\M@frak@num"1D51C\relax \Umathcode`Z=0+\M@frak@num"2128\relax \Umathcode`a=0+\M@frak@num"1D51E\relax \Umathcode`b=0+\M@frak@num"1D51F\relax \Umathcode`c=0+\M@frak@num"1D520\relax \Umathcode`d=0+\M@frak@num"1D521\relax \Umathcode`e=0+\M@frak@num"1D522\relax \Umathcode`f=0+\M@frak@num"1D523\relax \Umathcode`g=0+\M@frak@num"1D524\relax \Umathcode`h=0+\M@frak@num"1D525\relax \Umathcode`i=0+\M@frak@num"1D526\relax \Umathcode`j=0+\M@frak@num"1D527\relax \Umathcode`k=0+\M@frak@num"1D528\relax \Umathcode`l=0+\M@frak@num"1D529\relax \Umathcode`m=0+\M@frak@num"1D52A\relax \Umathcode`n=0+\M@frak@num"1D52B\relax \Umathcode`o=0+\M@frak@num"1D52C\relax \Umathcode`p=0+\M@frak@num"1D52D\relax \Umathcode`q=0+\M@frak@num"1D52E\relax \Umathcode`r=0+\M@frak@num"1D52F\relax \Umathcode`s=0+\M@frak@num"1D530\relax \Umathcode`t=0+\M@frak@num"1D531\relax \Umathcode`u=0+\M@frak@num"1D532\relax \Umathcode`v=0+\M@frak@num"1D533\relax \Umathcode`w=0+\M@frak@num"1D534\relax \Umathcode`x=0+\M@frak@num"1D535\relax \Umathcode`y=0+\M@frak@num"1D536\relax \Umathcode`z=0+\M@frak@num"1D537\relax}} % \end{macrocode} % Set bold caligraphic letters. % \begin{macrocode} \def\M@bcal@set{ \protected\def\mathbcal##1{\relax \ifmmode\else \M@HModeError\mathbcal $ \fi \begingroup \M@bcal@mathcodes ##1 \endgroup} \edef\M@bcal@num{\number \csname symM\@tempc-\M@bcalshape\endcsname} \protected\edef\M@bcal@mathcodes{ \Umathcode`A=0+\M@bcal@num"1D4D0\relax \Umathcode`B=0+\M@bcal@num"1D4D1\relax \Umathcode`C=0+\M@bcal@num"1D4D2\relax \Umathcode`D=0+\M@bcal@num"1D4D3\relax \Umathcode`E=0+\M@bcal@num"1D4D4\relax \Umathcode`F=0+\M@bcal@num"1D4D5\relax \Umathcode`G=0+\M@bcal@num"1D4D6\relax \Umathcode`H=0+\M@bcal@num"1D4D7\relax \Umathcode`I=0+\M@bcal@num"1D4D8\relax \Umathcode`J=0+\M@bcal@num"1D4D9\relax \Umathcode`K=0+\M@bcal@num"1D4DA\relax \Umathcode`L=0+\M@bcal@num"1D4DB\relax \Umathcode`M=0+\M@bcal@num"1D4DC\relax \Umathcode`N=0+\M@bcal@num"1D4DD\relax \Umathcode`O=0+\M@bcal@num"1D4DE\relax \Umathcode`P=0+\M@bcal@num"1D4DF\relax \Umathcode`Q=0+\M@bcal@num"1D4E0\relax \Umathcode`R=0+\M@bcal@num"1D4E1\relax \Umathcode`S=0+\M@bcal@num"1D4E2\relax \Umathcode`T=0+\M@bcal@num"1D4E3\relax \Umathcode`U=0+\M@bcal@num"1D4E4\relax \Umathcode`V=0+\M@bcal@num"1D4E5\relax \Umathcode`W=0+\M@bcal@num"1D4E6\relax \Umathcode`X=0+\M@bcal@num"1D4E7\relax \Umathcode`Y=0+\M@bcal@num"1D4E8\relax \Umathcode`Z=0+\M@bcal@num"1D4E9\relax \Umathcode`a=0+\M@bcal@num"1D4EA\relax \Umathcode`b=0+\M@bcal@num"1D4EB\relax \Umathcode`c=0+\M@bcal@num"1D4EC\relax \Umathcode`d=0+\M@bcal@num"1D4ED\relax \Umathcode`e=0+\M@bcal@num"1D4EE\relax \Umathcode`f=0+\M@bcal@num"1D4EF\relax \Umathcode`g=0+\M@bcal@num"1D4F0\relax \Umathcode`h=0+\M@bcal@num"1D4F1\relax \Umathcode`i=0+\M@bcal@num"1D4F2\relax \Umathcode`j=0+\M@bcal@num"1D4F3\relax \Umathcode`k=0+\M@bcal@num"1D4F4\relax \Umathcode`l=0+\M@bcal@num"1D4F5\relax \Umathcode`m=0+\M@bcal@num"1D4F6\relax \Umathcode`n=0+\M@bcal@num"1D4F7\relax \Umathcode`o=0+\M@bcal@num"1D4F8\relax \Umathcode`p=0+\M@bcal@num"1D4F9\relax \Umathcode`q=0+\M@bcal@num"1D4FA\relax \Umathcode`r=0+\M@bcal@num"1D4FB\relax \Umathcode`s=0+\M@bcal@num"1D4FC\relax \Umathcode`t=0+\M@bcal@num"1D4FD\relax \Umathcode`u=0+\M@bcal@num"1D4FE\relax \Umathcode`v=0+\M@bcal@num"1D4FF\relax \Umathcode`w=0+\M@bcal@num"1D500\relax \Umathcode`x=0+\M@bcal@num"1D501\relax \Umathcode`y=0+\M@bcal@num"1D502\relax \Umathcode`z=0+\M@bcal@num"1D503\relax}} % \end{macrocode} % Set bold fraktur letters. % \begin{macrocode} \def\M@bfrak@set{ \protected\def\mathbfrak##1{\relax \ifmmode\else \M@HModeError\mathbfrak $ \fi \begingroup \M@bfrak@mathcodes ##1 \endgroup} \edef\M@bfrak@num{\number \csname symM\@tempc-\M@bfrakshape\endcsname} \protected\edef\M@bfrak@mathcodes{ \Umathcode`A=0+\M@bfrak@num"1D56C\relax \Umathcode`B=0+\M@bfrak@num"1D56D\relax \Umathcode`C=0+\M@bfrak@num"1D56E\relax \Umathcode`D=0+\M@bfrak@num"1D56F\relax \Umathcode`E=0+\M@bfrak@num"1D570\relax \Umathcode`F=0+\M@bfrak@num"1D571\relax \Umathcode`G=0+\M@bfrak@num"1D572\relax \Umathcode`H=0+\M@bfrak@num"1D573\relax \Umathcode`I=0+\M@bfrak@num"1D574\relax \Umathcode`J=0+\M@bfrak@num"1D575\relax \Umathcode`K=0+\M@bfrak@num"1D576\relax \Umathcode`L=0+\M@bfrak@num"1D577\relax \Umathcode`M=0+\M@bfrak@num"1D578\relax \Umathcode`N=0+\M@bfrak@num"1D579\relax \Umathcode`O=0+\M@bfrak@num"1D57A\relax \Umathcode`P=0+\M@bfrak@num"1D57B\relax \Umathcode`Q=0+\M@bfrak@num"1D57C\relax \Umathcode`R=0+\M@bfrak@num"1D57D\relax \Umathcode`S=0+\M@bfrak@num"1D57E\relax \Umathcode`T=0+\M@bfrak@num"1D57F\relax \Umathcode`U=0+\M@bfrak@num"1D580\relax \Umathcode`V=0+\M@bfrak@num"1D581\relax \Umathcode`W=0+\M@bfrak@num"1D582\relax \Umathcode`X=0+\M@bfrak@num"1D583\relax \Umathcode`Y=0+\M@bfrak@num"1D584\relax \Umathcode`Z=0+\M@bfrak@num"1D585\relax \Umathcode`a=0+\M@bfrak@num"1D586\relax \Umathcode`b=0+\M@bfrak@num"1D587\relax \Umathcode`c=0+\M@bfrak@num"1D588\relax \Umathcode`d=0+\M@bfrak@num"1D589\relax \Umathcode`e=0+\M@bfrak@num"1D58A\relax \Umathcode`f=0+\M@bfrak@num"1D58B\relax \Umathcode`g=0+\M@bfrak@num"1D58C\relax \Umathcode`h=0+\M@bfrak@num"1D58D\relax \Umathcode`i=0+\M@bfrak@num"1D58E\relax \Umathcode`j=0+\M@bfrak@num"1D58F\relax \Umathcode`k=0+\M@bfrak@num"1D590\relax \Umathcode`l=0+\M@bfrak@num"1D591\relax \Umathcode`m=0+\M@bfrak@num"1D592\relax \Umathcode`n=0+\M@bfrak@num"1D593\relax \Umathcode`o=0+\M@bfrak@num"1D594\relax \Umathcode`p=0+\M@bfrak@num"1D595\relax \Umathcode`q=0+\M@bfrak@num"1D596\relax \Umathcode`r=0+\M@bfrak@num"1D597\relax \Umathcode`s=0+\M@bfrak@num"1D598\relax \Umathcode`t=0+\M@bfrak@num"1D599\relax \Umathcode`u=0+\M@bfrak@num"1D59A\relax \Umathcode`v=0+\M@bfrak@num"1D59B\relax \Umathcode`w=0+\M@bfrak@num"1D59C\relax \Umathcode`x=0+\M@bfrak@num"1D59D\relax \Umathcode`y=0+\M@bfrak@num"1D59E\relax \Umathcode`z=0+\M@bfrak@num"1D59F\relax}} % \end{macrocode} % Reset |\endlinechar|. % \begin{macrocode} \endlinechar\count@ % \end{macrocode} % And that's everything! % % \vfill\eject % % \section*{Version History} % % New features and updates with each version. Listed in no particular order. % % \begin{multicols*}{2} % \bgroup\raggedright\parskip\z@\parindent\z@\leftskip1em\obeylines % \setbox0\hbox{\hskip 1pt.\hskip 1pt} % \def\version#1#2{\par\bigskip % \hbox to \hsize{\textbf{#1}\kern2pt% % \cleaders\copy0\hfill\kern2pt#2\strut}\par} % \def\item{\leavevmode\raise0.5ex\hbox{\vrule height 1pt width 0.5em}\kern1pt} % \def\item{---\kern0.2ex\relax}^^A I like the em dash better than a vrule % % \version{1.1b}{July 2018} % \item initial release % % \version{1.2}{August 2018} % \item minor bug fix for |\mathfrak| % \item eliminated redundant batchfile % % \version{1.3}{January 2019} % \item added |symbols| keyword\par % \item created |mathfont_example.pdf| % \item corrected the description of the \textsf{mathastext} package % \item font-change |\message| added to |\mathfont| % % \version{1.4}{April 2019} % \item |\setfont| command added % \item |\mathfont| optional argument can parse spaces % \item |no-operators| now default package optional argument % \item added |\comma| command % \item new fancy fatal error message % \item improved messaging for |\mathfont| % \item internal command |\mathpound| changed to |\mathhash| % \item added a missing |#1| after |\char`\"| in the example code redefining |"| in the user guide % % \version{1.5}{April 2019} % \item separated |\increment| and |\Delta| % \item version history added % \item initial off-the-shelf use insert added % % \version{1.6}{December 2019} % \item separated implementation and user documentation % \item created |mathfont_heading.tex| % \item created |mathfont_doc_patch.tex| for use with the index % \item changed |mathfont_greek.pdf| to |mathfont_symbol_list.pdf| % \item eliminated |mathfont_example.pdf| % \item eliminated |operators| package option % \item eliminated |packages| package option % \item font name can be package option % \item added Hebrew and Cyrillic characters % \item separated ancient Greek from modern Greek characters % \item created new keywords: |extsymbols|, |delimiters|, |arrows|, |diacritics|, |bigops|, |extbigops| % \item improved messaging % \item improved internal code for local font-change commands % \item improved space parsing for the optional argument of |\mathfont| % \item bug fix for |\#|, etc.\ commands % \item bad input for |\mathbb|, etc.\ now gives a warning % \item improved error checking for |\newmathrm|, etc.\ commands % \item |\mathfont| now ignores bad options (on top of issuing an error) % \item iternal commands now begin with |\M@|\dots % \item added Easter Egg! % \item improved indexing % \item |mathfont.dtx| renamed as |mathfont_code.dtx| % \item |\newmathbold| renamed as |\newmathbf| % \item default local font changes now use |\updefault|, etc. % \item added fatal error for missing \textsf{fontspec} % \item fatal errors result in |\endinput| rather than |\@@end| % % \version{2.0}{December 2021} % {\smallskip\leftskip\z@ % \fboxrule=1pt\relax % \dimen@\hsize % \advance\dimen@ by -2\fboxrule % \advance\dimen@ by -2\fboxsep % \fbox{\vbox{\hsize\dimen@ % \strut\textbf{Big Change:} Font adjustments for Lua\TeX: new glyph boundaries for Latin letters in math mode, resizable delimiters, big operators, MathConstants table based on font metrics.\vphantom y}}\par\smallskip} % \item added |\charmline| and |\charmfile| % \item added |\mathconstantsfont| % \item certain dimensions in equations are now adjustable when typesetting with Lua\TeX % \item added |adjust| and |no-adjust| package options % \item automatic generation of |ind| file % \item fixed symbols for |\leftharpoonup|, |\leftharpoondown|, and fraktur R % \item cleaned up internal code and documentation % \item font names for |\mathfont| stored to avoid multiple symbol font declarations with the same font % \item more information about nfss family names stored and provided % \item added option |empty| % \item raised upper bound on |\DeclareSymbolFont| to 256 % \item reintroduced |mathfont_example.tex| with different contents % \item changed several symbol-commands to |\protected| rather than robust macros % \item many user-level commands are now |\protected| % \item |\updefault| changed to |\shapedefault| % \item eliminated |\catcode| change for space characters when scanning optional argument of |\mathfont| % \item improved messaging for |\mathfont| % \item removed dependence on \textsf{fontspec} and added internal font-loader % \item switched |\epsilon| and |\varepsilon| % \item switched |\phi| and |\varphi| % \item changed |/| to produce a solidus in math mode and added |\fractionslash| % \item removed |\restoremathinternals| from the user guide % \item |\setfont| now sets |\mathrm|, etc. % \item added |\newmathsc|, other math alphabet commands for small caps % % \version{2.1}{November 2022} % \item |\mathbb|, etc.\ commands change |\Umathcode|s of letters instead of |\M@|\meta{bb,etc.}|@|\meta{letter} commands % \item removed warnings about non-letter contents of |\mathbb|, etc. % \item fonts loaded twice, once with default settings (for text) and once in base mode (for math) % \item |mathconstantsfont| accepts ``upright'' or ``italic'' as optional argument % % \version{2.2}{December 2022} % \item changed the easter egg text % \item updated patch for |\DeclareSymbolFont| to work with changes to the kernel (fixed the |\M@p@tch@decl@re| error message) % \item calling Plain \TeX\ on \texttt{mathfont\_code.dtx} produces sty file and no pdf file % % \version{2.2a}{December 2022} % \item bug fix for |\mathconstantsfont| % \item bug fix for |\M@check@int| % \item added |doc2| option to |ltxdoc| in \texttt{mathfont\_code.dtx} % % \version{2.2b}{August 2023} % \item minor changes to code and documentation % \item |\ng| now works in math (as not greater than symbol) and text (as pronounciation symbol) % % \version{2.3}{September 2023} % \item solidus and |\fractionslash| are |\mathord| instead of |\mathbin| % \item removed |\mathfont{fontspec}| functionality % \item redesigned font-loader % \item added package options |default-loader| and |fontspec-loader| % % \version{2.4}{April 2025} % \item |\colon| is |\mathpunct| instead of |\mathord| % \item moved |\relbar| and |\Relbar| to |arrows| % \item reformatted |mathfont_code.pdf| % \item made compatible with |\mathbb|, etc.\ commands from other packages % \item renamed |set_nomath_true| to |set_nomath_false| % \item improved messaging |\AtBeginDocument| % \item removed deprecated package options, |\newmathbold|, |\restoremathinternals| % \item more Easter egg messages % % \version{2.4a}{June 2025} % \item bug fix involving nil value and |the_font| % \item changed underscores in file names to hyphens % % \version{3.0}{January 2026} % \item |\mathfont| and |\setfont| no longer restricted to preamble % \item effects of |\mathfont| are local instead of global % \item |\mathfont| now overrides previous calls to |\mathfont| % \item added |\mathfontshapes| % \item added |\mainfont| % \item changed |\setfont| to |\documentfont| (but kept old name for backwards compatibility) % \item changed |\setmathfontcommands| to |\mathfontcommands| and added documentation in the user guide % \item added support for arbitrary \textsc{nfss} series/shape codes in |\mathfont| % \item separated macros for default shapes from macros for shapes used in |\mathfont| % \item formalized language of keywords and shape identifiers % \item font-loader is better about using argument with spaces removed for checking \textsc{nfss} font family % \item font-loader now uses |\@tempshape| and |\@tempseries| when parsing argument % \item moved assignment of |\M@count| values into |\M@newfont| % \item changed |\CharmLine| to |\charmline| (but kept old name for backwards compatibility) % \item changed |\CharmFile| to |\charmfile| (but kept old name for backwards compatibility) % \item added |\charminfo| % \item added |\charmtype| % \item renamed counts for |\SurdHorizontalFactor|, etc.\ to be at user level % \item formalized language of user-friendly versions of Lua\TeX-only commands in the user guide % \item corrected axis height % \item font adjustments now happen only if |mode=base| % \item no more virtual Latin letters in extra encoding slots (package now modifies Latin letters in their regular encoding slots for base-mode fonts) % \item added |bold| and |bolditalic| shape identifiers % \item no more type |u| (became type |a|) % \item added separate charm information for upright and italic fonts (specified using |/| character) % \item reworked default charm values % \item possible to force type |a| and type |e| characters using |?| and |!| in |\charmline| % \item added extra field in type |e| for italic correction % \item clarified role of |bot_accent|, which does nothing, in the user guide % \item cleaned up Lua code % \item added |finishing_touches| callback % \item bug fix involving the handling of italic correction in Lua font adjustments % \item bug fix involving characters in operator font not displaying % \item corrected UTF-16BE information added to character subtables in the font % \item new definition for |\not| % \item added |\negslash| % \item added |script=math| to OpenType features for fonts if intended for math (so math fonts load with built-in math features) % \item added support for Unicode input % \item switched |\epsilon| and |\varepsilon| (so |\epsilon| is Unicode epsilon and |\varepsilon| is Unicode lunate epsilon) % \item surd is now an active character in math mode (|\mathcode"8000|) % \item cleaned up error messages % \item improved messaging |\AtBeginDocument| % \item better error checking in |\M@check@int| % % % % % % % % % \egroup % \end{multicols*} % % % % \iffalse % % %<*user> \documentclass[12pt]{article} \makeatletter \usepackage[margin=72.27pt]{geometry} \usepackage[factor=700,stretch=14,shrink=14,step=1]{microtype} \usepackage[bottom]{footmisc} \usepackage{booktabs} \usepackage{graphicx} \usepackage{tabularx} \usepackage{multirow} \usepackage[implicit=false,colorlinks=true,allcolors=blue]{hyperref} \usepackage{enumitem} \SetEnumitemKey{special}{topsep=\smallskipamount, itemsep=\smallskipamount, parsep=\z@,partopsep=\z@} \setlist{special} \usepackage{doc}[=v2] \MakeShortVerb{|} \protected\def\bigskip{\vskip\bigskipamount} \protected\def\medskip{\vskip\medskipamount} \protected\def\smallskip{\vskip\smallskipamount} \def\link#1{\href{#1}{\nolinkurl{#1}}} \newcount\fig \fig=1\relax \c@topnumber\@ne % \skip\footins=7pt % Our own label/ref scheme because the standard one isn't working \def\labelfig#1{\immediate\write\@auxout{\string\makelabel{#1}{\the\fig}}} \def\makelabel#1#2{\expandafter\gdef\csname fig@#1\endcsname{#2}} \begin{document} \def\ref#1{\csname fig@#1\endcsname} \def\documentname{User Guide} \def\showabstract{1} \input mathfont-heading.tex \baselineskip=\the\baselineskip minus 0.5pt \noindent Handling fonts in \TeX\ and \LaTeX\ is a notoriously difficult task because fonts are complicated.\footnote{The last few decades have seen huge advances in loading fonts with \TeX. Donald Knuth originally designed \TeX\ to load only fonts created with Metafont, and more recent engines such as Jonathan Kew's \XeTeX\ and Hans Hagen, et al.'s Lua\TeX\ have extended \TeX's font-loading capabilities to Unicode. \XeTeX\ supports OpenType and TrueType fonts natively, and Lua\TeX\ can load OpenType fonts through the \hbox{\textsf{luaotfload}} package. Information on \XeTeX\ is available at \link{https://tug.org/xetex/}, and information on Lua\TeX\ is available at the official website for Lua\TeX: \link{http://www.luatex.org/}. See also Ulrike Fischer, et al., ``\textsf{luaotfload}---OpenType `loader' for Plain \TeX\ and \LaTeX,'' \link{https://ctan.org/pkg/luaotfload}. For discussion of fonts generally, see Yannis Haralambous, \textit{Fonts \& Encodings} (Sebastopol: O'Reilly Media, Inc., 2007).} The \textsf{mathfont} package addresses this situation by providing tools to use TrueType and OpenType fonts in math mode and in the main text, and this user guide explains how to operate \textsf{mathfont}. For version history and code implementation, see |mathfont-code.pdf|, and for a list of all symbols accessible with \textsf{mathfont}, see |mathfont-symbol-list.pdf|. Those two pdf files, this user guide, and four example files are included in the \textsf{mathfont} installation and are available on \textsc{ctan}. Because Unicode text fonts are plentiful, I hope that this package expands the possibilities for typesetting math in \LaTeX. \section{Loading and Basic Functionality} Loading\vadjust{\penalty-9999} fonts for math typesetting is more complicated than for regular text. First, selecting fonts for math mode, both in plain \TeX\ and in the \textsc{nfss}, involves additional macros above and beyond what we need to load text fonts. Second, \TeX\ expects fonts for math to contain extra information for formatting equations.\footnote{Specifically, this extra information is a set of large variants, math-specific parameter values associated with individual characters, and a MathConstants table. Also, math fonts often use slightly wider bounding boxes for letters in math mode---the Computer Modern $f$ is a well-known example. (Compare math-mode {\fboxsep=0pt\fbox{$f$}} and italic {\fboxsep=0pt\fbox{\textit f}}. Without italic correction, we have {\fboxsep=0pt\fbox{\itshape f}}.) For this reason, \textsf{mathfont} provides an interface to enlarge the bounding boxes of most Unicode characters when they appear in math mode. See section~5 for details.} Broadly speaking, we say that a \textit{math font} contains this extra information, whereas a \textit{text font} does not, and typesetting math with glyphs from one or more text fonts may yield messier equations than using a properly prepared math font. The functionality of \textsf{mathfont} then is twofold: (1) provide a wrapper around the \textsc{nfss} commands for math typesetting that serves as a high-level interface; and (2) implement Lua\TeX\ callbacks that artificially convert text fonts into math fonts at loading.\footnote{Values for MathConstants table are different from but inspired by Ulrik Vieth, ``Understanding the \AE sthetics of Math Typesetting,'' (Bacho\TeX\ Conference, 2008) and Ulrik Vieth ``OpenType Math Illuminated,'' \textit{TUGboat} 30 (2009): 22--31. See also Bogus\l aw Jackowski, ``Appendix G Illuminated,'' \textit{TUGboat} 27 (2006): 83--90.} Although \textsf{mathfont} tries its best to get your fonts right, it may run into trouble when picking fonts to load. If this happens, you should declare your font family and shapes in the \textsc{nfss} before setting any fonts with \textsf{mathfont}. \begin{figure}[t]\labelfig{packages} \centerline{\bfseries Table \the\fig: Comparison of General Font-Loading Packages\strut} \global\advance\fig\@ne \begin{tabular*}{\textwidth}{@{\extracolsep{\fill}}lll}\toprule & Text font & Math font\\\cmidrule{2-3} Traditional \TeX\ font & \textsf{mathastext} & No general package\\ Unicode font (for math typesetting) & \textsf{mathfont} or \textsf{mathspec} & \textsf{unicode-math}\\ Unicode font (for text only) & \textsf{fontspec} & \textsf{fontspec} \\\bottomrule \end{tabular*} \end{figure} You must use one of \XeLaTeX\ or Lua\LaTeX\ to typeset a document with \textsf{mathfont}. You can load \textsf{mathfont} with the standard |\usepackage| syntax, and the package accepts five optional arguments. If you use Lua\TeX, the options |adjust| or |no-adjust| will manually specify whether \textsf{mathfont} should adapt text fonts for math mode, and \textsf{mathfont} selects |adjust| by default. If you use \XeTeX, \textsf{mathfont} cannot adjust any font objects with Lua callbacks, and either of these package options will cause an error.\footnote{With \XeLaTeX, \textsf{mathfont} does not add big operators or resizable delimiters to the font. This means you will have to use the Computer Modern defaults, load a separate math font for resizable characters, or end up with a document where large operators and delimiters do not scale like they do normally.} For this reason, using Lua\TeX\ with \textsf{mathfont} is recommended as of version 2.0. The options |default-loader| and |fontspec-loader| determine which font-loading code \textsf{mathfont} uses. If you load the package with the |default-loader| option, \textsf{mathfont} uses a built-in font-loader, and if you load the package with |fontspec-loader|, \textsf{mathfont} uses the font-loader from \textsf{fontspec}. If you load \textsf{mathfont} with any other optional argument, the package will interpret it as a font name and call |\documentfont| (described in the next section) on your argument. Doing so selects that font for the text of your document and for the character classes in the upper portion of Table~\ref{Keywords}. \begin{figure}[t]\labelfig{commands} \centerline{\bfseries Table \the\fig: Main User-Level Control Sequences Provided by \textsf{mathfont}\strut} \global\advance\fig\@ne \tabcolsep\z@ \begin{tabular*}{\textwidth}{@{\extracolsep{\fill}}llp{1in}<{\raggedright\arraybackslash}}\toprule Control Sequence & Use & Engine\\\midrule \vrb\documentfont & Set font for text and math & \multirow{6}{*}{\vbox{\XeTeX\ and Lua\TeX}}\\ \vrb\mainfont & Set font for text &\\ \vrb\mathfont & Set font for math &\\ \vrb\mathfontshapes & Declare font shapes in the preamble &\\ \vrb\newmath\meta{specifier} & Create local font-change command for math &\\ \vrb\mathfontcommands & Create several local font-change commands &\\\midrule \vrb\mathconstantsfont & Select MathConstants table for use &\multirow{8}{*}{Lua\TeX\ only}\\ \vrb\charmline & Enlarge bounding box; change size of extensibles &\\ \vrb\charmfile & Call \vrb\charmline\ on each line from a file &\\ \vrb\charminfo & Print charm information of a character &\\ \vrb\charmtype & Print type of a character for charm purposes &\\ \vrb\hsurdfactor & Move overline for square root horizontally &\\ \vrb\vsurdfactor & Move overline for square root vertically &\\ \vrb\rulethicknessfactor & Set rule thickness for square root, fractions &\\ \bottomrule \end{tabular*} \end{figure} \begin{figure}[t]\labelfig{Keywords} \centerline{\bfseries Table \the\fig: Character Classes\strut} \global\advance\fig by 1\relax \tabcolsep\z@ \begin{tabular*}{\textwidth}{@{\extracolsep{\fill}}lllc}\toprule Keyword & Meaning & Default Shape Identifier & Alphabetic?\\\midrule |upper| & Upper-Case Latin & |italic| & Yes\\ |lower| & Lower-Case Latin & |italic| & Yes\\ |diacritics| & Diacritics & |upright| & Yes\\ |greekupper| & Upper-Case Greek & |upright| & Yes\\ |greeklower| & Lower-Case Greek & |italic| & Yes\\ |digits| & Arabic Numerals & |upright| & Yes\\ |operator| & Operator Font & |upright*| & N/A\rlap{\textsuperscript\dag}\\ |delimiters| & Delimiter & |upright| & No\\ |radical| & Square Root Symbol & |upright| & No\\ |symbols| & Basic Math Symbols & |upright| & No\\ |bigops| & Big Operators & |upright| & No\\\midrule |agreekupper| & Upper-Case Ancient Greek & |upright| & Yes\\ |agreeklower| & Lower-Case Ancient Greek & |italic| & Yes\\ |cyrillicupper| & Upper-Case Cyrillic & |upright| & Yes\\ |cyrilliclower| & Lower-Case Cyrillic & |italic| & Yes\\ |hebrew| & Hebrew & |upright| & Yes\\ |extsymbols| & Extended Math Symbols & |upright| & No\\ |arrows| & Arrows & |upright| & No\\ |extbigops| & Extended Big Operators & |upright| & No\\ |bb| & Blackboard Bold (double-struck) & |upright| & No\\ |cal| & Caligraphic & |upright| & No\\ |frak| & Fraktur & |upright| & No\\ |bcal| & Bold Caligraphic & |upright| & No\\ |bfrak| & Bold Fraktur & |upright| & No\\ \bottomrule \end{tabular*} \smallskip\footnotesize \noindent\strut\textsuperscript\dag Technically |opererator| is not a class of symbols but rather is a local font-change instruction similar to what is described in section~3 of this user guide. \end{figure} \begin{figure}[t]\labelfig{Shape-Identifiers} \centerline{\bfseries Table \the\fig: Shape Identifiers\strut} \global\advance\fig by 1\relax \begin{tabular*}{\textwidth}{@{\extracolsep{\fill}}lllll}\toprule Identifier & Series & Uses \textsc{nfss} Series & Shape & Uses \textsc{nfss} Shape\\\midrule |upright| & medium & \vrb\mddefault & upright & \vrb\shapedefault\\ |italic| & medium & \vrb\mddefault & italic & \vrb\itdefault\\ |bold| & bold & \vrb\bfdefault & upright & \vrb\shapedefault\\ |bolditalic| & bold & \vrb\bfdefault & italic & \vrb\itdefault\\ \meta{series}|/|\meta{shape} && \meta{series} && \meta{shape}\\ \bottomrule \end{tabular*} \end{figure} The \textsf{mathfont} package is closely related to several other \LaTeX\ packages. The functionality is closest to that of \textsf{mathspec} by Andrew Gilbert Moschou.\footnote{Andrew Gilbert Moschou, ``\textsf{mathspec}---Specify arbitrary fonts for mathematics in \XeTeX,'' \link{https://ctan.org/pkg/mathspec}.} That package is compatible with \XeTeX\ only and loads text fonts for use in math. The \textsf{unicode-math} package is a main \LaTeX\ package for loading actual Unicode math fonts, and if you have a Unicode font with proper math support, rather than a text font that you want to use for equations, consider using that package instead of \textsf{mathfont}.\footnote{Will Robertson, et al., ``\textsf{unicode-math}---Unicode mathematics support for XeTeX and LuaTeX,'' \link{https://ctan.org/pkg/unicode-math}.} Users who want a text font for math with pdf\LaTeX\ should consider Jean-Fran\c cois Burnol's \textsf{mathastext} because \textsf{mathfont} is incompatible with pdf\TeX.\footnote{Jean-Fran\c cois Burnol, ``\textsf{mathastext}---Use the text font in maths mode,'' \link{https://ctan.org/pkg/mathastext}. In several previous versions of this documentation, I mischaracterized the approach of \textsf{mathastext} to \TeX's internal mathematics spacing. In fact, \textsf{mathastext} preserves and in some cases extends rules for space between various math-mode characters.} Finally, you may be better off using \textsf{fontspec} if your document does not contain any math.\footnote{Will Robertson and Khaled Hosny, ``\textsf{fontspec}---Advanced font selection in \XeLaTeX\ and Lua\LaTeX,'' \link{https://ctan.org/pkg/fontspec}.} The \textsf{fontspec} package is designed to load TrueType and OpenType fonts for text and provides a high-level interface for selecting OpenType font features. Table~\ref{packages} summarizes this information. \section{Setting the Default Font} The \textsf{mathfont} package provides three commands for setting fonts in your document. The |\mathfont| command sets the font for various classes of characters when they appear in math mode, and after you call |\mathfont| on any class of characters, you can use Unicode input for that class of characters in math mode. The |\mainfont| command sets the font outside of equations. The control sequence |\documentfont| calls both |\mainfont| and |\mathfont|, calls |\mathconstantsfont| if the engine is Lua\TeX, and calls |\mathfontcommands| if in the document preamble. Each of these three commands accepts one optional argument and one mandatory argument, so the full syntax is \begin{code} |\documentfont[|\meta{\textup{\ttfamily rm}, \textup{\ttfamily sf}, \textup{\ttfamily tt}, or empty}|]{|\meta{font name}|}|\\ |\mainfont[|\meta{\textup{\ttfamily rm}, \textup{\ttfamily sf}, \textup{\ttfamily tt}, or empty}|]{|\meta{font name}|}|\\ |\mathfont[|\meta{keywords}|]{|\meta{font name}|}| \end{code} More recent calls to any of these commands will override previous instructions, and all font changes through these macros are local. \textit{This is a backwards-incompatible change in version 3.0.} For context, \LaTeX\ classifies fonts into family (what most users typically think of as a ``font''), series (the weight, usually medium or bold), and shape (the appearance, usually upright or italic). The mandatory argument of these three commands specifies a font family, and the optional argument of |\mathfont| specifies font series and shape. To choose a series and shape outside of math mode, you should use the standard commands from the kernel.\footnote{Specifically,\vadjust{\penalty-1000} \vrb\fontseries\ and \vrb\fontshape\ locally select arbitrary series and shapes from the \textsc{nfss}, and the kernel provides macros that reformat their argument such as \vrb\textbf\ and \vrb\textit.} The optional argument for |\mainfont| and |\documentfont| determines how \textsf{mathfont} stores the font information. Using |rm|, |sf|, or |tt| will prompt \textsf{mathfont} to set both |\familydefault| and one of |\rmdefault|, |\sfdefault|, or |\ttdefault| respectively to the requested \textsc{nfss} family. The corresponding |\rmfamily|, |\sffamily|, or |\ttfamily| command will switch to the font family thereafter. Providing an empty optional argument instructs \textsf{mathfont} to switch to the font family without saving the font name, and in this case, you will see no change in the effects of |\rmfamily| and friends. If you do not provide an optional argument, \textsf{mathfont} uses |rm|. The optional argument for |\mathfont| should be a comma-separated list of keywords from Table~\ref{Keywords}, and it determines which math-mode characters will undergo a font change. When you use this command, \textsf{mathfont} sets the font family for every character in those keywords when in math mode to the mandatory argument. For a list of characters associated with the different keywords, see |mathfont_symbol_list.pdf|. If you do not specify an optional argument, |\mathfont| uses all keywords from the upper half of Table~\ref{Keywords} (but not including |delimiters|, |radical|, or |bigops| characters in \XeTeX), so calling |\mathfont| with no optional argument is a fast way to change the font for most common math characters. Characters in math mode often appear in different series or shapes from the same font family, and \textsf{mathfont} allows users to request particular series and shape combinations by using the shape identifiers in Table~\ref{Shape-Identifiers}. By default, the characters in a \meta{keyword} will follow the shape identifier stored in |\|\meta{keyword}|default|, so for example, |\upperdefault| is initially defined to be the character string |italic|. Table~\ref{Keywords} contains the initial value of each default setting. To change the series and shape, you can redefine any |\|\meta{keyword}|default| macro to a different shape identifier, or you can request a different shape identifier in the optional argument of |\mathfont|. If you say |=|\meta{shape identifier} immediately after a keyword and before the following comma, the package will apply your requested \meta{shape identifier} to that keyword. For example, if you say \begin{code} |\mathfont[upper=upright, lower=upright]{Baskerville}| \end{code} you will see Latin letters appear in upright Baskerville in your equations. You may include |*| character immediately after the shape identifier if you want \textsf{mathfont} to use unmodified characters from the font. This option is most appropriate for situations such as math operators where you want to use regular text in your equations and do not need enlarged bounding boxes. For example, the command \begin{code} |\mathfont[upper, lower, operator=italic*]{Times New Roman}| \end{code} changes all Latin letters to italic Times New Roman and switches math operators to the same italic text that you would see if you use Times New Roman outside of math. This feature does not do anything in \XeTeX. The mandatory argument of all three font-setting commands should be a system font name or an \textsc{nfss} font family name. If you use a system font, you can select OpenType features by putting a colon after the font name and following it with the appropriate tags.\footnote{By default, \textsf{mathfont} enables standard ligatures, traditional \TeX\ ligatures, and lining numbers. The package sets |smcp| to |true| or |false| depending on whether it is attempting to load a small-caps font. For the full list of OpenType features, see \link{https://docs.microsoft.com/en-us/typography/opentype/spec/featurelist}.} The syntax for specifying features depends on the font-loader: with the built-in font-loader, you should use the standard ``|+|\meta{tag}'' or ``|-|\meta{tag}'' syntax, and when using \textsf{fontspec} as the font-loader, you should use that package's high-level interface, as described in the \textsf{fontspec} documentation. For example, suppose you want math with oldstyle numbers. With the built-in font-loader, you should add ``|+onum|,'' or if using \textsf{fontspec}, you should add |Numbers=OldStyle| to your |\mathfont| command. So to load Adobe Garamond Pro with oldstyle numbering, you would say \begin{code} |\mathfont{Adobe Garamond Pro:+onum}| \end{code} with the built-in font-loader or \begin{code} |\mathfont{Adobe Garamond Pro: Numbers=OldStyle}| \end{code} if using \textsf{fontspec}. With the built-in font-loader, you should separate OpenType tags with semi-colons, and for \textsf{fontspec}, you should use commas. When the mandatory argument of a font-changing command is an \textsc{nfss} family name, \textsf{mathfont} uses that font family. When the engine is \XeTeX, you don't have to do anything special and can ignore the rest of this paragraph. When the engine is Lua\TeX, \textsf{mathfont} expects the \textsc{nfss} to contain a second entry for the same font family that uses base mode for loading.\footnote{The \textsf{luaotfload} package supports three modes for loading fonts: |node|, |base|, and |harf|. The default setting is |node| mode. It supports full OpenType features in text but none for math, whereas |base| mode supports fewer OpenType features, but they work in both text and math. Loading a font with |harf| mode engages HarfBuzz, a font shaper that arranges characters in potentially complicated layouts but also provides no access to OpenType features in math.} If \meta{name} is the mandatory argument, you should tell \textsf{mathfont} the family name for the base-mode version by storing it in the control sequence |\|\meta{name}|-base|. If you do not do this, you will see an error message. My intention is that the first font family is for text, and the base-mode font family is for math---using two different loading options provides the greatest access to OpenType font features throughout your document. You can access blackboard-bold, calligraphic, or fraktur letters in three ways. First, the Unicode standard contains encoding slots for these types of letters, and the last five keywords in Table~\ref{Keywords} access this portion of the Unicode table.\footnote{The Math Alphanumeric Symbols block is U+1D400--U+1D7FF. Most blackboard-bold, calligraphic, and fraktur letters live in this portion of the Unicode table, although a few live in other places.} If you call |\mathfont| on one of these \meta{keyword}s, the package defines the macro \begin{code} |\math|\meta{keyword}|{|\meta{text}|}| \end{code} which behaves like a local font-change command from the next section and converts Latin letters into \meta{keyword} style. For example, \begin{code} |\mathfont[bb]{STIXGeneral}| \end{code} defines |\mathbb| to typeset blackboard-bold letters using the glyphs from STIXGeneral. Second, you may have a Unicode font where the normal Latin letters are themselves double struck, calligraphic, or fraktur, and in that case, you should declare a local font-change command using the tools in the next section. Third, \textsf{mathfont} should play nicely with (local) font-changing macros from other packages, so you should have no problem using, for example, \textsf{amssymb} with \textsf{mathfont}.\footnote{American Mathematical Society, ``\textsf{amssymb}.'' See also American Mathematical Society, ``\textsf{amsfonts}---\TeX\ fonts from the American Mathematical Society,'' \link{https://ctan.org/pkg/amsfonts}.} \begin{figure}[t] \labelfig{MathAlpha} \centerline{\bfseries Table \the\fig: Macros to Create Local Font-Change Commands with Preset Shapes\strut} \global\advance\fig by 1\relax \tabcolsep\z@ \begin{tabular*}{\textwidth}{@{\extracolsep{\fill}}lllll}\toprule Command & Series & Uses \textsc{nfss} Series & Shape & Uses \textsc{nfss} Shape\\\midrule |\newmathrm| & Medium & |\mddefault| & Upright & |\shapedefault|\\ |\newmathit| & Medium & |\mddefault| & Italic & |\itdefault|\\ |\newmathbf| & Bold & |\bfdefault| & Upright & |\shapedefault|\\ |\newmathbfit| & Bold & |\bfdefault| & Italic & |\itdefault|\\ |\newmathsc| & Medium & |\mddefault| & Small Caps & |\scdefault|\\ |\newmathscit| & Medium & |\mddefault| & Italic Small Caps & |\scdefault\itdefault|\\ |\newmathbfsc| & Bold & |\bfdefault| & Small Caps & |\scdefault|\\ |\newmathbfscit| & Bold & |\bfdefault| & Italic Small Caps & |\scdefault\itdefault|\\\bottomrule \end{tabular*} \end{figure} \section{Local Font Changes} With \textsf{mathfont}, it is possible to create commands that locally change the font for math alphabet characters, i.e.\ those marked as alphabetic in Table~\ref{Keywords}. (I am slightly abusing notation. In this section, I mean local as in acting on a small portion of the document, not local with respect to grouping. All font-change commands from \textsf{mathfont} are local in that regard.) The commands from this section should appear only in the preamble. The eight commands in Table~\ref{MathAlpha} accept a \meta{control sequence} as their first mandatory argument and a \meta{font name} as the second, so for example, the macro |\newmathrm| looks like \begin{code} |\newmathrm{|\meta{control sequence}|}{|\meta{font name}|}| \end{code} You can specify OpenType features as part of the \meta{font name} the same way as in the previous section. The macros in Table~\ref{MathAlpha} define the control sequence in their first argument to accept a string of characters and convert it to the font family in the second argument. The series and shape information depend on the command used. For example, writing \begin{code} |\newmathrm{\matharial}{Arial}| \end{code} creates the macro \begin{code} |\matharial{|\meta{argument}|}| \end{code} which can be used only in math mode and which converts the math alphabet characters in its \meta{argument} into the Arial font with upright shape and medium weight. The macro |\mathfontcommands| accepts a single font name as its argument. It calls each |\newmath|\meta{specifier} command from Table~\ref{MathAlpha} to define |\math|\meta{specifier} using the font family from its argument. For example, \begin{code} |\mathfontcommands{Helvetica}| \end{code} makes the standard font-changing commands such as |\mathrm| and |\mathit| use Helvetica instead of Computer Modern. In traditional \LaTeX, |\mathrm| and friends do not change the font for Greek characters. That remains the case until you call |\mathfont| for |greeklower| or |greekupper| characters, and then any local font-change commands from this section will work on lower-case or upper-case Greek letters respectively. Similarly, the local font-change commands will affect Cyrillic and Hebrew characters after you call |\mathfont| for those keywords. These nine control sequences provide tools for most local font changes, but they won't be able to address everything. Accordingly, \textsf{mathfont} provides general |\newmathfontcommand| macro. Its argument structure is \begin{code} |\newmathfontcommand{|\meta{control sequence}|}{|\meta{font name}|}{|\meta{series}|}{|\meta{shape}|}| \end{code} where the \meta{control sequence} in the first argument again becomes the macro that changes characters to the \meta{font name}. You are welcome to use a system font name when you call |\newmathfontcommand|, but my intention behind this command is that you can use an \textsc{nfss} family name for the \meta{font name}. Then the series and shape values can correspond to more obscure font faces from the \textsc{nfss} family that you would be otherwise unable to access. As with |\mathfont|, if you are using Lua\TeX\ and the \meta{font name} is an \textsc{nfss} family, you should make sure that you defined |\|\meta{font name}|-base|, or you will see an error. \section{Default Math Parameters} Lua\TeX\ uses the MathConstants table from the most recent font assigned for use in math mode, and this means that in a document with multiple math fonts, the choice of MathConstants table can depend on the order of font declaration and be unpredictable. To avoid potential problems from using the wrong MathConstants table, \textsf{mathfont} provides \begin{code} |\mathconstantsfont[|\meta{shape identifier}|]{|\meta{font name}|}| \end{code} where \meta{shape identifier} is a shape identifier from Table~\ref{Shape-Identifiers} and \meta{font name} is a font name as in the previous two sections. By default, |\mathconstantsfont| uses |upright| for the optional argument. This macro forces Lua\TeX\ to use the MathConstants table from the requested font face, and once again, if you use an \textsc{nfss} family name for \meta{font name} with Lua\TeX, make sure to define |\|\meta{font name}|-base| appropriately. You don't need to set the MathConstants table when you use |\documentfont| or pass a font name to \textsf{mathfont} at loading because the package calls |\mathconstantsfont| automatically in this case. This command does not do anything in \XeTeX. \section{Declaring Font Shapes} You\vadjust{\penalty-9999} are welcome to use the commands from sections~2 and 4 after |\begin{document}|, but you are limited in what fonts you can use. \LaTeX\ prohibits new font declarations after the preamble, and at that point, \textsf{mathfont} will only use font faces that already exist in the \textsc{nfss} or that it used for any purpose previously. What this means in practical terms: if you want to use |\mathfont| or |\mainfont| after |\begin{document}|, you probably have to use a font that \textsf{mathfont} handled in some capacity in the preamble. This makes it nonobvious how to use a font after the preamble if you do not want to set that font for any characters in the preamble. To address this situation, \textsf{mathfont} provides the command |\mathfontshapes|. The purpose of this macro is to declare font shapes before |\begin{document}| without using them for anything. It accepts one optional argument and one mandatory argument, so the syntax is \begin{code} |\mathfontshapes[|\meta{shape identifiers}|]{|\meta{font name}|}| \end{code} The optional argument should be a comma-separated list of shape identifiers, and by default, the macro uses |upright|, |upright*|, |italic|, and |bold|. The mandatory argument should be a font name like in the previous sections. After you use |\mathfontshapes|, you should have no problem using the same font family for |\mainfont|. You will also be able to use the font family for |\mathfont| or |\mathconstantsfont| provided that you stick to shape identifiers that appeared in the optional argument of |\mathfontshapes|. For example, if you say \begin{code} |\mathfontshapes{Didot}| \end{code} in your preamble, you can include \begin{code} |\mathfont{Didot}| \end{code} after the preamble (even if you didn't have it in the preamble), but if you type \begin{code} |\mathfont[operator=italic*]{Didot}| \end{code} you will run into problems because |\mathfontshapes| does not normally use the shape identifier |italic*|. You should instead say \begin{code} |\mathfontshapes[italic*]{Didot}| \end{code} in your preamble to avoid any issues. \section{Lua Font Adjustments} When Lua\TeX\ reads in a font file, \textsf{mathfont} makes the font object in memory appear to be a math font rather than a text font. Most of this process happen behind the scenes, but \textsf{mathfont} provides control sequences that allow you to customize some modifications. With the exception of the read-only control sequences |\charminfo| and |\charmtype|, their wrapped equivalents, and the count variables, all macros from this section should appear in the preamble only. The main macro for doing so is |\charmline|. (Charm stands for ``character metric.'') It accepts one mandatory argument, so the syntax is \begin{code} |\charmline{|\meta{charm information}|}| \end{code} The \meta{charm information} should be a sequence of entries separated by a comma and/or space, where entry means one or two numbers or asterisks. If an entry is two numbers, two asterisks, or one of each, you must separate them with a slash, and the first entry in \meta{charm information} should be a single integer between 0 and 1,114,111. The command fully expands its argument, and you may see strange errors if \meta{charm information} contains unexpandable control sequences. Processing uses |tonumber()| from Lua, so your input can include anything that Lua recognizes as a number. In particular, you can specify hexadecimal numbers by prefixing them with |0x|. This macro controls how \textsf{mathfont} adjusts bounding boxes, accent placement, and large variants. The first entry in \meta{charm information} corresponds to an entry in the Unicode table, and \textsf{mathfont} references the remaining entries when it alters properties of the character in that encoding slot during font loading. For purposes of charm information, a character can have one of two types: |a| for ``alphabetic'' or |e| for ``extensible.''\footnote{Alphabetic is something of a misnomer that I kept for historical reasons.} Any character that resizes, such as delimiters, big operators, and the surd character has type |e|, and you should specify 33 additional entries after the encoding slot. All other characters have type |a|, and you should specify 4 additional entries after the encoding slot. If you specify too few charm values, \textsf{mathfont} will raise an error, and if you provide too many, \textsf{mathfont} ignores the extras and prints a warning on the terminal. Version 3.0 eliminates type |u| and requires an extra entry for type |e| characters, and \textit{these are backwards-incompatible changes.} If you call |\charmline| for an encoding slot that does not have any charm information, \textsf{mathfont} assumes that character should be type |a|. You can change a character to type |e| by including an |!| symbol immediately after the first entry, and you can change a character to type |a| by including a |?| symbol immediately after the first entry. \begin{figure}[t] \labelfig{Charm} \centerline{\bfseries Table \the\fig: Number of Entries Required in \vrb\charmline\strut} \global\advance\fig by 1\relax \begin{tabularx}\textwidth{Xcl}\toprule Character & Type & \hfil Total Number of Entries\\\midrule Everything Else & |a| & \hfil5\\ Delimiters, Radical (Surd Character), Big Operators & |e| & \hfil34\\ \bottomrule \end{tabularx} \end{figure} When \textsf{mathfont} parses \meta{charm information}, the order of the entries determines their purpose. As is standard in \TeX, \textsf{mathfont} divides all numbers in |\charmline| by 1000 to form floats before using them in calculations. For type |a| characters, the second and third entries tell Lua\TeX\ how much to stretch the left and right sides of the glyph's bounding box when it appears in math mode, and the third entry determines horizontal placement of top math accents. The final entry determines the |bot_accent| attribute for that character in the font object, although Lua\TeX\ does not use this piece of information for formatting equations.\footnote{See Hans Hagen and Mikael P. Sundqvist, ``On Bottom Accents in OpenType Math,'' \textit{TUGBoat} 44 (2023): 207--208. See also two threads from the Lua\TeX\ developer mailing list from 2012, available at \edef\temp{http://mailman.ntg.nl/archives/list/dev-luatex@ntg.nl/thread/3SDPLVHQYLVHHOBUA3DWROTWLMUBUQI5/\string#WX432F6M52MUIK4WE5I3W7YSJOWDIA4G}% \edef\tempurl{http:\break//mailman.ntg.nl/archives/list/dev-luatex@ntg.nl/thread/3SDPLVHQYLVHHOBUA3DWROTWLMUBUQI5/\hfil\break\string#WX432F6M52MUIK4WE5I3W7YSJOWDIA4G}% \@onelevel@sanitize\temp \href{\temp}{\texttt{\tempurl}} and \edef\temp{https://mailman.ntg.nl/archives/list/dev-luatex@ntg.nl/thread/PU2VYNG7XBWVBBUY4VIPJOS75NNZM7UE/\string#PU2VYNG7XBWVBBUY4VIPJOS75NNZM7UE}% \@onelevel@sanitize\temp\expandafter\link\expandafter{\temp}.} If the Unicode value corresponds to a type |e| character, \textsf{mathfont} interprets the first 30 entries after the encoding slot as 15 successive pairs of horizontal and vertical scale factors that determine the size of large variants. For example, the second and third entries in \meta{charm information} are the horizontal and vertical scale factors for the first large variant. The last three entries determine, respectively,\vadjust{\penalty-1000} horizontal placement of top accents, the |bot_accent| attribute, and the character's italic correction. Asterisks and subentries affect how \textsf{mathfont} uses charm information in memory. Writing an asterisk tells \textsf{mathfont} to use whatever value it has saved in memory, either the default value or the value from the most recent call to |\charmline| or |\charmfile|. When an entry contains two subentries, \textsf{mathfont} uses the first subentry for unslanted fonts and the second subentry for slanted or italic fonts. If an entry is a single number or asterisk, \textsf{mathfont} uses that input for both slanted and unslanted fonts. If you want to store charm information in a file instead of your document preamble, you should use the control sequence |\charmfile|. This command accepts one mandatory argument, so the syntax is \begin{code} |\charmfile{|\meta{file name}|}| \end{code} It reads in a file and calls |\charmline| individually on each line from the file. The default settings are decent, so for most applications, you can probably ignore charm information altogether. However, if you find bounding boxes or accent placement to be off slightly in your equations or if you want to change the scaling for a delimiter or big operator, you should try calling |\charmline| with different values to see what works. For a given character, the scale for changes is the width of that character's unmodified bounding box.\footnote{For type |a|, it's technically the unmodified bounding box width plus italic correction because \textsf{mathfont} incorporates the italic correction into the character width.} For example, \begin{code} |\charmline{0x61, 200, -100, *, 50}| \end{code} tells \textsf{mathfont} to take the lower-case ``a'' (U+61, i.e.\ encoding slot number 97), increase the bounding box on the left side by 20\% of the character width, decrease the bounding box on the right side by 10\% of the character width, do nothing to the top accent, and shift the |bot_accent| attribute right by 5\% of the character width. There is no general formula for what charm values to use for a given font! Rather, you will need to make a design choice based on what looks best, and if you regularly use a specific font, consider making a custom set of charm values and uploading it to \textsc{ctan}. The package provides two commands to query charm information in memory, namely |\charminfo| and |\charmtype|. These macros are weird in that they don't take an argument. Rather, they scan (and remove) the next integer from the input stream in the same manner as a |\count| variable, so the syntax is \begin{code} |\charminfo|\meta{integer}\\ |\charmtype|\meta{integer} \end{code} Both macros are fully expandable and work outside the document preamble. If \textsf{mathfont} has charm information in memory for the Unicode encoding slot \meta{integer}, |\charmtype| expands to |a| or |e| depending on the type of that character, and |\charminfo| expands to a space-separated lists of charm entries. The results of |\charminfo| look exactly like the input of |\charmline|, so typing \begin{code} |\charmline{|\meta{encoding slot}|,\charminfo|\meta{encoding slot}|}| \end{code} is valid syntax and reassigns the charm information for \meta{encoding slot} to itself. If \meta{integer} is not the encoding slot for a character with charm information, both macros expand to |none|. Three count variables affect equation formatting with \textsf{mathfont}. Their default value is 1000, and \textsf{mathfont} divides\vadjust{\penalty-1000} their value by 1000 to convert them to floats before using them. The first two, |\hsurdfactor| and |\vsurdvactor|, affect the positioning of the overline in square root expressions. Specifically, changing either count scales the bounding box for the surd (square root) character by the corresponding float value. Larger values of |\hsurdvactor| therefore shift the overline to the right, and smaller values do the opposite. Larger values of |\vsurdfactor| raise the overline. The third count, |\rulethicknessfactor|, determines the thickness of horizontal rules such as the overline in square root expressions or the fraction bar. You will probably want to increase |\rulethicknessfactor| for fonts with heavier weight and decrease it for fonts with lighter weight. Please be aware that \textsf{mathfont} uses the value of each count only once per font when \TeX\ loads the font for math typesetting. This typically happens the first time the user enters math mode. The package provides user-friendly versions of each control sequence in this section. The macros |\CharmInfo| and |\CharmType| accept an integer as a single mandatory argument and print the results of |\charminfo| and |\charmtype| to the terminal. The macros |\SurdHorizontalFactor|, |\SurdVerticalFactor|, and |\RuleThicknessFactor| similarly accept a single integer as a mandatory argument and set the corresponding count variable to that value. Additionally, |\IntegralItalicFactor| accepts an integer as its argument and divides the argument by 1000 to form a float. When \TeX\ loads a font, it increases the italic correction of the integral symbol by that fraction of the symbol's width, which affects positioning of limits. For parity in macro names and backwards compatibility, |\CharmLine| and |\CharmFile| are defined to do the same thing as their lower-case counterparts. \begin{figure}[t] \labelfig{Callbacks} \centerline{\bfseries Table \the\fig: Lua Callbacks Created by \textsf{mathfont}\strut} \global\advance\fig by 1\relax \newbox\mybox \setbox\mybox\vbox{\raggedright \hsize0.9in\relax If base mode\break and |nomath|} \begin{tabularx}\textwidth{lXl}\toprule Callback Name & What It Does By Default & Called?\\\midrule |"mathfont.inspect_font"| & Nothing & Always\\\midrule |"mathfont.pre_adjust"| & Nothing & \multirow{7}{*}{\copy\mybox}\\ |"mathfont.disable_nomath"| & Set font attribute |nomath| to false &\\ |"mathfont.add_math_constants"| & Create a MathConstants table &\\ |"mathfont.fix_character_metrics"|& \raggedright\arraybackslash Adjust bounding boxes, add character-specific math fields, create large variants &\\ |"mathfont.post_adjust"| & Nothing &\\\midrule |"mathfont.finishing_touches"| & Nothing & Always\\ \bottomrule \end{tabularx} \end{figure} Advanced users who want to interact with the font adjustment process directly should use the seven callbacks in Table~\ref{Callbacks}. When \textsf{luaotfload} loads a font, \textsf{mathfont} (1) always calls |mathfont.inspect_font|; (2) calls the middle five callbacks in the order that they appear in Table~\ref{Callbacks} if the font object contains |nomath=true| and was loaded with |base| mode; and (3) always calls |mathfont.finishing_touches|. Functions added to these callbacks should accept a font object as a single argument and return nothing. Further, please be careful when loading functions in |disable_nomath|, |add_math_constants|, and |fix_character_metrics|. If you add a function there, Lua\TeX\ will not carry out the default behavior associated with the callback, so do not mess with these three callbacks unless you are duplicating the default behavior or you really know what you're doing. Otherwise, you risk breaking the package. See |mathfont-code.pdf| for more information. \end{document} % %<*chars> \documentclass[12pt]{article} \makeatletter \usepackage[margin=72.27pt]{geometry} \usepackage{tabularx} \usepackage{booktabs} \usepackage{multicol} \multicolsep=\bigskipamount \premulticols=\z@ \postmulticols=4\bigskipamount \usepackage{graphicx} \usepackage{mathfont} \mathfont[\M@keys]{STIXGeneral} \mathfont[agreeklower=upright,agreekupper]{Crimson} \mathfont[hebrew]{Coelacanth} \usepackage{shortvrb} \MakeShortVerb{|} \def\meta#1{\ensuremath{\langle\textit{#1}\rangle}} \raggedcolumns \parskip=0pt \fboxrule=1pt \charmline{8747 1200 1700 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} \charmline{8748 1200 1700 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} \charmline{8749 1200 1700 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} \charmline{8750 1200 1700 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} \charmline{8751 1200 1700 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} \charmline{8752 1200 1700 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *} \begin{document} \def\documentname{Symbol List} \def\showabstract{1} \input mathfont-heading.tex \noindent The \textsf{mathfont} package provides tools to access several hundred characters for math typesetting, and this document lists these symbols along with the control sequences to access them. To get access to the symbols from a section of this document, call |\mathfont| with the keyword-option for that section and the name of a font that contains those symbols. The package does not define any math symbols until you call |\mathfont| or |\setfont| (or load \textsf{mathfont} with a font name as package option), and if you see a symbol or control sequence here that is not part of standard \LaTeX, you will not be able to access it until you call |\mathfont| on the corresponding keyword. Further, \textsf{mathfont} does not come with or load any fonts by itself, so you are responsible for the fonts. Not all fonts contain all math symbols, so choose your font wisely!\footnote{Besides letters and digits, most Unicode text fonts should contain diacritics, delimiters, and the basic math characters in the keyword |symbols|. Text fonts will often contain square root and basic operator symbols, but they may not be suitable for math typesetting. Greek characters are hit or miss, and it is unusual for English text fonts to contain Cyrillic, Hebrew, ancient Greek, arrows, letterlike characters, or any extended (keywords |extbigops| and |extsymbols|) set of symbols. After you load \textsf{mathfont}, \TeX\ will print a message to the terminal if you try to typeset a missing character from some font.} This document shows ancient Greek in Crimson, Hebrew in Coelacanth, and all other math characters in STIXGeneral. \begin{figure}[t] \centerline{\bfseries Table 1: Characters Defined by Multiple Keywords\strut} \begin{tabularx}\textwidth{XXX}\toprule Character & Keywords & Default Font\\\midrule \vrb\increment & \texttt{greekupper} & \texttt{symbols}\\ & \texttt{symbols} & \\\midrule \vrb\nabla & \texttt{greekupper} & \texttt{(ext)symbols}\\ & \texttt{symbols} with Lua\TeX & \\ & \texttt{extsymbols} with \XeTeX & \\\midrule \expandafter\vrb\string| & \texttt{symbols} & \texttt{symbols} normally\\ & \texttt{delimiters} with Lua\TeX & \texttt{delimiters} after |\left|, \hfil\penalty0|\right|, etc.\\\midrule \vrb\simeq\ and \vrb\cong & \texttt{symbols} & \texttt{extsymbols} \\ & \texttt{extsymbols} & \\\bottomrule \end{tabularx} \end{figure} As of version 2.0, \textsf{mathfont} artificially adds resizable delimiters and big operator characters to text fonts when you compile with Lua\LaTeX. In this case, square root symbols will automatically resize, big operators will appear larger in |\displaystyle|, and you can use |\left|, |\right|, and |\big|, etc.\ with characters from the keyword |delimiters|. If you use \XeTeX, \textsf{mathfont} will not create large variants of characters, and your Unicode math symbols will all be the same size as they appear in the font. In this case, you may be best off sticking with the Computer Modern defaults for resizable characters provided they don't clash with the rest of your document. Throughout this document, anything labeled ``Lua\TeX\ only'' means that \textsf{mathfont} provides this functionality only if you enable Lua-based font adjustments. If you load \textsf{mathfont} in Lua\TeX\ with the |no-adjust| option, you will not be able to access these features the same as if you typeset with \XeTeX. A few characters appear multiple times in this list. When that happens, it means that \textsf{mathfont} defines the control sequence for multiple keywords. If you call |\mathfont| for only one of those keywords, your symbol will appear in the font associated with that keyword. If you call |\mathfont| on multiple keywords, the package uses the font associated with the default keyword/font for that character. Table~1 lists the default keyword for each command that appears multiple times in this document. If you need Unicode encoding slot numbers for character metric adjustments, each symbol corresponds to its standard Unicode encoding value, with the exception of the fake angle brackets. When you typeset with Lua\TeX, \textsf{mathfont} artificially adds |\fakelangle|, |\fakerangle|, |\fakellangle|, and |\fakerrangle| to the font in encoding slots 1,044,508--1,044,511 respectively. \bigskip\bigskip \nointerlineskip\centerline{\vrule height 0.5pt width 2.5in} \bigskip\bigskip \catcode`\|=12 \blockheader{lower}{Lower-Case Latin} \begin{multicols}{3} \charexample a \charexample b \charexample c \charexample d \charexample e \charexample f \charexample g \charexample h \charexample i \charexample j \charexample k \charexample l \charexample m \charexample n \charexample o \charexample p \charexample q \charexample r \charexample s \charexample t \charexample u \charexample v \charexample w \charexample x \charexample y \charexample z \charexample\hbar \charexample\imath \charexample\jmath \end{multicols} \blockheader{upper}{Upper-Case Latin} \begin{multicols}{3} \charexample A \charexample B \charexample C \charexample D \charexample E \charexample F \charexample G \charexample H \charexample I \charexample J \charexample K \charexample L \charexample M \charexample N \charexample O \charexample P \charexample Q \charexample R \charexample S \charexample T \charexample U \charexample V \charexample W \charexample X \charexample Y \charexample Z \end{multicols} \blockheader{diacritics}{Accent} \begin{multicols}{3} \def\hook{\footnote{You will run into trouble if you load \textsf{amsmath} after calling \vrb\mathfont\ with the \texttt{accent} keyword. This is a known bug.}} \accentexample\acute \let\hook\relax \accentexample\aacute \accentexample\dot \accentexample\ddot \accentexample\grave \accentexample\breve \accentexample\hat \accentexample\check \accentexample\bar \accentexample\mathring \accentexample\tilde \end{multicols} \blockheader{digits}{Arabic Numeral} \begin{multicols}{3} \charexample0 \charexample1 \charexample2 \charexample3 \charexample4 \charexample5 \charexample6 \charexample7 \charexample8 \charexample9 \end{multicols} \blockheader{greekupper}{Upper-Case Greek} \begin{multicols}{3} \charexample\Alpha \charexample\Beta \charexample\Gamma \charexample\Delta \charexample\Epsilon \charexample\Zeta \charexample\Eta \charexample\Theta \charexample\Iota \charexample\Kappa \charexample\Lambda \charexample\Mu \charexample\Nu \charexample\Xi \charexample\Omicron \charexample\Pi \charexample\Rho \charexample\Sigma \charexample\Tau \charexample\Upsilon \charexample\Phi \charexample\Chi \charexample\Psi \charexample\Omega \charexample\varTheta \charexample\increment \charexample\nabla \end{multicols} \blockheader{greeklower}{Lower-Case Greek} \begin{multicols}{3} \charexample\alpha \charexample\beta \charexample\gamma \charexample\delta \charexample\epsilon \charexample\zeta \charexample\eta \charexample\theta \charexample\iota \charexample\kappa \charexample\lambda \charexample\mu \charexample\nu \charexample\xi \charexample\omicron \charexample\pi \charexample\rho \charexample\sigma \charexample\tau \charexample\upsilon \charexample\phi \charexample\chi \charexample\psi \charexample\omega \charexample\varbeta \charexample\varepsilon \charexample\varkappa \charexample\vartheta \charexample\varrho \charexample\varsigma \charexample\varphi \end{multicols} \blockheader{agreekupper}{Upper-Case Ancient Greek} \begin{multicols}{3} \charexample\Heta \charexample\Sampi \charexample\Digamma \charexample\Koppa \charexample\Stigma \charexample\Sho \charexample\San \charexample\varSampi \charexample\varDigamma \charexample\varKoppa \end{multicols} \blockheader{agreeklower}{Lower-Case Ancient Greek} \begin{multicols}{3} \charexample\heta \charexample\sampi \charexample\digamma \charexample\koppa \charexample\stigma \charexample\sho \charexample\san \charexample\varsampi \charexample\vardigamma \charexample\varkoppa \end{multicols} \blockheader{cyrillicupper}{Upper-Case Cyrillic} \begin{multicols}{3} \charexample\cyrA \charexample\cyrBe \charexample\cyrVe \charexample\cyrGhe \charexample\cyrDe \charexample\cyrIe \charexample\cyrZhe \charexample\cyrZe \charexample\cyrI \charexample\cyrKa \charexample\cyrEl \charexample\cyrEm \charexample\cyrEn \charexample\cyrO \charexample\cyrPe \charexample\cyrEr \charexample\cyrEs \charexample\cyrTe \charexample\cyrU \charexample\cyrEf \charexample\cyrHa \charexample\cyrTse \charexample\cyrChe \charexample\cyrSha \charexample\cyrShcha \charexample\cyrHard \charexample\cyrYeru \charexample\cyrSoft \charexample\cyrE \charexample\cyrYu \charexample\cyrYa \charexample\cyrvarI \end{multicols} \blockheader{cyrilliclower}{Lower-Case Cyrillic} \begin{multicols}{3} \charexample\cyra \charexample\cyrbe \charexample\cyrve \charexample\cyrghe \charexample\cyrde \charexample\cyrie \charexample\cyrzhe \charexample\cyrze \charexample\cyri \charexample\cyrka \charexample\cyrel \charexample\cyrem \charexample\cyren \charexample\cyro \charexample\cyrpe \charexample\cyrer \charexample\cyres \charexample\cyrte \charexample\cyru \charexample\cyref \charexample\cyrha \charexample\cyrtse \charexample\cyrche \charexample\cyrsha \charexample\cyrshcha \charexample\cyrhard \charexample\cyryeru \charexample\cyrsoft \charexample\cyre \charexample\cyryu \charexample\cyrya \charexample\cyrvari \end{multicols} \blockheader{hebrew}{Hebrew} \begin{multicols}{3} \charexample\aleph \charexample\beth \charexample\gimel \charexample\daleth \charexample\he \charexample\vav \charexample\zayin \charexample\het \charexample\tet \charexample\yod \charexample\kaf \charexample\lamed \charexample\mem \charexample\nun \charexample\samekh \charexample\ayin \charexample\pe \charexample\tsadi \charexample\qof \charexample\resh \charexample\shin \charexample\tav \charexample\varkaf \charexample\varmem \charexample\varnun \charexample\varpe \charexample\vartsadi \end{multicols} \medskip \def\temp{; shown in \texttt{\vrb\big}, etc.\ sizes} \blockheader{delimiters\aftergroup\temp}{Delimiter} \medskip \begin{multicols}{3} \delimexample( \delimexample) \delimexample[ \delimexample] \delimexample{\{\ifmmode\else\space(Lua\TeX\ only)\fi} \delimexample{\}\ifmmode\else\space(Lua\TeX\ only)\fi} \delimexample{|\,\ifmmode\else\space(Lua\TeX\ only)\fi} \delimexample\lguil \delimexample\rguil \delimexample\llguil \delimexample\rrguil \luadelimexample\fakelangle \luadelimexample\fakerangle \luadelimexample\fakellangle \luadelimexample\fakerrangle \hbox to \hsize{\hbox to 0.8in{$\leftbrace$\hfil}\vrb\leftbrace\hfil} \hbox to \hsize{\hbox to 0.8in{$\rightbrace$\hfil}\vrb\rightbrace\hfil} \end{multicols} \medskip \blockheader{radical}{Square Root} \smallskip \begin{multicols}{2} \charexample\surd \def\temp{ (Lua\TeX\ only)\hfill} \charexample{\sqrt{\ifmmode\mkern 12mu\vphantom{1}\else\temp\fi}} \end{multicols} \blockheader{bigops}{Big Operator} \smallskip \begin{multicols}{2} \operatorexample\sum \operatorexample\prod \operatorexample\intop \end{multicols} \medskip \blockheader{extbigops}{Extended Big Operators} \smallskip \begin{multicols}{3} \operatorexample\coprod \operatorexample\bigvee \operatorexample\bigwedge \operatorexample\bigcap \operatorexample\bigcup \operatorexample\bigoplus \operatorexample\bigotimes \operatorexample\bigodot \operatorexample\bigsqcap \operatorexample\bigsqcup \operatorexample\iint \operatorexample\iiint \operatorexample\oint \operatorexample\oiint \operatorexample\oiiint \end{multicols} \medskip \blockheader{symbols}{Basic Math} \begin{multicols}{3} \charexample. \charexample @ \let\par\relax \charexample\# \charexample\$ \charexample\% \charexample\& \charexample\P \charexample\S \charexample\pounds \charexample| \charexample\neg \charexample\infty \charexample\partial \charexample\mathbackslash \charexample\degree \charexample\increment \def\temp{ (Lua\TeX\ only)} \charexample{\nabla\ifmmode\else\temp\fi} \charexample' \charexample\prime \charexample" \charexample+ \charexample- \charexample* \charexample\times \charexample/ \charexample\fractionslash \charexample\div \charexample\pm \charexample\bullet \charexample\dag \charexample\ddag \charexample\cdot \charexample\setminus \charexample= \charexample< \charexample> \charexample\leq \charexample\geq \charexample\sim \charexample\approx \charexample\simeq \charexample\equiv \charexample\cong \charexample\mid \charexample\parallel \charexample! \charexample? \charexample{,\ifmmode\else\phantom{\texttt{comma}} \rlap{(as \vrb\mathpunct)}\fi} \charexample{\comma\ifmmode\else\space(as \vrb\mathord)\fi} \charexample{:\ifmmode\else\phantom{\texttt{colon}} (as \vrb\mathrel)\fi} \charexample{\colon\ifmmode\else\space\rlap{(as \vrb\mathpunct)}\fi}\charexample; \charexample\mathellipsis \end{multicols} \blockheader{symbols}{Lua\TeX-only (!) Operator} \begin{multicols}{3} \operatorexample\bigat \operatorexample\bighash \operatorexample\bigdollar \operatorexample\bigpercent \operatorexample\bigand \operatorexample\bigplus \operatorexample\bigp \operatorexample\bigq \operatorexample\bigS \operatorexample\bigtimes \operatorexample\bigdiv \end{multicols} \blockheader{extsymbols}{Extended Math} \begin{multicols}{3} \charexample\wp \charexample\Re \charexample\Im \charexample\ell \charexample\forall \charexample\exists \charexample\emptyset \charexample{\nabla\ifmmode\else\space(\XeTeX\ only)\fi} \charexample\in \charexample\ni \charexample\mp \charexample\angle \charexample\top \charexample\bot \charexample\vdash \charexample\dashv \charexample\flat \charexample\natural \charexample\sharp \charexample\clubsuit \charexample\spadesuit \charexample\diamondsuit \charexample\heartsuit \charexample\bclubsuit \charexample\bdiamondsuit \charexample\bheartsuit \charexample\bspadesuit \charexample\wclubsuit \charexample\wdiamondsuit \charexample\wheartsuit \charexample\wspadesuit \charexample\wedge \charexample\vee \charexample\cap \charexample\cup \charexample\sqcap \charexample\sqcup \charexample\amalg \charexample\wr \charexample\ast \charexample\star \charexample\diamond \charexample\varcdot \charexample\varsetminus \charexample\oplus \charexample\otimes \charexample\ominus \charexample\odiv \charexample\oslash \charexample\odot \charexample\sqplus \charexample\sqtimes \charexample\sqminus \charexample\sqdot \charexample\in \charexample\ni \charexample\subset \charexample\supset \charexample\subseteq \charexample\supseteq \charexample\sqsubset \charexample\sqsupset \charexample\sqsubseteq \charexample\sqsupseteq \charexample\triangleleft \charexample\triangleright \charexample\trianglelefteq \charexample\trianglerighteq \charexample\propto \charexample\bowtie \charexample\hourglass \charexample\therefore \charexample\because \charexample\ratio \charexample\proportion \charexample\ll \charexample\gg \charexample\lll \charexample\ggg \charexample\leqq \charexample\geqq \charexample\lapprox \charexample\gapprox \charexample\simeq \charexample\eqsim \charexample\simeqq \charexample\cong \charexample\approxeq \charexample\sssim \charexample\seq \charexample\doteq \charexample\coloneq \charexample\eqcolon \charexample\ringeq \charexample\arceq \charexample\wedgeeq \charexample\veeeq \charexample\stareq \charexample\triangleeq \charexample\defeq \charexample\qeq \charexample\lsim \charexample\gsim \charexample\prec \charexample\succ \charexample\preceq \charexample\succeq \charexample\preceqq \charexample\succeqq \charexample\precsim \charexample\succsim \charexample\precapprox \charexample\succapprox \charexample\precprec \charexample\succsucc \charexample\asymp \charexample\nin \charexample\nni \charexample\nsubset \charexample\nsupset \charexample\nsubseteq \charexample\nsupseteq \charexample\subsetneq \charexample\supsetneq \charexample\nsqsubseteq \charexample\nsqsupseteq \charexample\sqsubsetneq \charexample\sqsupsetneq \charexample\neq \charexample\nl \def\hook{\footnote{In text mode, \vrb\ng\ produces \ng---as of version 2.2b, \textsf{mathfont} redefines the math-mode version only and leaves the text-mode version alone. If you are using the \textsf{hyperref} package, you should type \vrb\mathng\ instead of \vrb\ng.}} \charexample\ng \let\hook\relax \charexample\nleq \charexample\ngeq \charexample\lneq \charexample\gneq \charexample\lneqq \charexample\gneqq \charexample\ntriangleleft \charexample\ntriangleright \charexample\ntrianglelefteq \charexample\ntrianglerighteq \charexample\nsim \charexample\napprox \charexample\nsimeq \charexample\nsimeqq \charexample\simneqq \charexample\nlsim \charexample\ngsim \charexample\lnsim \charexample\gnsim \charexample\lnapprox \charexample\gnapprox \charexample\nprec \charexample\nsucc \charexample\npreceq \charexample\nsucceq \charexample\precneq \charexample\succneq \charexample\precneqq \charexample\succneqq \charexample\precnsim \charexample\succnsim \charexample\precnapprox \charexample\succnapprox \charexample\nequiv \end{multicols} \blockheader{arrows}{Arrow} \begin{multicols}{2} \def\hook{\footnote{Both \vrb\relbar\space and \vrb\Relbar\space are helper macros that certain packages use to elongate various horizontal arrows.}} \charexample\relbar \let\hook\relax \charexample\Relbar \charexample\rightarrow \charexample\to \charexample\nrightarrow \charexample\Rightarrow \charexample\nRightarrow \charexample\Rrightarrow \charexample\longrightarrow \charexample\Longrightarrow \charexample\rightbararrow \charexample\mapsto \charexample\Rightbararrow \charexample\longrightbararrow \charexample\longmapsto \charexample\Longrightbararrow \charexample\hookrightarrow \charexample\rightdasharrow \charexample\rightharpoonup \charexample\rightharpoondown \charexample\rightarrowtail \charexample\rightoplusarrow \charexample\rightwavearrow \charexample\rightsquigarrow \charexample\longrightsquigarrow \charexample\looparrowright \charexample\curvearrowright \charexample\circlearrowright \charexample\twoheadrightarrow \charexample\rightarrowtobar \charexample\rightwhitearrow \charexample\rightrightarrows \charexample\rightrightrightarrows \charexample\leftarrow \charexample\from \charexample\nleftarrow \charexample\Leftarrow \charexample\nLeftarrow \charexample\Lleftarrow \charexample\longleftarrow \charexample\Longleftarrow \charexample\leftbararrow \charexample\mapsfrom \charexample\Leftbararrow \charexample\longleftbararrow \charexample\longmapsfrom \charexample\Longleftbararrow \charexample\hookleftarrow \charexample\leftdasharrow \charexample\leftharpoonup \charexample\leftharpoondown \charexample\leftarrowtail \charexample\leftoplusarrow \charexample\leftwavearrow \charexample\leftsquigarrow \charexample\longleftsquigarrow \charexample\looparrowleft \charexample\curvearrowleft \charexample\circlearrowleft \charexample\twoheadleftarrow \charexample\leftarrowtobar \charexample\leftwhitearrow \charexample\leftleftarrows \charexample\leftleftleftarrows \charexample\leftrightarrow \charexample\Leftrightarrow \charexample\nLeftrightarrow \charexample\longleftrightarrow \charexample\Longleftrightarrow \charexample\leftrightwavearrow \charexample\leftrightarrows \charexample\leftrightharpoons \charexample\leftrightarrowstobar \charexample\rightleftarrows \charexample\rightleftharpoons \charexample\uparrow \charexample\Uparrow \charexample\Uuparrow \charexample\upbararrow \charexample\updasharrow \charexample\upharpoonleft \charexample\upharpoonright \charexample\twoheaduparrow \charexample\uparrowtobar \charexample\upwhitearrow \charexample\upwhitebararrow \charexample\upuparrows \charexample\downarrow \charexample\Downarrow \charexample\Ddownarrow \charexample\downbararrow \charexample\downdasharrow \charexample\zigzagarrow \charexample\lightningboltarrow \charexample\downharpoonleft \charexample\downharpoonright \charexample\twoheaddownarrow \charexample\downarrowtobar \charexample\downwhitearrow \charexample\downdownarrows \charexample\updownarrow \charexample\Updownarrow \charexample\updownarrows \charexample\downuparrows \charexample\updownharpoons \charexample\downupharpoons \charexample\nearrow \charexample\Nearrow \charexample\nwarrow \charexample\Nwarrow \charexample\searrow \charexample\Searrow \charexample\swarrow \charexample\Swarrow \charexample\nwsearrow \charexample\neswarrow \charexample\lcirclearrow \charexample\rcirclearrow \end{multicols} \blockheader{bb}{Blackboard Bold} \vskip\multicolsep \letterlikechars\mathbb \hbox to \hsize{\printchars\digits\hfil} \vskip\multicolsep \blockheader{cal}{Caligraphic} \vskip\multicolsep \letterlikechars\mathcal \vskip\multicolsep \blockheader{frak}{Fraktur} \vskip\multicolsep \letterlikechars\mathfrak \vskip\multicolsep \blockheader{bcal}{Bold Calligraphic} \vskip\multicolsep \letterlikechars\mathbcal \vskip\multicolsep \blockheader{bfrak}{Bold Fraktur} \vskip\multicolsep \letterlikechars\mathbfrak \end{document} % %<*equations> \multicolsep=0pt\relax \bigskip \begin{multicols*}{2} Black-Scholes Equation \[ \frac{\partial V}{\partial t}+ \frac12\sigma^2S^2\frac{\partial^2V}{\partial S^2} =rV-rS\frac{\partial V}{\partial X} \] \vfill Cardano's Formula/Cubic Formula \begin{align*} t_i&=\omega_i\sqrt[3]{-\frac q2+\sqrt{\frac{q^2}4+\frac{p^3}{27}}}\\ &\qquad\qquad{}+\omega_i^2\sqrt[3]{-\frac q2-\sqrt{\frac{q^2}4+\frac{p^3}{27}}} \end{align*} \vfill Einstein's Field Equation (General Relativity) \[ R_{\mu\nu}-\frac12Rg_{\mu\nu}+\Lambda g_{\mu\nu}=\frac{8\pi G}{c^4}T_{\mu\nu} \] \vfill First Isomorphism Theorem \[ \phi(X)\cong X/\ker(\phi) \] \vfill Gauss-Bonnet Formula \[ \int_MK\ dA+\int_{\partial M}k_g\ ds=2\pi\chi(M) \] \vfill Maxwell's Equations \begin{align*} \nabla\bullet\mathbf E&=\frac\rho{\epsilon_0}& \nabla\bullet\mathbf B&=0\\ \nabla\times\mathbf E&=-\frac{\partial\mathbf B}{\partial t}& \nabla\times\mathbf B&=\mu_0\left(\mathbf J+ \epsilon_0\frac{\partial\mathbf E}{\partial t}\right) \end{align*} \vfill Michaelis-Menten Model \bgroup \belowdisplayskip=0pt\relax \belowdisplayshortskip=0pt\relax \[ v=\frac{d[P]}{dt}=V\frac{[S]}{K_M+[S]} \] \par\egroup \hrule height 0pt \columnbreak %% next column begins here Navier-Stokes Equation \begin{align*} \frac{\partial}{\partial t}(\rho\mathbf{u})+\nabla\bullet (\rho \mathbf{u}\otimes \mathbf{u})={} &{-}\nabla\bar p+\mu\nabla^2\mathbf{u}\\ &+\frac13\mu\nabla(\nabla\bullet u)+ \rho\mathbf{g} \end{align*} \vfill Quadratic Formula \[ x=\frac{-b\pm\sqrt{b^2-4ac}}{2a} \] \vfill Ramanujan's Approximation for $\Gamma$ \[ \Gamma(1+x)\approx\sqrt\pi\,x^xe^{-x}\,\sqrt[6]{8x^3+4x^2+x+\frac1{30}} \] \vfill Residue Theorem \[ \frac1{2i\pi}\int_{\gamma}f(z)\ dz=\sum_{k=1}^n\Res_{a_k}(f) \] \vfill Riemann Zeta Function \begin{align*} \zeta(z)&=\sum_{i=1}^\infty\frac1{z^i} =\frac1{\Gamma(z)}\int_0^\infty\frac{x^{z-1}}{e^x-1}\ dx\\ &=2^z\pi^{z-1}\sin\left(\frac{\pi z}2\right)\,\Gamma(1-z)\,\zeta(1-z) \end{align*} \vfill Schrodinger Equation \[ i\hbar\frac d{dt}|\Psi(t)\fakerangle=\hat H|\Psi(t)\fakerangle \] \vfill Lorentz Transformation (Special Relativity) \belowdisplayskip=0pt\relax \belowdisplayshortskip=0pt\relax \[ t'=\left(t-\frac{vx}{c^2}\right)\frac1{\sqrt{1-\frac{v^2}{c^2}}} \] \hrule height 0pt \end{multicols*} % %<*cormorant> \ifx\directlua\undefined \PackageError{mathfont} {\MessageBreak LuaLaTeX is recommended for\MessageBreak mathfont-example-cormorant.tex} {It's recommended that you typeset this file\MessageBreak with LuaTeX. You can use XeLaTeX if you want,\MessageBreak but things will turn out weird. To resolve\MessageBreak this error, typeset the file with LuaLaTeX.} \fi \documentclass[12pt]{article} \usepackage[margin=1in]{geometry} \usepackage{innerscript} \usepackage{multicol} \usepackage{amsmath} \DeclareMathOperator{\Res}{Res} \usepackage{mathfont} \documentfont{Cormorant:-liga} \mathfont[greeklower=upright,greekupper]{Crimson} \mathfont[diacritics]{Bona Nova} \RuleThicknessFactor{800} \parindent=0pt\relax \begin{document} \def\footnote#1{} \def\showabstract{0} \let\textsf\relax \let\ttfamily\relax \def\documentname{Example---Cormorant} \input mathfont-heading.tex This is Cormorant with Crimson for Greek characters and Bona Nova for diacritics. ``Testing. Testing.'' Brown foxes quickly jump over dazzling does and harts. This document shows an example of mathfont in action. Unfortunately, there are many more equations in the world than I have space for here. Nevertheless, I hope I hit some of the highlights. Happy \TeX ing! \input{mathfont-equations.tex} \end{document} % %<*kelvinch> \ifx\directlua\undefined \PackageError{mathfont} {\MessageBreak LuaLaTeX is recommended for\MessageBreak mathfont-example-kelvinch.tex} {It's recommended that you typeset this file\MessageBreak with LuaTeX. You can use XeLaTeX if you want,\MessageBreak but things will turn out weird. To resolve\MessageBreak this error, typeset the file with LuaLaTeX.} \fi \documentclass[12pt]{article} \usepackage[margin=1in]{geometry} \usepackage{innerscript} \usepackage{multicol} \usepackage{amsmath} \DeclareMathOperator{\Res}{Res} \usepackage{mathfont} \documentfont{Kelvinch:-clig} \mathfont[radical]{Crimson} \IntegralItalicFactor{500} \hsurdfactor=900 \rulethicknessfactor=1300 \parindent=0pt\relax \begin{document} \def\footnote#1{} \def\showabstract{0} \let\textsf\relax \let\ttfamily\relax \def\documentname{Example---Kelvinch} \input mathfont-heading.tex This is Kelvinch with Crimson for the radical signs. ``Testing. Testing.'' Brown foxes quickly jump over dazzling does and harts. This document shows an example of mathfont in action. Unfortunately, there are many more equations in the world than I have space for here. Nevertheless, I hope I hit some of the highlights. Happy \TeX ing! \input{mathfont-equations.tex} \end{document} % %<*roboto> \ifx\directlua\undefined \PackageError{mathfont} {\MessageBreak LuaLaTeX is recommended for\MessageBreak mathfont-example-roboto.tex} {It's recommended that you typeset this file\MessageBreak with LuaTeX. You can use XeLaTeX if you want,\MessageBreak but things will turn out weird. To resolve\MessageBreak this error, typeset the file with LuaLaTeX.} \fi \documentclass[12pt]{article} \usepackage[margin=1in]{geometry} \usepackage{innerscript} \usepackage{multicol} \usepackage{amsmath} \DeclareMathOperator{\Res}{Res} \usepackage[Roboto]{mathfont} \mathfont[radical]{Overpass} \mathfontshapes{STIXGeneral} \DeclareMathSymbol{\otimes}{\mathbin}{M5-m/n}{"2297} \rulethicknessfactor=1600 \IntegralItalicFactor{500} \hsurdfactor=800 \parindent=0pt\relax \begin{document} \def\footnote#1{} \def\showabstract{0} \let\textsf\relax \let\ttfamily\relax \def\documentname{Example---Roboto} \input mathfont-heading.tex This is Roboto with Overpass for the radical signs and STIXGeneral for the tensor product. ``Testing. Testing.'' Brown foxes quickly jump over dazzling does and harts. This document shows an example of mathfont in action. Unfortunately, there are many more equations in the world than I have space for here. Nevertheless, I hope I hit some of the highlights. Happy \TeX ing! \input{mathfont-equations.tex} \end{document} % %<*typey> \ifx\directlua\undefined \PackageError{mathfont} {\MessageBreak LuaLaTeX is recommended for\MessageBreak mathfont-example-typey.tex} {It's recommended that you typeset this file\MessageBreak with LuaTeX. You can use XeLaTeX if you want,\MessageBreak but things will turn out weird. To resolve\MessageBreak this error, typeset the file with LuaLaTeX.} \fi \documentclass[12pt]{article} \usepackage[margin=1in]{geometry} \usepackage{innerscript} \usepackage{multicol} \usepackage{amsmath} \DeclareMathOperator{\Res}{Res} \usepackage{mathfont} %% We have to declare Typey McTypeface manually because %% it has no bold fontface---we use embolden from luaotflaod %% to make a fake bold \makeatletter \DeclareFontFamily{TU}{Typey}{} \DeclareFontShape{TU}{Typey}{m}{n} {<->"Typey McTypeface:\M@otf@features"}{} \DeclareFontShape{TU}{Typey}{m}{it} {<->"Typey McTypeface/I:\M@otf@features"}{} \DeclareFontShape{TU}{Typey}{b}{n} {<->"Typey McTypeface:\M@otf@features;embolden=6"}{} \DeclareFontShape{TU}{Typey}{b}{it} {<->"Typey McTypeface/I:\M@otf@features;embolden=6"}{} %% We also need to declare Typey-base family for math mode \DeclareFontFamily{TU}{Typey-base}{} \DeclareFontShape{TU}{Typey-base}{\mddefault}{\shapedefault} {<->"Typey McTypeface:\M@otf@features;mode=base"}{} \DeclareFontShape{TU}{Typey-base}{\mddefault}{\itdefault} {<->"Typey McTypeface/I:\M@otf@features;mode=base"}{} \DeclareFontShape{TU}{Typey-base}{\bfdefault}{\shapedefault} {<->"Typey McTypeface:\M@otf@features;embolden=6;mode=base"}{} \DeclareFontShape{TU}{Typey-base}{\bfdefault}{\itdefault} {<->"Typey McTypeface/I:\M@otf@features;embolden=6;mode=base"}{} %% And link the Typey-base font family to the Typey family \expandafter\def\csname Typey-base\endcsname{Typey-base} \makeatother \documentfont{Typey} \mathfont[radical]{Crimson} \mathfontshapes{STIXGeneral} \DeclareMathSymbol{\otimes}{\mathbin}{M5-m/n}{"2297} \RuleThicknessFactor{1300} \hsurdfactor850 \parindent=0pt\relax \begin{document} \def\footnote#1{} \def\showabstract{0} \let\textsf\relax \let\ttfamily\relax \def\documentname{Example---Typey McTypeface} \input mathfont-heading.tex This is Typey McTypeface with Crimson for the radical signs and STIXGeneral for the tensor product. ``Testing. Testing.'' Brown foxes quickly jump over dazzling does and harts. This document shows mathfont in action. Unfortunately, there are many more equations in the world than I have space for here. Nevertheless, I hope I hit some of the highlights. Happy \TeX ing! \let\bullet\cdot \input{mathfont-equations.tex} \end{document} % %<*heading> \csname count@\endcsname\catcode`\@ \makeatletter % package date and edition \def\packagedate{January 2026} \def\packageversion{3.0} % header and footer commands \let\@@section\section \def\section{\par \penalty\z@ \vskip0.7in\relax \penalty\z@ \vskip-0.7in\relax \vskip\z@ \@ifstar\star@sect\no@star@sect} \def\star@sect#1{\@@section*{#1}\section@name{#1}} \def\no@star@sect#1{\@@section{#1}\section@name{#1}} \def\section@name#1{\expandafter \def\csname section@\thesection\endcsname{#1}} \def\sectionname{\csname section@\thesection\endcsname} \def\@oddhead{\ifnum\c@page>\@ne \ifodd\c@page \rlap{\textit{\sectionname}}\hfil \hbox to 0pt{\hss\documentname\hss}\hfil \llap{\the\c@page}\relax \else \rlap{\the\c@page}\hfil \hb@xt@\z@{\hss\documentname\hss}\hfil \llap{\textit{\sectionname}}\relax \fi \else \hfil \fi} \def\@oddfoot{\hfil\ifnum\count0=1\relax1\fi\hfil} \let\@evenfoot\@empty % penalties \pretolerance=20 \hyphenpenalty=10 \exhyphenpenalty=5 \brokenpenalty=0 \clubpenalty=5 \widowpenalty=5 \finalhyphendemerits=300 \doublehyphendemerits=500 \flushbottom % general macros \protected\def\XeTeX{X\kern-0.125em \raise-0.5ex\hbox{\reflectbox{E}}\kern-0.1667em \TeX} \protected\def\XeLaTeX{X\kern-0.125em \raise-0.5ex\hbox{\reflectbox{E}}\kern-0.125em \LaTeX} \bgroup \catcode`\_=12 \protected\gdef \fontspeccommand{\texttt{\string\fontspec_set_family:Nnn}} \protected\gdef \fontspecbool{\texttt{\string\g__fontspec_math_bool}} \egroup \def\topfraction{1} \def\bottomfraction{1} \let\code\@undefined \newenvironment{code} {\strut\vadjust\bgroup\vskip 5pt plus 1pt minus 3pt\relax \parindent\z@\leftskip2em\relax \noindent\strut\ignorespaces} {\strut\par\vskip 5pt plus 1pt minus 3pt\relax \egroup\hfill\break\strut\ignorespacesafterend} \def\vrb#1{\expandafter\texttt\expandafter{\string#1}} \parskip=0pt % symbol list macros \def\charexample#1{\hbox to \hsize{\hbox to 0.4in{$#1$\hfil}\vrb#1\hook\hfil}} \def\accentexample#1{\hbox to \hsize{\hbox to 0.4in{$#1 a$\hfil}\vrb#1\hook\hfil}} \let\hook\relax \def\delimexample#1{\hbox to \hsize{% \hbox to 0.8in{$#1\big#1\Big#1\bigg#1\Bigg#1$\hfil}\vrb#1\hfil}} \def\luadelimexample#1{\hbox{\vbox{\hbox to 0.8in{% $#1\big#1\Big#1\bigg#1\Bigg#1$\hfil}\hrule width 0pt height 0pt\relax}% \hbox to \dimexpr\hsize-0.8in{\vbox{\vss \hbox{\vrb#1} \hbox{\quad(Lua\TeX only)} \vss}\hfil}}} \def\operatorexample#1{\hbox to \hsize{% \hbox to 0.4in{$#1$\hfil}% \hbox to 0.4in{$\displaystyle#1$\hfil}\vrb#1\hfil}\smallskip} \def\blockheader#1#2{% \hbox{\fbox{\hbox to \dimexpr\hsize-2\fboxrule-2\fboxsep\relax{% \hfil#2 Characters (Keyword \texttt{#1})\strut\hfil}}}} \def\upperalphabet{ABCDEFGHIJKLMNOPQRSTUVWXYZ} \def\loweralphabet{abcdefghijklmnopqrstuvwxyz} \def\digits{0123456789} \def\printchars#1{% \expandafter\@tfor\expandafter\letter\expandafter:\expandafter=#1\do{% \hbox to \dimexpr\hsize/26{$\@tempstyle{\letter}$\hfil}}} \def\letterlikechars#1{\smallskip\let\@tempstyle#1 \noindent\printchars\upperalphabet\par \noindent\printchars\loweralphabet\par} % title information {\large\parindent=0pt\leftskip=0pt plus 1 fil\rightskip=0pt plus 1fil\parfillskip=0pt {\global\setbox0\hbox{\strut\Large Package \textsf{mathfont} v.\ \packageversion\ \documentname}% \unhcopy0\let\thefootnote\relax\footnote{Acknowledgements: Thanks to Lyric Bingham for her work checking my Unicode hex values. Thanks to Matthew Braham, Sergio Callegari, Daniel Flipo, Shyam Sundar, Adrian Vollmer, Herbert Voss, and Andreas Zidak for pointing out bugs in previous versions of \textsf{mathfont}. Thanks to Jean-Fran\c cois Burnol for pointing out an error in the documentation in reference to his \textsf{mathastext} package.}\global\advance\c@footnote\m@ne}\par {\strut Conrad Kosowsky}\par {\strut\packagedate}\par {\strut\ttfamily kosowsky.latex@gmail.com}\par} \medskip \ifnum\showabstract=1\relax % off-the-shelf insert {% add margin \leftskip 0.5in \rightskip 0.5in % margin changes for user guide and symbol list \ifdim\hsize>6in \advance\leftskip 0.5in \advance\rightskip -0.5in \fi % set \hsize \hsize\dimexpr\paperwidth - 3in\relax % no \parindent \parindent\z@ % now make the insert \leavevmode\hb@xt@\dimexpr\hsize - \leftskip - \rightskip\relax{% \vrule width \p@ \kern-\p@\relax \vbox{\hsize\dimexpr\hsize - \leftskip - \rightskip\relax \parindent\z@ \leftskip\medskipamount \rightskip\medskipamount \hrule height \p@ \smallskip \strut For easy, off-the-shelf use, type the following in your preamble and compile with \XeLaTeX\ or Lua\LaTeX:\par \medskip \hfil|\usepackage[|\meta{font name}|]{mathfont}|\par \medskip As of version 2.0, using Lua\LaTeX\ is recommended. Minor backwards incompatible changes in version 3.0.\strut\par \smallskip \hrule height \p@}% \kern-\p@ \vrule width \p@} \medskip % abstract {\small {\hfil\bfseries Overview\strut\par} The \textsf{mathfont} package adapts Unicode text fonts for math mode. The package allows the user to specify a default font for different classes of math symbols, and it enables Unicode input in math mode. The package provides tools to change the font locally for math alphabet characters. When typesetting with Lua\TeX, \textsf{mathfont} adds resizable delimiters, big operators, and a MathConstants table to text fonts.\par}} \bigskip\bigskip\nointerlineskip \centerline{\vrule height 0.5pt width 2.5in}\bigskip\bigskip \nointerlineskip \fi \catcode`\@\count@ % %<*doc> % definitions and a new toks \let\?\SpecialUsageIndex \expandafter\newif\csname if@def\endcsname \newtoks\index@nomainlist \index@nomainlist{} \MacrocodeTopsep=2.5pt plus 3pt minus 1pt \def\@defname{def} \def\@edefname{edef} \def\@gdefname{gdef} \def\@xdefname{xdef} \def\@letname{let} \let\main\textbf % choose macros not to index by definition \def\DoNotIndexMain{\bgroup \catcode`\\=12\relax \do@not@index@main} \def\do@not@index@main#1{\egroup \index@nomainlist\expandafter{\the\index@nomainlist#1,}} % the patch \reversemarginpar \@mparswitchfalse \marginparsep=0.5em \newbox\@tempboxb \newbox\macrobox \marginparwidth=\dimexpr1.5in-2\marginparsep\relax % macro to put macros in the margin % we need to \let\par\relax because \marginpar % contains a transition to h mode and back to v % mode that will mess up our code line numbering \def\marginmacro#1\@nil{\begingroup\footnotesize \setbox\macrobox\vbox{}\relax \setbox\@tempboxa\hbox{\@backslashchar}\relax \@tfor\@i:=#1\do {\setbox\@tempboxb\hbox{\@i}\relax \ifdim\dimexpr\wd\@tempboxa+\wd\@tempboxb\relax <\marginparwidth \setbox\@tempboxa\hbox{\unhbox\@tempboxa\unhbox\@tempboxb}\else \@break@tfor\fi}\relax \let\par\relax \marginpar{\hb@xt@\marginparwidth{\hfil\unhbox\@tempboxa}}\endgroup} \def\macro@finish{\macro@namepart \if@def \@deffalse \@expandtwoargs\in@{\macro@namepart}{\the\index@excludelist}\relax \ifin@ \else \@expandtwoargs\in@{\macro@namepart}{\the\index@nomainlist}\relax \ifin@ \edef\@tempa{\noexpand\SpecialIndex{\bslash\macro@namepart}}\relax \@tempa \else \edef\@tempa{\noexpand\SpecialMainIndex{\bslash\macro@namepart}}\relax \expandafter\marginmacro\macro@namepart\@nil \@tempa \fi \fi \else \ifx\macro@namepart\@defname \@deftrue \else \ifx\macro@namepart\@edefname \@deftrue \else \ifx\macro@namepart\@letname \@deftrue \else \ifx\macro@namepart\@gdefname \@deftrue \else \ifx\macro@namepart\@xdefname \@deftrue \fi \fi \fi \fi \fi \@expandtwoargs\in@{\macro@namepart}{\the\index@excludelist}\relax \ifin@ \else \edef\@tempa{\noexpand\SpecialIndex{\bslash\macro@namepart}}\relax \@tempa \fi \fi} % the other patch (just one change: \parskip\z@ to \parskip 0pt plus 0.2pt) \def\macro@code{% \topsep \MacrocodeTopsep \@beginparpenalty0% \predisplaypenalty \if@inlabel\leavevmode\fi \trivlist \parskip 0pt plus 0.2pt \item[]% \macro@font \leftskip\@totalleftmargin \advance\leftskip\MacroIndent \rightskip\z@ \parindent\z@ \parfillskip\@flushglue \blank@linefalse \def\par{\ifblank@line \leavevmode\fi \blank@linetrue\@@par \penalty\interlinepenalty} \obeylines \let\do\do@noligs \verbatim@nolig@list \let\do\@makeother \dospecials \global\@newlistfalse \global\@minipagefalse \ifcodeline@index \everypar{\global\advance\c@CodelineNo\@ne \llap{\theCodelineNo\ \hskip\@totalleftmargin}% \check@module}% \else \everypar{\check@module}% \fi \init@crossref} % % % \fi % % \check@checksum % \endinput