Add a loop to check for font changes due to web fonts either in the math or the surrounding font. Resolves issue #558.

This commit is contained in:
Davide P. Cervone 2013-09-29 16:23:42 -04:00
parent c05ab62ecc
commit c777547f97
3 changed files with 147 additions and 24 deletions

View File

@ -789,7 +789,7 @@ MathJax.fileversion = "2.2";
check = BASE.Callback(check); check = BASE.Callback(check);
check.execute = this.execute; check.time = this.time; check.execute = this.execute; check.time = this.time;
check.STATUS = AJAX.STATUS; check.timeout = timeout || AJAX.timeout; check.STATUS = AJAX.STATUS; check.timeout = timeout || AJAX.timeout;
check.delay = check.total = 0; check.delay = check.total = delay || 0;
if (delay) {setTimeout(check,delay)} else {check()} if (delay) {setTimeout(check,delay)} else {check()}
}, },
// //

View File

@ -36,6 +36,10 @@ MathJax.OutputJax.NativeMML = MathJax.OutputJax({
scale: 100, // scaling factor for all math scale: 100, // scaling factor for all math
minScaleAdjust: 50, // minimum scaling to adjust to surrounding text minScaleAdjust: 50, // minimum scaling to adjust to surrounding text
// (since the code for that is a bit delicate) // (since the code for that is a bit delicate)
widthCheckDelay: 500, // initial delay for the first width check for web fonts
// (set to null to prevent the width checks)
widthCheckTimeout: 15 * 1000, // how long to keep looking for width changes (15 seconds)
styles: { styles: {
"DIV.MathJax_MathML": { "DIV.MathJax_MathML": {
"text-align": "center", "text-align": "center",

View File

@ -253,13 +253,13 @@
script = scripts[i]; if (!script.parentNode) continue; script = scripts[i]; if (!script.parentNode) continue;
jax = script.MathJax.elementJax; if (!jax) continue; jax = script.MathJax.elementJax; if (!jax) continue;
if (!isMSIE) { if (!isMSIE) {
test = script.previousSibling; span = test.previousSibling; test = script.previousSibling;
ex = test.firstChild.offsetWidth/60; ex = test.firstChild.offsetWidth/60;
mex = test.lastChild.offsetWidth/60; mex = test.lastChild.offsetWidth/60;
if (ex === 0 || ex === "NaN") {ex = this.defaultEx; mex = this.defaultMEx} if (ex === 0 || ex === "NaN") {ex = this.defaultEx; mex = this.defaultMEx}
scale = (this.config.matchFontHeight && mex > 1 ? ex/mex : 1); scale = (this.config.matchFontHeight && mex > 1 ? ex/mex : 1);
scale = Math.floor(Math.max(this.config.minScaleAdjust/100,scale) * this.config.scale); scale = Math.floor(Math.max(this.config.minScaleAdjust/100,scale) * this.config.scale);
jax.NativeMML.ex = ex; jax.NativeMML.ex = ex; jax.NativeMML.mex = mex;
} else {scale = 100} } else {scale = 100}
jax.NativeMML.fontSize = scale+"%"; jax.NativeMML.fontSize = scale+"%";
jax.NativeMML.scale = scale/100; jax.NativeMML.scale = scale/100;
@ -269,9 +269,10 @@
// //
if (!isMSIE) { if (!isMSIE) {
for (i = 0; i < m; i++) { for (i = 0; i < m; i++) {
script = scripts[i]; if (!script.parentNode || !script.MathJax.elementJax) continue; script = scripts[i];
test = scripts[i].previousSibling; if (script.parentNode && script.MathJax.elementJax) {
test.parentNode.removeChild(test); script.parentNode.removeChild(script.previousSibling);
}
} }
} }
}, },
@ -326,6 +327,15 @@
}, },
postTranslate: function (state) { postTranslate: function (state) {
if (!isMSIE && this.config.widthCheckDelay != null) {
//
// Check for changes in the web fonts that might affect the sizes
// of math elements. This is a periodic check that goes on until
// a timeout is reached.
//
AJAX.timer.start(AJAX,["checkWidths",this,state.jax[this.id]],
this.config.widthCheckDelay,this.config.widthCheckTimeout);
}
if (this.forceReflow) { if (this.forceReflow) {
// //
// Firefox messes up some mtable's when they are dynamically created // Firefox messes up some mtable's when they are dynamically created
@ -336,6 +346,101 @@
} }
}, },
//
// Check to see if web fonts have been loaded that change the ex size
// of the surrounding font, the ex size within the math, or the widths
// of math elements. We do this by rechecking the ex and mex sizes
// (to see if the font scaling needs adjusting) and by checking the
// size of the inner mrow of math elements and mtd elements. The
// sizes of these have been stored in the NativeMML object of the
// element jax so that we can check for them here.
//
checkWidths: function (check,scripts) {
if (check.time(function () {})) return;
var adjust = [], mtd = [], size = [], i, m;
//
// Add the elements used for testing ex and em sizes
//
for (i = 0, m = scripts.length; i < m; i++) {
if (!scripts[i].parentNode || !scripts[i].MathJax.elementJax) continue;
scripts[i].parentNode.insertBefore(this.EmExSpan.cloneNode(true),scripts[i]);
}
//
// Check to see if anything has changed
//
for (i = 0, m = scripts.length; i < m; i++) {
if (!scripts[i].parentNode) continue;
var jax = scripts[i].MathJax.elementJax;
if (!jax) continue;
var span = document.getElementById(jax.inputID+"-Frame");
var math = span.getElementsByTagName("math")[0]; if (!math) continue;
jax = jax.NativeMML;
//
// Check if ex or mex has changed
//
var test = scripts[i].previousSibling;
var ex = test.firstChild.offsetWidth/60;
var mex = test.lastChild.offsetWidth/60;
if (ex === 0 || ex === "NaN") {ex = this.defaultEx; mex = this.defaultMEx}
var newEx = (ex !== jax.ex);
if (newEx || mex != jax.mex) {
scale = (this.config.matchFontHeight && mex > 1 ? ex/mex : 1);
scale = Math.floor(Math.max(this.config.minScaleAdjust/100,scale) * this.config.scale);
if (scale/100 !== jax.scale) {size.push([span.style,scale])}
jax.scale = scale/100; jax.fontScale = scale+"%"; jax.ex = ex; jax.mex = mex;
}
//
// Check width of math elements
//
if ("scrollWidth" in jax && (newEx || jax.scrollWidth !== math.firstChild.scrollWidth)) {
jax.scrollWidth = math.firstChild.scrollWidth;
adjust.push([math.parentNode.style,jax.scrollWidth/jax.ex/jax.scale]);
}
//
// Check widths of mtd elements
//
if (math.MathJaxMtds) {
for (j = 0, n = math.MathJaxMtds.length; j < n; j++) {
if (!math.MathJaxMtds[j].parentNode) continue;
if (newEx || math.MathJaxMtds[j].firstChild.scrollWidth !== jax.mtds[j]) {
jax.mtds[j] = math.MathJaxMtds[j].firstChild.scrollWidth;
mtd.push([math.MathJaxMtds[j],jax.mtds[j]/jax.ex]);
}
}
}
}
//
// Remove markers
//
for (i = 0, m = scripts.length; i < m; i++) {
if (scripts[i].parentNode && scripts[i].MathJax.elementJax) {
scripts[i].parentNode.removeChild(scripts[i].previousSibling);
}
}
//
// Adjust scaling factor
//
for (i = 0, m = size.length; i < m; i++) {
size[i][0].fontSize = size[i][1] + "%";
}
//
// Adjust width of spans containing math elements that have changed
//
for (i = 0, m = adjust.length; i < m; i++) {
adjust[i][0].width = adjust[i][1].toFixed(3)+"ex";
}
//
// Adjust widths of mtd elements that have changed
//
for (i = 0, m = mtd.length; i < m; i++) {
var style = mtd[i][0].getAttribute("style");
style = style.replace(/(($|;)\s*min-width:).*?ex/,"$1 "+mtd[i][1].toFixed(3)+"ex");
mtd[i][0].setAttribute("style",style);
}
setTimeout(check,check.delay);
},
// //
// Remove MathML preceeding the script // Remove MathML preceeding the script
// //
@ -605,7 +710,7 @@
}); });
if (!isMSIE) { if (!isMSIE) {
var SPLIT = MathJax.Hub.SplitList; var SPLIT = HUB.SplitList;
MML.mtable.Augment({ MML.mtable.Augment({
toNativeMML: function (parent) { toNativeMML: function (parent) {
var i, m; var i, m;
@ -834,14 +939,13 @@
if (nMML.spaceWidthBug && this.width) { if (nMML.spaceWidthBug && this.width) {
var mspace = parent.lastChild; var mspace = parent.lastChild;
var width = mspace.getAttribute("width"); var width = mspace.getAttribute("width");
var style = mspace.getAttribute("style") || ""; var style = (mspace.getAttribute("style") || "").replace(/;?\s*/,"; ");
if (style != "") {style += ";"}
mspace.setAttribute("style",style+"width:"+width); mspace.setAttribute("style",style+"width:"+width);
} }
} }
}); });
var fontDir = MathJax.Ajax.fileURL(MathJax.OutputJax.fontDir+"/HTML-CSS/TeX/otf"); var fontDir = AJAX.fileURL(MathJax.OutputJax.fontDir+"/HTML-CSS/TeX/otf");
/* /*
* Add fix for mathvariant issues in FF * Add fix for mathvariant issues in FF
@ -895,7 +999,7 @@
MML.math.Augment({ MML.math.Augment({
toNativeMML: function (parent) { toNativeMML: function (parent) {
var tag = this.NativeMMLelement(this.type), math = tag; var tag = this.NativeMMLelement(this.type), math = tag, jax;
nMML.adjustWidths = []; nMML.adjustWidths = [];
// //
// Some browsers don't seem to add the xmlns attribute, so do it by hand. // Some browsers don't seem to add the xmlns attribute, so do it by hand.
@ -950,22 +1054,37 @@
// has a different font size. // has a different font size.
// //
parent.style.width = (math.firstChild.scrollWidth/nMML.ex/nMML.scale).toFixed(3) + "ex"; parent.style.width = (math.firstChild.scrollWidth/nMML.ex/nMML.scale).toFixed(3) + "ex";
//
// Save size for later when we check if Web fonts have arrived
//
jax = HUB.getJaxFor(parent);
if (jax) {jax.NativeMML.scrollWidth = math.firstChild.scrollWidth}
} }
// if (nMML.adjustWidths.length) {
// Firefox gets the widths of <mtd> elements wrong, so run //
// through them (now that the math is part of the page) and // Firefox gets the widths of <mtd> elements wrong, so run
// fix them up. Use ex's so that they print properly (see above). // through them (now that the math is part of the page) and
// // fix them up. Use ex's so that they print properly (see above).
for (var i = 0, m = nMML.adjustWidths.length; i < m; i++) { //
var tag = nMML.adjustWidths[i]; var mtd = [];
var style = tag.getAttribute("style") || ""; for (var i = 0, m = nMML.adjustWidths.length; i < m; i++) {
if (!style.match(/(^|;)\s*width:/)) { var tag = nMML.adjustWidths[i];
var width = tag.scrollWidth/nMML.ex; var style = tag.getAttribute("style") || "";
if (style !== "") {style += "; "} if (!style.match(/(^|;)\s*min-width:/)) {
tag.setAttribute("style",style+"width:"+width+"ex"); mtd.push(tag.scrollWidth);
var width = (tag.scrollWidth/nMML.ex).toFixed(3)+"ex";
style = style.replace(/;?\s*$/,"; ");
tag.setAttribute("style",style+"min-width:"+width);
}
} }
//
// Save the lists so that we can check them later for web font downloads
//
if (!jax) {jax = HUB.getJaxFor(parent)}
if (jax) {jax.NativeMML.mtds = mtd}
math.MathJaxMtds = nMML.adjustWidths;
nMML.adjustWidths = []; // clear it so we don't hold onto the DOM elements
} }
nMML.adjustWidths = []; // clear it so we don't hold onto the DOM elements
} }
}); });