www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

MatchWebFonts.js (11991B)


      1 /* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 
      4 /*************************************************************
      5  *
      6  *  MathJax/extensions/MatchWebFonts.js
      7  *  
      8  *  Adds code to the output jax so that if web fonts are used on the page,
      9  *  MathJax will be able to detect their arrival and update the math to
     10  *  accommodate the change in font.  For the NativeMML output, this works
     11  *  both for web fonts in main text, and for web fonts in the math as well.
     12  *
     13  *  ---------------------------------------------------------------------
     14  *  
     15  *  Copyright (c) 2013-2015 The MathJax Consortium
     16  * 
     17  *  Licensed under the Apache License, Version 2.0 (the "License");
     18  *  you may not use this file except in compliance with the License.
     19  *  You may obtain a copy of the License at
     20  * 
     21  *      http://www.apache.org/licenses/LICENSE-2.0
     22  * 
     23  *  Unless required by applicable law or agreed to in writing, software
     24  *  distributed under the License is distributed on an "AS IS" BASIS,
     25  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     26  *  See the License for the specific language governing permissions and
     27  *  limitations under the License.
     28  */
     29 
     30 (function (HUB,AJAX) {
     31   var VERSION = "2.6.0";
     32   
     33   var CONFIG = MathJax.Hub.CombineConfig("MatchWebFonts",{
     34     matchFor: {
     35       "HTML-CSS": true,
     36       NativeMML: true,
     37       SVG: true
     38     },
     39     fontCheckDelay: 500,          // initial delay for the first check for web fonts
     40     fontCheckTimeout: 15 * 1000,  // how long to keep looking for fonts (15 seconds)
     41   });
     42   
     43   MathJax.Extension.MatchWebFonts = {
     44     version: VERSION,
     45     config: CONFIG
     46   };
     47   
     48   HUB.Register.StartupHook("HTML-CSS Jax Ready",function () {
     49     var HTMLCSS = MathJax.OutputJax["HTML-CSS"];
     50     var POSTTRANSLATE = HTMLCSS.postTranslate;
     51 
     52     HTMLCSS.Augment({
     53       postTranslate: function (state,partial) {
     54         if (!partial && CONFIG.matchFor["HTML-CSS"] && this.config.matchFontHeight) {
     55           //
     56           //  Check for changes in the web fonts that might affect the font
     57           //  size for math elements.  This is a periodic check that goes on
     58           //  until a timeout is reached.
     59           //
     60           AJAX.timer.start(AJAX,["checkFonts",this,state.jax[this.id]],
     61                            CONFIG.fontCheckDelay,CONFIG.fontCheckTimeout);
     62         }
     63         return POSTTRANSLATE.apply(this,arguments); // do the original function
     64       },
     65       
     66       checkFonts: function (check,scripts) {
     67         if (check.time(function () {})) return;
     68         var size = [], i, m, retry = false;
     69         //
     70         //  Add the elements used for testing ex and em sizes
     71         //
     72         for (i = 0, m = scripts.length; i < m; i++) {
     73           script = scripts[i];
     74           if (script.parentNode && script.MathJax.elementJax) {
     75             script.parentNode.insertBefore(this.EmExSpan.cloneNode(true),script);
     76           }
     77         }
     78         //
     79         //  Check to see if anything has changed
     80         //
     81         for (i = 0, m = scripts.length; i < m; i++) {
     82           script = scripts[i]; if (!script.parentNode) continue; retry = true;
     83           var jax = script.MathJax.elementJax; if (!jax) continue;
     84           //
     85           //  Check if ex or mex has changed
     86           //
     87           var test = script.previousSibling;
     88           var ex = test.firstChild.offsetHeight/60;
     89           var em = test.lastChild.lastChild.offsetHeight/60;
     90           if (ex === 0 || ex === "NaN") {ex = this.defaultEx; em = this.defaultEm}
     91           if (ex !== jax.HTMLCSS.ex || em !== jax.HTMLCSS.em) {
     92             var scale = ex/this.TeX.x_height/em;
     93             scale = Math.floor(Math.max(this.config.minScaleAdjust/100,scale)*this.config.scale);
     94             if (scale/100 !== jax.scale) {size.push(script); scripts[i] = {}}
     95           }
     96         }
     97         //
     98         //  Remove markers
     99         //
    100         scripts = scripts.concat(size);  // some scripts have been moved to the size array
    101         for (i = 0, m = scripts.length; i < m; i++) {
    102           script = scripts[i];
    103           if (script && script.parentNode && script.MathJax.elementJax) {
    104             script.parentNode.removeChild(script.previousSibling);
    105           }
    106         }
    107         //
    108         //  Rerender the changed items
    109         //
    110         if (size.length) {HUB.Queue(["Rerender",HUB,[size],{}])}
    111         //
    112         //  Try again later
    113         //
    114         if (retry) {setTimeout(check,check.delay)}
    115       }
    116     });
    117   });
    118   
    119   HUB.Register.StartupHook("SVG Jax Ready",function () {
    120     var SVG = MathJax.OutputJax.SVG;
    121     var POSTTRANSLATE = SVG.postTranslate;
    122 
    123     SVG.Augment({
    124       postTranslate: function (state,partial) {
    125         if (!partial && CONFIG.matchFor.SVG) {
    126           //
    127           //  Check for changes in the web fonts that might affect the font
    128           //  size for math elements.  This is a periodic check that goes on
    129           //  until a timeout is reached.
    130           //
    131           AJAX.timer.start(AJAX,["checkFonts",this,state.jax[this.id]],
    132                            CONFIG.fontCheckDelay,CONFIG.fontCheckTimeout);
    133         }
    134         return POSTTRANSLATE.apply(this,arguments); // do the original function
    135       },
    136       
    137       checkFonts: function (check,scripts) {
    138         if (check.time(function () {})) return;
    139         var size = [], i, m, retry = false;
    140         //
    141         //  Add the elements used for testing ex and em sizes
    142         //
    143         for (i = 0, m = scripts.length; i < m; i++) {
    144           script = scripts[i];
    145           if (script.parentNode && script.MathJax.elementJax) {
    146             script.parentNode.insertBefore(this.ExSpan.cloneNode(true),script);
    147           }
    148         }
    149         //
    150         //  Check to see if anything has changed
    151         //
    152         for (i = 0, m = scripts.length; i < m; i++) {
    153           script = scripts[i]; if (!script.parentNode) continue; retry = true;
    154           var jax = script.MathJax.elementJax; if (!jax) continue;
    155           //
    156           //  Check if ex or mex has changed
    157           //
    158           var test = script.previousSibling;
    159           var ex = test.firstChild.offsetHeight/60;
    160           if (ex === 0 || ex === "NaN") {ex = this.defaultEx}
    161           if (ex !== jax.SVG.ex) {size.push(script); scripts[i] = {}}
    162         }
    163         //
    164         //  Remove markers
    165         //
    166         scripts = scripts.concat(size);  // some scripts have been moved to the size array
    167         for (i = 0, m = scripts.length; i < m; i++) {
    168           script = scripts[i];
    169           if (script.parentNode && script.MathJax.elementJax) {
    170             script.parentNode.removeChild(script.previousSibling);
    171           }
    172         }
    173         //
    174         //  Rerender the changed items
    175         //
    176         if (size.length) {HUB.Queue(["Rerender",HUB,[size],{}])}
    177         //
    178         //  Try again later (if not all the scripts are null)
    179         //
    180 
    181         if (retry) setTimeout(check,check.delay);
    182       }
    183     });
    184   });
    185  
    186   HUB.Register.StartupHook("NativeMML Jax Ready",function () {
    187     var nMML = MathJax.OutputJax.NativeMML;
    188     var POSTTRANSLATE = nMML.postTranslate;
    189     
    190     nMML.Augment({
    191       postTranslate: function (state) {
    192         if (!HUB.Browser.isMSIE && CONFIG.matchFor.NativeMML) {
    193           //
    194           //  Check for changes in the web fonts that might affect the sizes
    195           //  of math elements.  This is a periodic check that goes on until
    196           //  a timeout is reached.
    197           //
    198           AJAX.timer.start(AJAX,["checkFonts",this,state.jax[this.id]],
    199                            CONFIG.fontCheckDelay,CONFIG.fontCheckTimeout);
    200         }
    201         POSTTRANSLATE.apply(this,arguments); // do the original routine
    202       },
    203       
    204       //
    205       //  Check to see if web fonts have been loaded that change the ex size
    206       //  of the surrounding font, the ex size within the math, or the widths
    207       //  of math elements.  We do this by rechecking the ex and mex sizes
    208       //  (to see if the font scaling needs adjusting) and by checking the
    209       //  size of the inner mrow of math elements and mtd elements.  The
    210       //  sizes of these have been stored in the NativeMML object of the
    211       //  element jax so that we can check for them here.
    212       //
    213       checkFonts: function (check,scripts) {
    214         if (check.time(function () {})) return;
    215         var adjust = [], mtd = [], size = [], i, m, script;
    216         //
    217         //  Add the elements used for testing ex and em sizes
    218         //
    219         for (i = 0, m = scripts.length; i < m; i++) {
    220           script = scripts[i];
    221           if (script.parentNode && script.MathJax.elementJax) {
    222             script.parentNode.insertBefore(this.EmExSpan.cloneNode(true),script);
    223           }
    224         }
    225         //
    226         //  Check to see if anything has changed
    227         //
    228         for (i = 0, m = scripts.length; i < m; i++) {
    229           script = scripts[i]; if (!script.parentNode) continue;
    230           var jax = script.MathJax.elementJax; if (!jax) continue;
    231           var span = document.getElementById(jax.inputID+"-Frame");
    232           var math = span.getElementsByTagName("math")[0]; if (!math) continue;
    233           jax = jax.NativeMML;
    234           //
    235           //  Check if ex or mex has changed
    236           //
    237           var test = script.previousSibling;
    238           var ex = test.firstChild.offsetWidth/60;
    239           var mex = test.lastChild.offsetWidth/60;
    240           if (ex === 0 || ex === "NaN") {ex = this.defaultEx; mex = this.defaultMEx}
    241           var newEx = (ex !== jax.ex);
    242           if (newEx || mex != jax.mex) {
    243             var scale = (this.config.matchFontHeight && mex > 1 ? ex/mex : 1);
    244             scale = Math.floor(Math.max(this.config.minScaleAdjust/100,scale) * this.config.scale);
    245             if (scale/100 !== jax.scale) {size.push([span.style,scale])}
    246             jax.scale = scale/100; jax.fontScale = scale+"%"; jax.ex = ex; jax.mex = mex;
    247           }
    248           
    249           //
    250           //  Check width of math elements
    251           //
    252           if ("scrollWidth" in jax && (newEx || jax.scrollWidth !== math.firstChild.scrollWidth)) {
    253             jax.scrollWidth = math.firstChild.scrollWidth;
    254             adjust.push([math.parentNode.style,jax.scrollWidth/jax.ex/jax.scale]);
    255           }
    256           //
    257           //  Check widths of mtd elements
    258           //
    259           if (math.MathJaxMtds) {
    260             for (var j = 0, n = math.MathJaxMtds.length; j < n; j++) {
    261               if (!math.MathJaxMtds[j].parentNode) continue;
    262               if (newEx || math.MathJaxMtds[j].firstChild.scrollWidth !== jax.mtds[j]) {
    263                 jax.mtds[j] = math.MathJaxMtds[j].firstChild.scrollWidth;
    264                 mtd.push([math.MathJaxMtds[j],jax.mtds[j]/jax.ex]);
    265               }
    266             }
    267           }
    268         }
    269         //
    270         //  Remove markers
    271         //
    272         for (i = 0, m = scripts.length; i < m; i++) {
    273           script = scripts[i];
    274           if (script.parentNode && script.MathJax.elementJax) {
    275             script.parentNode.removeChild(script.previousSibling);
    276           }
    277         }
    278         //
    279         //  Adjust scaling factor
    280         //
    281         for (i = 0, m = size.length; i < m; i++) {
    282           size[i][0].fontSize = size[i][1] + "%";
    283         }
    284         //
    285         //  Adjust width of spans containing math elements that have changed
    286         //
    287         for (i = 0, m = adjust.length; i < m; i++) {
    288           adjust[i][0].width = adjust[i][1].toFixed(3)+"ex";
    289         }
    290         //
    291         //  Adjust widths of mtd elements that have changed
    292         //
    293         for (i = 0, m = mtd.length; i < m; i++) {
    294           var style = mtd[i][0].getAttribute("style");
    295           style = style.replace(/(($|;)\s*min-width:).*?ex/,"$1 "+mtd[i][1].toFixed(3)+"ex");
    296           mtd[i][0].setAttribute("style",style);
    297         }
    298         //
    299         //  Try again later
    300         //
    301         setTimeout(check,check.delay);
    302       }
    303     });
    304   });
    305   
    306   HUB.Startup.signal.Post("MatchWebFonts Extension Ready");
    307   AJAX.loadComplete("[MathJax]/extensions/MatchWebFonts.js");
    308 
    309 })(MathJax.Hub,MathJax.Ajax);