For my CJK documents, I’m mixing TeX Gyre Termes (a Times clone) with Source Han Serif and TeX Gyre Heros (a Helvetica clone) with Source Han Sans. I’m also using the MathTime Professional 2 fonts for my formulae. However, the Latin and math letters appear smaller than the CJK characters, so I need to scale up the former.

  1. The Roman family: The largest cap height among the four TeX Gyre Termes fonts is 676/1000 (TeX Gyre Termes bold), while the cap height of Source Han Serif is 729/1000. So a scale factor of 1.078402 (729/676) is fine.
  2. The sans family: The cap height of TeX Gyre Heros is 729/1000, while that of Source Han Sans is 733/1000. So a scale factor of 1.005487 (733/729) is fine.
  3. The math family: A scale factor of 1.078402 (same as the Roman family) is fine.

My attempt

The first two requests can be met by a single line of code:


where TeX Gyre Heros is loaded at scale 1.078402*0.932386.

The mtpro2 package doesn’t come with a scaled key value option. To meet the third request, I resorted to a manual solution: \DeclareMathSizes. And, according to this answer, the amsmath package should be loaded to use text font changing commands in mathematics that resize appropriately. But using \DeclareMathSizes leads to unexpected results:

Strange scaling within scripts

By scaling mtpro2 manually via \DeclareMathSizes, scaling newtxtext automatically via scaled= and loading amsmath, I noticed strange scaling behaviors within math scripts. If you wish to reproduce the following result, please make sure that NotoSerifCJKsc-[weight].otf is installed and please compile by XeLaTeX:

% Please install Noto Serif CJK SC and compile by XeLaTeX
% Scale up math sizes manually
% Based on \DeclareMathSizes{10.5bp}{10.5bp}{7pt}{5pt} from the CTeX classes
% Scale up Latin size automatically
% Set up CJK font
\setCJKmainfont{Noto Serif CJK SC}

  #1 has width \the\wd0\relax}




\verb|\the\ccwd|: \the\ccwd\relax

\verb|\fontdimen6\font|: \the\fontdimen6\font\relax

\verb|\fontdimen6\textfont2|: \the\fontdimen6\textfont2\relax

\verb|\fontdimen6\scriptfont2|: \the\fontdimen6\scriptfont2

\verb|\fontdimen6\scriptscriptfont2|: \the\fontdimen6\scriptscriptfont2






\measurement{$\displaystyle M$}

\measurement{$\textstyle M$}

\measurement{$\scriptstyle M$}

\measurement{$\scriptscriptstyle M$}












Inconsistent scaling within scripts

My observations

  1. \ccwd yields the size of the em-box for CJK characters: 10.5bp = 10.539375pt.
  2. The first 3 rows: For \displaystyle or \textstyle, both the Latin em-box and the math em-box are properly scaled by 1.078402, as expected.
    • MathTime Pro 2: The designed cap height is 675/1000. After the manual scaling, the scaled cap height to the math em and to the \ccwd ratios are 0.675 and 0.72792 (0.675*729/676), respectively, as expected.
    • TeX Gyre Termes bold: The designed cap height is 676/1000. After the automatic scaling, the scaled cap height to the Latin em and to the \ccwd ratios are 0.676 and 0.729, respectively, as expected.
  3. The 6 cap lines in the first 3 rows hardly have any distinction, as expected, although those of MathTime Pro 2 are in fact slightly lower.
  4. The 4th row: For \scriptstyle, it appears that all em-boxes are of the same size, as declared, which means: Math em = Latin em = \ccwd.
    • MathTime Pro 2: The designed cap height is 722/1000 and its ratio to the \ccwd (= math em) is precisely 0.722.
    • TeX Gyre Termes bold: The designed cap height is 676/1000, but the actual cap height to the Latin em (= \ccwd) ratio somehow becomes 0.729! It seems like the glyph is magnified by 1.078402 but somehow the em-box stays at the same size. Why?
    • The math cap line is slightly lower than the Latin one: 0.722<0.729.
  5. The 5th row: For \scriptscriptstyle, it also appears that all em-boxes are of the same size, as declared.
    • MathTime Pro 2: The designed cap height is 732/1000 and its ratio to the \ccwd (= math em) is precisely 0.732.
    • TeX Gyre Termes bold: Again, the actual cap height to the Latin em (= \ccwd) ratio somehow becomes 0.729! Why?
    • The math cap line is slightly higher than the Latin one (by pixels if the PDF is magnified by 6400%): 0.732>0.729.


