MathJax and STIX webfonts

1,309 views
Skip to first unread message

steve...@googlemail.com

unread,
Sep 24, 2013, 9:28:38 PM9/24/13
to mathja...@googlegroups.com
Hi, 

I have a website where I will use the STIX fonts as webfonts anyway. I now want to incorporate MathJax into the site as well, and I am wondering if MathJax can just use my STIX webfonts. I looked through the MathJax documentation where I see that currently only Tex is supported as webfont. As a solution to my problem, I am thinking the following: 

Configure MathJax to only use locally installed STIX fonts. Somehow fake MathJax into thinking that my STIX webfont is that locally installed STIX font. 

For that to work, how does MathJax detect local installation of fonts. Can this detection be "rerouted" to detect webfonts instead?

Thanks!

- Steven

Frédéric WANG

unread,
Sep 25, 2013, 6:00:26 AM9/25/13
to mathja...@googlegroups.com
Hi Steven,

Supporting math fonts is complicated to do in MathJax and some work must
be done to overcome many issues. However, we plan to add more free Web
fonts in the upcoming v2.3 release, including STIX. For testing purpose
only, you can download that archive:

https://github.com/fred-wang/MathJax/archive/open-type-fonts.zip

Be sure that your test page points to the unpacked version
MathJax-open-type-fonts/unpacked/MathJax.js

Then you'll be able to use

webFont: "STIX-Web"

in your HTML-CSS config. Other options are "Asana-Math", "Gyre-Pagella",
"Gyre-Termes", "Latin-Modern" and "Neo-Euler".

Le 25/09/2013 03:28, steve...@googlemail.com a �crit :

steve...@googlemail.com

unread,
Sep 25, 2013, 12:32:22 PM9/25/13
to mathja...@googlegroups.com
Thanks Fred, 

I can use the STIX webfonts. They do not render in the same quality as the desktop STIX fonts, though. 

I also have the problem that I cannot use it in JavaFX WebView, because it does not support font-face. I can load fonts anyway through a different mechanism, going through JavaFX interfaces. I've used this to display STIX fonts in the WebView. 

Still, do you think that it is possible to simulate the locally installed fonts somehow? Given that there is no official way to detect that fonts are locally installed, MathJax must use some kind of trick to find out if fonts are locally installed. To me it sounds very plausible that I can trick MathJax into using my fonts, especially as these are exactly the ones that are installed on my desktop. Any advice to make this happen? Then I could use MathJax with Stix also in JavaFX WebView.

Thanks,

Steven


On Wednesday, September 25, 2013 12:00:26 PM UTC+2, fred wrote:
Hi Steven,

Supporting math fonts is complicated to do in MathJax and some work must
be done to overcome many issues. However, we plan to add more free Web
fonts in the upcoming v2.3 release, including STIX. For testing purpose
only, you can download that archive:

https://github.com/fred-wang/MathJax/archive/open-type-fonts.zip

Be sure that your test page points to the unpacked version
MathJax-open-type-fonts/unpacked/MathJax.js

Then you'll be able to use

webFont: "STIX-Web"

in your HTML-CSS config. Other options are "Asana-Math", "Gyre-Pagella",
"Gyre-Termes", "Latin-Modern" and "Neo-Euler".

Le 25/09/2013 03:28, steve...@googlemail.com a �crit :

Frédéric WANG

unread,
Sep 25, 2013, 12:54:59 PM9/25/13
to mathja...@googlegroups.com
Le 25/09/2013 18:32, steve...@googlemail.com a �crit :
> I can use the STIX webfonts. They do not render in the same quality as
> the desktop STIX fonts, though.
>
This is still in development, but in theory they should render the same.
Can you elaborate on when they don't have the same quality as local fonts?

> Still, do you think that it is possible to simulate the locally
> installed fonts somehow? Given that there is no official way to detect
> that fonts are locally installed, MathJax must use some kind of trick
> to find out if fonts are locally installed. To me it sounds very
> plausible that I can trick MathJax into using my fonts, especially as
> these are exactly the ones that are installed on my desktop. Any
> advice to make this happen? Then I could use MathJax with Stix also in
> JavaFX WebView.
I think it's possible in theory, but I don't think that could be done
easily and I suspect that will require to rewrite some parts of the code
since MathJax currently assumes a strict distinction between local and
Web fonts (Personally, I think this distinction is not necessary and
that it should just mimics @font-face rules in browser where you can
define local + Web fonts fallback)

What you could try is to define @font-face rules for

STIXGeneral
STIXGeneral-italic
STIXGeneral-bold
STIXGeneral-bold-italic
STIXNonUnicode
STIXNonUnicode-italic
STIXNonUnicode-bold
STIXNonUnicode-bold-italic
STIXVariants
STIXSizeOneSym
STIXSizeTwoSym
STIXSizeThreeSym
STIXSizeFourSym
STIXSizeFiveSym
STIXIntegralsD

