%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Module:    ZzTeX Font Facilities
%
% Synopsis:  This module contains all the macros necessary to define type
%            sizes, styles, and fonts.
%
% Author:    Paul C. Anagnostopoulos
% Created:   28 August 1989
%
% Copyright 1989--2020 by Paul C. Anagnostopoulos
% under The MIT License (opensource.org/licenses/MIT)
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%                       Baselines & Struts
%                       --------- - ------


\zremovePlaindef \strutbox
\definebox{\strutbox}           % Strut for current type size.

\def \strut {%
  \relax
  \if \mathmodep
    \copy \strutbox
  \else
    \unhcopy \strutbox
  \fi}

\def \normalbaselines {%
  \baselineskip = \the\baselinemultiplier\normalbaselineskip
  \lineskiplimit = \normallineskiplimit
  \lineskip = \normallineskip}

%                       Type Style & Size Definition
%                       ---- ----- - ---- ----------


% The following character set encodings are available. Odd numbers
% indicate italic; numbers > 20 indicate monospaced.

\chardef \encoderoman         =  0      % Roman. %^encoding
\chardef \encodeitalic        =  1      % Italic. %^encoding
\chardef \encodemathitalic    =  3      % Math italic. %^encoding
\chardef \encodemathsymbol    =  4      % Math symbols. %^encoding
\chardef \encodemathextended  =  6      % Math extended symbols. %^encoding
\chardef \encodematharrow     =  8      % Math arrows. %^encoding
\chardef \encodeother         = 10      % Generic. %^encoding
\chardef \encodemono          = 22      % Monospaced. %^encoding
\chardef \encodemonoitalic    = 23      % Monospaced italic. %^encoding

\setlist \zfsizelist = {}
\setlist \zfstylelist = {}