There are 15 glyphs drawn in the MWE, all but 2 of which are understandably scaled. The bottom 2 glyphs in the middle column seem to be scaled while somehow maintain their em-boxes unchanged.

By pure coincidence (even with the aforementioned “mistake”), the actual cap height to \ccwd ratios ended up surprisingly close to each other throughout 3 fonts and 3 math styles, which were aimed at 0.729 in the beginning.

                     Table: Actual cap height to \ccwd ratio
                    display/text style      script style     script script style
 mtpro2             0.72792              0.722                0.732
 Termes bold        0.729                0.729*, why?         0.729*, why?
 Source Han Serif   0.729 (by design)    0.729 (by design)    0.729 (by design)
* These should be 0.676, shouldn’t they?

Added on July 4, 2018: Here is a full table showing the strange scaling behaviors within math scripts.

Scaling results

How to properly scale up fonts from newtxtext and mtpro2?

I got extremely lucky with the cap heights. Is this the proper way of matching these mentioned fonts? More specifically:

  1. Is there a better way to scale up MathTime Pro 2? It’d be nice to use it just like \usepackage[scaled=1.1]{newtxmath}.

    • I’m open to modifying the mtpro2.sty file, as it contains many known problems. For instance, problems pointed out in this answer by @egreg and in this comment by @DavidCarlisle.

    • In fact, a redefinition of \left and \right would break the \LEFTRIGHT command from accessing large curly parentheses and braces. I solved this by replacing



  2. Why is the text font at different math styles scaled inconsistently?

  • Does \mathit work?
    – cfr
    Jul 3, 2018 at 0:36
  • @cfr Yes, it does! But I hesitate to use a new math alphabet. I found loading amsmath seems to solve the problem (partially), but it creates something subtler. I also believe using \mathit makes the glyphs in the whole middle column to be scaled “twice”. Jul 3, 2018 at 7:39
  • Why? It exists whether you use it or not.
    – cfr
    Jul 3, 2018 at 22:07
  • @cfr You’re right. But my question leans more on understanding how scaling works and applying it properly. The non-scaled \textit problem disappeared after I read this answer. I removed that MWE to highlight the very subtle and previously hidden scaling problem in math scripts. Jul 4, 2018 at 3:07
  • Why do you have stuff crossed out in your question? If we don't need to read it, delete it; if we do, don't cross it out.
    – cfr
    Jul 5, 2018 at 21:40

2 Answers 2


I think I’ve finally found satisfactory answers.

  • Q1: Is there a better way to scale up MathTime Pro 2?

    • A: Yes!!! And there’s no need to modify mtpro2.sty!
  • Q2: Why is the text font at different math styles scaled inconsistently?

    • A: It isn’t. The text font is scaled consistently.

      When inside \scriptstyle and \scriptscriptstyle, the claim

      all em-boxes are of the same size, as declared

      is not true. In fact, the Latin em-box is scaled by 1.078402 as specified by newtxtext. I mistakenly drew math em-boxes for both Latin text and CJK text, which led to a wrong observation.

Side note: If \usepackage[scaled=1.078402]{mtpro2} were possible, it’d make the ratios between math cap height and CJK em equaling 0.72792, 0.77861 and 0.78939 (which are 1.078402 * <designed values>) at the 3 math styles, respectively. Then, the last two scales may not blend well with Source Han Serif.

My implementation

The font declaration source code can be found here on CTAN. We can simply override how the MathTime Pro 2 fonts are loaded.

There’re 68 fonts of MathTime Pro 2 (complete version). The 5 fonts mt2xl, mt2exe, mt2xxxl, mt2exf and mt2exg contain extra large parentheses, braces, radicals, integrals, etc. These 5 fonts have absolute design sizes, so they do not need to be scaled.

To allow different scaling factors being applied to different optical sizes, I created 3 macros: \mtpscale@scaled, \mtpscale@scriptscaled and \mtpscale@scriptscriptscaled. These 3 macros are to be applied to the other 63 fonts. Although large symbols mt2exa, mt2bexa and mt2hexa don’t have optical sizes, they should be scaled using these 3 different factors as well.

Therefore, the total number of \DeclareFontShape’s we need to override is precisely (63+3*2)/3 = 23. Among these 23 \DeclareFontShape’s, 12 of them are written in the .sty file, while the other 11 are written in the four .fd files. So we also need the four \DeclareFontFamily’s from the .fd files, too.

% Please install Noto Serif CJK SC and compile by XeLaTeX
\setCJKmainfont{Noto Serif CJK SC}