and try to delay MathJax execution until the web fonts are available
(there is no js API for that, so a standard hack as the one used in
MathJax is necessary) so that MathJax will just believe they are local
fonts and process normally.

Of course, one of the problem with that approach is that MathJax has to
wait that the (large) font files are available before doing the
rendering. That's the point of using the STIX Web fonts of MathJax 2.3:
they have been split in smaller files and so MathJax doesn't have to
download everything before starting the layout.

steve...@googlemail.com

unread,
Sep 26, 2013, 7:56:18 PM9/26/13
to mathja...@googlegroups.com
Hi fred,

thanks for your advice, it was very helpful! I finally managed to trick MathJax (version 2.2) into accepting my external STIX fonts as local STIX fonts. It is working both in JavaFX/webview and normal browsers (on Mac OS X Lion, at least ...). It was quite a struggle with a lot of trial and error, so I'll outline below how to do it for anyone else who might want to do such a thing. 

For normal browsers (Chrome, Safari, Firefox, etc.)

1) As you suggested, delaying MathJax until the fonts are loaded is key. I used the technique described here to wait until fonts are loaded before loading MathJax.

2) I am using the following MathJax configuration to put MathJax into "local STIX fonts only" mode. My MathJax installation (without external fonts) can be stripped down to about 1.7 MB using this configuration: 

<script type="text/x-mathjax-config">
     MathJax.Hub.Config({
           tex2jax: { inlineMath: [['$', '$']] },
           jax: ["input/TeX","output/HTML-CSS"],
           extensions: ["tex2jax.js","FontWarnings.js"],
           TeX: {
             extensions: ["AMSmath.js","AMSsymbols.js","noErrors.js","noUndefined.js"]
           },
           "HTML-CSS": {
             preferredFont: "STIX",
             availableFonts: ["STIX"],
             webFont: null
           },
           FontWarnings: {
             fadeoutTime: 15*1000
           }
         });
</script>

3) MathJax uses the STIXSizeOneSym font to check for local STIX fonts. So you need to load at least this font. You will also usually need at least STIXGeneral-Regular and STIXGeneral-Italic to render anything interesting with MathJax, and in the following I am only talking about such a minimal font setup (you can easily adapt this to load all of the STIX fonts). You can include these fonts with the following font-face rules (adapt the location of the font files to whereever you are storing your external fonts):

<style type="text/css">
@font-face {
  font-family:"STIXSizeOneSym";
  src:url("fonts/STIX/STIXSizeOneSym-Regular.otf");
}
@font-face {
  font-family:"STIXSizeOneSym";
  src:url("fonts/STIX/STIXSizeOneSym-Bold.otf")
  font-weight:bold;
}
@font-face {
  font-family:"STIXGeneral";
  src:url("fonts/STIX/STIXGeneral-Regular.otf");
  font-weight:normal;
  font-style:normal;
}
@font-face {
  font-family:"STIXGeneral";
  src:url("fonts/STIX/STIXGeneral-Italic.otf");
  font-weight:normal;
  font-style:italic;
}
</style>

4) MathJax works around a bug in certain WebKit versions by renaming font-families of certain STIX fonts. This is done in the file ./jax/output/HTML-CSS/fonts/fontdata.js via the following code: 

  if (MathJax.Hub.Browser.STIXfontBug) {
    HTMLCSS.FONTDATA.FONTS["STIXGeneral"].family = "STIXGeneral-Regular";
    HTMLCSS.FONTDATA.FONTS["STIXGeneral-italic"].family = "STIXGeneral-Italic";
    delete HTMLCSS.FONTDATA.FONTS["STIXGeneral-italic"].style;
    HTMLCSS.FONTDATA.FONTS["STIXNonUnicode"].family = "STIXNonUnicode-Regular";
    HTMLCSS.FONTDATA.FONTS["STIXNonUnicode-italic"].family = "STIXNonUnicode-Italic";
    delete HTMLCSS.FONTDATA.FONTS["STIXNonUnicode-italic"].style;
  }

To properly load the regular / italic fonts when this workaround is triggered, you therefore also need the following font-face rules:

@font-face {
  font-family:"STIXGeneral-Regular";
  src:url("fonts/STIX/STIXGeneral-Regular.otf");
  font-weight:normal;
  font-style:normal;
}
@font-face {
  font-family:"STIXGeneral-Italic";
  src:url("fonts/STIX/STIXGeneral-Italic.otf");
  font-weight:normal;
  font-style:normal;
}

JavaFX / WebView

Basically the same logic applies as in the previous case, but the loading of fonts is not done with font-face (this might change when a more up-to-date Webkit version is used by JavaFX), but a JavaFX function from your classes folder / JAR file. This introduces additional troubles ...

