PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/talk2/mathjax/unpacked/jax/output/SVG/autoload/multiline.js

https://github.com/williamstein/mazur-explicit-formula
JavaScript | 622 lines | 369 code | 41 blank | 212 comment | 151 complexity | 20c82a51f16041e11c7ba5ca0c1ffd91 MD5 | raw file
Possible License(s): Apache-2.0, GPL-2.0, MIT
  1. /*************************************************************
  2. *
  3. * MathJax/jax/output/SVG/autoload/multiline.js
  4. *
  5. * Implements the SVG output for <mrow>'s that contain line breaks.
  6. *
  7. * ---------------------------------------------------------------------
  8. *
  9. * Copyright (c) 2011-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("SVG Jax Ready",function () {
  24. var VERSION = "2.1";
  25. var MML = MathJax.ElementJax.mml,
  26. SVG = MathJax.OutputJax.SVG,
  27. BBOX = SVG.BBOX;
  28. //
  29. // Penalties for the various line breaks
  30. //
  31. var PENALTY = {
  32. newline: 0,
  33. nobreak: 1000000,
  34. goodbreak: [-200],
  35. badbreak: [+200],
  36. auto: [0],
  37. toobig: 800,
  38. nestfactor: 400,
  39. spacefactor: -100,
  40. spaceoffset: 2,
  41. spacelimit: 1, // spaces larger than this get a penalty boost
  42. fence: 500,
  43. close: 500
  44. };
  45. var ENDVALUES = {linebreakstyle: "after"};
  46. /**************************************************************************/
  47. MML.mrow.Augment({
  48. //
  49. // Handle breaking an mrow into separate lines
  50. //
  51. SVGmultiline: function (svg) {
  52. //
  53. // Find the parent element and mark it as multiline
  54. //
  55. var parent = this;
  56. while (parent.inferred || (parent.parent && parent.parent.type === "mrow" &&
  57. parent.parent.data.length === 1)) {parent = parent.parent}
  58. var isTop = ((parent.type === "math" && parent.Get("display") === "block") ||
  59. parent.type === "mtd");
  60. parent.isMultiline = true;
  61. //
  62. // Default values for the line-breaking parameters
  63. //
  64. var VALUES = this.getValues(
  65. "linebreak","linebreakstyle","lineleading","linebreakmultchar",
  66. "indentalign","indentshift",
  67. "indentalignfirst","indentshiftfirst",
  68. "indentalignlast","indentshiftlast"
  69. );
  70. if (VALUES.linebreakstyle === MML.LINEBREAKSTYLE.INFIXLINEBREAKSTYLE)
  71. {VALUES.linebreakstyle = this.Get("infixlinebreakstyle")}
  72. VALUES.lineleading = SVG.length2em(VALUES.lineleading,1,0.5);
  73. //
  74. // Start with a fresh SVG element
  75. // and make it full width if we are breaking to a specific width
  76. //
  77. svg = this.SVG();
  78. if (SVG.linebreakWidth < SVG.BIGDIMEN) {svg.w = SVG.linebreakWidth}
  79. else {svg.w = SVG.cwidth/SVG.em * 1000}
  80. var state = {
  81. n: 0, Y: 0,
  82. scale: this.SVGgetScale(),
  83. isTop: isTop,
  84. values: {},
  85. VALUES: VALUES
  86. },
  87. align = this.SVGgetAlign(state,{}),
  88. shift = this.SVGgetShift(state,{},align),
  89. start = [],
  90. end = {
  91. index:[], penalty:PENALTY.nobreak,
  92. w:0, W:shift, shift:shift, scanW:shift,
  93. nest: 0
  94. },
  95. broken = false;
  96. //
  97. // Break the expression at its best line breaks
  98. //
  99. while (this.SVGbetterBreak(end,state) &&
  100. (end.scanW >= SVG.linebreakWidth || end.penalty == PENALTY.newline)) {
  101. this.SVGaddLine(svg,start,end.index,state,end.values,broken);
  102. start = end.index.slice(0); broken = true;
  103. align = this.SVGgetAlign(state,end.values);
  104. shift = this.SVGgetShift(state,end.values,align);
  105. if (align === MML.INDENTALIGN.CENTER) {shift = 0}
  106. end.W = end.shift = end.scanW = shift; end.penalty = PENALTY.nobreak;
  107. }
  108. state.isLast = true;
  109. this.SVGaddLine(svg,start,[],state,ENDVALUES,broken);
  110. this.SVGhandleSpace(svg);
  111. this.SVGhandleColor(svg);
  112. svg.isMultiline = true;
  113. this.SVGsaveData(svg);
  114. return svg;
  115. }
  116. });
  117. /**************************************************************************/
  118. MML.mbase.Augment({
  119. SVGlinebreakPenalty: PENALTY,
  120. /****************************************************************/
  121. //
  122. // Locate the next linebreak that is better than the current one
  123. //
  124. SVGbetterBreak: function (info,state) {
  125. if (this.isToken) {return false} // FIXME: handle breaking of token elements
  126. if (this.isEmbellished()) {
  127. info.embellished = this;
  128. return this.CoreMO().SVGbetterBreak(info,state);
  129. }
  130. if (this.linebreakContainer) {return false}
  131. //
  132. // Get the current breakpoint position and other data
  133. //
  134. var index = info.index.slice(0), i = info.index.shift(),
  135. m = this.data.length, W, w, scanW, broken = (info.index.length > 0), better = false;
  136. if (i == null) {i = -1}; if (!broken) {i++; info.W += info.w; info.w = 0}
  137. scanW = info.scanW = info.W; info.nest++;
  138. //
  139. // Look through the line for breakpoints,
  140. // (as long as we are not too far past the breaking width)
  141. //
  142. while (i < m && info.scanW < 1.33*SVG.linebreakWidth) {
  143. if (this.data[i]) {
  144. if (this.data[i].SVGbetterBreak(info,state)) {
  145. better = true; index = [i].concat(info.index); W = info.W; w = info.w;
  146. if (info.penalty === PENALTY.newline) {info.index = index; info.nest--; return true}
  147. }
  148. scanW = (broken ? info.scanW : this.SVGaddWidth(i,info,scanW));
  149. }
  150. info.index = []; i++; broken = false;
  151. }
  152. info.nest--; info.index = index;
  153. if (better) {info.W = W}
  154. return better;
  155. },
  156. SVGaddWidth: function (i,info,scanW) {
  157. if (this.data[i]) {
  158. var svg = this.data[i].SVGdata;
  159. scanW += svg.w + svg.x; if (svg.X) {scanW += svg.X}
  160. info.W = info.scanW = scanW; info.w = 0;
  161. }
  162. return scanW;
  163. },
  164. /****************************************************************/
  165. //
  166. // Create a new line and move the required elements into it
  167. // Position it using proper alignment and indenting
  168. //
  169. SVGaddLine: function (svg,start,end,state,values,broken) {
  170. //
  171. // Create a box for the line, with empty BBox
  172. // fill it with the proper elements,
  173. // and clean up the bbox
  174. //
  175. var line = BBOX();
  176. state.first = broken; state.last = true;
  177. this.SVGmoveLine(start,end,line,state,values);
  178. line.Clean();
  179. //
  180. // Get the alignment and shift values
  181. //
  182. var align = this.SVGgetAlign(state,values),
  183. shift = this.SVGgetShift(state,values,align);
  184. //
  185. // Add in space for the shift
  186. //
  187. if (shift) {
  188. if (align === MML.INDENTALIGN.LEFT) {line.x = shift} else
  189. if (align === MML.INDENTALIGN.RIGHT) {line.w += shift; line.r = line.w}
  190. }
  191. //
  192. // Set the Y offset based on previous depth, leading, and current height
  193. //
  194. if (state.n > 0) {
  195. var LHD = SVG.FONTDATA.baselineskip * state.scale;
  196. var leading = (state.values.lineleading == null ? state.VALUES : state.values).lineleading;
  197. state.Y -= Math.max(LHD,state.d + line.h + leading);
  198. }
  199. //
  200. // Place the new line
  201. //
  202. svg.Align(line,align,0,state.Y);
  203. //
  204. // Save the values needed for the future
  205. //
  206. state.d = line.d; state.values = values; state.n++;
  207. },
  208. /****************************************************************/
  209. //
  210. // Get alignment and shift values from the given data
  211. //
  212. SVGgetAlign: function (state,values) {
  213. var cur = values, prev = state.values, def = state.VALUES, align;
  214. if (state.n === 0) {align = cur.indentalignfirst || prev.indentalignfirst || def.indentalignfirst}
  215. else if (state.isLast) {align = prev.indentalignlast || def.indentalignlast}
  216. else {align = prev.indentalign || def.indentalign}
  217. if (align === MML.INDENTALIGN.INDENTALIGN) {align = prev.indentalign || def.indentalign}
  218. if (align === MML.INDENTALIGN.AUTO) {align = (state.isTop ? this.displayAlign : MML.INDENTALIGN.LEFT)}
  219. return align;
  220. },
  221. SVGgetShift: function (state,values,align) {
  222. if (align === MML.INDENTALIGN.CENTER) {return 0}
  223. var cur = values, prev = state.values, def = state.VALUES, shift;
  224. if (state.n === 0) {shift = cur.indentshiftfirst || prev.indentshiftfirst || def.indentshiftfirst}
  225. else if (state.isLast) {shift = prev.indentshiftlast || def.indentshiftlast}
  226. else {shift = prev.indentshift || def.indentshift}
  227. if (shift === MML.INDENTSHIFT.INDENTSHIFT) {shift = prev.indentshift || def.indentshift}
  228. if (shift === "auto" || shift === "") {shift = (state.isTSop ? this.displayIndent : "0")}
  229. return SVG.length2em(shift,0);
  230. },
  231. /****************************************************************/
  232. //
  233. // Move the selected elements into the new line,
  234. // moving whole items when possible, and parts of ones
  235. // that are split by a line break.
  236. //
  237. SVGmoveLine: function (start,end,svg,state,values) {
  238. var i = start[0], j = end[0];
  239. if (i == null) {i = -1}; if (j == null) {j = this.data.length-1}
  240. if (i === j && start.length > 1) {
  241. //
  242. // If starting and ending in the same element move the subpiece to the new line
  243. //
  244. this.data[i].SVGmoveSlice(start.slice(1),end.slice(1),svg,state,values,"paddingLeft");
  245. } else {
  246. //
  247. // Otherwise, move the remainder of the initial item
  248. // and any others up to the last one
  249. //
  250. var last = state.last; state.last = false;
  251. while (i < j) {
  252. if (this.data[i]) {
  253. if (start.length <= 1) {this.data[i].SVGmove(svg,state,values)}
  254. else {this.data[i].SVGmoveSlice(start.slice(1),[],svg,state,values,"paddingLeft")}
  255. }
  256. i++; state.first = false; start = [];
  257. }
  258. //
  259. // If the last item is complete, move it,
  260. // otherwise move the first part of it up to the split
  261. //
  262. state.last = last;
  263. if (this.data[i]) {
  264. if (end.length <= 1) {this.data[i].SVGmove(svg,state,values)}
  265. else {this.data[i].SVGmoveSlice([],end.slice(1),svg,state,values,"paddingRight")}
  266. }
  267. }
  268. },
  269. /****************************************************************/
  270. //
  271. // Split an element and copy the selected items into the new part
  272. //
  273. SVGmoveSlice: function (start,end,svg,state,values,padding) {
  274. //
  275. // Create a new container for the slice of the element
  276. // Move the selected portion into the slice
  277. //
  278. var slice = BBOX();
  279. this.SVGmoveLine(start,end,slice,state,values);
  280. slice.Clean();
  281. this.SVGhandleColor(slice);
  282. svg.Add(slice,svg.w,0,true);
  283. return slice;
  284. },
  285. /****************************************************************/
  286. //
  287. // Move an element from its original position to its new location in
  288. // a split element or the new line's position
  289. //
  290. SVGmove: function (line,state,values) {
  291. // FIXME: handle linebreakstyle === "duplicate"
  292. // FIXME: handle linebreakmultchar
  293. if (!(state.first || state.last) ||
  294. (state.first && state.values.linebreakstyle === MML.LINEBREAKSTYLE.BEFORE) ||
  295. (state.last && values.linebreakstyle === MML.LINEBREAKSTYLE.AFTER)) {
  296. //
  297. // Recreate output
  298. // Remove padding (if first, remove at right, if last remove at left)
  299. // Add to line
  300. //
  301. var svg = this.toSVG(this.SVGdata.HW,this.SVGdata.D);
  302. if (state.last) {svg.x = 0}
  303. if (state.first || state.nextIsFirst) {delete state.nextIsFirst; if (svg.X) {svg.X = 0}}
  304. line.Add(svg,line.w,0,true);
  305. } else if (state.first) {state.nextIsFirst = true} else {delete state.nextIsFirst}
  306. }
  307. });
  308. /**************************************************************************/
  309. MML.mfenced.Augment({
  310. SVGbetterBreak: function (info,state) {
  311. //
  312. // Get the current breakpoint position and other data
  313. //
  314. var index = info.index.slice(0), i = info.index.shift(),
  315. m = this.data.length, W, w, scanW, broken = (info.index.length > 0), better = false;
  316. if (i == null) {i = -1}; if (!broken) {i++; info.W += info.w; info.w = 0}
  317. scanW = info.scanW = info.W; info.nest++;
  318. //
  319. // Create indices that include the delimiters and separators
  320. //
  321. if (!this.dataI) {
  322. this.dataI = [];
  323. if (this.data.open) {this.dataI.push("open")}
  324. if (m) {this.dataI.push(0)}
  325. for (var j = 1; j < m; j++) {
  326. if (this.data["sep"+j]) {this.dataI.push("sep"+j)}
  327. this.dataI.push(j);
  328. }
  329. if (this.data.close) {this.dataI.push("close")}
  330. }
  331. m = this.dataI.length;
  332. //
  333. // Look through the line for breakpoints, including the open, close, and separators
  334. // (as long as we are not too far past the breaking width)
  335. //
  336. while (i < m && info.scanW < 1.33*SVG.linebreakWidth) {
  337. var k = this.dataI[i];
  338. if (this.data[k]) {
  339. if (this.data[k].SVGbetterBreak(info,state)) {
  340. better = true; index = [i].concat(info.index); W = info.W; w = info.w;
  341. if (info.penalty === PENALTY.newline) {info.index = index; info.nest--; return true}
  342. }
  343. scanW = (broken ? info.scanW : this.SVGaddWidth(i,info,scanW));
  344. }
  345. info.index = []; i++; broken = false;
  346. }
  347. info.nest--; info.index = index;
  348. if (better) {info.W = W; info.w = w}
  349. return better;
  350. },
  351. SVGmoveLine: function (start,end,svg,state,values) {
  352. var i = start[0], j = end[0];
  353. if (i == null) {i = -1}; if (j == null) {j = this.dataI.length-1}
  354. if (i === j && start.length > 1) {
  355. //
  356. // If starting and ending in the same element move the subpiece to the new line
  357. //
  358. this.data[this.dataI[i]].SVGmoveSlice(start.slice(1),end.slice(1),svg,state,values,"paddingLeft");
  359. } else {
  360. //
  361. // Otherwise, move the remainder of the initial item
  362. // and any others (including open and separators) up to the last one
  363. //
  364. var last = state.last; state.last = false; var k = this.dataI[i];
  365. while (i < j) {
  366. if (this.data[k]) {
  367. if (start.length <= 1) {this.data[k].SVGmove(svg,state,values)}
  368. else {this.data[k].SVGmoveSlice(start.slice(1),[],svg,state,values,"paddingLeft")}
  369. }
  370. i++; k = this.dataI[i]; state.first = false; start = [];
  371. }
  372. //
  373. // If the last item is complete, move it
  374. //
  375. state.last = last;
  376. if (this.data[k]) {
  377. if (end.length <= 1) {this.data[k].SVGmove(svg,state,values)}
  378. else {this.data[k].SVGmoveSlice([],end.slice(1),svg,state,values,"paddingRight")}
  379. }
  380. }
  381. }
  382. });
  383. /**************************************************************************/
  384. MML.msubsup.Augment({
  385. SVGbetterBreak: function (info,state) {
  386. if (!this.data[this.base]) {return false}
  387. //
  388. // Get the current breakpoint position and other data
  389. //
  390. var index = info.index.slice(0), i = info.index.shift(),
  391. W, w, scanW, broken = (info.index.length > 0), better = false;
  392. if (!broken) {info.W += info.w; info.w = 0}
  393. scanW = info.scanW = info.W;
  394. //
  395. // Record the width of the base and the super- and subscripts
  396. //
  397. if (i == null) {this.SVGdata.dw = this.SVGdata.w - this.data[this.base].SVGdata.w}
  398. //
  399. // Check if the base can be broken
  400. //
  401. if (this.data[this.base].SVGbetterBreak(info,state)) {
  402. better = true; index = [this.base].concat(info.index); W = info.W; w = info.w;
  403. if (info.penalty === PENALTY.newline) {better = broken = true}
  404. }
  405. //
  406. // Add in the base if it is unbroken, and add the scripts
  407. //
  408. if (!broken) {this.SVGaddWidth(this.base,info,scanW)}
  409. info.scanW += this.SVGdata.dw; info.W = info.scanW;
  410. info.index = []; if (better) {info.W = W; info.w = w; info.index = index}
  411. return better;
  412. },
  413. SVGmoveLine: function (start,end,svg,state,values) {
  414. //
  415. // Move the proper part of the base
  416. //
  417. if (this.data[this.base]) {
  418. if (start.length > 1) {
  419. this.data[this.base].SVGmoveSlice(start.slice(1),end.slice(1),svg,state,values,"paddingLeft");
  420. } else {
  421. if (end.length <= 1) {this.data[this.base].SVGmove(svg,state,values)}
  422. else {this.data[this.base].SVGmoveSlice([],end.slice(1),svg,state,values,"paddingRight")}
  423. }
  424. }
  425. //
  426. // If this is the end, check for super and subscripts, and move those
  427. // by moving the stack tht contains them, and shifting by the amount of the
  428. // base that has been removed. Remove the empty base box from the stack.
  429. //
  430. if (end.length === 0) {
  431. var sup = this.data[this.sup], sub = this.data[this.sub], w = svg.w, data;
  432. if (sup) {data = sup.SVGdata; svg.Add(sup.toSVG(),w+(data.dx||0),data.dy)}
  433. if (sub) {data = sub.SVGdata; svg.Add(sub.toSVG(),w+(data.dx||0),data.dy)}
  434. }
  435. }
  436. });
  437. /**************************************************************************/
  438. MML.mo.Augment({
  439. //
  440. // Override the method for checking line breaks to properly handle <mo>
  441. //
  442. SVGbetterBreak: function (info,state) {
  443. if (info.values && info.values.last === this) {return false}
  444. var values = this.getValues(
  445. "linebreak","linebreakstyle","lineleading","linebreakmultchar",
  446. "indentalign","indentshift",
  447. "indentalignfirst","indentshiftfirst",
  448. "indentalignlast","indentshiftlast",
  449. "texClass", "fence"
  450. );
  451. if (values.linebreakstyle === MML.LINEBREAKSTYLE.INFIXLINEBREAKSTYLE)
  452. {values.linebreakstyle = this.Get("infixlinebreakstyle")}
  453. //
  454. // Adjust nesting by TeX class (helps output that does not include
  455. // mrows for nesting, but can leave these unbalanced.
  456. //
  457. if (values.texClass === MML.TEXCLASS.OPEN) {info.nest++}
  458. if (values.texClass === MML.TEXCLASS.CLOSE) {info.nest--}
  459. //
  460. // Get the default penalty for this location
  461. //
  462. var W = info.scanW, mo = (info.embellished||this); delete info.embellished;
  463. var svg = mo.SVGdata, w = svg.w + svg.x;
  464. if (values.linebreakstyle === MML.LINEBREAKSTYLE.AFTER) {W += w; w = 0}
  465. if (W - info.shift === 0) {return false} // don't break at zero width (FIXME?)
  466. var offset = SVG.linebreakWidth - W;
  467. // adjust offest for explicit first-line indent and align
  468. if (state.n === 0 && (values.indentshiftfirst !== state.VALUES.indentshiftfirst ||
  469. values.indentalignfirst !== state.VALUES.indentalignfirst)) {
  470. var align = this.SVGgetAlign(state,values),
  471. shift = this.SVGgetShift(state,values,align);
  472. offset += (info.shift - shift);
  473. }
  474. //
  475. var penalty = Math.floor(offset / SVG.linebreakWidth * 1000);
  476. if (penalty < 0) {penalty = PENALTY.toobig - 3*penalty}
  477. if (values.fence) {penalty += PENALTY.fence}
  478. if ((values.linebreakstyle === MML.LINEBREAKSTYLE.AFTER &&
  479. values.texClass === MML.TEXCLASS.OPEN) ||
  480. values.texClass === MML.TEXCLASS.CLOSE) {penalty += PENALTY.close}
  481. penalty += info.nest * PENALTY.nestfactor;
  482. //
  483. // Get the penalty for this type of break and
  484. // use it to modify the default penalty
  485. //
  486. var linebreak = PENALTY[values.linebreak||MML.LINEBREAK.AUTO];
  487. if (!(linebreak instanceof Array)) {
  488. // for breaks past the width, don't modify penalty
  489. if (offset >= 0) {penalty = linebreak * info.nest}
  490. } else {penalty = Math.max(1,penalty + linebreak[0] * info.nest)}
  491. //
  492. // If the penalty is no better than the current one, return false
  493. // Otherwise save the data for this breakpoint and return true
  494. //
  495. if (penalty >= info.penalty) {return false}
  496. info.penalty = penalty; info.values = values; info.W = W; info.w = w;
  497. values.lineleading = SVG.length2em(values.lineleading,state.VALUES.lineleading);
  498. values.last = this;
  499. return true;
  500. }
  501. });
  502. /**************************************************************************/
  503. MML.mspace.Augment({
  504. //
  505. // Override the method for checking line breaks to properly handle <mspace>
  506. //
  507. SVGbetterBreak: function (info,state) {
  508. if (info.values && info.values.last === this) {return false}
  509. var values = this.getValues("linebreak");
  510. //
  511. // Get the default penalty for this location
  512. //
  513. var W = info.scanW, svg = this.SVGdata, w = svg.w + svg.x;
  514. if (W - info.shift === 0) {return false} // don't break at zero width (FIXME?)
  515. var offset = SVG.linebreakWidth - W;
  516. //
  517. var penalty = Math.floor(offset / SVG.linebreakWidth * 1000);
  518. if (penalty < 0) {penalty = PENALTY.toobig - 3*penalty}
  519. penalty += info.nest * PENALTY.nestfactor;
  520. //
  521. // Get the penalty for this type of break and
  522. // use it to modify the default penalty
  523. //
  524. var linebreak = PENALTY[values.linebreak||MML.LINEBREAK.AUTO];
  525. if (values.linebreak === MML.LINEBREAK.AUTO && w >= PENALTY.spacelimit*1000)
  526. {linebreak = [(w+PENALTY.spaceoffset)*PENALTY.spacefactor]}
  527. if (!(linebreak instanceof Array)) {
  528. // for breaks past the width, don't modify penalty
  529. if (offset >= 0) {penalty = linebreak * info.nest}
  530. } else {penalty = Math.max(1,penalty + linebreak[0] * info.nest)}
  531. //
  532. // If the penalty is no better than the current one, return false
  533. // Otherwise save the data for this breakpoint and return true
  534. //
  535. if (penalty >= info.penalty) {return false}
  536. info.penalty = penalty; info.values = values; info.W = W; info.w = w;
  537. values.lineleading = state.VALUES.lineleading;
  538. values.linebreakstyle = "before"; values.last = this;
  539. return true;
  540. }
  541. });
  542. //
  543. // Hook into the mathchoice extension
  544. //
  545. MathJax.Hub.Register.StartupHook("TeX mathchoice Ready",function () {
  546. MML.TeXmathchoice.Augment({
  547. SVGbetterBreak: function (info,state) {
  548. return this.Core().SVGbetterBreak(info,state);
  549. },
  550. SVGmoveLine: function (start,end,svg,state,values) {
  551. return this.Core().SVGmoveSlice(start,end,svg,state,values);
  552. }
  553. });
  554. });
  555. //
  556. // Have maction process only the selected item
  557. //
  558. MML.maction.Augment({
  559. SVGbetterBreak: function (info,state) {
  560. return this.Core().SVGbetterBreak(info,state);
  561. },
  562. SVGmoveLine: function (start,end,svg,state,values) {
  563. return this.Core().SVGmoveSlice(start,end,svg,state,values);
  564. },
  565. });
  566. //
  567. // Have semantics only do the first element
  568. // (FIXME: do we need to do anything special about annotation-xml?)
  569. //
  570. MML.semantics.Augment({
  571. SVGbetterBreak: function (info,state) {
  572. return (this.data[0] ? this.data[0].SVGbetterBreak(info,state) : false);
  573. },
  574. SVGmoveLine: function (start,end,svg,state,values) {
  575. return (this.data[0] ? this.data[0].SVGmoveSlice(start,end,svg,state,values) : null);
  576. }
  577. });
  578. /**************************************************************************/
  579. MathJax.Hub.Startup.signal.Post("SVG multiline Ready");
  580. MathJax.Ajax.loadComplete(SVG.autoloadDir+"/multiline.js");
  581. });