% My implementation
% Customize different scaling factors here
% Fonts available in the `lite' version
% Source code found in `mtpro2.sty'
  <-7> s*[\mtpscale@scriptscriptscaled] mt2mif
  <7-9> s*[\mtpscale@scriptscaled] mt2mis
  <9-> s*[\mtpscale@scaled] mt2mit}{}
  <-7> s*[\mtpscale@scriptscriptscaled] mt2syf
  <7-9> s*[\mtpscale@scriptscaled] mt2sys
  <9-> s*[\mtpscale@scaled] mt2syt}{\skewchar\font32}
  <-7> s*[\mtpscale@scriptscriptscaled] mt2exa
  <7-9> s*[\mtpscale@scriptscaled] mt2exa
  <9-> s*[\mtpscale@scaled] mt2exa}{}
  <-7> s*[\mtpscale@scriptscriptscaled] mt2mbf
  <7-9> s*[\mtpscale@scriptscaled] mt2mbs
  <9-> s*[\mtpscale@scaled] mt2mbt}{}% (MJ)
% Fonts available in the `complete' version
% Source code found in `mtpro2.sty'
  <-7> s*[\mtpscale@scriptscriptscaled] mt2bmif
  <7-9> s*[\mtpscale@scriptscaled] mt2bmis
  <9-> s*[\mtpscale@scaled] mt2bmit}{}
  <-7> s*[\mtpscale@scriptscriptscaled] mt2bsyf
  <7-9> s*[\mtpscale@scriptscaled] mt2bsys
  <9-> s*[\mtpscale@scaled] mt2bsyt}{\skewchar\font32}
  <-7> s*[\mtpscale@scriptscriptscaled] mt2hsyf
  <7-9> s*[\mtpscale@scriptscaled] mt2hsys
  <9-> s*[\mtpscale@scaled] mt2hsyt}{\skewchar\font32}
  <-7> s*[\mtpscale@scriptscriptscaled] mt2bexa
  <7-9> s*[\mtpscale@scriptscaled] mt2bexa
  <9-> s*[\mtpscale@scaled] mt2bexa}{}
  <-7> s*[\mtpscale@scriptscriptscaled] mt2hexa
  <7-9> s*[\mtpscale@scriptscaled] mt2hexa
  <9-> s*[\mtpscale@scaled] mt2hexa}{}
  <-7> s*[\mtpscale@scriptscriptscaled] mt2syaf
  <7-9> s*[\mtpscale@scriptscaled] mt2syas
  <9-> s*[\mtpscale@scaled] mt2syat}{}%
  <-7> s*[\mtpscale@scriptscriptscaled] mt2bsyaf
  <7-9> s*[\mtpscale@scriptscaled] mt2bsyas
  <9-> s*[\mtpscale@scaled] mt2bsyat}{}%
  <-7> s*[\mtpscale@scriptscriptscaled] mt2hsyaf
  <7-9> s*[\mtpscale@scriptscaled] mt2hsyas
  <9-> s*[\mtpscale@scaled] mt2hsyat}{}%
% Source code found in `umt2ms.fd'
  <-7> s*[\mtpscale@scriptscriptscaled] mt2mcf
  <7-9> s*[\mtpscale@scriptscaled] mt2mcs
  <9-> s*[\mtpscale@scaled] mt2mct}{}%
  <-7> s*[\mtpscale@scriptscriptscaled] mt2msf
  <7-9> s*[\mtpscale@scriptscaled] mt2mss
  <9-> s*[\mtpscale@scaled] mt2mst}{}%
  <-7> s*[\mtpscale@scriptscriptscaled] mt2bmsf
  <7-9> s*[\mtpscale@scriptscaled] mt2bmss
  <9-> s*[\mtpscale@scaled] mt2bmst}{}%
% Source code found in `umt2mf.fd'
  <-7> s*[\mtpscale@scriptscriptscaled] mt2mff
  <7-9> s*[\mtpscale@scriptscaled] mt2mfs
  <9-> s*[\mtpscale@scaled] mt2mft}{}%
  <-7> s*[\mtpscale@scriptscriptscaled] mt2bmff
  <7-9> s*[\mtpscale@scriptscaled] mt2bmfs
  <9-> s*[\mtpscale@scaled] mt2bmft}{}%
