aboutsummaryrefslogtreecommitdiff
path: root/js/mathjax/jax/output/CommonHTML/autoload/multiline.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/mathjax/jax/output/CommonHTML/autoload/multiline.js')
-rw-r--r--js/mathjax/jax/output/CommonHTML/autoload/multiline.js799
1 files changed, 799 insertions, 0 deletions
diff --git a/js/mathjax/jax/output/CommonHTML/autoload/multiline.js b/js/mathjax/jax/output/CommonHTML/autoload/multiline.js
new file mode 100644
index 0000000..9d54b99
--- /dev/null
+++ b/js/mathjax/jax/output/CommonHTML/autoload/multiline.js
@@ -0,0 +1,799 @@
+// @license magnet:?xt=urn:btih:8e4f440f4c65981c5bf93c76d35135ba5064d8b7dn=apache-2.0.txt Apache-2.0
+/* -*- 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 <mrow>'s that contain line breaks.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (c) 2015-2020 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.7.9";
+ var MML = MathJax.ElementJax.mml,
+ CONFIG = MathJax.Hub.config,
+ CHTML = MathJax.OutputJax.CommonHTML;
+ //
+ // Fake node used for testing end-of-line potential breakpoint
+ //
+ var MO = MML.mo().With({CHTML: CHTML.BBOX.empty()});
+
+ //
+ // Penalties for the various line breaks
+ //
+ var PENALTY = {
+ newline: 0,
+ nobreak: 1000000,
+ goodbreak: [-200],
+ badbreak: [+200],
+ auto: [0],
+
+ maxwidth: 1.33, // stop looking for breaks after this time the line-break width
+ 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.isEmbellished())) {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 = this.CHTMLlength2em(VALUES.lineleading,0.5);
+
+ //
+ // Break the math at its best line breaks
+ //
+ CHTML.BBOX.empty(this.CHTML);
+ var stack = CHTML.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,true) &&
+ (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);
+
+ if (parent.type === "math") {
+ node.style.width = stack.style.width = this.CHTML.pwidth = "100%";
+ }
+ this.CHTML.mwidth = CHTML.Em(this.CHTML.w);
+ 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,toplevel) {
+ 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 < PENALTY.maxwidth*CHTML.linebreakWidth || info.w === 0)) {
+ 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;
+ }
+ //
+ // Check if end-of-line is a better breakpoint
+ //
+ if (toplevel && better) {
+ MO.parent = this.parent; MO.inherit = this.inherit;
+ if (MO.CHTMLbetterBreak(info,state)) {better = false; index = info.index}
+ }
+ 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 bbox = this.data[i].CHTML;
+ scanW += (bbox.w + (bbox.L||0) + (bbox.R||0)) * (bbox.scale || 1);
+ 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 = CHTML.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);
+ //
+ // 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 = this.CHTMLlength2em(shift,CHTML.cwidth);
+ if (state.isTop && CONFIG.displayIndent !== "0") {
+ var indent = this.CHTMLlength2em(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();
+ if (this.href) node = node.parentNode;
+ 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;
+ if (this.href) NODE = NODE.parentNode;
+ 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();
+ if (this.href) node = node.parentNode;
+ line.appendChild(node);
+ if (this.CHTML.pwidth && !line.style.width) line.style.width = this.CHTML.pwidth;
+ //
+ // 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 < PENALTY.maxwidth*CHTML.linebreakWidth || info.w === 0)) {
+ 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]) {
+ var base = CHTML.addElement(node,"mjx-base");
+ var ic = this.data[this.base].CHTML.ic;
+ if (ic) base.style.marginRight = CHTML.Em(-ic);
+ if (start.length > 1) {
+ this.data[this.base].CHTMLmoveSlice(start.slice(1),end.slice(1),base,state,values,"marginLeft");
+ } else {
+ if (end.length <= 1) this.data[this.base].CHTMLmoveNode(base,state,values);
+ else this.data[this.base].CHTMLmoveSlice([],end.slice(1),base,state,values,"marginRight");
+ }
+ }
+ //
+ // If this is the end, check for super and subscripts, and move those
+ // by moving the elements that contains them. Adjust the bounding box
+ // to include the super and subscripts.
+ //
+ if (end.length === 0) {
+ var NODE = this.CHTMLnodeElement(),
+ stack = CHTML.getNode(NODE,"mjx-stack"),
+ sup = CHTML.getNode(NODE,"mjx-sup"),
+ sub = CHTML.getNode(NODE,"mjx-sub");
+ if (stack) node.appendChild(stack);
+ else if (sup) node.appendChild(sup);
+ else if (sub) node.appendChild(sub);
+ var w = state.bbox.w, bbox;
+ if (sup) {
+ bbox = this.data[this.sup].CHTML;
+ state.bbox.combine(bbox,w,bbox.Y);
+ }
+ if (sub) {
+ bbox = this.data[this.sub].CHTML;
+ state.bbox.combine(bbox,w,bbox.Y);
+ }
+ }
+ }
+
+ });
+
+ /**************************************************************************/
+
+ 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 - (bbox.X||0);
+ //
+ // Add in the width of the prescripts
+ //
+ info.scanW += bbox.X||0; 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, BOX = this.CHTMLbbox, w;
+ //
+ // If this is the start, move the prescripts, if any.
+ //
+ if (start.length < 1) {
+ NODE = this.CHTMLnodeElement();
+ var prestack = CHTML.getNode(NODE,"mjx-prestack"),
+ presup = CHTML.getNode(NODE,"mjx-presup"),
+ presub = CHTML.getNode(NODE,"mjx-presub");
+ if (prestack) node.appendChild(prestack);
+ else if (presup) node.appendChild(presup);
+ else if (presub) node.appendChild(presub);
+ w = state.bbox.w;
+ if (presup) state.bbox.combine(BOX.presup,w+BOX.presup.X,BOX.presup.Y);
+ if (presub) state.bbox.combine(BOX.presub,w+BOX.presub.X,BOX.presub.Y);
+ }
+ //
+ // Move the proper part of the base
+ //
+ if (this.data[this.base]) {
+ var base = CHTML.addElement(node,"mjx-base");
+ if (start.length > 1) {
+ this.data[this.base].CHTMLmoveSlice(start.slice(1),end.slice(1),base,state,values,"marginLeft");
+ } else {
+ if (end.length <= 1) this.data[this.base].CHTMLmoveNode(base,state,values);
+ else this.data[this.base].CHTMLmoveSlice([],end.slice(1),base,state,values,"marginRight");
+ }
+ }
+ //
+ // If this is the end, check for super and subscripts, and move those
+ // by moving the elements that contains them. Adjust the bounding box
+ // to include the super and subscripts.
+ //
+ if (end.length === 0) {
+ NODE = this.CHTMLnodeElement();
+ var stack = CHTML.getNode(NODE,"mjx-stack"),
+ sup = CHTML.getNode(NODE,"mjx-sup"),
+ sub = CHTML.getNode(NODE,"mjx-sub");
+ if (stack) node.appendChild(stack);
+ else if (sup) node.appendChild(sup);
+ else if (sub) node.appendChild(sub);
+ w = state.bbox.w;
+ if (sup) state.bbox.combine(BOX.sup,w,BOX.sup.Y);
+ if (sub) state.bbox.combine(BOX.sub,w,BOX.sub.Y);
+ }
+ }
+
+ });
+
+ /**************************************************************************/
+
+ MML.mo.Augment({
+ //
+ // Override the method for checking line breaks to properly handle <mo>
+ //
+ 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; 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]||0;
+ if (!MathJax.Object.isArray(linebreak)) {
+ // for breaks past the width, keep original penalty for newline
+ if (linebreak || 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 = this.CHTMLlength2em(values.lineleading,state.VALUES.lineleading);
+ values.id = this.CHTMLnodeID;
+ return true;
+ }
+ });
+
+ /**************************************************************************/
+
+ MML.mspace.Augment({
+ //
+ // Override the method for checking line breaks to properly handle <mspace>
+ //
+ 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]||0;
+ if (linebreakValue === MML.LINEBREAK.AUTO && w >= PENALTY.spacelimit &&
+ !this.mathbackground && !this.background)
+ linebreak = [(w+PENALTY.spaceoffset)*PENALTY.spacefactor];
+ if (!MathJax.Object.isArray(linebreak)) {
+ // for breaks past the width, keep original penalty for newline
+ if (linebreak || 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");
+
+});
+// @license-end