diff --git a/unpacked/jax/output/CommonHTML/autoload/multiline.js b/unpacked/jax/output/CommonHTML/autoload/multiline.js
new file mode 100644
index 000000000..f65413125
--- /dev/null
+++ b/unpacked/jax/output/CommonHTML/autoload/multiline.js
@@ -0,0 +1,780 @@
+/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+
+/*************************************************************
+ *
+ * MathJax/jax/output/CommonHTML/autoload/multiline.js
+ *
+ * Implements the CommonHTML output for 's that contain line breaks.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (c) 2015 The MathJax Consortium
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+MathJax.Hub.Register.StartupHook("CommonHTML Jax Ready",function () {
+ var VERSION = "2.5.0";
+ var MML = MathJax.ElementJax.mml,
+ HTML = MathJax.HTML, CONFIG = MathJax.Hub.config,
+ CHTML = MathJax.OutputJax.CommonHTML;
+
+ //
+ // Penalties for the various line breaks
+ //
+ var PENALTY = {
+ newline: 0,
+ nobreak: 1000000,
+ goodbreak: [-200],
+ badbreak: [+200],
+ auto: [0],
+
+ toobig: 800,
+ nestfactor: 400,
+ spacefactor: -100,
+ spaceoffset: 2,
+ spacelimit: 1, // spaces larger than this get a penalty boost
+ fence: 500,
+ close: 500
+ };
+
+ var ENDVALUES = {linebreakstyle: "after"};
+
+
+ /**************************************************************************/
+
+ MML.mbase.Augment({
+ CHTMLlinebreakPenalty: PENALTY,
+
+ /****************************************************************/
+ //
+ // Handle breaking an mrow into separate lines
+ //
+ CHTMLmultiline: function (node) {
+
+ //
+ // Find the parent element and mark it as multiline
+ //
+ var parent = this;
+ while (parent.inferred || (parent.parent && parent.parent.type === "mrow" &&
+ parent.parent.data.length === 1)) {parent = parent.parent}
+ var isTop = ((parent.type === "math" && parent.Get("display") === "block") ||
+ parent.type === "mtd");
+ parent.isMultiline = true;
+
+ //
+ // Default values for the line-breaking parameters
+ //
+ var VALUES = this.getValues(
+ "linebreak","linebreakstyle","lineleading","linebreakmultchar",
+ "indentalign","indentshift",
+ "indentalignfirst","indentshiftfirst",
+ "indentalignlast","indentshiftlast"
+ );
+ if (VALUES.linebreakstyle === MML.LINEBREAKSTYLE.INFIXLINEBREAKSTYLE)
+ VALUES.linebreakstyle = this.Get("infixlinebreakstyle");
+ VALUES.lineleading = CHTML.length2em(VALUES.lineleading,0.5);
+
+ //
+ // Break the math at its best line breaks
+ //
+ CHTML.BBOX.empty(this.CHTML);
+ var stack = HTML.addElement(node,"mjx-stack");
+ var state = {
+ BBOX: this.CHTML,
+ n: 0, Y: 0,
+ scale: (this.CHTML.scale||1),
+ isTop: isTop,
+ values: {},
+ VALUES: VALUES
+ },
+ align = this.CHTMLgetAlign(state,{}),
+ shift = this.CHTMLgetShift(state,{},align),
+ start = [],
+ end = {
+ index:[], penalty:PENALTY.nobreak,
+ w:0, W:shift, shift:shift, scanW:shift,
+ nest: 0
+ },
+ broken = false;
+
+ while (this.CHTMLbetterBreak(end,state) &&
+ (end.scanW >= CHTML.linebreakWidth || end.penalty === PENALTY.newline)) {
+ this.CHTMLaddLine(stack,start,end.index,state,end.values,broken);
+ start = end.index.slice(0); broken = true;
+ align = this.CHTMLgetAlign(state,end.values);
+ shift = this.CHTMLgetShift(state,end.values,align);
+ end.W = end.shift = end.scanW = shift; end.penalty = PENALTY.nobreak;
+ }
+ state.isLast = true;
+ this.CHTMLaddLine(stack,start,[],state,ENDVALUES,broken);
+
+ node.style.width = stack.style.width = this.CHTML.pwidth = "100%";
+ this.CHTML.isMultiline = parent.CHTML.isMultiline = true;
+ stack.style.verticalAlign = CHTML.Em(state.d - this.CHTML.d);
+
+ return node;
+ },
+
+ /****************************************************************/
+ //
+ // Locate the next linebreak that is better than the current one
+ //
+ CHTMLbetterBreak: function (info,state) {
+ if (this.isToken) return false; // FIXME: handle breaking of token elements
+ if (this.isEmbellished()) {
+ info.embellished = this;
+ return this.CoreMO().CHTMLbetterBreak(info,state);
+ }
+ if (this.linebreakContainer) return false;
+ //
+ // Get the current breakpoint position and other data
+ //
+ var index = info.index.slice(0), i = info.index.shift(),
+ m = this.data.length, W, w, scanW, broken = (info.index.length > 0), better = false;
+ if (i == null) i = -1; if (!broken) {i++; info.W += info.w; info.w = 0}
+ scanW = info.scanW = info.W; info.nest++;
+ //
+ // Look through the line for breakpoints,
+ // (as long as we are not too far past the breaking width)
+ //
+ while (i < m && info.scanW < 1.33*CHTML.linebreakWidth) {
+ if (this.data[i]) {
+ if (this.data[i].CHTMLbetterBreak(info,state)) {
+ better = true; index = [i].concat(info.index); W = info.W; w = info.w;
+ if (info.penalty === PENALTY.newline) {
+ info.index = index;
+ if (info.nest) {info.nest--}
+ return true;
+ }
+ }
+ scanW = (broken ? info.scanW : this.CHTMLaddWidth(i,info,scanW));
+ }
+ info.index = []; i++; broken = false;
+ }
+ if (info.nest) {info.nest--}
+ info.index = index;
+ if (better) {info.W = W; info.w = w}
+ return better;
+ },
+ CHTMLaddWidth: function (i,info,scanW) {
+ if (this.data[i]) {
+ var node = this.data[i].CHTMLnodeElement(), bbox = this.data[i].CHTML;
+ scanW += bbox.w + (bbox.L||0) + (bbox.R||0);
+ info.W = info.scanW = scanW; info.w = 0;
+ }
+ return scanW;
+ },
+
+ /****************************************************************/
+ //
+ // Create a new line and move the required elements into it
+ // Position it using proper alignment and indenting
+ //
+ CHTMLaddLine: function (stack,start,end,state,values,broken) {
+ //
+ // Create a box for the line, with empty BBox
+ // fill it with the proper elements,
+ // and clean up the bbox
+ //
+ var block = HTML.addElement(stack,"mjx-block",{},[["mjx-box"]]), line = block.firstChild;
+ var bbox = state.bbox = CHTML.BBOX.empty();
+ state.first = broken; state.last = true;
+ this.CHTMLmoveLine(start,end,line,state,values);
+ bbox.clean();
+ //
+ // Get the alignment and shift values
+ //
+ var align = this.CHTMLgetAlign(state,values),
+ shift = this.CHTMLgetShift(state,values,align,true);
+ //
+ // Set the Y offset based on previous depth, leading, and current height
+ //
+ var dY = 0;
+ if (state.n > 0) {
+ var LHD = CHTML.FONTDATA.baselineskip;
+ var leading = (state.values.lineleading == null ? state.VALUES : state.values).lineleading * state.scale;
+ var Y = state.Y;
+ state.Y -= Math.max(LHD,state.d + bbox.h + leading);
+ dY = Y - state.Y - state.d - bbox.h;
+ }
+ //
+ // Place the new line
+ //
+ if (shift) line.style.margin = "0 "+CHTML.Em(-shift)+" 0 "+CHTML.Em(shift);
+ if (align !== MML.INDENTALIGN.LEFT) block.style.textAlign = align;
+ if (dY) block.style.paddingTop = CHTML.Em(dY);
+ state.BBOX.combine(bbox,shift,state.Y);
+//this.CHTMLdrawBBox(line,bbox);
+ //
+ // Save the values needed for the future
+ //
+ state.d = state.bbox.d; state.values = values; state.n++;
+ },
+
+ /****************************************************************/
+ //
+ // Get alignment and shift values from the given data
+ //
+ CHTMLgetAlign: function (state,values) {
+ var cur = values, prev = state.values, def = state.VALUES, align;
+ if (state.n === 0) align = cur.indentalignfirst || prev.indentalignfirst || def.indentalignfirst;
+ else if (state.isLast) align = prev.indentalignlast || def.indentalignlast;
+ else align = prev.indentalign || def.indentalign;
+ if (align === MML.INDENTALIGN.INDENTALIGN) align = prev.indentalign || def.indentalign;
+ if (align === MML.INDENTALIGN.AUTO) align = (state.isTop ? CONFIG.displayAlign : MML.INDENTALIGN.LEFT);
+ return align;
+ },
+ CHTMLgetShift: function (state,values,align,noadjust) {
+ var cur = values, prev = state.values, def = state.VALUES, shift;
+ if (state.n === 0) shift = cur.indentshiftfirst || prev.indentshiftfirst || def.indentshiftfirst;
+ else if (state.isLast) shift = prev.indentshiftlast || def.indentshiftlast;
+ else shift = prev.indentshift || def.indentshift;
+ if (shift === MML.INDENTSHIFT.INDENTSHIFT) shift = prev.indentshift || def.indentshift;
+ if (shift === "auto" || shift === "") shift = "0";
+ shift = CHTML.length2em(shift,CHTML.cwidth);
+ if (state.isTop && CONFIG.displayIndent !== "0") {
+ var indent = CHTML.length2em(CONFIG.displayIndent,CHTML.cwidth);
+ shift += (align === MML.INDENTALIGN.RIGHT ? -indent : indent);
+ }
+ return (align === MML.INDENTALIGN.RIGHT && !noadjust ? -shift : shift);
+ },
+
+ /****************************************************************/
+ //
+ // Move the selected elements into the new line's box,
+ // moving whole items when possible, and parts of ones
+ // that are split by a line break.
+ //
+ CHTMLmoveLine: function (start,end,node,state,values) {
+ var i = start[0], j = end[0];
+ if (i == null) i = -1; if (j == null) j = this.data.length-1;
+ if (i === j && start.length > 1) {
+ //
+ // If starting and ending in the same element move the subpiece to the new line
+ //
+ this.data[i].CHTMLmoveSlice(start.slice(1),end.slice(1),node,state,values,"marginLeft");
+ } else {
+ //
+ // Otherwise, move the remainder of the initial item
+ // and any others up to the last one
+ //
+ var last = state.last; state.last = false;
+ while (i < j) {
+ if (this.data[i]) {
+ if (start.length <= 1) {this.data[i].CHTMLmoveNode(node,state,values)}
+ else {this.data[i].CHTMLmoveSlice(start.slice(1),[],node,state,values,"marginLeft")}
+ }
+ i++; state.first = false; start = [];
+ }
+ //
+ // If the last item is complete, move it,
+ // otherwise move the first part of it up to the split
+ //
+ state.last = last;
+ if (this.data[i]) {
+ if (end.length <= 1) {this.data[i].CHTMLmoveNode(node,state,values)}
+ else {this.data[i].CHTMLmoveSlice([],end.slice(1),node,state,values,"marginRight")}
+ }
+ }
+ },
+
+ /****************************************************************/
+ //
+ // Split an element and copy the selected items into the new part
+ //
+ CHTMLmoveSlice: function (start,end,node,state,values,margin) {
+ //
+ // Create a new box for the slice of the element
+ // Move the selected portion into the slice
+ // If it is the last slice
+ // Remove the original (now empty) node
+ // Rename the Continue-0 node with the original name (for CHTMLnodeElement)
+ //
+ var slice = this.CHTMLcreateSliceNode(node);
+ this.CHTMLmoveLine(start,end,slice,state,values);
+ if (slice.style[margin]) slice.style[margin] = "";
+ if (this.CHTML.L) {
+ if (margin !== "marginLeft") state.bbox.w += this.CHTML.L;
+ else slice.className = slice.className.replace(/ MJXc-space\d/,"");
+ }
+ if (this.CHTML.R && margin !== "marginRight") state.bbox.w += this.CHTML.R;
+ if (end.length === 0) {
+ node = this.CHTMLnodeElement();
+ node.parentNode.removeChild(node);
+ node.nextMathJaxNode.id = node.id;
+ }
+ return slice;
+ },
+
+ /****************************************************************/
+ //
+ // Create a new node for an element that is split in two
+ // Clone the original and update its ID.
+ // Link the old node to the new one so we can find it later
+ //
+ CHTMLcreateSliceNode: function (node) {
+ var NODE = this.CHTMLnodeElement(), n = 0;
+ var LAST = NODE; while (LAST.nextMathJaxNode) {LAST = LAST.nextMathJaxNode; n++}
+ var SLICE = NODE.cloneNode(false); LAST.nextMathJaxNode = SLICE; SLICE.nextMathJaxNode = null;
+ SLICE.id += "-MJX-Continue-"+n;
+ return node.appendChild(SLICE);
+ },
+
+ /****************************************************************/
+ //
+ // Move an element from its original node to its new location in
+ // a split element or the new line's node
+ //
+ CHTMLmoveNode: function (line,state,values) {
+ // FIXME: handle linebreakstyle === "duplicate"
+ // FIXME: handle linebreakmultchar
+ if (!(state.first || state.last) ||
+ (state.first && state.values.linebreakstyle === MML.LINEBREAKSTYLE.BEFORE) ||
+ (state.last && values.linebreakstyle === MML.LINEBREAKSTYLE.AFTER)) {
+ //
+ // Move node
+ //
+ var node = this.CHTMLnodeElement();
+ line.appendChild(node);
+ //
+ // If it is last, remove right margin
+ // If it is first, remove left margin
+ //
+ if (state.last) node.style.marginRight = "";
+ if (state.first || state.nextIsFirst) {
+ node.style.marginLeft = ""; this.CHTML.L = 0;
+ node.className = node.className.replace(/ MJXc-space\d/,"");
+ }
+ if (state.first && this.CHTML.w === 0) {state.nextIsFirst = true}
+ else {delete state.nextIsFirst}
+ //
+ // Update bounding box
+ //
+ state.bbox.combine(this.CHTML,state.bbox.w,0);
+ }
+ }
+ });
+
+ /**************************************************************************/
+
+ MML.mfenced.Augment({
+ CHTMLbetterBreak: function (info,state) {
+ //
+ // Get the current breakpoint position and other data
+ //
+ var index = info.index.slice(0), i = info.index.shift(),
+ m = this.data.length, W, w, scanW, broken = (info.index.length > 0), better = false;
+ if (i == null) i = -1; if (!broken) {i++; info.W += info.w; info.w = 0}
+ scanW = info.scanW = info.W; info.nest++;
+ //
+ // Create indices that include the delimiters and separators
+ //
+ if (!this.dataI) {
+ this.dataI = [];
+ if (this.data.open) this.dataI.push("open");
+ if (m) this.dataI.push(0);
+ for (var j = 1; j < m; j++) {
+ if (this.data["sep"+j]) this.dataI.push("sep"+j);
+ this.dataI.push(j);
+ }
+ if (this.data.close) this.dataI.push("close");
+ }
+ m = this.dataI.length;
+ //
+ // Look through the line for breakpoints, including the open, close, and separators
+ // (as long as we are not too far past the breaking width)
+ //
+ while (i < m && info.scanW < 1.33*CHTML.linebreakWidth) {
+ var k = this.dataI[i];
+ if (this.data[k]) {
+ if (this.data[k].CHTMLbetterBreak(info,state)) {
+ better = true; index = [i].concat(info.index); W = info.W; w = info.w;
+ if (info.penalty === PENALTY.newline) {
+ info.index = index;
+ if (info.nest) info.nest--;
+ return true;
+ }
+ }
+ scanW = (broken ? info.scanW : this.CHTMLaddWidth(i,info,scanW));
+ }
+ info.index = []; i++; broken = false;
+ }
+ if (info.nest) info.nest--;
+ info.index = index;
+ if (better) {info.W = W; info.w = w}
+ return better;
+ },
+
+ CHTMLmoveLine: function (start,end,node,state,values) {
+ var i = start[0], j = end[0];
+ if (i == null) i = -1; if (j == null) j = this.dataI.length-1;
+ if (i === j && start.length > 1) {
+ //
+ // If starting and ending in the same element move the subpiece to the new line
+ //
+ this.data[this.dataI[i]].CHTMLmoveSlice(start.slice(1),end.slice(1),node,state,values,"marginLeft");
+ } else {
+ //
+ // Otherwise, move the remainder of the initial item
+ // and any others (including open and separators) up to the last one
+ //
+ var last = state.last; state.last = false; var k = this.dataI[i];
+ while (i < j) {
+ if (this.data[k]) {
+ if (start.length <= 1) {this.data[k].CHTMLmoveNode(node,state,values)}
+ else {this.data[k].CHTMLmoveSlice(start.slice(1),[],node,state,values,"marginLeft")}
+ }
+ i++; k = this.dataI[i]; state.first = false; start = [];
+ }
+ //
+ // If the last item is complete, move it
+ //
+ state.last = last;
+ if (this.data[k]) {
+ if (end.length <= 1) {this.data[k].CHTMLmoveNode(node,state,values)}
+ else {this.data[k].CHTMLmoveSlice([],end.slice(1),node,state,values,"marginRight")}
+ }
+ }
+ }
+
+ });
+
+ /**************************************************************************/
+
+ MML.msubsup.Augment({
+ CHTMLbetterBreak: function (info,state) {
+ if (!this.data[this.base]) {return false}
+ //
+ // Get the current breakpoint position and other data
+ //
+ var index = info.index.slice(0), i = info.index.shift(),
+ W, w, scanW, broken = (info.index.length > 0), better = false;
+ if (!broken) {info.W += info.w; info.w = 0}
+ scanW = info.scanW = info.W;
+ //
+ // Record the width of the base and the super- and subscripts
+ //
+ if (i == null) {
+ this.CHTML.baseW = this.data[this.base].CHTML.w;
+ this.CHTML.dw = this.CHTML.w - this.CHTML.baseW;
+ }
+ //
+ // Check if the base can be broken
+ //
+ if (this.data[this.base].CHTMLbetterBreak(info,state)) {
+ better = true; index = [this.base].concat(info.index); W = info.W; w = info.w;
+ if (info.penalty === PENALTY.newline) better = broken = true;
+ }
+ //
+ // Add in the base if it is unbroken, and add the scripts
+ //
+ if (!broken) this.CHTMLaddWidth(this.base,info,scanW);
+ info.scanW += this.CHTML.dw; info.W = info.scanW;
+ info.index = []; if (better) {info.W = W; info.w = w; info.index = index}
+ return better;
+ },
+
+ CHTMLmoveLine: function (start,end,node,state,values) {
+ //
+ // Move the proper part of the base
+ //
+ if (this.data[this.base]) {
+ if (start.length > 1) {
+ this.data[this.base].CHTMLmoveSlice(start.slice(1),end.slice(1),node,state,values,"marginLeft");
+ } else {
+ if (end.length <= 1) {this.data[this.base].CHTMLmoveNode(node,state,values)}
+ else {this.data[this.base].CHTMLmoveSlice([],end.slice(1),node,state,values,"marginRight")}
+ }
+ }
+ //
+ // If this is the end, check for super and subscripts, and move those
+ // by moving the stack that contains them, and shifting by the amount of the
+ // base that has been removed. Remove the empty base box from the stack.
+ //
+ if (end.length === 0) {
+ var s = this.data[this.sup] || this.data[this.sub];
+ if (s && this.CHTMLnotEmpty(s)) {
+ var box = s.CHTMLnodeElement().parentNode, stack = box.parentNode;
+ if (this.data[this.base]) stack.removeChild(stack.firstChild);
+ for (box = stack.firstChild; box; box = box.nextSibling)
+ {box.style.left = CHTML.Em(CHTML.unEm(box.style.left)-this.CHTML.baseW)}
+// stack.bbox.w -= this.CHTML.baseW; stack.style.width = CHTML.Em(stack.bbox.w);
+// this.HTMLcombineBBoxes(stack,span.bbox);
+ node.appendChild(stack);
+ }
+ }
+ }
+
+ });
+
+ /**************************************************************************/
+
+ MML.mmultiscripts.Augment({
+ CHTMLbetterBreak: function (info,state) {
+ if (!this.data[this.base]) return false;
+ //
+ // Get the current breakpoint position and other data
+ //
+ var index = info.index.slice(0); info.index.shift();
+ var W, w, scanW, broken = (info.index.length > 0), better = false;
+ if (!broken) {info.W += info.w; info.w = 0}
+ info.scanW = info.W;
+ //
+ // Get the bounding boxes and the width of the scripts
+ //
+ var bbox = this.CHTML,
+ base = this.data[this.base].CHTML;
+ var dw = bbox.w - base.w;
+ //
+ // Add in the prescripts
+ //
+ info.scanW += bbox.dx; scanW = info.scanW;
+ //
+ // Check if the base can be broken
+ //
+ if (this.data[this.base].CHTMLbetterBreak(info,state)) {
+ better = true; index = [this.base].concat(info.index); W = info.W; w = info.w;
+ if (info.penalty === PENALTY.newline) better = broken = true;
+ }
+ //
+ // Add in the base if it is unbroken, and add the scripts
+ //
+ if (!broken) this.CHTMLaddWidth(this.base,info,scanW);
+ info.scanW += dw; info.W = info.scanW;
+ info.index = []; if (better) {info.W = W; info.w = w; info.index = index}
+ return better;
+ },
+
+ CHTMLmoveLine: function (start,end,node,state,values) {
+ var NODE = this.CHTMLnodeElement(), data = this.CHTML,
+ stack = NODE.firstChild, BOX = {};
+ var box = stack.firstChild;
+
+ //
+ // Get the boxes for the scripts (if any)
+ //
+// while (box) {
+// if (box.bbox && box.bbox.name) {BOX[box.bbox.name] = box}
+// box = box.nextSibling;
+// }
+ //
+ // If this is the start, move the prescripts, if any.
+ //
+ if (start.length < 1) {
+ if (BOX.presub || BOX.presup) {
+ var STACK = HTMLCSS.createStack(node);
+ if (BOX.presup) {
+ HTMLCSS.addBox(STACK,BOX.presup);
+ HTMLCSS.placeBox(BOX.presup,data.dx-BOX.presup.bbox.w,data.u);
+ }
+ if (BOX.presub) {
+ HTMLCSS.addBox(STACK,BOX.presub);
+ HTMLCSS.placeBox(BOX.presub,data.dx+data.delta-BOX.presub.bbox.w,-data.v);
+ }
+ this.HTMLcombineBBoxes(STACK,node.bbox);
+ node.appendChild(STACK);
+ STACK.style.width = HTMLCSS.Em(data.dx);
+ }
+ }
+ //
+ // Move the proper part of the base
+ //
+ if (this.data[this.base]) {
+ if (start.length > 1) {
+ this.data[this.base].CHTMLmoveSlice(start.slice(1),end.slice(1),node,state,values,"marginLeft");
+ } else {
+ if (end.length <= 1) {this.data[this.base].CHTMLmoveNode(node,state,values)}
+ else {this.data[this.base].CHTMLmoveSlice([],end.slice(1),node,state,values,"marginRight")}
+ }
+ }
+ //
+ // If this is the end, check for super and subscripts, and move those
+ // by moving the stack that contains them, and shifting by the amount of the
+ // base that has been removed. Remove the empty base box from the stack.
+ //
+ if (end.length === 0) {
+ if (this.data[this.base]) stack.removeChild(stack.firstChild);
+ for (box = stack.firstChild; box; box = box.nextSibling)
+ box.style.left = CHTML.Em(CHTML.unEm(box.style.left)-data.px);
+// stack.bbox.w -= data.px; stack.style.width = HTMLCSS.Em(stack.bbox.w);
+// this.HTMLcombineBBoxes(stack,node.bbox);
+ node.appendChild(stack);
+ }
+ }
+
+ });
+
+ /**************************************************************************/
+
+ MML.mo.Augment({
+ //
+ // Override the method for checking line breaks to properly handle
+ //
+ CHTMLbetterBreak: function (info,state) {
+ if (info.values && info.values.id === this.CHTMLnodeID) return false;
+ var values = this.getValues(
+ "linebreak","linebreakstyle","lineleading","linebreakmultchar",
+ "indentalign","indentshift",
+ "indentalignfirst","indentshiftfirst",
+ "indentalignlast","indentshiftlast",
+ "texClass", "fence"
+ );
+ if (values.linebreakstyle === MML.LINEBREAKSTYLE.INFIXLINEBREAKSTYLE)
+ values.linebreakstyle = this.Get("infixlinebreakstyle");
+ //
+ // Adjust nesting by TeX class (helps output that does not include
+ // mrows for nesting, but can leave these unbalanced.
+ //
+ if (values.texClass === MML.TEXCLASS.OPEN) info.nest++;
+ if (values.texClass === MML.TEXCLASS.CLOSE && info.nest) info.nest--;
+ //
+ // Get the default penalty for this location
+ //
+ var W = info.scanW, mo = (info.embellished||this); delete info.embellished;
+ var w = this.CHTML.w + (this.CHTML.L||0) + (this.CHTML.R||0);
+ if (values.linebreakstyle === MML.LINEBREAKSTYLE.AFTER) {W += w; w = 0}
+ if (W - info.shift === 0 && values.linebreak !== MML.LINEBREAK.NEWLINE)
+ return false; // don't break at zero width (FIXME?)
+ var offset = CHTML.linebreakWidth - W;
+ // Adjust offest for explicit first-line indent and align
+ if (state.n === 0 && (values.indentshiftfirst !== state.VALUES.indentshiftfirst ||
+ values.indentalignfirst !== state.VALUES.indentalignfirst)) {
+ var align = this.CHTMLgetAlign(state,values),
+ shift = this.CHTMLgetShift(state,values,align);
+ offset += (info.shift - shift);
+ }
+ //
+ var penalty = Math.floor(offset / CHTML.linebreakWidth * 1000);
+ if (penalty < 0) penalty = PENALTY.toobig - 3*penalty;
+ if (values.fence) penalty += PENALTY.fence;
+ if ((values.linebreakstyle === MML.LINEBREAKSTYLE.AFTER &&
+ values.texClass === MML.TEXCLASS.OPEN) ||
+ values.texClass === MML.TEXCLASS.CLOSE) penalty += PENALTY.close;
+ penalty += info.nest * PENALTY.nestfactor;
+ //
+ // Get the penalty for this type of break and
+ // use it to modify the default penalty
+ //
+ var linebreak = PENALTY[values.linebreak||MML.LINEBREAK.AUTO];
+ if (!(linebreak instanceof Array)) {
+ // for breaks past the width, don't modify penalty
+ if (offset >= 0) {penalty = linebreak * info.nest}
+ } else {penalty = Math.max(1,penalty + linebreak[0] * info.nest)}
+ //
+ // If the penalty is no better than the current one, return false
+ // Otherwise save the data for this breakpoint and return true
+ //
+ if (penalty >= info.penalty) return false;
+ info.penalty = penalty; info.values = values; info.W = W; info.w = w;
+ values.lineleading = CHTML.length2em(values.lineleading,state.VALUES.lineleading);
+ values.id = this.CHTMLnodeID;
+ return true;
+ }
+ });
+
+ /**************************************************************************/
+
+ MML.mspace.Augment({
+ //
+ // Override the method for checking line breaks to properly handle
+ //
+ CHTMLbetterBreak: function (info,state) {
+ if (info.values && info.values.id === this.CHTMLnodeID) return false;
+ var values = this.getValues("linebreak");
+ var linebreakValue = values.linebreak;
+ if (!linebreakValue || this.hasDimAttr()) {
+ // The MathML spec says that the linebreak attribute should be ignored
+ // if any dimensional attribute is set.
+ linebreakValue = MML.LINEBREAK.AUTO;
+ }
+ //
+ // Get the default penalty for this location
+ //
+ var W = info.scanW, w = this.CHTML.w + (this.CHTML.L||0) + (this.CHTML.R||0);
+ if (W - info.shift === 0) return false; // don't break at zero width (FIXME?)
+ var offset = CHTML.linebreakWidth - W;
+ //
+ var penalty = Math.floor(offset / CHTML.linebreakWidth * 1000);
+ if (penalty < 0) penalty = PENALTY.toobig - 3*penalty;
+ penalty += info.nest * PENALTY.nestfactor;
+ //
+ // Get the penalty for this type of break and
+ // use it to modify the default penalty
+ //
+ var linebreak = PENALTY[linebreakValue];
+ if (linebreakValue === MML.LINEBREAK.AUTO && w >= PENALTY.spacelimit &&
+ !this.mathbackground && !this.background)
+ linebreak = [(w+PENALTY.spaceoffset)*PENALTY.spacefactor];
+ if (!(linebreak instanceof Array)) {
+ // for breaks past the width, don't modify penalty
+ if (offset >= 0) {penalty = linebreak * info.nest}
+ } else {penalty = Math.max(1,penalty + linebreak[0] * info.nest)}
+ //
+ // If the penalty is no better than the current one, return false
+ // Otherwise save the data for this breakpoint and return true
+ //
+ if (penalty >= info.penalty) return false;
+ info.penalty = penalty; info.values = values; info.W = W; info.w = w;
+ values.lineleading = state.VALUES.lineleading;
+ values.linebreakstyle = "before"; values.id = this.CHTMLnodeID;
+ return true;
+ }
+ });
+
+ //
+ // Hook into the mathchoice extension
+ //
+ MathJax.Hub.Register.StartupHook("TeX mathchoice Ready",function () {
+ MML.TeXmathchoice.Augment({
+ CHTMLbetterBreak: function (info,state) {
+ return this.Core().CHTMLbetterBreak(info,state);
+ },
+ CHTMLmoveLine: function (start,end,node,state,values) {
+ return this.Core().CHTMLmoveSlice(start,end,node,state,values);
+ }
+ });
+ });
+
+ //
+ // Have maction process only the selected item
+ //
+ MML.maction.Augment({
+ CHTMLbetterBreak: function (info,state) {
+ return this.Core().CHTMLbetterBreak(info,state);
+ },
+ CHTMLmoveLine: function (start,end,node,state,values) {
+ return this.Core().CHTMLmoveSlice(start,end,node,state,values);
+ }
+ });
+
+ //
+ // Have semantics only do the first element
+ // (FIXME: do we need to do anything special about annotation-xml?)
+ //
+ MML.semantics.Augment({
+ CHTMLbetterBreak: function (info,state) {
+ return (this.data[0] ? this.data[0].CHTMLbetterBreak(info,state) : false);
+ },
+ CHTMLmoveLine: function (start,end,node,state,values) {
+ return (this.data[0] ? this.data[0].CHTMLmoveSlice(start,end,node,state,values) : null);
+ }
+ });
+
+ /**************************************************************************/
+
+ MathJax.Hub.Startup.signal.Post("CommonHTML multiline Ready");
+ MathJax.Ajax.loadComplete(CHTML.autoloadDir+"/multiline.js");
+
+});
diff --git a/unpacked/jax/output/CommonHTML/jax.js b/unpacked/jax/output/CommonHTML/jax.js
index 603813f82..8d4706e8b 100644
--- a/unpacked/jax/output/CommonHTML/jax.js
+++ b/unpacked/jax/output/CommonHTML/jax.js
@@ -184,6 +184,7 @@
var BIGDIMEN = 1000000;
var V = "V", H = "H";
+ var LINEBREAKS = {};
CHTML.Augment({
settings: HUB.config.menuSettings,
@@ -197,6 +198,7 @@
if (settings.scale) {this.config.scale = settings.scale}
this.require.push(this.fontDir+"/TeX/fontdata.js");
this.require.push(MathJax.OutputJax.extensionDir+"/MathEvents.js");
+ LINEBREAKS = this.config.linebreaks;
},
Startup: function () {
@@ -286,8 +288,7 @@
// Get linebreaking information
//
var maxwidth = 100000, relwidth = false, cwidth = 0,
- linebreak = this.config.linebreaks.automatic,
- width = this.config.linebreaks.width;
+ linebreak = LINEBREAKS.automatic, width = LINEBREAKS.width;
if (linebreak) {
relwidth = !!width.match(/^\s*(\d+(\.\d*)?%\s*)?container\s*$/);
if (relwidth) {width = width.replace(/\s*container\s*/,"")}
@@ -354,7 +355,7 @@
if (style.maxWidth !== "none") {cwidth = parseFloat(style.maxWidth); break}
node = node.parentNode;
}
-
+ if (relwidth) maxwidth = cwidth;
scale = (this.config.matchFontHeight ? ex/this.TEX.x_height/em : 1);
scale = Math.floor(Math.max(this.config.minScaleAdjust/100,scale)*this.config.scale);
jax.CHTML.scale = scale/100; jax.CHTML.fontSize = scale+"%";
@@ -1224,6 +1225,7 @@
toCommonHTML: function (node,options) {
return this.CHTMLdefaultNode(node,options);
},
+ CHTMLmultiline: function () {MML.mbase.CHTMLautoloadFile("multiline")},
CHTMLdefaultNode: function (node,options) {
if (!options) options = {};
@@ -1384,7 +1386,7 @@
CHTMLhandleBBox: function (node) {
var BBOX = this.CHTML, style = node.style;
- if (this.data.length === 1 && this.data[0].CHTML.pwidth) {
+ if (this.data.length === 1 && (this.data[0].CHTML||{}).pwidth) {
BBOX.pwidth = this.data[0].CHTML.pwidth;
BBOX.mwidth = this.data[0].CHTML.mwidth;
style.width = "100%";
@@ -1483,8 +1485,8 @@
//
// Debugging function to see if internal BBox matches actual bbox
//
- CHTMLdrawBBox: function (node) {
- var bbox = this.CHTML;
+ CHTMLdrawBBox: function (node,bbox) {
+ if (!bbox) bbox = this.CHTML;
var box = HTML.Element("mjx-box",
{style:{"font-size":node.style.fontSize, opacity:.25,"margin-left":CHTML.Em(-(bbox.w+(bbox.R||0)))}},[
["mjx-box",{style:{
@@ -2356,8 +2358,13 @@
node = this.CHTMLdefaultNode(node);
var bbox = this.CHTML, H = bbox.h, D = bbox.d;
for (var i = 0, m = this.data.length; i < m; i++) this.CHTMLstretchChildV(i,H,D);
+ if (this.CHTMLlineBreaks()) this.CHTMLmultiline(node);
return node;
},
+ CHTMLlineBreaks: function () {
+ if (!LINEBREAKS.automatic || !this.parent.linebreakContainer) return false;
+ return (this.CHTML.w > CHTML.linebreakWidth) || this.hasNewline();
+ },
CHTMLstretchV: function (h,d) {
this.CHTMLstretchChildV(this.CoreIndex(),h,d);
return this.CHTML;