123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781 |
- /* -*- 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-2017 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.2";
- var MML = MathJax.ElementJax.mml,
- 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.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) &&
- (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.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) {
- 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 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 = 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 < 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]) {
- 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) {
- 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;
- //
- // Add in the width of the prescripts
- //
- info.scanW += bbox.X; 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];
- if (!MathJax.Object.isArray(linebreak)) {
- // 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 = 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];
- 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, 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");
-
- });
|