latex3 / unicode-math

XeLaTeX/LuaLaTeX package for using unicode/OpenType maths fonts
http://ctan.org/pkg/unicode-math
LaTeX Project Public License v1.3c
241 stars 28 forks source link

Discrepancies in font size selection #478

Open eg9 opened 6 years ago

eg9 commented 6 years ago

Description

The font size selected don't honor \DeclareMathSizes as set in the LaTeX kernel and differ according to the main document size.

Check/indicate

Minimal example demonstrating the issue

\documentclass[12pt]{article}
\usepackage{unicode-math}

\newwrite\report
\immediate\openout\report=\jobname.rep

\makeatletter
\newcommand{\test}[1]{%
  \begingroup
  #1\check@mathfonts
  \immediate\write\report{\string#1--\f@size pt}%
  \immediate\write\report{\fontname\textfont0}%
  \immediate\write\report{\fontname\scriptfont0}%
  \immediate\write\report{\fontname\scriptscriptfont0}%
  \endgroup
}
\makeatother

\begin{document}

\test{\normalsize}
\test{\large}
\test{\Large}

\end{document}

Further details

When compiled, the .rep file will contain

\normalsize--12pt
[latinmodern-math.otf]:mode=base;script=math;language=DFLT; at 12.0pt
[latinmodern-math.otf]:mode=base;script=math;language=DFLT;+ssty=0; at 8.41483pt
[latinmodern-math.otf]:mode=base;script=math;language=DFLT;+ssty=1; at 5.97688pt
\large--14.4pt
[latinmodern-math.otf]:mode=base;script=math;language=DFLT; at 14.4pt
[latinmodern-math.otf]:mode=base;script=math;language=DFLT;
[latinmodern-math.otf]:mode=base;script=math;language=DFLT;+ssty=0; at 7.0pt
\Large--17.28pt
[latinmodern-math.otf]:mode=base;script=math;language=DFLT; at 17.28pt
[latinmodern-math.otf]:mode=base;script=math;language=DFLT; at 12.0pt
[latinmodern-math.otf]:mode=base;script=math;language=DFLT;

If 12pt is changed into 10pt, the sizes will be reported as

\normalsize--10pt
[latinmodern-math.otf]:mode=base;script=math;language=DFLT;
[latinmodern-math.otf]:mode=base;script=math;language=DFLT;+ssty=0; at 7.01236pt
[latinmodern-math.otf]:mode=base;script=math;language=DFLT;+ssty=1; at 4.98074pt
\large--12pt
[latinmodern-math.otf]:mode=base;script=math;language=DFLT; at 12.0pt
[latinmodern-math.otf]:mode=base;script=math;language=DFLT;+ssty=0; at 8.0pt
[latinmodern-math.otf]:mode=base;script=math;language=DFLT;+ssty=0; at 6.0pt
\Large--14.4pt
[latinmodern-math.otf]:mode=base;script=math;language=DFLT; at 14.4pt
[latinmodern-math.otf]:mode=base;script=math;language=DFLT;
[latinmodern-math.otf]:mode=base;script=math;language=DFLT;+ssty=0; at 7.0pt
RuixiZhang42 commented 5 years ago

I think Will Robertson has mentioned this problem back in 2015 in his TeX.SX answer and I think I know where this go wrong.

The problem is with the following implementation in um-code-fontparam.dtx (Lines 290–297, as of 2018/12/11):

\cs_new:Nn \@@_fontdimen_to_percent:nN
  {
    \fp_eval:n { \dim_to_decimal:n { \fontdimen #1 #2 } * 65536 / 100 }
  }
\cs_new:Nn \@@_fontdimen_to_scale:nN
  {
    \fp_eval:n { \@@_fontdimen_to_percent:nN {#1} #2 * \f@size } pt
  }

Apparently, \dim_to_decimal:n produces a result which is rounded by TeX to four or five decimal places (The LaTeX3 Interfaces, Chapter XIX.7, as of 2018/12/11). So we could just follow the math:

  1. For first-level script size.

    • The \fontdimen10 of Latin Modern Math is 70.
    • The result of \dim_to_decimal:n is 70 / 65536 = 0.00107.
    • The result of \@@_fontdimen_to_percent:nN is 0.00107 * 65536 / 100 = 0.7012352.

    This explains the 8.41483pt and 7.01236pt for 12pt and 10pt articles, respectively.

  2. For second-level script size.

    • The \fontdimen11 of Latin Modern Math is 50.
    • The result of \dim_to_decimal:n is 50 / 65536 = 0.00076.
    • The result of \@@_fontdimen_to_percent:nN is 0.00076 * 65536 / 100 = 0.4980736.

    This explains the 5.97688pt and 4.98074pt for 12pt and 10pt articles, respectively.

IMHO, it is perhaps better to use

\fp_eval:n { \dim_to_decimal:n { 65536 \fontdimen #1 #2 } / 100 }

BTW, I think unicode-math intentionally ignores the LaTeX kernel \DeclareMathSizes and uses OpenType parameters ScriptPercentScaleDown and ScriptScriptPercentScaleDown instead, but only at \normalsize for some reasons.

RuixiZhang42 commented 5 years ago

A full example illustrating my proposed fix:

% !TeX program = XeLaTeX
\documentclass[12pt]{article}
\usepackage{unicode-math}

\ExplSyntaxOn
\cs_set:Nn \__um_fontdimen_to_percent:nN
  {
    \fp_eval:n { \dim_to_decimal:n { 65536 \fontdimen #1 #2 } / 100 }
  }
\ExplSyntaxOff

\newwrite\report
\immediate\openout\report=\jobname.rep

\makeatletter
\newcommand{\test}[1]{%
  \begingroup
  #1\check@mathfonts
  \immediate\write\report{\string#1--\f@size pt}%
  \immediate\write\report{\fontname\textfont0}%
  \immediate\write\report{\fontname\scriptfont0}%
  \immediate\write\report{\fontname\scriptscriptfont0}%
  \endgroup
}
\makeatother

\begin{document}

\test{\normalsize}
\test{\large}
\test{\Large}

\end{document}

With 12pt, in .rep I get

\normalsize--12pt
"[latinmodern-math.otf]/OT:script=math;language=DFLT;" at 12.0pt
"[latinmodern-math.otf]/OT:script=math;language=DFLT;+ssty=0;" at 8.4pt
"[latinmodern-math.otf]/OT:script=math;language=DFLT;+ssty=1;" at 6.0pt
\large--14.4pt
"[latinmodern-math.otf]/OT:script=math;language=DFLT;" at 14.4pt
"[latinmodern-math.otf]/OT:script=math;language=DFLT;"
"[latinmodern-math.otf]/OT:script=math;language=DFLT;+ssty=0;" at 7.0pt
\Large--17.28pt
"[latinmodern-math.otf]/OT:script=math;language=DFLT;" at 17.28pt
"[latinmodern-math.otf]/OT:script=math;language=DFLT;" at 12.0pt
"[latinmodern-math.otf]/OT:script=math;language=DFLT;"

With 10pt, in .rep I get

\normalsize--10pt
"[latinmodern-math.otf]/OT:script=math;language=DFLT;"
"[latinmodern-math.otf]/OT:script=math;language=DFLT;+ssty=0;" at 7.0pt
"[latinmodern-math.otf]/OT:script=math;language=DFLT;+ssty=1;" at 5.0pt
\large--12pt
"[latinmodern-math.otf]/OT:script=math;language=DFLT;" at 12.0pt
"[latinmodern-math.otf]/OT:script=math;language=DFLT;+ssty=0;" at 8.0pt
"[latinmodern-math.otf]/OT:script=math;language=DFLT;+ssty=0;" at 6.0pt
\Large--14.4pt
"[latinmodern-math.otf]/OT:script=math;language=DFLT;" at 14.4pt
"[latinmodern-math.otf]/OT:script=math;language=DFLT;"
"[latinmodern-math.otf]/OT:script=math;language=DFLT;+ssty=0;" at 7.0pt

Yeah!!!

wspr commented 5 years ago

Thanks, this looks great to me. Sorry I can’t analyse this in detail right now — does this address the issue entirely or is it only part of the solution?

RuixiZhang42 commented 5 years ago

It depends…

Given that pre-multiplying 65536 results in accurate point sizes, this issue may be closed if you think that the overwriting is “by design” (i.e., we should ignore the legacy \DeclareMathSizes and use OTF parameters instead).

wspr commented 5 years ago

@RuixiZhang42 — thanks, I see what you mean. I think the default should be to use the font-specific scaling present in the font metadata itself (i.e., override \DeclareMathSizes by default). But... users should have a way to override (do you agree @eg9, ?). I'll leave it open to decide what the best interface for this would be.

Perhaps unicode-math should do something like \DeclareMathSizes{0}{0}{0}, then when \setmathfont runs it checks to see whether the user has called \DeclareMathSizes and if so uses the now-updated values; otherwise use the data from the font.

Alternatively, I could deprecate \DeclareMathSizes (have it call an error or warning) and just make the override one of the keyval options for \setmathfont with something like [math-sizes={12}{7}{5}].

Or both! Thoughts?