commit 15b392889184f43d5ef89baf0f9aa2487b9af78c
parent cb13a059bbb4d302e11163200106f78595538326
Author: Davide P. Cervone <dpvc@union.edu>
Date: Sat, 14 Feb 2015 15:30:37 -0500
Break HTML-CSS output into phases so that the final measurement can be done all at once. Restores timing improvements that were lost due to a change made in the testing for v2.5.
Diffstat:
2 files changed, 170 insertions(+), 127 deletions(-)
diff --git a/unpacked/MathJax.js b/unpacked/MathJax.js
@@ -2273,15 +2273,23 @@ MathJax.Hub = {
var jax = script.MathJax.elementJax; if (!jax) {state.i++; continue}
//
// Call the output Jax's Process method (which will be its Translate()
- // method once loaded). Mark it as complete and remove the preview.
+ // method once loaded). Mark it as complete and remove the preview unless
+ // the Process() call returns an explicit false value (in which case, it will
+ // handle this later during the postProcess phase, as HTML-CSS does).
//
result = MathJax.OutputJax[jax.outputJax].Process(script,state);
- script.MathJax.state = STATE.PROCESSED; state.i++;
- if (script.MathJax.preview) {script.MathJax.preview.innerHTML = ""}
+ if (result !== false) {
+ script.MathJax.state = STATE.PROCESSED;
+ if (script.MathJax.preview) {script.MathJax.preview.innerHTML = ""}
+ //
+ // Signal that new math is available
+ //
+ this.signal.Post(["New Math",jax.inputID]); // FIXME: wait for this? (i.e., restart if returns uncalled callback)
+ }
//
- // Signal that new math is available
+ // Go on to next math expression
//
- this.signal.Post(["New Math",jax.inputID]); // FIXME: wait for this? (i.e., restart if returns uncalled callback)
+ state.i++;
//
// Update the processing message, if needed
//
diff --git a/unpacked/jax/output/HTML-CSS/jax.js b/unpacked/jax/output/HTML-CSS/jax.js
@@ -176,7 +176,6 @@
loadWebFont: function (font) {
HUB.Startup.signal.Post("HTML-CSS Jax - Web-Font "+HTMLCSS.fontInUse+"/"+font.directory);
var n = MESSAGE(["LoadWebFont","Loading web-font %1",HTMLCSS.fontInUse+"/"+font.directory]);
- if (HTMLCSS.noReflows) return;
var done = MathJax.Callback({}); // called when font is loaded
var callback = MathJax.Callback(["loadComplete",this,font,n,done]);
AJAX.timer.start(AJAX,[this.checkWebFont,font,callback],0,this.timeout);
@@ -240,7 +239,7 @@
});
var EVENT, TOUCH, HOVER; // filled in later
-
+
HTMLCSS.Augment({
config: {
styles: {
@@ -358,8 +357,6 @@
},
settings: HUB.config.menuSettings,
- hideProcessedMath: true, // use display:none until all math is processed
-
Font: null, // created by Config() below
webFontDefault: "MathJax_Blank",
allowWebFonts: "otf", // assume browser can use OTF web fonts
@@ -637,6 +634,8 @@
state.HTMLCSSdelay = false;
},
+ PHASE: {I: 1, II: 2, III: 3}, // processing phases
+
Translate: function (script,state) {
if (!script.parentNode) return;
@@ -658,10 +657,7 @@
//
// Set the font metrics
//
- this.em = MML.mbase.prototype.em = jax.HTMLCSS.em * jax.HTMLCSS.scale;
- this.outerEm = jax.HTMLCSS.em; this.scale = jax.HTMLCSS.scale;
- this.cwidth = jax.HTMLCSS.cwidth;
- this.linebreakWidth = jax.HTMLCSS.lineWidth;
+ this.getMetrics(jax);
if (this.scale !== 1) {span.style.fontSize = jax.HTMLCSS.fontSize}
//
// Typeset the math
@@ -671,7 +667,8 @@
this.savePreview(script);
try {
math.setTeXclass();
- math.toHTML(span,div);
+ jax.HTMLCSS.span = span; jax.HTMLCSS.div = div; // save for phase II and III
+ math.toHTML(span,div,this.PHASE.I);
} catch (err) {
if (err.restart) {while (span.firstChild) {span.removeChild(span.firstChild)}}
this.restorePreview(script);
@@ -679,32 +676,21 @@
}
this.restorePreview(script);
//
- // Put it in place, and remove the processing marker
+ // Put it in place, remove the processing marker, and signal the new math
//
if (jax.HTMLCSS.isHidden) {script.parentNode.insertBefore(div,script)}
- div.className = div.className.split(/ /)[0];
+ div.className = div.className.split(/ /)[0] + " MathJax_Processed";
+ HUB.signal.Post(["New Math Pending",jax.inputID]); // FIXME: wait for this? (i.e., restart if returns uncalled callback)
//
- // Check if we are hiding the math until more is processed
+ // Check if we should show this chunk of equations
//
- if (this.hideProcessedMath) {
- //
- // Hide the math and don't let its preview be removed
- //
- div.className += " MathJax_Processed";
- if (script.MathJax.preview) {
- jax.HTMLCSS.preview = script.MathJax.preview;
- delete script.MathJax.preview;
- }
- //
- // Check if we should show this chunk of equations
- //
- state.HTMLCSSeqn += (state.i - state.HTMLCSSi); state.HTMLCSSi = state.i;
- if (state.HTMLCSSeqn >= state.HTMLCSSlast + state.HTMLCSSchunk) {
- this.postTranslate(state,true);
- state.HTMLCSSchunk = Math.floor(state.HTMLCSSchunk*this.config.EqnChunkFactor);
- state.HTMLCSSdelay = true; // delay if there are more scripts
- }
+ state.HTMLCSSeqn += (state.i - state.HTMLCSSi); state.HTMLCSSi = state.i;
+ if (state.HTMLCSSeqn >= state.HTMLCSSlast + state.HTMLCSSchunk) {
+ this.postTranslate(state,true);
+ state.HTMLCSSchunk = Math.floor(state.HTMLCSSchunk*this.config.EqnChunkFactor);
+ state.HTMLCSSdelay = true; // delay if there are more scripts
}
+ return false;
},
//
// MathML previews can contain the same ID's as the HTML output,
@@ -725,17 +711,48 @@
delete script.MathJax.tmpPreview;
}
},
+ //
+ // Get the jax metric information
+ //
+ getMetrics: function(jax) {
+ var data = jax.HTMLCSS;
+ this.em = MML.mbase.prototype.em = data.em * data.scale;
+ this.outerEm = data.em;
+ this.scale = data.scale;
+ this.cwidth = data.cwidth;
+ this.linebreakWidth = data.lineWidth;
+ },
postTranslate: function (state,partial) {
- var scripts = state.jax[this.id];
- if (!this.hideProcessedMath) return;
+ var scripts = state.jax[this.id], script, jax, i, m;
+ //
+ // Merasure the math in this chunk (toHTML phase II)
+ //
+ for (i = state.HTMLCSSlast, m = state.HTMLCSSeqn; i < m; i++) {
+ script = scripts[i];
+ if (script && script.MathJax.elementJax) {
+ jax = script.MathJax.elementJax; this.getMetrics(jax);
+ jax.root.toHTML(jax.HTMLCSS.span,jax.HTMLCSS.div,this.PHASE.II);
+ }
+ }
//
// Reveal this chunk of math
//
- for (var i = state.HTMLCSSlast, m = state.HTMLCSSeqn; i < m; i++) {
+ for (i = state.HTMLCSSlast, m = state.HTMLCSSeqn; i < m; i++) {
var script = scripts[i];
if (script && script.MathJax.elementJax) {
//
+ // Finish the math with its measured size (toHTML phase III)
+ //
+ jax = script.MathJax.elementJax; this.getMetrics(jax);
+ jax.root.toHTML(jax.HTMLCSS.span,jax.HTMLCSS.div,this.PHASE.III);
+ delete jax.HTMLCSS.span; delete jax.HTMLCSS.div;
+ //
+ // The math is now fully processed
+ //
+ script.MathJax.state = jax.STATE.PROCESSED;
+ HUB.signal.Post(["New Math",script.MathJax.elementJax.inputID]); // FIXME: wait for this? (i.e., restart if returns uncalled callback)
+ //
// Remove the processed marker
//
script.previousSibling.className = script.previousSibling.className.split(/ /)[0];
@@ -743,11 +760,7 @@
//
// Remove the preview, if any
//
- if (data.preview) {
- data.preview.innerHTML = "";
- script.MathJax.preview = data.preview;
- delete data.preview;
- }
+ if (script.MathJax.preview) {script.MathJax.preview.innerHTML = ""}
}
}
if (this.forceReflow) {
@@ -1113,8 +1126,7 @@
width:0, height:H, verticalAlign:D},
bbox: {h:h, d:d, w:w, rw:w, lw:0, exactW:true}, noAdjust:true, HH:h+d, isMathJax:true
});
- // ### FIXME: figure out which IE has this bug and make a flag for it
- if (w > 0 && !this.noReflows && rule.offsetWidth == 0) {rule.style.width = this.Em(w)}
+ if (this.msieRuleBug && w > 0) {rule.style.width = this.Em(w)}
if (span.isBox || span.className == "mspace") {span.bbox = rule.bbox, span.HH = h+d}
return rule;
},
@@ -2820,93 +2832,115 @@
MML.annotation.Augment({toHTML: function (span) {return this.HTMLcreateSpan(span)}});
MML.math.Augment({
- toHTML: function (span,node) {
- var nobr = HTMLCSS.addElement(span,"nobr",{isMathJax: true});
- span = this.HTMLcreateSpan(nobr);
- var alttext = this.Get("alttext");
- if (alttext && !span.getAttribute("aria-label")) span.setAttribute("aria-label",alttext);
- if (!span.getAttribute("role")) span.setAttribute("role","math");
-// span.setAttribute("tabindex",0); // causes focus outline, so disable for now
- var stack = HTMLCSS.createStack(span), box = HTMLCSS.createBox(stack), math;
- // Move font-size from outer span to stack to avoid line separation
- // problem in strict HTML mode
- stack.style.fontSize = nobr.parentNode.style.fontSize; nobr.parentNode.style.fontSize = "";
- if (this.data[0] != null) {
- if (HTMLCSS.msieColorBug) {
- if (this.background) {this.data[0].background = this.background; delete this.background}
- if (this.mathbackground) {this.data[0].mathbackground = this.mathbackground; delete this.mathbackground}
- }
- MML.mbase.prototype.displayAlign = HUB.config.displayAlign;
- MML.mbase.prototype.displayIndent = HUB.config.displayIndent;
- if (String(HUB.config.displayIndent).match(/^0($|[a-z%])/i))
- MML.mbase.prototype.displayIndent = "0";
- var html = this.data[0].toHTML(box); html.bbox.exactW = false; // force remeasure just to be sure
- math = HTMLCSS.Measured(html,box);
- }
- HTMLCSS.placeBox(box,0,0);
+ toHTML: function (span,node,phase) {
+ var stack, box, html, math;
//
- // Get width right if minimum font size is set:
- // Round to nearest pixel (plus a small amount), and convert back to outer-em's.
- // Add the width to the span (outside the MathJax class, so uses outer em size,
- // which makes it work even when minimum font size is in effect).
+ // Phase I lays out the math, but doesn't measure the final math yet
+ // (that is done for a chunk at a time, to avoid reflows)
//
- span.style.width = HTMLCSS.Em(Math.max(0,Math.round(math.bbox.w*this.em)+.25)/HTMLCSS.outerEm);
- span.style.display = "inline-block";
- //
- // Adjust bbox to match outer em-size
- //
- var p = 1/HTMLCSS.em, f = HTMLCSS.em / HTMLCSS.outerEm; HTMLCSS.em /= f;
- span.bbox.h *= f; span.bbox.d *= f; span.bbox.w *= f;
- span.bbox.lw *= f; span.bbox.rw *= f;
- if (span.bbox.H) {span.bbox.H *= f}
- if (span.bbox.D) {span.bbox.D *= f}
- if (math && math.bbox.width != null) {
- span.style.minWidth = (math.bbox.minWidth || span.style.width);
- span.style.width = math.bbox.width;
- box.style.width = stack.style.width = "100%";
- }
- //
- // Add color (if any)
- //
- var color = this.HTMLhandleColor(span);
- //
- // Make math span be the correct height and depth
- //
- if (math) {HTMLCSS.createRule(span,(math.bbox.h+p)*f,(math.bbox.d+p)*f,0)}
- //
- // Handle indentalign and indentshift for single-line display equations
- //
- if (!this.isMultiline && this.Get("display") === "block" && span.bbox.width == null) {
- var values = this.getValues("indentalignfirst","indentshiftfirst","indentalign","indentshift");
- if (values.indentalignfirst !== MML.INDENTALIGN.INDENTALIGN) {values.indentalign = values.indentalignfirst}
- if (values.indentalign === MML.INDENTALIGN.AUTO) {values.indentalign = this.displayAlign}
- if (values.indentshiftfirst !== MML.INDENTSHIFT.INDENTSHIFT) {values.indentshift = values.indentshiftfirst}
- if (values.indentshift === "auto") {values.indentshift = "0"}
- var shift = HTMLCSS.length2em(values.indentshift,1,HTMLCSS.scale*HTMLCSS.cwidth);
- if (this.displayIndent !== "0") {
- var indent = HTMLCSS.length2em(this.displayIndent,1,HTMLCSS.scale*HTMLCSS.cwidth);
- shift += (values.indentalign === MML.INDENTALIGN.RIGHT ? -indent : indent);
+ if (!phase || phase === HTMLCSS.PHASE.I) {
+ var nobr = HTMLCSS.addElement(span,"nobr",{isMathJax: true});
+ span = this.HTMLcreateSpan(nobr);
+ var alttext = this.Get("alttext");
+ if (alttext && !span.getAttribute("aria-label")) span.setAttribute("aria-label",alttext);
+ if (!span.getAttribute("role")) span.setAttribute("role","math");
+// span.setAttribute("tabindex",0); // causes focus outline, so disable for now
+ stack = HTMLCSS.createStack(span); box = HTMLCSS.createBox(stack);
+ // Move font-size from outer span to stack to avoid line separation
+ // problem in strict HTML mode
+ stack.style.fontSize = nobr.parentNode.style.fontSize; nobr.parentNode.style.fontSize = "";
+ if (this.data[0] != null) {
+ if (HTMLCSS.msieColorBug) {
+ if (this.background) {this.data[0].background = this.background; delete this.background}
+ if (this.mathbackground) {this.data[0].mathbackground = this.mathbackground; delete this.mathbackground}
+ }
+ MML.mbase.prototype.displayAlign = HUB.config.displayAlign;
+ MML.mbase.prototype.displayIndent = HUB.config.displayIndent;
+ if (String(HUB.config.displayIndent).match(/^0($|[a-z%])/i))
+ MML.mbase.prototype.displayIndent = "0";
+ html = this.data[0].toHTML(box); html.bbox.exactW = true; // force remeasure just to be sure
}
- node.style.textAlign = values.indentalign;
- // ### FIXME: make percentage widths respond to changes in container
- if (shift) {
- shift *= HTMLCSS.em/HTMLCSS.outerEm;
- HUB.Insert(span.style,({
- left: {marginLeft: HTMLCSS.Em(shift)},
- right: {marginLeft: HTMLCSS.Em(Math.max(0,span.bbox.w+shift)), marginRight: HTMLCSS.Em(-shift)},
- center: {marginLeft: HTMLCSS.Em(shift), marginRight: HTMLCSS.Em(-shift)}
- })[values.indentalign]);
- //
- // Move the background color, of any
- //
- if (color) {
- color.style.marginLeft = HTMLCSS.Em(parseFloat(color.style.marginLeft)+shift);
- color.style.marginRight =
- HTMLCSS.Em(parseFloat(color.style.marginRight)-shift
- + (values.indentalign === "right" ? Math.min(0,span.bbox.w+shift) - span.bbox.w : 0));
+ } else {
+ span = span.firstChild.firstChild;
+ if (this.href) span = span.firstChild;
+ stack = span.firstChild;
+ if (stack.style.position !== "relative") stack = stack.nextSibling;
+ box = stack.firstChild;
+ html = box.firstChild;
+ }
+ //
+ // Phase II measures the math (this is done for each one in the chunk at once)
+ //
+ math = ((!phase || phase === HTMLCSS.PHASE.II) ? HTMLCSS.Measured(html,box) : html);
+ //
+ // Phase III finishes the layout using the measured math
+ //
+ if (!phase || phase === HTMLCSS.PHASE.III) {
+ HTMLCSS.placeBox(box,0,0);
+ //
+ // Get width right if minimum font size is set:
+ // Round to nearest pixel (plus a small amount), and convert back to outer-em's.
+ // Add the width to the span (outside the MathJax class, so uses outer em size,
+ // which makes it work even when minimum font size is in effect).
+ //
+ span.style.width = HTMLCSS.Em(Math.max(0,Math.round(math.bbox.w*this.em)+.25)/HTMLCSS.outerEm);
+ span.style.display = "inline-block";
+ //
+ // Adjust bbox to match outer em-size
+ //
+ var p = 1/HTMLCSS.em, f = HTMLCSS.em / HTMLCSS.outerEm; HTMLCSS.em /= f;
+ span.bbox.h *= f; span.bbox.d *= f; span.bbox.w *= f;
+ span.bbox.lw *= f; span.bbox.rw *= f;
+ if (span.bbox.H) {span.bbox.H *= f}
+ if (span.bbox.D) {span.bbox.D *= f}
+ if (math && math.bbox.width != null) {
+ span.style.minWidth = (math.bbox.minWidth || span.style.width);
+ span.style.width = math.bbox.width;
+ box.style.width = stack.style.width = "100%";
+ }
+ //
+ // Add color (if any)
+ //
+ var color = this.HTMLhandleColor(span);
+ //
+ // Make math span be the correct height and depth
+ //
+ if (math) {HTMLCSS.createRule(span,(math.bbox.h+p)*f,(math.bbox.d+p)*f,0)}
+ //
+ // Handle indentalign and indentshift for single-line display equations
+ //
+ if (!this.isMultiline && this.Get("display") === "block" && span.bbox.width == null) {
+ var values = this.getValues("indentalignfirst","indentshiftfirst","indentalign","indentshift");
+ if (values.indentalignfirst !== MML.INDENTALIGN.INDENTALIGN) {values.indentalign = values.indentalignfirst}
+ if (values.indentalign === MML.INDENTALIGN.AUTO) {values.indentalign = this.displayAlign}
+ if (values.indentshiftfirst !== MML.INDENTSHIFT.INDENTSHIFT) {values.indentshift = values.indentshiftfirst}
+ if (values.indentshift === "auto") {values.indentshift = "0"}
+ var shift = HTMLCSS.length2em(values.indentshift,1,HTMLCSS.scale*HTMLCSS.cwidth);
+ if (this.displayIndent !== "0") {
+ var indent = HTMLCSS.length2em(this.displayIndent,1,HTMLCSS.scale*HTMLCSS.cwidth);
+ shift += (values.indentalign === MML.INDENTALIGN.RIGHT ? -indent : indent);
+ }
+ node.style.textAlign = values.indentalign;
+ // ### FIXME: make percentage widths respond to changes in container
+ if (shift) {
+ shift *= HTMLCSS.em/HTMLCSS.outerEm;
+ HUB.Insert(span.style,({
+ left: {marginLeft: HTMLCSS.Em(shift)},
+ right: {marginLeft: HTMLCSS.Em(Math.max(0,span.bbox.w+shift)), marginRight: HTMLCSS.Em(-shift)},
+ center: {marginLeft: HTMLCSS.Em(shift), marginRight: HTMLCSS.Em(-shift)}
+ })[values.indentalign]);
+ //
+ // Move the background color, of any
+ //
+ if (color) {
+ color.style.marginLeft = HTMLCSS.Em(parseFloat(color.style.marginLeft)+shift);
+ color.style.marginRight =
+ HTMLCSS.Em(parseFloat(color.style.marginRight)-shift
+ + (values.indentalign === "right" ? Math.min(0,span.bbox.w+shift) - span.bbox.w : 0));
+ }
}
}
- }
+ }
return span;
},
HTMLspanElement: MML.mbase.prototype.HTMLspanElement
@@ -2988,6 +3022,7 @@
msiePlaceBoxBug: (isIE8 && !quirks),
msieClipRectBug: !isIE8,
msieNegativeSpaceBug: quirks,
+ msieRuleBug: (mode < 7), // rules need to be measured
cloneNodeBug: (isIE8 && browser.version === "8.0"),
msieItalicWidthBug: true, // can't measure boxes ending in italics correctly
initialSkipBug: (mode < 8), // confused by initial left-margin values