PageRenderTime 60ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/talk2/mathjax/unpacked/jax/output/HTML-CSS/autoload/multiline.js

https://github.com/williamstein/mazur-explicit-formula
JavaScript | 692 lines | 421 code | 40 blank | 231 comment | 162 complexity | 2dc816b18bc40a33f615e37186f5c095 MD5 | raw file
Possible License(s): Apache-2.0, GPL-2.0, MIT
  1. /*************************************************************
  2. *
  3. * MathJax/jax/output/HTML-CSS/autoload/multiline.js
  4. *
  5. * Implements the HTML-CSS output for <mrow>'s that contain line breaks.
  6. *
  7. * ---------------------------------------------------------------------
  8. *
  9. * Copyright (c) 2010-2012 Design Science, Inc.
  10. *
  11. * Licensed under the Apache License, Version 2.0 (the "License");
  12. * you may not use this file except in compliance with the License.
  13. * You may obtain a copy of the License at
  14. *
  15. * http://www.apache.org/licenses/LICENSE-2.0
  16. *
  17. * Unless required by applicable law or agreed to in writing, software
  18. * distributed under the License is distributed on an "AS IS" BASIS,
  19. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  20. * See the License for the specific language governing permissions and
  21. * limitations under the License.
  22. */
  23. MathJax.Hub.Register.StartupHook("HTML-CSS Jax Ready",function () {
  24. var VERSION = "2.1";
  25. var MML = MathJax.ElementJax.mml,
  26. HTMLCSS = MathJax.OutputJax["HTML-CSS"];
  27. //
  28. // Penalties for the various line breaks
  29. //
  30. var PENALTY = {
  31. newline: 0,
  32. nobreak: 1000000,
  33. goodbreak: [-200],
  34. badbreak: [+200],
  35. auto: [0],
  36. toobig: 800,
  37. nestfactor: 400,
  38. spacefactor: -100,
  39. spaceoffset: 2,
  40. spacelimit: 1, // spaces larger than this get a penalty boost
  41. fence: 500,
  42. close: 500
  43. };
  44. var ENDVALUES = {linebreakstyle: "after"};
  45. /**************************************************************************/
  46. MML.mbase.Augment({
  47. HTMLlinebreakPenalty: PENALTY,
  48. /****************************************************************/
  49. //
  50. // Handle breaking an mrow into separate lines
  51. //
  52. HTMLmultiline: function (span) {
  53. //
  54. // Find the parent element and mark it as multiline
  55. //
  56. var parent = this;
  57. while (parent.inferred || (parent.parent && parent.parent.type === "mrow" &&
  58. parent.parent.data.length === 1)) {parent = parent.parent}
  59. var isTop = ((parent.type === "math" && parent.Get("display") === "block") ||
  60. parent.type === "mtd");
  61. parent.isMultiline = true;
  62. //
  63. // Default values for the line-breaking parameters
  64. //
  65. var VALUES = this.getValues(
  66. "linebreak","linebreakstyle","lineleading","linebreakmultchar",
  67. "indentalign","indentshift",
  68. "indentalignfirst","indentshiftfirst",
  69. "indentalignlast","indentshiftlast"
  70. );
  71. if (VALUES.linebreakstyle === MML.LINEBREAKSTYLE.INFIXLINEBREAKSTYLE)
  72. {VALUES.linebreakstyle = this.Get("infixlinebreakstyle")}
  73. VALUES.lineleading = HTMLCSS.length2em(VALUES.lineleading,1,0.5);
  74. //
  75. // Remove old color and break the span at its best line breaks
  76. //
  77. this.HTMLremoveColor(span);
  78. var stack = HTMLCSS.createStack(span);
  79. var state = {
  80. n: 0, Y: 0,
  81. scale: this.HTMLgetScale(),
  82. isTop: isTop,
  83. values: {},
  84. VALUES: VALUES
  85. },
  86. align = this.HTMLgetAlign(state,{}),
  87. shift = this.HTMLgetShift(state,{},align),
  88. start = [],
  89. end = {
  90. index:[], penalty:PENALTY.nobreak,
  91. w:0, W:shift, shift:shift, scanW:shift,
  92. nest: 0
  93. },
  94. broken = false;
  95. while (this.HTMLbetterBreak(end,state) &&
  96. (end.scanW >= HTMLCSS.linebreakWidth || end.penalty == PENALTY.newline)) {
  97. this.HTMLaddLine(stack,start,end.index,state,end.values,broken);
  98. start = end.index.slice(0); broken = true;
  99. align = this.HTMLgetAlign(state,end.values);
  100. shift = this.HTMLgetShift(state,end.values,align);
  101. if (align === MML.INDENTALIGN.CENTER) {shift = 0}
  102. end.W = end.shift = end.scanW = shift; end.penalty = PENALTY.nobreak;
  103. }
  104. state.isLast = true;
  105. this.HTMLaddLine(stack,start,[],state,ENDVALUES,broken);
  106. //
  107. // Make top-level spans 100% wide.
  108. // Finish up the space and add the color again
  109. //
  110. if (isTop) {
  111. stack.style.width = "100%";
  112. if (parent.type === "math") {span.bbox.width = "100%"}
  113. }
  114. this.HTMLhandleSpace(span);
  115. this.HTMLhandleColor(span);
  116. span.bbox.isMultiline = true;
  117. return span;
  118. },
  119. /****************************************************************/
  120. //
  121. // Locate the next linebreak that is better than the current one
  122. //
  123. HTMLbetterBreak: function (info,state) {
  124. if (this.isToken) {return false} // FIXME: handle breaking of token elements
  125. if (this.isEmbellished()) {
  126. info.embellished = this;
  127. return this.CoreMO().HTMLbetterBreak(info,state);
  128. }
  129. if (this.linebreakContainer) {return false}
  130. //
  131. // Get the current breakpoint position and other data
  132. //
  133. var index = info.index.slice(0), i = info.index.shift(),
  134. m = this.data.length, W, w, scanW, broken = (info.index.length > 0), better = false;
  135. if (i == null) {i = -1}; if (!broken) {i++; info.W += info.w; info.w = 0}
  136. scanW = info.scanW = info.W; info.nest++;
  137. //
  138. // Look through the line for breakpoints,
  139. // (as long as we are not too far past the breaking width)
  140. //
  141. while (i < m && info.scanW < 1.33*HTMLCSS.linebreakWidth) {
  142. if (this.data[i]) {
  143. if (this.data[i].HTMLbetterBreak(info,state)) {
  144. better = true; index = [i].concat(info.index); W = info.W; w = info.w;
  145. if (info.penalty === PENALTY.newline) {info.index = index; info.nest--; return true}
  146. }
  147. scanW = (broken ? info.scanW : this.HTMLaddWidth(i,info,scanW));
  148. }
  149. info.index = []; i++; broken = false;
  150. }
  151. info.nest--; info.index = index;
  152. if (better) {info.W = W; info.w = w}
  153. return better;
  154. },
  155. HTMLaddWidth: function (i,info,scanW) {
  156. if (this.data[i]) {
  157. var span = this.data[i].HTMLspanElement();
  158. scanW += span.bbox.w;
  159. if (span.style.paddingLeft) {scanW += HTMLCSS.unEm(span.style.paddingLeft)}
  160. if (span.style.paddingRight) {scanW += HTMLCSS.unEm(span.style.paddingRight)}
  161. info.W = info.scanW = scanW; info.w = 0;
  162. }
  163. return scanW;
  164. },
  165. /****************************************************************/
  166. //
  167. // Create a new line and move the required elements into it
  168. // Position it using proper alignment and indenting
  169. //
  170. HTMLaddLine: function (stack,start,end,state,values,broken) {
  171. //
  172. // Create a box for the line, with empty BBox
  173. // fill it with the proper elements,
  174. // and clean up the bbox
  175. //
  176. line = HTMLCSS.createBox(stack);
  177. line.bbox = this.HTMLemptyBBox({});
  178. state.first = broken; state.last = true;
  179. this.HTMLmoveLine(start,end,line,state,values);
  180. this.HTMLcleanBBox(line.bbox);
  181. //
  182. // Get the alignment and shift values
  183. //
  184. var align = this.HTMLgetAlign(state,values),
  185. shift = this.HTMLgetShift(state,values,align);
  186. //
  187. // Add in space for the shift
  188. //
  189. if (shift) {
  190. HTMLCSS.createBlank(line,shift,(align !== MML.INDENTALIGN.RIGHT));
  191. line.bbox.w += shift; line.bbox.rw += shift;
  192. }
  193. //
  194. // Set the Y offset based on previous depth, leading, and current height
  195. //
  196. if (state.n > 0) {
  197. var LHD = HTMLCSS.FONTDATA.baselineskip * state.scale;
  198. var leading = (state.values.lineleading == null ? state.VALUES : state.values).lineleading;
  199. state.Y -= Math.max(LHD,state.d + line.bbox.h + leading);
  200. }
  201. //
  202. // Place the new line
  203. //
  204. HTMLCSS.alignBox(line,align,state.Y);
  205. //
  206. // Save the values needed for the future
  207. //
  208. state.d = line.bbox.d; state.values = values; state.n++;
  209. },
  210. /****************************************************************/
  211. //
  212. // Get alignment and shift values from the given data
  213. //
  214. HTMLgetAlign: function (state,values) {
  215. var cur = values, prev = state.values, def = state.VALUES, align;
  216. if (state.n === 0) {align = cur.indentalignfirst || prev.indentalignfirst || def.indentalignfirst}
  217. else if (state.isLast) {align = prev.indentalignlast || def.indentalignlast}
  218. else {align = prev.indentalign || def.indentalign}
  219. if (align === MML.INDENTALIGN.INDENTALIGN) {align = prev.indentalign || def.indentalign}
  220. if (align === MML.INDENTALIGN.AUTO) {align = (state.isTop ? this.displayAlign : MML.INDENTALIGN.LEFT)}
  221. return align;
  222. },
  223. HTMLgetShift: function (state,values,align) {
  224. if (align === MML.INDENTALIGN.CENTER) {return 0}
  225. var cur = values, prev = state.values, def = state.VALUES, shift;
  226. if (state.n === 0) {shift = cur.indentshiftfirst || prev.indentshiftfirst || def.indentshiftfirst}
  227. else if (state.isLast) {shift = prev.indentshiftlast || def.indentshiftlast}
  228. else {shift = prev.indentshift || def.indentshift}
  229. if (shift === MML.INDENTSHIFT.INDENTSHIFT) {shift = prev.indentshift || def.indentshift}
  230. if (shift === "auto" || shift === "") {shift = (state.isTSop ? this.displayIndent : "0")}
  231. return HTMLCSS.length2em(shift,0);
  232. },
  233. /****************************************************************/
  234. //
  235. // Move the selected elements into the new line's span,
  236. // moving whole items when possible, and parts of ones
  237. // that are split by a line break.
  238. //
  239. HTMLmoveLine: function (start,end,span,state,values) {
  240. var i = start[0], j = end[0];
  241. if (i == null) {i = -1}; if (j == null) {j = this.data.length-1}
  242. if (i === j && start.length > 1) {
  243. //
  244. // If starting and ending in the same element move the subpiece to the new line
  245. //
  246. this.data[i].HTMLmoveSlice(start.slice(1),end.slice(1),span,state,values,"paddingLeft");
  247. } else {
  248. //
  249. // Otherwise, move the remainder of the initial item
  250. // and any others up to the last one
  251. //
  252. var last = state.last; state.last = false;
  253. while (i < j) {
  254. if (this.data[i]) {
  255. if (start.length <= 1) {this.data[i].HTMLmoveSpan(span,state,values)}
  256. else {this.data[i].HTMLmoveSlice(start.slice(1),[],span,state,values,"paddingLeft")}
  257. }
  258. i++; state.first = false; start = [];
  259. }
  260. //
  261. // If the last item is complete, move it,
  262. // otherwise move the first part of it up to the split
  263. //
  264. state.last = last;
  265. if (this.data[i]) {
  266. if (end.length <= 1) {this.data[i].HTMLmoveSpan(span,state,values)}
  267. else {this.data[i].HTMLmoveSlice([],end.slice(1),span,state,values,"paddingRight")}
  268. }
  269. }
  270. },
  271. /****************************************************************/
  272. //
  273. // Split an element and copy the selected items into the new part
  274. //
  275. HTMLmoveSlice: function (start,end,span,state,values,padding) {
  276. //
  277. // Get rid of color, if any (added back in later)
  278. // Create a new span for the slice of the element
  279. // Move the selected portion into the slice
  280. // If it is the last slice
  281. // Remove the original (now empty) span
  282. // Rename the Continue-0 span with the original name (for HTMLspanElement)
  283. // Add back the color
  284. //
  285. this.HTMLremoveColor();
  286. var slice = this.HTMLcreateSliceSpan(span);
  287. this.HTMLmoveLine(start,end,slice,state,values);
  288. slice.style[padding] = "";
  289. this.HTMLcombineBBoxes(slice,span.bbox);
  290. this.HTMLcleanBBox(slice.bbox);
  291. if (end.length === 0) {
  292. span = this.HTMLspanElement();
  293. span.parentNode.removeChild(span);
  294. span.nextMathJaxSpan.id = span.id; var n = 0;
  295. while (span = span.nextMathJaxSpan) {
  296. var color = this.HTMLhandleColor(span);
  297. if (color) {color.id += "-MathJax-Continue-"+n; n++}
  298. }
  299. }
  300. return slice;
  301. },
  302. /****************************************************************/
  303. //
  304. // Create a new span for an element that is split in two
  305. // Clone the original and update its ID.
  306. // Link the old span to the new one so we can find it later
  307. //
  308. HTMLcreateSliceSpan: function (span) {
  309. var SPAN = this.HTMLspanElement(), n = 0;
  310. var LAST = SPAN; while (LAST.nextMathJaxSpan) {LAST = LAST.nextMathJaxSpan; n++}
  311. var SLICE = SPAN.cloneNode(false); LAST.nextMathJaxSpan = SLICE; SLICE.nextMathJaxSpan = null;
  312. SLICE.id += "-MathJax-Continue-"+n;
  313. SLICE.bbox = this.HTMLemptyBBox({});
  314. return span.appendChild(SLICE);
  315. },
  316. /****************************************************************/
  317. //
  318. // Move an element from its original span to its new location in
  319. // a split element or the new line's span
  320. //
  321. HTMLmoveSpan: function (line,state,values) {
  322. // FIXME: handle linebreakstyle === "duplicate"
  323. // FIXME: handle linebreakmultchar
  324. if (!(state.first || state.last) ||
  325. (state.first && state.values.linebreakstyle === MML.LINEBREAKSTYLE.BEFORE) ||
  326. (state.last && values.linebreakstyle === MML.LINEBREAKSTYLE.AFTER)) {
  327. //
  328. // Move color and span
  329. //
  330. var color = document.getElementById("MathJax-Color-"+this.spanID+HTMLCSS.idPostfix);
  331. if (color) {line.appendChild(color)}
  332. var span = this.HTMLspanElement();
  333. line.appendChild(span);
  334. //
  335. // If it is last, remove right padding
  336. // If it is first, remove left padding and recolor
  337. //
  338. if (state.last) {span.style.paddingRight = ""}
  339. if (state.first || state.nextIsFirst) {
  340. delete state.nextIsFirst;
  341. span.style.paddingLeft = "";
  342. if (color) {this.HTMLremoveColor(span); this.HTMLhandleColor(span)}
  343. }
  344. //
  345. // Update bounding box
  346. //
  347. this.HTMLcombineBBoxes(this,line.bbox);
  348. } else if (state.first) {state.nextIsFirst = true} else {delete state.nextIsFirst}
  349. }
  350. });
  351. /**************************************************************************/
  352. MML.mfenced.Augment({
  353. HTMLbetterBreak: function (info,state) {
  354. //
  355. // Get the current breakpoint position and other data
  356. //
  357. var index = info.index.slice(0), i = info.index.shift(),
  358. m = this.data.length, W, w, scanW, broken = (info.index.length > 0), better = false;
  359. if (i == null) {i = -1}; if (!broken) {i++; info.W += info.w; info.w = 0}
  360. scanW = info.scanW = info.W; info.nest++;
  361. //
  362. // Create indices that include the delimiters and separators
  363. //
  364. if (!this.dataI) {
  365. this.dataI = [];
  366. if (this.data.open) {this.dataI.push("open")}
  367. if (m) {this.dataI.push(0)}
  368. for (var j = 1; j < m; j++) {
  369. if (this.data["sep"+j]) {this.dataI.push("sep"+j)}
  370. this.dataI.push(j);
  371. }
  372. if (this.data.close) {this.dataI.push("close")}
  373. }
  374. m = this.dataI.length;
  375. //
  376. // Look through the line for breakpoints, including the open, close, and separators
  377. // (as long as we are not too far past the breaking width)
  378. //
  379. while (i < m && info.scanW < 1.33*HTMLCSS.linebreakWidth) {
  380. var k = this.dataI[i];
  381. if (this.data[k]) {
  382. if (this.data[k].HTMLbetterBreak(info,state)) {
  383. better = true; index = [i].concat(info.index); W = info.W; w = info.w;
  384. if (info.penalty === PENALTY.newline) {info.index = index; info.nest--; return true}
  385. }
  386. scanW = (broken ? info.scanW : this.HTMLaddWidth(i,info,scanW));
  387. }
  388. info.index = []; i++; broken = false;
  389. }
  390. info.nest--; info.index = index;
  391. if (better) {info.W = W; info.w = w}
  392. return better;
  393. },
  394. HTMLmoveLine: function (start,end,span,state,values) {
  395. var i = start[0], j = end[0];
  396. if (i == null) {i = -1}; if (j == null) {j = this.dataI.length-1}
  397. if (i === j && start.length > 1) {
  398. //
  399. // If starting and ending in the same element move the subpiece to the new line
  400. //
  401. this.data[this.dataI[i]].HTMLmoveSlice(start.slice(1),end.slice(1),span,state,values,"paddingLeft");
  402. } else {
  403. //
  404. // Otherwise, move the remainder of the initial item
  405. // and any others (including open and separators) up to the last one
  406. //
  407. var last = state.last; state.last = false; var k = this.dataI[i];
  408. while (i < j) {
  409. if (this.data[k]) {
  410. if (start.length <= 1) {this.data[k].HTMLmoveSpan(span,state,values)}
  411. else {this.data[k].HTMLmoveSlice(start.slice(1),[],span,state,values,"paddingLeft")}
  412. }
  413. i++; k = this.dataI[i]; state.first = false; start = [];
  414. }
  415. //
  416. // If the last item is complete, move it
  417. //
  418. state.last = last;
  419. if (this.data[k]) {
  420. if (end.length <= 1) {this.data[k].HTMLmoveSpan(span,state,values)}
  421. else {this.data[k].HTMLmoveSlice([],end.slice(1),span,state,values,"paddingRight")}
  422. }
  423. }
  424. }
  425. });
  426. /**************************************************************************/
  427. MML.msubsup.Augment({
  428. HTMLbetterBreak: function (info,state) {
  429. if (!this.data[this.base]) {return false}
  430. //
  431. // Get the current breakpoint position and other data
  432. //
  433. var index = info.index.slice(0), i = info.index.shift(),
  434. W, w, scanW, broken = (info.index.length > 0), better = false;
  435. if (!broken) {info.W += info.w; info.w = 0}
  436. scanW = info.scanW = info.W;
  437. //
  438. // Record the width of the base and the super- and subscripts
  439. //
  440. if (i == null) {
  441. this.HTMLbaseW = this.data[this.base].HTMLspanElement().bbox.w;
  442. this.HTMLdw = this.HTMLspanElement().bbox.w - this.HTMLbaseW;
  443. }
  444. //
  445. // Check if the base can be broken
  446. //
  447. if (this.data[this.base].HTMLbetterBreak(info,state)) {
  448. better = true; index = [this.base].concat(info.index); W = info.W; w = info.w;
  449. if (info.penalty === PENALTY.newline) {better = broken = true}
  450. }
  451. //
  452. // Add in the base if it is unbroken, and add the scripts
  453. //
  454. if (!broken) {this.HTMLaddWidth(this.base,info,scanW)}
  455. info.scanW += this.HTMLdw; info.W = info.scanW;
  456. info.index = []; if (better) {info.W = W; info.w = w; info.index = index}
  457. return better;
  458. },
  459. HTMLmoveLine: function (start,end,span,state,values) {
  460. //
  461. // Move the proper part of the base
  462. //
  463. if (this.data[this.base]) {
  464. if (start.length > 1) {
  465. this.data[this.base].HTMLmoveSlice(start.slice(1),end.slice(1),span,state,values,"paddingLeft");
  466. } else {
  467. if (end.length <= 1) {this.data[this.base].HTMLmoveSpan(span,state,values)}
  468. else {this.data[this.base].HTMLmoveSlice([],end.slice(1),span,state,values,"paddingRight")}
  469. }
  470. }
  471. //
  472. // If this is the end, check for super and subscripts, and move those
  473. // by moving the stack tht contains them, and shifting by the amount of the
  474. // base that has been removed. Remove the empty base box from the stack.
  475. //
  476. if (end.length === 0) {
  477. var s = this.data[this.sup] || this.data[this.sub];
  478. if (s) {
  479. var box = s.HTMLspanElement().parentNode, stack = box.parentNode;
  480. if (this.data[this.base]) {stack.removeChild(stack.firstChild)}
  481. for (box = stack.firstChild; box; box = box.nextSibling)
  482. {box.style.left = HTMLCSS.Em(HTMLCSS.unEm(box.style.left)-this.HTMLbaseW)}
  483. stack.bbox.w -= this.HTMLbaseW; stack.style.width = HTMLCSS.Em(stack.bbox.w);
  484. this.HTMLcombineBBoxes(stack,span.bbox);
  485. span.appendChild(stack);
  486. }
  487. }
  488. }
  489. });
  490. /**************************************************************************/
  491. MML.mo.Augment({
  492. //
  493. // Override the method for checking line breaks to properly handle <mo>
  494. //
  495. HTMLbetterBreak: function (info,state) {
  496. if (info.values && info.values.id === this.spanID) {return false}
  497. var values = this.getValues(
  498. "linebreak","linebreakstyle","lineleading","linebreakmultchar",
  499. "indentalign","indentshift",
  500. "indentalignfirst","indentshiftfirst",
  501. "indentalignlast","indentshiftlast",
  502. "texClass", "fence"
  503. );
  504. if (values.linebreakstyle === MML.LINEBREAKSTYLE.INFIXLINEBREAKSTYLE)
  505. {values.linebreakstyle = this.Get("infixlinebreakstyle")}
  506. //
  507. // Adjust nesting by TeX class (helps output that does not include
  508. // mrows for nesting, but can leave these unbalanced.
  509. //
  510. if (values.texClass === MML.TEXCLASS.OPEN) {info.nest++}
  511. if (values.texClass === MML.TEXCLASS.CLOSE) {info.nest--}
  512. //
  513. // Get the default penalty for this location
  514. //
  515. var W = info.scanW, mo = (info.embellished||this); delete info.embellished;
  516. var span = mo.HTMLspanElement(), w = span.bbox.w;
  517. if (span.style.paddingLeft) {w += HTMLCSS.unEm(span.style.paddingLeft)}
  518. if (values.linebreakstyle === MML.LINEBREAKSTYLE.AFTER) {W += w; w = 0}
  519. if (W - info.shift === 0) {return false} // don't break at zero width (FIXME?)
  520. var offset = HTMLCSS.linebreakWidth - W;
  521. // Adjust offest for explicit first-line indent and align
  522. if (state.n === 0 && (values.indentshiftfirst !== state.VALUES.indentshiftfirst ||
  523. values.indentalignfirst !== state.VALUES.indentalignfirst)) {
  524. var align = this.HTMLgetAlign(state,values),
  525. shift = this.HTMLgetShift(state,values,align);
  526. offset += (info.shift - shift);
  527. }
  528. //
  529. var penalty = Math.floor(offset / HTMLCSS.linebreakWidth * 1000);
  530. if (penalty < 0) {penalty = PENALTY.toobig - 3*penalty}
  531. if (values.fence) {penalty += PENALTY.fence}
  532. if ((values.linebreakstyle === MML.LINEBREAKSTYLE.AFTER &&
  533. values.texClass === MML.TEXCLASS.OPEN) ||
  534. values.texClass === MML.TEXCLASS.CLOSE) {penalty += PENALTY.close}
  535. penalty += info.nest * PENALTY.nestfactor;
  536. //
  537. // Get the penalty for this type of break and
  538. // use it to modify the default penalty
  539. //
  540. var linebreak = PENALTY[values.linebreak||MML.LINEBREAK.AUTO];
  541. if (!(linebreak instanceof Array)) {
  542. // for breaks past the width, don't modify penalty
  543. if (offset >= 0) {penalty = linebreak * info.nest}
  544. } else {penalty = Math.max(1,penalty + linebreak[0] * info.nest)}
  545. //
  546. // If the penalty is no better than the current one, return false
  547. // Otherwise save the data for this breakpoint and return true
  548. //
  549. if (penalty >= info.penalty) {return false}
  550. info.penalty = penalty; info.values = values; info.W = W; info.w = w;
  551. values.lineleading = HTMLCSS.length2em(values.lineleading,state.VALUES.lineleading);
  552. values.id = this.spanID;
  553. return true;
  554. }
  555. });
  556. /**************************************************************************/
  557. MML.mspace.Augment({
  558. //
  559. // Override the method for checking line breaks to properly handle <mspace>
  560. //
  561. HTMLbetterBreak: function (info,state) {
  562. if (info.values && info.values.id === this.spanID) {return false}
  563. var values = this.getValues("linebreak");
  564. //
  565. // Get the default penalty for this location
  566. //
  567. var W = info.scanW, span = this.HTMLspanElement(), w = span.bbox.w;
  568. if (span.style.paddingLeft) {w += HTMLCSS.unEm(span.style.paddingLeft)}
  569. if (W - info.shift === 0) {return false} // don't break at zero width (FIXME?)
  570. var offset = HTMLCSS.linebreakWidth - W;
  571. //
  572. var penalty = Math.floor(offset / HTMLCSS.linebreakWidth * 1000);
  573. if (penalty < 0) {penalty = PENALTY.toobig - 3*penalty}
  574. penalty += info.nest * PENALTY.nestfactor;
  575. //
  576. // Get the penalty for this type of break and
  577. // use it to modify the default penalty
  578. //
  579. var linebreak = PENALTY[values.linebreak||MML.LINEBREAK.AUTO];
  580. if (values.linebreak === MML.LINEBREAK.AUTO && w >= PENALTY.spacelimit)
  581. {linebreak = [(w+PENALTY.spaceoffset)*PENALTY.spacefactor]}
  582. if (!(linebreak instanceof Array)) {
  583. // for breaks past the width, don't modify penalty
  584. if (offset >= 0) {penalty = linebreak * info.nest}
  585. } else {penalty = Math.max(1,penalty + linebreak[0] * info.nest)}
  586. //
  587. // If the penalty is no better than the current one, return false
  588. // Otherwise save the data for this breakpoint and return true
  589. //
  590. if (penalty >= info.penalty) {return false}
  591. info.penalty = penalty; info.values = values; info.W = W; info.w = w;
  592. values.lineleading = state.VALUES.lineleading;
  593. values.linebreakstyle = "before"; values.id = this.spanID;
  594. return true;
  595. }
  596. });
  597. //
  598. // Hook into the mathchoice extension
  599. //
  600. MathJax.Hub.Register.StartupHook("TeX mathchoice Ready",function () {
  601. MML.TeXmathchoice.Augment({
  602. HTMLbetterBreak: function (info,state) {
  603. return this.Core().HTMLbetterBreak(info,state);
  604. },
  605. HTMLmoveLine: function (start,end,span,state,values) {
  606. return this.Core().HTMLmoveSlice(start,end,span,state,values);
  607. }
  608. });
  609. });
  610. //
  611. // Have maction process only the selected item
  612. //
  613. MML.maction.Augment({
  614. HTMLbetterBreak: function (info,state) {
  615. return this.Core().HTMLbetterBreak(info,state);
  616. },
  617. HTMLmoveLine: function (start,end,span,state,values) {
  618. return this.Core().HTMLmoveSlice(start,end,span,state,values);
  619. },
  620. //
  621. // Split and move the hit boxes as well
  622. //
  623. HTMLmoveSlice: function (start,end,span,state,values,padding) {
  624. var hitbox = document.getElementById("MathJax-HitBox-"+this.spanID+HTMLCSS.idPostfix);
  625. if (hitbox) {hitbox.parentNode.removeChild(hitbox)}
  626. var slice = this.SUPER(arguments).HTMLmoveSlice.apply(this,arguments);
  627. if (end.length === 0) {
  628. span = this.HTMLspanElement(); var n = 0;
  629. while (span) {
  630. hitbox = this.HTMLhandleHitBox(span,"-Continue-"+n);
  631. span = span.nextMathJaxSpan; n++;
  632. }
  633. }
  634. return slice;
  635. }
  636. });
  637. //
  638. // Have semantics only do the first element
  639. // (FIXME: do we need to do anything special about annotation-xml?)
  640. //
  641. MML.semantics.Augment({
  642. HTMLbetterBreak: function (info,state) {
  643. return (this.data[0] ? this.data[0].HTMLbetterBreak(info,state) : false);
  644. },
  645. HTMLmoveLine: function (start,end,span,state,values) {
  646. return (this.data[0] ? this.data[0].HTMLmoveSlice(start,end,span,state,values) : null);
  647. }
  648. });
  649. /**************************************************************************/
  650. MathJax.Hub.Startup.signal.Post("HTML-CSS multiline Ready");
  651. MathJax.Ajax.loadComplete(HTMLCSS.autoloadDir+"/multiline.js");
  652. });