% Source code found in `umt2bb.fd'
  <-7> s*[\mtpscale@scriptscriptscaled] mt2bbf
  <7-9> s*[\mtpscale@scriptscaled] mt2bbs
  <9-> s*[\mtpscale@scaled] mt2bbt}{}%
  <-7> s*[\mtpscale@scriptscriptscaled] mt2bbif
  <7-9> s*[\mtpscale@scriptscaled] mt2bbis
  <9-> s*[\mtpscale@scaled] mt2bbit}{}%
  <-7> s*[\mtpscale@scriptscriptscaled] mt2bbdf
  <7-9> s*[\mtpscale@scriptscaled] mt2bbds
  <9-> s*[\mtpscale@scaled] mt2bbdt}{}%
% Source code found in `umt2hrb.fd'
  <-7> s*[\mtpscale@scriptscriptscaled] mt2hrbf
  <7-9> s*[\mtpscale@scriptscaled] mt2hrbs
  <9-> s*[\mtpscale@scaled] mt2hrbt}{}%
  <-7> s*[\mtpscale@scriptscriptscaled] mt2hbif
  <7-9> s*[\mtpscale@scriptscaled] mt2hbis
  <9-> s*[\mtpscale@scaled] mt2hbit}{}%
  <-7> s*[\mtpscale@scriptscriptscaled] mt2hrbdf
  <7-9> s*[\mtpscale@scriptscaled] mt2hrbds
  <9-> s*[\mtpscale@scaled] mt2hrbdt}{}%



After scaling

And here’s what the output looks like without scaling:

Before scaling

My solution can also be applied to this question.


Here’s an approach that allows you to use modern OpenType fonts, and scales as many of them automatically for you as possible.

It still uses the ctexat documentclass, but sets up the fonts with mathspec so that you can still use OTF text fonts with the math font you chose. Since you were using newtxtext, I use the OpenType version of Termes from the newtx collection, but you could substitute any other font if that’s not a requirement. I also replace the letters and digits with the text font so that numbers in text mode and math mode match. (If you would rather use an OTF math font instead, you can load unicode-math and the math font will scale for you automatically as well.)

For the purposes of loading a legacy math font, this document computes the ratio of the x-heights of both the text font and the math font, as well as the font sizes of the main math font, script font and script-script font. You will want to use whatever option your package supports to scale it until the ratio of x-heights is 1.0. (I didn’t bother to remove the spurious pt afterward.)

Since I don’t have the commercial fonts you selected, I substituted newtxmath for this example.

% Please install all the fonts needed, and compile by XeLaTeX
\RequirePackage[no-math]{fontspec} % Workaround for option clash
%\usepackage[lite]{mtpro2} % I do not have these fonts to test.
\usepackage[scaled=1.05159]{newtxmath} % For testing purposes.

\setmainfont{TeXGyreTermesX} % Matches newtxtext.
\setCJKmainfont{Noto Serif CJK SC}
\setsansfont{TeX Gyre Heros}
\setCJKsansfont{Noto Sans CJK SC}
\setCJKmonofont{Source Han Sans SC}


\setlength{\xratio}{\dimexpr 1.0pt*(\numexpr\textxheight\relax)/(\numexpr\mathxheight\relax)\relax}

% Now that we’ve computed the ratio of x-heights, change the letters of the
% math font to match the text.  If you don’t want to, at least consider
% changing the digits.

The ratio of the heights of x and \(x\) is {\the\xratio}.

I did not remove the spurious ``pt."  Thank e-tex.

Scale your math font until the above says 1.0pt.

\( \text{\the\fontdimen6\textfont2}_{\text{\the\fontdimen6\scriptfont2}_\text{\the\fontdimen6\scriptscriptfont2}} \)

\( \emptyset M\text{M字}_{\emptyset M\text{M字}_{\emptyset M\text{M字}}} \).

Scale test

Also note that polyglossia would allow you to change between different East Asian scripts, should a single \setCJKmainfont not suffice.

  • Wow! This is very neat! Thank you for detailed answers! I should’ve read the fontspec and mathspec manuals more thoroughly. However (and this is very subjective), I’m more comfortable with manual scaling as opposed to automatic matching x- or cap-heights (I’m paranoid about “black box” code). Side notes: 1) The lite version of MTPro2 is actually free; 2) When setting mono fonts with Source Han Sans SC, I wouldn’t recommend scaling Inconsolata: Mono CJK should blend with “half-width” Latin. So, non-scaled Inconsolata, or Source Han Sans HW SC (alias Noto Sans Mono CJK SC) suffices. Jul 27, 2018 at 18:55
  • @RuixiZhang In that case, fontspec lets you provide a manual scaling factor, like \setsansfont[Scale=1.1]{TeX Gyre Heros}. My method of comparing the scale of two fonts is a bit of a hack, but you can check out the source code of, e.g. tgpagella.sty to see another method.
    – Davislor
    Jul 27, 2018 at 21:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.