1) I am using jdk1.7.0_25, which comes with JavaFX built in. I have the following functions for loading fonts (I am using Scala):

    def getSourceURL(path : String) : String = {

      val url = getClass().getResource("/" + path)

      if (url == null

        throw new RuntimeException("getSourceURL: no url found for '"+path+"'")

      else 

        return url.toExternalForm()

    }

    

    def loadFont(path : String, fontFamily : String, fontStyle : FontStyle) {

      val font = javafx.scene.text.Font.loadFont(getSourceURL(path), 1.0)

      val ff = font.getFamily()

      if (ff != fontFamily) {

        throw new RuntimeException("Unexpected font family, found '"+ff+"' instead of '"+fontFamily+"'")

      }

      val fs = fontStyle match {

        case FontStyle.REGULAR => "Regular"

        case FontStyle.BOLD => "Bold"

        case FontStyle.ITALIC => "Italic"

        case FontStyle.BOLD_ITALIC => "Bold Italic"

      }

      if (fs != font.getStyle()) {

        throw new RuntimeException("Unexpected font style, found '"+font.getStyle()+"' instead of '"+fs+"'.")

      }

    }

2) Using the loadFont function you can now load the fonts as follows:

loadFont("fonts/STIX/STIXSizeOneSym-Regular.otf""STIXSizeOneSym"FontStyle.REGULAR)
loadFont("fonts/STIX/STIXSizeOneSym-Bold.otf""STIXSizeOneSym"FontStyle.BOLD)
loadFont("fonts/STIX/STIXGeneral-Regular.otf", "STIXGeneral", FontStyle.REGULAR)
loadFont("fonts/STIX/STIXGeneral-Italic.otf", "STIXGeneral", FontStyle.ITALIC)

3) The WebKit version that comes with JavaFX triggers the earlier mentioned bug for which MathJax has a workaround. Because of this, you will need to also load the fonts involved with the bug with different font family names. The trouble is that JavaFX does not let you set the font family name of the font you loaded (like font-face does), but derives the family name directly from the font. I worked around this by using the TTX tool to create new fonts with adjusted font family names and font styles. In particular, I created 
  • a font STIXGeneral-Regular-bugfix.ttf which is the same as STIXGeneral-Regular.otf but with family name STIXGeneral-Regular instead of STIXGeneral,
  • a font STIXGeneral-Italic-bugfix.ttf which is the same as STIXGeneral-Italic.otf but with family name STIXGeneral-Italic instead of STIXGeneral, and style Regular instead of Italic.
You can now load these additional fonts via:

loadFont("fonts/STIX/STIXGeneral-Regular-bugfix.ttf""STIXGeneral-Regular"FontStyle.REGULAR)
loadFont("fonts/STIX/STIXGeneral-Italic-bugfix.ttf", "STIXGeneral-Italic", FontStyle.REGULAR)

4) Just like before, you need to wait until your webview has successfully loaded the fonts before initialising MathJax. As an additional caveat, you have to make sure that you load the fonts before you load any content into the webview! 
 

           

 

           
 



Frédéric WANG

unread,
Sep 27, 2013, 5:21:36 AM9/27/13
to mathja...@googlegroups.com
Hi Steven,

That's great that you were able to do something from my hints!

I think the idea would be worth integrating as an option in MathJax core, but there are two issues I see:

1) We don't have a reliable way to determine when Web fonts are downloaded. MathJax only tests the Size1 font and a test for other STIX fonts will be necessary, otherwise it may start to do the (wrong) layout without having all the STIX fonts available. The STIX-Web fonts of MathJax 2.3 have special glyphs in the PUA with some known sizes in order to make the detection a bit more reliable.

2) We have to wait that all the Web fonts are downloaded before doing the layout. This may slow down the rendering considerably especially when downloading fonts from a server on when using mobile platforms. The detection hack measures glyphs at regular time interval, which is not as efficient as just using a callback function when fonts are ready. As a comparison, the STIX-Web fonts of MathJax 2.3 are split into smaller files so that we can only download what is necessary (in general only the main fonts) and start earlier.

In theory, I think having Web fonts just be handled as local fonts is the preferred option. This is what is done in native MathML: the layout is performed quickly with the local fonts available and refined after a few seconds when Web fonts are available. In practice, this is not really possible in MathJax at the moment because of the lack of API to detect Web fonts (1) and the necessity to wait the fonts before performing the layout (2) + the HTML-CSS output is slow. And of course, that won't work for all fonts since many glyphs are not accessible from Javascript (in the Web fonts of MathJax 2.3, the glyphs are reorganized to become accessible).

Anyway, thank you for your report I think that will be useful for some people!

Frédéric
--
You received this message because you are subscribed to the Google Groups "MathJax Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mathjax-user...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

steve...@googlemail.com

unread,
Sep 27, 2013, 12:49:09 PM9/27/13
to mathja...@googlegroups.com
Hi Frédéric,

I think it makes totally sense how MathJax currently works, given that most users will not host it themselves, but just point to the MathJax CDN. 

In my case, I am managing the loading of resources myself anyway as there are other large resources besides MathJax that the app will use. This won't be the general use case for MathJax, but is more for suited for rich client (web) apps. 

MathJax is a fantastic tool that I am sure will be central to Mathematics on the Web for some time to come.

Cheers,

Steven

Reply all
Reply to author
Forward
0 new messages