\def \definetypestyle #1#2{%                    {\name}{\encoding}
  \append{#1}{\zfstylelist}%
  \zfwithfam{\zdeffam}{#1}%
  \zfwithmat{\def}{#1}{\zfl}{}%
  \zfwithmat{\xdef}{#1}{\zen}{#2}}

\def \definetypesize #1#2{%                     {\name}{size/baseline}
  \append{#1}{\zfsizelist}%
  \zdefsize #1#2/%
  \zdefstrut #1#2/%
  \zfbldsize{#1}}

\def \zdefsize #1#2/#3/{%                       \name size/baseline/
  \zfwithmat{\xdef}{#1}{\zsz}{#2pt}}

\def \zdefstrut #1#2/#3/{%                      \name size/baseline/
  {\calculate \tdimena = {#3pt,P,70}%
   \tdimenb = #3pt\relax
   \advance \tdimenb by -\tdimena
   \zfwithmat{\xdef}{#1}{\zst}{height \the\tdimena\space depth \the\tdimenb}}}


% A few useful predicates.

\def \typestylep #1{%                                   {\style}
  \xtokeqlp{\the\typestyle}{#1}}

\def \italicencodingp {%
  \oddp{\typeencoding}}

\def \monoencodingp {%
  \gtrp{\typeencoding}{20}}

% Commands to set font parameters.

\def \setstylefontparam #1#2#3{%                {\style}{param}{value}
  \zfwithmat\maplistlf {#1}{\zfl}{%
    \zfsetfp{##1}{#2}{#3}}}

\def \setstylehyphenchar #1#2{%                 {\style}{number}
  \setstylefontparam{#1}{-2}{#2}}

\def \setstyleskewchar #1#2{%                   {\style}{number}
  \setstylefontparam{#1}{-1}{#2}}

\def \zfsetfp #1#2#3{%                          {font}{param}{value}
  \if \eqlp{#2}{-2}%
    \hyphenchar #1=#3\relax
  \else\if \eqlp{#2}{-1}%
    \skewchar #1=#3\relax
  \else
    \fontdimen#2#1=#3\relax
  \fi\fi}

%                       Style Relations
%                       ----- ---------


\def \definestylerelation #1#2#3{%              {\style}{\relation}{\style}
  \zfwithmat{\gdef}{#1}{#2}{#3}%
  \gdef #2{\bgroup \zfrelstyle{#2}%
                   \if \italicencodingp \aftergroup \/\fi
                   \let \znext}}

\def \zfrelstyle #1{%                           {\relation}
  \if \mathmodep
    \ztoksa = \expandaftertwice{\zfmat\math#1}%
    \expandafter\ifx \the\ztoksa\relax
      \zfnorelstyle{math}{#1}%
    \fi
  \else
    \ztoksa = \expandafterthrice{\expandafter\zfmat\the\typestyle#1}%
    \expandafter\ifx \the\ztoksa\relax
      \zfnorelstyle{\the\typestyle}{#1}%
    \fi
  \fi
  \the\ztoksa}

\def \zfnorelstyle #1#2{%
  \error{norelstyle}
        {The current `#1' style has no related style for `\string#2'}}

%                       Font Definition
%                       ---- ----------


\setlist \ztfmlist = {}%


\def \definefont #1#2{%                         {\name}{tfm at size}
  \global\font #1 = #2\relax
  \zregistertfm #2\zmark
  \if \zcommonencoding
    \if \andp{\dimposp{\fontdimen7#1}}{\dimlssp{\fontdimen7#1}{.1pt}}%
      \fontdimen7#1 = \fontdimen2#1\relax       % Unlock it.
    \else\if \dimeqlp{\fontdimen7#1}{\fontdimen2#1}
      \relax                                    % Already unlocked.
    \else
      \error{lockedfont}{The TFM for font `#2' is locked}%
    \fi\fi
  \fi}

\def \zregistertfm #1 #2\zmark{%                tfm at size\zmark
  \member{\ztfmreg}{#1}{\ztfmlist}%
  \if \notp{\ztfmreg}\append{#1}{\ztfmlist}\fi}  

\def \fontinterwordspacing #1#2{%               {font}{factor}
  \fontdimen2#1= #2\fontdimen2#1%
  \fontdimen3#1= #2\fontdimen3#1%
  \fontdimen4#1= #2\fontdimen4#1%
  \fontdimen7#1= #2\fontdimen7#1}

%                       Font Selection
%                       ---- ---------


\definetoks{\typesizename}              % Current type size name.
\definedimen{\typesize}{0pt}            % Current type size in points.
\definetoks{\typestyle}                 % Current type style.
\definecount{\typeencoding}{0}          % Current type encoding.


% Equal signs and by's have been omitted for the sake of efficiency.

\def \setfont #1#2#3{%                          {\size}{\style}{\font}
  \setfontmath{#1}{#2}{#3}{\nullfont}{\nullfont}}
  
\def \setfontmath #1#2#3#4#5{%  {\size}{\style}{\text}{\script}{\scriptscript}
  \edef \zfam {\zffam{#2}}%
  \zfwithmat{\xdef}{#1}{#2}{%
    \textfont \zfam #3%
    \scriptfont \zfam #4%
    \scriptscriptfont \zfam #5%
    \def \noexpand#2{%
      \typestyle {\noexpand#2}%
      \typeencoding \zfmat{#2}{\zen}%
      #3%
      \fam \zfam}}%
  \zfbldsize{#1}%
  \zfaddfont{#2}{#3}%
  \zfaddfont{#2}{#4}%
  \zfaddfont{#2}{#5}}

\def \zfbldsize #1{%                            {\size}
  {\gdef #1{}
   \maplist{\zfaddstyle{#1}{##1}}{\zfstylelist}%
   \ztoksa \expandafter{#1}%
   \xdef #1{%
     \typesizename {\noexpand#1}%
     \typesize \zfmat{#1}{\zsz}%
     \the\ztoksa
     \setbox\strutbox \hbox{\vrule \zfmat{#1}{\zst} width 0pt}%
     \normalbaselineskip \ht\strutbox
     \advance \normalbaselineskip \dp\strutbox
     \noexpand\normalbaselines
     \typestyle {none}\nullfont \fam -1\relax}}}

\def \zfaddstyle #1#2{%                                 {\size}{\style}
  \ztoksa \expandafter{#1}%
  \ztoksb \expandaftertwice{\zfmat{#1}{#2}}%
  \expandafter\ifx \the\ztoksb\relax
    \xdef #1{\the\ztoksa
             \noexpand\zclearfam{\zffam{#2}}%
             \def \noexpand#2{\noexpand\zfundef{\noexpand#1}{\noexpand#2}}}%
  \else
    \xdef #1{\the\ztoksa \the\ztoksb}%
  \fi}

\def \zfaddfont #1#2{%                                  {\style}{font}
  \zfwithmat{\appendlf}{#1}{\zfl}{#2}}


% This macro clears out a family so TeX can't set math in it.

\def \zclearfam #1{%                                    {family}
  \textfont #1 \nullfont
  \scriptfont #1 \nullfont
  \scriptscriptfont #1 \nullfont}

% This macro is called if the user selects a type style that has no font
% in the current size.

\def \zfundef #1#2{%                                    {\size}{\style}
  \error{nofontset}
        {No font has been set for size `\string#1' style `\string#2'}}

%                       Miscellaneous
%                       -------------


% The following definition allows the user to write:
%   \withfont{\bf Hi there}

\let \withfont = \relax

% This macro helps with defining math fonts.

\def \definemathfonts #1#2#3#4#5#6{%    {prefix}{rm-font}{mit}{msy}{mex}{size}
  \edef \znext {%
    \noexpand\definefont{\name{#1rm}}{#2 at #6}%
    \noexpand\definefont{\name{#1mit}}{#3 at #6}%
    \noexpand\definefont{\name{#1msy}}{#4 at #6}%
    \noexpand\definefont{\name{#1mex}}{#5 at #6}}%
  \znext}

% This macro helps with setting math fonts.

\def \setmathfonts #1#2#3#4{%           {\size}{\text}{\script}{\scriptscript}
  \edef \znext {%
    \noexpand\setfontmath{\noexpand#1}{\noexpand\rm}%
                         {\name{#2rm}}{\name{#3rm}}{\name{#4rm}}%
    \noexpand\setfontmath{\noexpand#1}{\noexpand\mit}%
                         {\name{#2mit}}{\name{#3mit}}{\name{#4mit}}%
    \noexpand\setfontmath{\noexpand#1}{\noexpand\msy}%
                         {\name{#2msy}}{\name{#3msy}}{\name{#4msy}}%
    \noexpand\setfontmath{\noexpand#1}{\noexpand\mex}%
                         {\name{#2mex}}{\name{#2mex}}{\name{#2mex}}}%
  \znext}

%                       Measuring Things
%                       --------- ------


\definebox{\zmeasbox}


\def \measureascenderheight #1{%                        {\dimen}
  \zsetmeasbox{bdfhijklt}%
  #1 = \ht\zmeasbox}

\def \measurecapheight #1{%                             {\dimen}
  \zsetmeasbox{ABCDEFGHIJKLMNOPQRSTUVWXYZ}%
  #1 = \ht\zmeasbox}

\def \measuredescenderdepth #1{%                        {\dimen}
  \zsetmeasbox{gjpqy}%
  #1 = \dp\zmeasbox}

\def \measuredigitheight #1{%                           {\dimen}
  \zsetmeasbox{0123456789}%
  #1 = \ht\zmeasbox}

\def \measuredigitwidth #1{%                            {\dimen}
  \zsetmeasbox{0}%
  #1 = \wd\zmeasbox}

\def \measureemwidth #1{%                               {\dimen}
  #1 = 1em}

\def \measurespacewidth #1{%                            {\dimen}
  #1 = \fontdimen2\font}

\def \measurexheight #1{%                               {\dimen}
  #1 = 1ex}

\def \measuretextwidth #1#2{%                           {\dimen}{text}
  \zsetmeasbox{#2}%
  #1 = \wd\zmeasbox}

\def \measuretextheight #1#2{%                          {\dimen}{text}
  \zsetmeasbox{#2}%
  #1 = \ht\zmeasbox}

\def \measuretextdepth #1#2{%                           {\dimen}{text}
  \zsetmeasbox{#2}%
  #1 = \dp\zmeasbox}

\def \zsetmeasbox #1{\setbox\zmeasbox = \hbox{#1}}

\def \definewidthdimen #1#2{%                           {\dimen}{text}
  \definedimen{#1}{0pt}%
  \measuretextwidth{#1}{#2}}

%                       Utilities
%                       ---------


\def \zfmat #1#2{%                              {\size}{\style}
  \csname zf\expandafter\discardtok \string#1%
            \expandafter\discardtok \string#2\endcsname}

\def \zfwithmat #1#2#3{%                        {\command}{\size}{\style}
  \expandafter#1\csname zf\expandafter\discardtok \string#2%
                          \expandafter\discardtok \string#3\endcsname}


\def \zffam #1{%                                {\style}
  \csname \expandafter\discardtok \string#1fam\endcsname}

\def \zfwithfam #1#2{%                          {\command}{\style}
  \expandafter#1\csname \expandafter\discardtok \string#2fam\endcsname}

%                       Built-in Styles
%                       -------- ------


\zremovePlaindef \itfam
\zremovePlaindef \bffam
\zremovePlaindef \ttfam

                                             % Family  Name
\definetypestyle{\rm}{\encoderoman}          %   0     RoMan
\definetypestyle{\mit}{\encodemathitalic}    %   1     Math ITalic
\definetypestyle{\msy}{\encodemathsymbol}    %   2     Math SYmbol
\definetypestyle{\mex}{\encodemathextended}  %   3     Math EXtended symbol
\definetypestyle{\cal}{\encoderoman}         %   4     CALigraphic letters
\definetypestyle{\bbb}{\encoderoman}         %   5     BlackBoard Bold
\definetypestyle{\it}{\encodeitalic}         %   6     ITalic
\definetypestyle{\bf}{\encoderoman}          %   7     Bold Face
\definetypestyle{\bi}{\encodeitalic}         %   8     Bold Italic
\definetypestyle{\tt}{\encodemono}           %   9     monospaced (TypewriTer)

% Note: style \math is reserved for math mode.

\definestylerelation{\math}{\bbbold}{\bbb}
\definestylerelation{\math}{\bold}{\bf}
\definestylerelation{\rm}{\bold}{\bf}
\definestylerelation{\it}{\bold}{\bi}
\definestylerelation{\math}{\callig}{\cal}
\definestylerelation{\rm}{\callig}{\cal}
\definestylerelation{\rm}{\emph}{\it}
\definestylerelation{\it}{\emph}{\rm}
\definestylerelation{\bf}{\emph}{\bi}
\definestylerelation{\bi}{\emph}{\bf}
\definestylerelation{\math}{\fraktur}{\frk}
\definestylerelation{\tt}{\meta}{\it}
\definestylerelation{\math}{\roman}{\rm}
\definestylerelation{\rm}{\roman}{\rm}
\definestylerelation{\it}{\roman}{\rm}
\definestylerelation{\bf}{\roman}{\rm}
\definestylerelation{\tt}{\roman}{\rm}
\definestylerelation{\rm}{\smallcaps}{\sc}

% We do not define any sizes or fonts.  They just take up memory.

%                       Doodad Font
%                       ------ ----


\def \zrequiredoodad #1#2{%                             {\name}{size}
  \if \undefinedp{\zfdoodad#2}%
    \withname\definefont {\zfdoodad#2}{zztexorn at #2}%
  \fi
  \edef \znext {\let \noexpand#1\name{\zfdoodad#2}}%
  \znext}

%                       Font Style Summary
%                       ---- ----- -------


{\catcode`\_ = \catactive

\gdef \zfontsummary #1{%                                {font-list?}
  {\def _{\space}%
   \writelog{}%
   \writelog{Type Styles:}%
   \writelog{}%
   \writelog{Name_____Math Family}%
   \writelog{----_____-----------}%
   \maplist{\zfsone{##1}}{\zfstylelist}%
   \if #1%
     \writelog{}%
     \maplist{\writelog{ZzTeX: Font used: ##1}}{\ztfmlist}%
   \fi
   \writelog{}}}

\gdef \zfsone #1{%
  \tcounta = \name{#1fam}%
  \writelog{\string #1______%
            \if \lssp{\tcounta}{10}%
              _\number\tcounta
            \else\if \lssp{\tcounta}{15}%
              \number\tcounta
            \else
              ---%
            \fi\fi}}

}% \catcode

%                       TFM List File
%                       --- ---- ----


\definewrite{\ztfmlistfile}


\def \zopentfmlist {%
  \if \zcommonencoding
    \immediate\openout \ztfmlistfile = tfmlist.zzz\relax
    \immediate\write \ztfmlistfile {\jobname}%
  \fi}

\def \zwritetfmlist {%
  \if \zcommonencoding
    \maplist{\immediate\write \ztfmlistfile {##1}}{\ztfmlist}%
    \immediate\closeout \ztfmlistfile
  \fi}