jax.js 79 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025
  1. /* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
  2. /* vim: set ts=2 et sw=2 tw=80: */
  3. /*************************************************************
  4. *
  5. * MathJax/jax/output/SVG/jax.js
  6. *
  7. * Implements the SVG OutputJax that displays mathematics using
  8. * SVG (or VML in IE) to position the characters from math fonts
  9. * in their proper locations.
  10. *
  11. * ---------------------------------------------------------------------
  12. *
  13. * Copyright (c) 2011-2013 The MathJax Consortium
  14. *
  15. * Licensed under the Apache License, Version 2.0 (the "License");
  16. * you may not use this file except in compliance with the License.
  17. * You may obtain a copy of the License at
  18. *
  19. * http://www.apache.org/licenses/LICENSE-2.0
  20. *
  21. * Unless required by applicable law or agreed to in writing, software
  22. * distributed under the License is distributed on an "AS IS" BASIS,
  23. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  24. * See the License for the specific language governing permissions and
  25. * limitations under the License.
  26. */
  27. (function (AJAX,HUB,HTML,SVG) {
  28. var MML;
  29. var SVGNS = "http://www.w3.org/2000/svg";
  30. var XLINKNS = "http://www.w3.org/1999/xlink";
  31. SVG.Augment({
  32. config: {
  33. styles: {
  34. ".MathJax_SVG": {
  35. "display": "inline",
  36. "font-style": "normal",
  37. "font-weight": "normal",
  38. "line-height": "normal",
  39. "font-size": "100%",
  40. "font-size-adjust":"none",
  41. "text-indent": 0,
  42. "text-align": "left",
  43. "text-transform": "none",
  44. "letter-spacing": "normal",
  45. "word-spacing": "normal",
  46. "word-wrap": "normal",
  47. "white-space": "nowrap",
  48. "float": "none",
  49. "direction": "ltr",
  50. border: 0, padding: 0, margin: 0
  51. },
  52. ".MathJax_SVG_Display": {
  53. position: "relative",
  54. display: "block",
  55. width: "100%"
  56. },
  57. ".MathJax_SVG *": {
  58. transition: "none",
  59. "-webkit-transition": "none",
  60. "-moz-transition": "none",
  61. "-ms-transition": "none",
  62. "-o-transition": "none"
  63. },
  64. ".mjx-svg-href": {
  65. fill: "blue", stroke: "blue"
  66. },
  67. ".MathJax_SVG_Processing": {
  68. visibility: "hidden", position:"absolute", top:0, left:0,
  69. width:0, height: 0, overflow:"hidden", display:"block"
  70. },
  71. ".MathJax_SVG_Processed": {display:"none!important"},
  72. ".MathJax_SVG_ExBox": {
  73. display:"block", overflow:"hidden",
  74. width:"1px", height:"60ex"
  75. },
  76. "#MathJax_SVG_Tooltip": {
  77. position: "absolute", left: 0, top: 0,
  78. width: "auto", height: "auto",
  79. display: "none"
  80. }
  81. }
  82. },
  83. hideProcessedMath: true, // use display:none until all math is processed
  84. Config: function () {
  85. var settings = HUB.config.menuSettings;
  86. if (settings.scale) {this.config.scale = settings.scale}
  87. this.SUPER(arguments).Config.apply(this,arguments);
  88. this.fontInUse = this.config.font; this.fontDir += "/" + this.config.font;
  89. if (!this.require) {this.require = []}
  90. this.require.push(this.fontDir+"/fontdata.js");
  91. this.require.push(MathJax.OutputJax.extensionDir+"/MathEvents.js");
  92. },
  93. Startup: function () {
  94. // Set up event handling
  95. EVENT = MathJax.Extension.MathEvents.Event;
  96. TOUCH = MathJax.Extension.MathEvents.Touch;
  97. HOVER = MathJax.Extension.MathEvents.Hover;
  98. this.ContextMenu = EVENT.ContextMenu;
  99. this.Mousedown = EVENT.AltContextMenu;
  100. this.Mouseover = HOVER.Mouseover;
  101. this.Mouseout = HOVER.Mouseout;
  102. this.Mousemove = HOVER.Mousemove;
  103. // Make hidden div for doing tests and storing global SVG <defs>
  104. this.hiddenDiv = HTML.Element("div",{
  105. style:{visibility:"hidden", overflow:"hidden", position:"absolute", top:0,
  106. height:"1px", width: "auto", padding:0, border:0, margin:0,
  107. textAlign:"left", textIndent:0, textTransform:"none",
  108. lineHeight:"normal", letterSpacing:"normal", wordSpacing:"normal"}
  109. });
  110. if (!document.body.firstChild) {document.body.appendChild(this.hiddenDiv)}
  111. else {document.body.insertBefore(this.hiddenDiv,document.body.firstChild)}
  112. this.hiddenDiv = HTML.addElement(this.hiddenDiv,"div",{id:"MathJax_SVG_Hidden"});
  113. // Determine pixels-per-inch and em-size
  114. var div = HTML.addElement(this.hiddenDiv,"div",{style:{width:"5in"}});
  115. this.pxPerInch = div.offsetWidth/5; this.hiddenDiv.removeChild(div);
  116. // Used for measuring text sizes
  117. this.textSVG = this.Element("svg");
  118. // Global defs for font glyphs
  119. DEFS = this.addElement(this.addElement(this.hiddenDiv.parentNode,"svg"),"defs",{id:"MathJax_SVG_glyphs"});
  120. GLYPHS = {};
  121. // Used in preTranslate to get scaling factors
  122. this.ExSpan = HTML.Element("span",
  123. {style:{position:"absolute","font-size-adjust":"none"}},
  124. [["span",{className:"MathJax_SVG_ExBox"}]]
  125. );
  126. // Used in preTranslate to get linebreak width
  127. this.linebreakSpan = HTML.Element("span",null,
  128. [["hr",{style: {width:"auto", size:1, padding:0, border:0, margin:0}}]]);
  129. // Set up styles
  130. return AJAX.Styles(this.config.styles,["InitializeSVG",this]);
  131. },
  132. //
  133. // Handle initialization that requires styles to be set up
  134. //
  135. InitializeSVG: function () {
  136. //
  137. // Get the default sizes (need styles in place to do this)
  138. //
  139. document.body.appendChild(this.ExSpan);
  140. document.body.appendChild(this.linebreakSpan);
  141. this.defaultEx = this.ExSpan.firstChild.offsetHeight/60;
  142. this.defaultWidth = this.linebreakSpan.firstChild.offsetWidth;
  143. document.body.removeChild(this.linebreakSpan);
  144. document.body.removeChild(this.ExSpan);
  145. },
  146. preTranslate: function (state) {
  147. var scripts = state.jax[this.id], i, m = scripts.length,
  148. script, prev, span, div, test, jax, ex, em, maxwidth, relwidth = false, cwidth,
  149. linebreak = this.config.linebreaks.automatic, width = this.config.linebreaks.width;
  150. if (linebreak) {
  151. relwidth = (width.match(/^\s*(\d+(\.\d*)?%\s*)?container\s*$/) != null);
  152. if (relwidth) {width = width.replace(/\s*container\s*/,"")}
  153. else {maxwidth = this.defaultWidth}
  154. if (width === "") {width = "100%"}
  155. } else {maxwidth = 100000} // a big width, so no implicit line breaks
  156. //
  157. // Loop through the scripts
  158. //
  159. for (i = 0; i < m; i++) {
  160. script = scripts[i]; if (!script.parentNode) continue;
  161. //
  162. // Remove any existing output
  163. //
  164. prev = script.previousSibling;
  165. if (prev && String(prev.className).match(/^MathJax(_SVG)?(_Display)?( MathJax(_SVG)?_Processing)?$/))
  166. {prev.parentNode.removeChild(prev)}
  167. //
  168. // Add the span, and a div if in display mode,
  169. // then set the role and mark it as being processed
  170. //
  171. jax = script.MathJax.elementJax; if (!jax) continue;
  172. jax.SVG = {display: (jax.root.Get("display") === "block")}
  173. span = div = HTML.Element("span",{
  174. style: {"font-size": this.config.scale+"%", display:"inline-block"},
  175. className:"MathJax_SVG", id:jax.inputID+"-Frame", isMathJax:true, jaxID:this.id,
  176. oncontextmenu:EVENT.Menu, onmousedown: EVENT.Mousedown,
  177. onmouseover:EVENT.Mouseover, onmouseout:EVENT.Mouseout, onmousemove:EVENT.Mousemove,
  178. onclick:EVENT.Click, ondblclick:EVENT.DblClick
  179. });
  180. if (HUB.Browser.noContextMenu) {
  181. span.ontouchstart = TOUCH.start;
  182. span.ontouchend = TOUCH.end;
  183. }
  184. if (jax.SVG.display) {
  185. div = HTML.Element("div",{className:"MathJax_SVG_Display"});
  186. div.appendChild(span);
  187. }
  188. //
  189. // Mark math for screen readers
  190. // (screen readers don't know about role="math" yet, so use "textbox" instead)
  191. //
  192. div.setAttribute("role","textbox"); div.setAttribute("aria-readonly","true");
  193. div.className += " MathJax_SVG_Processing";
  194. script.parentNode.insertBefore(div,script);
  195. //
  196. // Add the test span for determining scales and linebreak widths
  197. //
  198. script.parentNode.insertBefore(this.ExSpan.cloneNode(true),script);
  199. div.parentNode.insertBefore(this.linebreakSpan.cloneNode(true),div);
  200. }
  201. //
  202. // Determine the scaling factors for each script
  203. // (this only requires one reflow rather than a reflow for each equation)
  204. //
  205. for (i = 0; i < m; i++) {
  206. script = scripts[i]; if (!script.parentNode) continue;
  207. test = script.previousSibling; div = test.previousSibling;
  208. jax = script.MathJax.elementJax; if (!jax) continue;
  209. ex = test.firstChild.offsetHeight/60;
  210. cwidth = div.previousSibling.firstChild.offsetWidth;
  211. if (relwidth) {maxwidth = cwidth}
  212. if (ex === 0 || ex === "NaN") {
  213. // can't read width, so move to hidden div for processing
  214. // (this will cause a reflow for each math element that is hidden)
  215. this.hiddenDiv.appendChild(div);
  216. jax.SVG.isHidden = true;
  217. ex = this.defaultEx; cwidth = this.defaultWidth;
  218. if (relwidth) {maxwidth = this.defaultWidth}
  219. }
  220. jax.SVG.ex = ex; jax.SVG.cwidth = cwidth;
  221. jax.SVG.em = em = ex / SVG.TeX.x_height * 1000; // scale ex to x_height
  222. jax.SVG.lineWidth = (linebreak ? this.length2em(width,1,maxwidth/em) : 1000000);
  223. }
  224. //
  225. // Remove the test spans used for determining scales and linebreak widths
  226. //
  227. for (i = 0; i < m; i++) {
  228. script = scripts[i]; if (!script.parentNode) continue;
  229. test = scripts[i].previousSibling; span = test.previousSibling;
  230. jax = scripts[i].MathJax.elementJax; if (!jax) continue;
  231. if (!jax.SVG.isHidden) {span = span.previousSibling}
  232. span.parentNode.removeChild(span);
  233. test.parentNode.removeChild(test);
  234. }
  235. //
  236. // Set state variables used for displaying equations in chunks
  237. //
  238. state.SVGeqn = state.SVGlast = 0; state.SVGi = -1;
  239. state.SVGchunk = this.config.EqnChunk;
  240. state.SVGdelay = false;
  241. },
  242. Translate: function (script,state) {
  243. if (!script.parentNode) return;
  244. //
  245. // If we are supposed to do a chunk delay, do it
  246. //
  247. if (state.SVGdelay) {
  248. state.SVGdelay = false;
  249. HUB.RestartAfter(MathJax.Callback.Delay(this.config.EqnChunkDelay));
  250. }
  251. //
  252. // Get the data about the math
  253. //
  254. var jax = script.MathJax.elementJax, math = jax.root,
  255. span = document.getElementById(jax.inputID+"-Frame"),
  256. div = (jax.SVG.display ? span.parentNode : span);
  257. //
  258. // Set the font metrics
  259. //
  260. this.em = MML.mbase.prototype.em = jax.SVG.em; this.ex = jax.SVG.ex;
  261. this.linebreakWidth = jax.SVG.lineWidth * 1000; this.cwidth = jax.SVG.cwidth;
  262. //
  263. // Typeset the math
  264. //
  265. this.mathDiv = div;
  266. span.appendChild(this.textSVG);
  267. this.initSVG(math,span);
  268. math.setTeXclass();
  269. try {math.toSVG(span,div)} catch (err) {
  270. if (err.restart) {while (span.firstChild) {span.removeChild(span.firstChild)}}
  271. throw err;
  272. }
  273. span.removeChild(this.textSVG);
  274. //
  275. // Put it in place, and remove the processing marker
  276. //
  277. if (jax.SVG.isHidden) {script.parentNode.insertBefore(div,script)}
  278. div.className = div.className.split(/ /)[0];
  279. //
  280. // Check if we are hiding the math until more is processed
  281. //
  282. if (this.hideProcessedMath) {
  283. //
  284. // Hide the math and don't let its preview be removed
  285. //
  286. div.className += " MathJax_SVG_Processed";
  287. if (script.MathJax.preview) {
  288. jax.SVG.preview = script.MathJax.preview;
  289. delete script.MathJax.preview;
  290. }
  291. //
  292. // Check if we should show this chunk of equations
  293. //
  294. state.SVGeqn += (state.i - state.SVGi); state.SVGi = state.i;
  295. if (state.SVGeqn >= state.SVGlast + state.SVGchunk) {
  296. this.postTranslate(state);
  297. state.SVGchunk = Math.floor(state.SVGchunk*this.config.EqnChunkFactor);
  298. state.SVGdelay = true; // delay if there are more scripts
  299. }
  300. }
  301. },
  302. postTranslate: function (state) {
  303. var scripts = state.jax[this.id];
  304. if (!this.hideProcessedMath) return;
  305. //
  306. // Reveal this chunk of math
  307. //
  308. for (var i = state.SVGlast, m = state.SVGeqn; i < m; i++) {
  309. var script = scripts[i];
  310. if (script && script.MathJax.elementJax) {
  311. //
  312. // Remove the processed marker
  313. //
  314. script.previousSibling.className = script.previousSibling.className.split(/ /)[0];
  315. var data = script.MathJax.elementJax.SVG;
  316. //
  317. // Remove the preview, if any
  318. //
  319. if (data.preview) {
  320. data.preview.innerHTML = "";
  321. script.MathJax.preview = data.preview;
  322. delete data.preview;
  323. }
  324. }
  325. }
  326. //
  327. // Save our place so we know what is revealed
  328. //
  329. state.SVGlast = state.SVGeqn;
  330. },
  331. //
  332. // Return the containing HTML element rather than the SVG element, since
  333. // most browsers can't position to an SVG element properly.
  334. //
  335. hashCheck: function (target) {
  336. if (target && target.nodeName === "g")
  337. {do {target = target.parentNode} while (target && target.firstChild.nodeName !== "svg")}
  338. return target;
  339. },
  340. getJaxFromMath: function (math) {
  341. if (math.parentNode.className === "MathJax_SVG_Display") {math = math.parentNode}
  342. do {math = math.nextSibling} while (math && math.nodeName.toLowerCase() !== "script");
  343. return HUB.getJaxFor(math);
  344. },
  345. getHoverSpan: function (jax,math) {
  346. math.style.position = "relative"; // make sure inline containers have position set
  347. return math.firstChild;
  348. },
  349. getHoverBBox: function (jax,span,math) {
  350. var bbox = EVENT.getBBox(span.parentNode);
  351. bbox.h += 2; bbox.d -= 2; // bbox seems to be a bit off, so compensate (FIXME)
  352. return bbox;
  353. },
  354. Zoom: function (jax,span,math,Mw,Mh) {
  355. //
  356. // Re-render at larger size
  357. //
  358. span.className = "MathJax_SVG";
  359. //
  360. // get em size (taken from this.preTranslate)
  361. //
  362. var emex = span.appendChild(this.ExSpan.cloneNode(true));
  363. var ex = emex.firstChild.offsetHeight/60;
  364. this.em = MML.mbase.prototype.em = ex / SVG.TeX.x_height * 1000;
  365. this.cwidth = .85*SVG.defaultWidth;
  366. emex.parentNode.removeChild(emex);
  367. span.appendChild(this.textSVG);
  368. this.mathDIV = span;
  369. this.idPostfix = "-zoom"; jax.root.toSVG(span,span); this.idPostfix = "";
  370. span.removeChild(this.textSVG);
  371. if (this.operaZoomRefresh)
  372. {setTimeout(function () {span.firstChild.style.border="1px solid transparent"},1)}
  373. //
  374. // Get height and width of zoomed math and original math
  375. //
  376. span.style.position = math.style.position = "absolute";
  377. var zW = span.offsetWidth, zH = span.offsetHeight,
  378. mH = math.offsetHeight, mW = math.offsetWidth;
  379. span.style.position = math.style.position = "";
  380. //
  381. return {Y:-EVENT.getBBox(span).h, mW:mW, mH:mH, zW:zW, zH:zH};
  382. },
  383. initSVG: function (math,span) {},
  384. Remove: function (jax) {
  385. var span = document.getElementById(jax.inputID+"-Frame");
  386. if (span) {
  387. if (jax.SVG.display) {span = span.parentNode}
  388. span.parentNode.removeChild(span);
  389. }
  390. delete jax.SVG;
  391. },
  392. Em: function (m) {
  393. if (Math.abs(m) < .0006) {return "0em"}
  394. return m.toFixed(3).replace(/\.?0+$/,"") + "em";
  395. },
  396. Ex: function (m) {
  397. m = Math.round(m / this.TeX.x_height * this.ex) / this.ex; // try to use closest pixel size
  398. if (Math.abs(m) < .0006) {return "0ex"}
  399. return m.toFixed(3).replace(/\.?0+$/,"") + "ex";
  400. },
  401. Percent: function (m) {
  402. return (100*m).toFixed(1).replace(/\.?0+$/,"") + "%";
  403. },
  404. length2em: function (length,mu,size) {
  405. if (typeof(length) !== "string") {length = length.toString()}
  406. if (length === "") {return ""}
  407. if (length === MML.SIZE.NORMAL) {return 1000}
  408. if (length === MML.SIZE.BIG) {return 2000}
  409. if (length === MML.SIZE.SMALL) {return 710}
  410. if (length === "infinity") {return SVG.BIGDIMEN}
  411. if (length.match(/mathspace$/)) {return 1000*SVG.MATHSPACE[length]}
  412. var match = length.match(/^\s*([-+]?(?:\.\d+|\d+(?:\.\d*)?))?(pt|em|ex|mu|px|pc|in|mm|cm|%)?/);
  413. var m = parseFloat(match[1]||"1") * 1000, unit = match[2];
  414. if (size == null) {size = 1000}; if (mu == null) {mu = 1}
  415. if (unit === "em") {return m}
  416. if (unit === "ex") {return m * SVG.TeX.x_height/1000}
  417. if (unit === "%") {return m / 100 * size / 1000}
  418. if (unit === "px") {return m / SVG.em}
  419. if (unit === "pt") {return m / 10} // 10 pt to an em
  420. if (unit === "pc") {return m * 1.2} // 12 pt to a pc
  421. if (unit === "in") {return m * this.pxPerInch / SVG.em}
  422. if (unit === "cm") {return m * this.pxPerInch / SVG.em / 2.54} // 2.54 cm to an inch
  423. if (unit === "mm") {return m * this.pxPerInch / SVG.em / 25.4} // 10 mm to a cm
  424. if (unit === "mu") {return m / 18 * mu}
  425. return m*size / 1000; // relative to given size (or 1em as default)
  426. },
  427. thickness2em: function (length,mu) {
  428. var thick = SVG.TeX.rule_thickness;
  429. if (length === MML.LINETHICKNESS.MEDIUM) {return thick}
  430. if (length === MML.LINETHICKNESS.THIN) {return .67*thick}
  431. if (length === MML.LINETHICKNESS.THICK) {return 1.67*thick}
  432. return this.length2em(length,mu,thick);
  433. },
  434. getPadding: function (span) {
  435. var padding = {top:0, right:0, bottom:0, left:0}, has = false;
  436. for (var id in padding) {if (padding.hasOwnProperty(id)) {
  437. var pad = span.style["padding"+id.charAt(0).toUpperCase()+id.substr(1)];
  438. if (pad) {padding[id] = this.length2em(pad); has = true;}
  439. }}
  440. return (has ? padding : false);
  441. },
  442. getBorders: function (span) {
  443. var border = {top:0, right:0, bottom:0, left:0}, has = false;
  444. for (var id in border) {if (border.hasOwnProperty(id)) {
  445. var ID = "border"+id.charAt(0).toUpperCase()+id.substr(1);
  446. var style = span.style[ID+"Style"];
  447. if (style) {
  448. has = true;
  449. border[id] = this.length2em(span.style[ID+"Width"]);
  450. border[id+"Style"] = span.style[ID+"Style"];
  451. border[id+"Color"] = span.style[ID+"Color"];
  452. if (border[id+"Color"] === "initial") {border[id+"Color"] = ""}
  453. }
  454. }}
  455. return (has ? border : false);
  456. },
  457. Element: function (type,def) {
  458. var obj = (typeof(type) === "string" ? document.createElementNS(SVGNS,type) : type);
  459. obj.isMathJax = true;
  460. if (def) {for (var id in def) {if (def.hasOwnProperty(id)) {obj.setAttribute(id,def[id].toString())}}}
  461. return obj;
  462. },
  463. addElement: function (parent,type,def) {return parent.appendChild(this.Element(type,def))},
  464. TextNode: HTML.TextNode,
  465. addText: HTML.addText,
  466. ucMatch: HTML.ucMatch,
  467. HandleVariant: function (variant,scale,text) {
  468. var svg = BBOX.G();
  469. var n, N, c, font, VARIANT, i, m, id, M, RANGES;
  470. if (!variant) {variant = this.FONTDATA.VARIANT[MML.VARIANT.NORMAL]}
  471. if (variant.forceFamily) {
  472. text = BBOX.TEXT(scale,text,variant.font);
  473. if (variant.h != null) {text.h = variant.h}; if (variant.d != null) {text.d = variant.d}
  474. svg.Add(text); text = "";
  475. }
  476. VARIANT = variant;
  477. for (i = 0, m = text.length; i < m; i++) {
  478. variant = VARIANT;
  479. n = text.charCodeAt(i); c = text.charAt(i);
  480. if (n >= 0xD800 && n < 0xDBFF) {
  481. i++; n = (((n-0xD800)<<10)+(text.charCodeAt(i)-0xDC00))+0x10000;
  482. if (this.FONTDATA.RemapPlane1) {
  483. var nv = this.FONTDATA.RemapPlane1(n,variant);
  484. n = nv.n; variant = nv.variant;
  485. }
  486. } else {
  487. RANGES = this.FONTDATA.RANGES;
  488. for (id = 0, M = RANGES.length; id < M; id++) {
  489. if (RANGES[id].name === "alpha" && variant.noLowerCase) continue;
  490. N = variant["offset"+RANGES[id].offset];
  491. if (N && n >= RANGES[id].low && n <= RANGES[id].high) {
  492. if (RANGES[id].remap && RANGES[id].remap[n]) {
  493. n = N + RANGES[id].remap[n];
  494. } else {
  495. n = n - RANGES[id].low + N;
  496. if (RANGES[id].add) {n += RANGES[id].add}
  497. }
  498. if (variant["variant"+RANGES[id].offset])
  499. {variant = this.FONTDATA.VARIANT[variant["variant"+RANGES[id].offset]]}
  500. break;
  501. }
  502. }
  503. }
  504. if (variant.remap && variant.remap[n]) {
  505. if (variant.remap[n] instanceof Array) {
  506. var remap = variant.remap[n];
  507. n = remap[0]; variant = this.FONTDATA.VARIANT[remap[1]];
  508. } else if (typeof(variant.remap[n]) === "string") {
  509. text = variant.remap[n]+text.substr(i+1);
  510. i = 0; m = text.length; n = text.charCodeAt(0);
  511. } else {
  512. n = variant.remap[n];
  513. if (variant.remap.variant) {variant = this.FONTDATA.VARIANT[variant.remap.variant]}
  514. }
  515. }
  516. if (this.FONTDATA.REMAP[n] && !variant.noRemap) {
  517. n = this.FONTDATA.REMAP[n];
  518. if (n instanceof Array) {variant = this.FONTDATA.VARIANT[n[1]]; n = n[0]}
  519. if (typeof(n) === "string") {
  520. text = n+text.substr(i+1);
  521. i = 0; m = text.length;
  522. n = n.charCodeAt(0);
  523. }
  524. }
  525. font = this.lookupChar(variant,n); c = font[n];
  526. if (c) {
  527. if (c[5] && c[5].space) {svg.w += c[2]} else {
  528. c = [scale,font.id+"-"+n.toString(16).toUpperCase()].concat(c);
  529. svg.Add(BBOX.GLYPH.apply(BBOX,c),svg.w,0);
  530. }
  531. } else if (this.FONTDATA.DELIMITERS[n]) {
  532. c = this.createDelimiter(n,0,1,font);
  533. svg.Add(c,svg.w,(this.FONTDATA.DELIMITERS[n].dir === "V" ? c.d: 0));
  534. } else {
  535. if (n <= 0xFFFF) {c = String.fromCharCode(n)} else {
  536. N = n - 0x10000;
  537. c = String.fromCharCode((N>>10)+0xD800)
  538. + String.fromCharCode((N&0x3FF)+0xDC00);
  539. }
  540. var box = BBOX.TEXT(scale,c,{
  541. "font-family":variant.defaultFamily||SVG.config.undefinedFamily,
  542. "font-style":(variant.italic?"italic":""),
  543. "font-weight":(variant.bold?"bold":"")
  544. })
  545. if (variant.h != null) {box.h = variant.h}; if (variant.d != null) {box.d = variant.d}
  546. c = BBOX.G(); c.Add(box); svg.Add(c,svg.w,0);
  547. HUB.signal.Post(["SVG Jax - unknown char",n,variant]);
  548. }
  549. }
  550. if (text.length == 1 && font.skew && font.skew[n]) {svg.skew = font.skew[n]*1000}
  551. if (svg.element.childNodes.length === 1) {
  552. svg.element = svg.element.firstChild;
  553. svg.removeable = false; svg.scale = scale;
  554. }
  555. return svg;
  556. },
  557. lookupChar: function (variant,n) {
  558. var i, m;
  559. if (!variant.FONTS) {
  560. var FONTS = this.FONTDATA.FONTS;
  561. var fonts = (variant.fonts || this.FONTDATA.VARIANT.normal.fonts);
  562. if (!(fonts instanceof Array)) {fonts = [fonts]}
  563. if (variant.fonts != fonts) {variant.fonts = fonts}
  564. variant.FONTS = [];
  565. for (i = 0, m = fonts.length; i < m; i++) {
  566. if (FONTS[fonts[i]]) {variant.FONTS.push(FONTS[fonts[i]])}
  567. }
  568. }
  569. for (i = 0, m = variant.FONTS.length; i < m; i++) {
  570. var font = variant.FONTS[i];
  571. if (typeof(font) === "string") {delete variant.FONTS; this.loadFont(font)}
  572. if (font[n]) {return font} else {this.findBlock(font,n)}
  573. }
  574. return {id:"unknown"};
  575. },
  576. findBlock: function (font,c) {
  577. if (font.Ranges) {
  578. // FIXME: do binary search?
  579. for (var i = 0, m = font.Ranges.length; i < m; i++) {
  580. if (c < font.Ranges[i][0]) return;
  581. if (c <= font.Ranges[i][1]) {
  582. var file = font.Ranges[i][2];
  583. for (var j = font.Ranges.length-1; j >= 0; j--)
  584. {if (font.Ranges[j][2] == file) {font.Ranges.splice(j,1)}}
  585. this.loadFont(font.directory+"/"+file+".js");
  586. }
  587. }
  588. }
  589. },
  590. loadFont: function (file) {
  591. HUB.RestartAfter(AJAX.Require(this.fontDir+"/"+file));
  592. },
  593. createDelimiter: function (code,HW,scale,font) {
  594. if (!scale) {scale = 1};
  595. var svg = BBOX.G();
  596. if (!code) {
  597. svg.Clean(); delete svg.element;
  598. svg.w = svg.r = this.TeX.nulldelimiterspace * scale;
  599. return svg;
  600. }
  601. if (!(HW instanceof Array)) {HW = [HW,HW]}
  602. var hw = HW[1]; HW = HW[0];
  603. var delim = {alias: code};
  604. while (delim.alias) {
  605. code = delim.alias; delim = this.FONTDATA.DELIMITERS[code];
  606. if (!delim) {delim = {HW: [0,this.FONTDATA.VARIANT[MML.VARIANT.NORMAL]]}}
  607. }
  608. if (delim.load) {HUB.RestartAfter(AJAX.Require(this.fontDir+"/fontdata-"+delim.load+".js"))}
  609. for (var i = 0, m = delim.HW.length; i < m; i++) {
  610. if (delim.HW[i][0]*scale >= HW-10-SVG.config.blacker || (i == m-1 && !delim.stretch)) {
  611. if (delim.HW[i][2]) {scale *= delim.HW[i][2]}
  612. if (delim.HW[i][3]) {code = delim.HW[i][3]}
  613. return this.createChar(scale,[code,delim.HW[i][1]],font).With({stretched: true});
  614. }
  615. }
  616. if (delim.stretch) {this["extendDelimiter"+delim.dir](svg,hw,delim.stretch,scale,font)}
  617. return svg;
  618. },
  619. createChar: function (scale,data,font) {
  620. var text = "", variant = {fonts: [data[1]], noRemap:true};
  621. if (font && font === MML.VARIANT.BOLD) {variant.fonts = [data[1]+"-bold",data[1]]}
  622. if (typeof(data[1]) !== "string") {variant = data[1]}
  623. if (data[0] instanceof Array) {
  624. for (var i = 0, m = data[0].length; i < m; i++) {text += String.fromCharCode(data[0][i])}
  625. } else {text = String.fromCharCode(data[0])}
  626. if (data[4]) {scale = scale*data[4]}
  627. var svg = this.HandleVariant(variant,scale,text);
  628. if (data[2]) {svg.x = data[2]*1000}
  629. if (data[3]) {svg.y = data[3]*1000}
  630. if (data[5]) {svg.h += data[5]*1000}
  631. if (data[6]) {svg.d += data[6]*1000}
  632. return svg;
  633. },
  634. extendDelimiterV: function (svg,H,delim,scale,font) {
  635. var top = this.createChar(scale,(delim.top||delim.ext),font);
  636. var bot = this.createChar(scale,(delim.bot||delim.ext),font);
  637. var h = top.h + top.d + bot.h + bot.d;
  638. var y = -top.h; svg.Add(top,0,y); y -= top.d;
  639. if (delim.mid) {var mid = this.createChar(scale,delim.mid,font); h += mid.h + mid.d}
  640. if (delim.min && H < h*delim.min) {H = h*delim.min}
  641. if (H > h) {
  642. var ext = this.createChar(scale,delim.ext,font);
  643. var k = (delim.mid ? 2 : 1), eH = (H-h) / k, s = (eH+100) / (ext.h+ext.d);
  644. while (k-- > 0) {
  645. var g = SVG.Element("g",{transform:"translate("+ext.y+","+(y-s*ext.h+50+ext.y)+") scale(1,"+s+")"});
  646. g.appendChild(ext.element.cloneNode(false)); svg.element.appendChild(g); y -= eH;
  647. if (delim.mid && k) {svg.Add(mid,0,y-mid.h); y -= (mid.h+mid.d)}
  648. }
  649. } else if (delim.mid) {
  650. y += (h - H)/2; svg.Add(mid,0,y-mid.h); y += -(mid.h + mid.d) + (h - H)/2;
  651. } else {
  652. y += (h - H);
  653. }
  654. svg.Add(bot,0,y-bot.h); svg.Clean();
  655. svg.scale = scale;
  656. svg.isMultiChar = true;
  657. },
  658. extendDelimiterH: function (svg,W,delim,scale,font) {
  659. var left = this.createChar(scale,(delim.left||delim.rep),font);
  660. var right = this.createChar(scale,(delim.right||delim.rep),font);
  661. svg.Add(left,-left.l,0);
  662. var w = (left.r - left.l) + (right.r - right.l), x = left.r - left.l;
  663. if (delim.mid) {var mid = this.createChar(scale,delim.mid,font); w += mid.w}
  664. if (delim.min && W < w*delim.min) {W = w*delim.min}
  665. if (W > w) {
  666. var rep = this.createChar(scale,delim.rep,font), fuzz = delim.fuzz || 0;
  667. var k = (delim.mid ? 2 : 1), rW = (W-w) / k, s = (rW+fuzz) / (rep.r-rep.l);
  668. while (k-- > 0) {
  669. var g = SVG.Element("g",{transform:"translate("+(x-fuzz/2-s*rep.l+rep.x)+","+rep.y+") scale("+s+",1)"});
  670. g.appendChild(rep.element.cloneNode(false)); svg.element.appendChild(g); x += rW;
  671. if (delim.mid && k) {svg.Add(mid,x,0); x += mid.w}
  672. }
  673. } else if (delim.mid) {
  674. x -= (w - W)/2; svg.Add(mid,x,0); x += mid.w - (w - W)/2;
  675. } else {
  676. x -= (w - W);
  677. }
  678. svg.Add(right,x-right.l,0); svg.Clean();
  679. svg.scale = scale;
  680. svg.isMultiChar = true;
  681. },
  682. MATHSPACE: {
  683. veryverythinmathspace: 1/18,
  684. verythinmathspace: 2/18,
  685. thinmathspace: 3/18,
  686. mediummathspace: 4/18,
  687. thickmathspace: 5/18,
  688. verythickmathspace: 6/18,
  689. veryverythickmathspace: 7/18,
  690. negativeveryverythinmathspace: -1/18,
  691. negativeverythinmathspace: -2/18,
  692. negativethinmathspace: -3/18,
  693. negativemediummathspace: -4/18,
  694. negativethickmathspace: -5/18,
  695. negativeverythickmathspace: -6/18,
  696. negativeveryverythickmathspace: -7/18
  697. },
  698. //
  699. // Units are em/1000 so quad is 1em
  700. //
  701. TeX: {
  702. x_height: 430.554,
  703. quad: 1000,
  704. num1: 676.508,
  705. num2: 393.732,
  706. num3: 443.73,
  707. denom1: 685.951,
  708. denom2: 344.841,
  709. sup1: 412.892,
  710. sup2: 362.892,
  711. sup3: 288.888,
  712. sub1: 150,
  713. sub2: 247.217,
  714. sup_drop: 386.108,
  715. sub_drop: 50,
  716. delim1: 2390,
  717. delim2: 1000,
  718. axis_height: 250,
  719. rule_thickness: 60,
  720. big_op_spacing1: 111.111,
  721. big_op_spacing2: 166.666,
  722. big_op_spacing3: 200,
  723. big_op_spacing4: 600,
  724. big_op_spacing5: 100,
  725. scriptspace: 100,
  726. nulldelimiterspace: 120,
  727. delimiterfactor: 901,
  728. delimitershortfall: 100, // originally 300,
  729. min_rule_thickness: 1.25, // in pixels
  730. min_root_space: 1.5 // in pixels
  731. },
  732. BIGDIMEN: 10000000,
  733. NBSP: "\u00A0"
  734. });
  735. var BBOX = SVG.BBOX = MathJax.Object.Subclass({
  736. type: "g", removeable: true,
  737. Init: function (def) {
  738. this.h = this.d = -SVG.BIGDIMEN; this.H = this.D = 0;
  739. this.w = this.r = 0; this.l = SVG.BIGDIMEN;
  740. this.x = this.y = 0; this.scale = 1; this.n = 0;
  741. if (this.type) {this.element = SVG.Element(this.type,def)}
  742. },
  743. With: function (def) {return HUB.Insert(this,def)},
  744. Add: function (svg,dx,dy,forcew,infront) {
  745. if (dx) {svg.x += dx}; if (dy) {svg.y += dy};
  746. if (svg.element) {
  747. if (svg.removeable && svg.element.childNodes.length === 1 && svg.n === 1) {
  748. var child = svg.element.firstChild;
  749. if (child.nodeName === "use" || child.nodeName === "rect") {
  750. svg.element = child; svg.scale = svg.childScale;
  751. var x = svg.childX, y = svg.childY;
  752. svg.x += x; svg.y += y;
  753. svg.h -= y; svg.d += y; svg.H -= y; svg.D +=y;
  754. svg.w -= x; svg.r -= x; svg.l += x;
  755. svg.removeable = false;
  756. }
  757. }
  758. if (Math.abs(svg.x) < 1 && Math.abs(svg.y) < 1) {
  759. svg.remove = svg.removeable;
  760. } else {
  761. if (svg.element.nodeName === "g") {
  762. if (!svg.element.firstChild) {svg.remove = svg.removeable}
  763. else {svg.element.setAttribute("transform","translate("+Math.floor(svg.x)+","+Math.floor(svg.y)+")")}
  764. } else if (svg.element.nodeName === "line" ||
  765. svg.element.nodeName === "polygon" ||
  766. svg.element.nodeName === "path" ||
  767. svg.element.nodeName === "a") {
  768. svg.element.setAttribute("transform","translate("+Math.floor(svg.x)+","+Math.floor(svg.y)+")");
  769. } else {
  770. svg.element.setAttribute("x",Math.floor(svg.x/svg.scale));
  771. svg.element.setAttribute("y",Math.floor(svg.y/svg.scale));
  772. }
  773. }
  774. if (svg.remove) {
  775. this.n += svg.n;
  776. while (svg.element.firstChild) {
  777. if (infront && this.element.firstChild) {
  778. this.element.insertBefore(svg.element.firstChild,this.element.firstChild);
  779. } else {
  780. this.element.appendChild(svg.element.firstChild);
  781. }
  782. }
  783. } else {
  784. if (infront) {this.element.insertBefore(svg.element,this.element.firstChild)}
  785. else {this.element.appendChild(svg.element)}
  786. }
  787. delete svg.element;
  788. }
  789. if (svg.hasIndent) {this.hasIndent = svg.hasIndent}
  790. if (svg.d - svg.y > this.d) {this.d = svg.d - svg.y; if (this.d > this.D) {this.D = this.d}}
  791. if (svg.y + svg.h > this.h) {this.h = svg.y + svg.h; if (this.h > this.H) {this.H = this.h}}
  792. if (svg.D - svg.y > this.D) {this.D = svg.D - svg.y}
  793. if (svg.y + svg.H > this.H) {this.H = svg.y + svg.H}
  794. if (svg.x + svg.l < this.l) {this.l = svg.x + svg.l}
  795. if (svg.x + svg.r > this.r) {this.r = svg.x + svg.r}
  796. if (forcew || svg.x + svg.w + (svg.X||0) > this.w) {this.w = svg.x + svg.w + (svg.X||0)}
  797. this.childScale = svg.scale; this.childX = svg.x; this.childY = svg.y; this.n++;
  798. return svg;
  799. },
  800. Align: function (svg,align,dx,dy) {
  801. dx = ({left: dx, center: (this.w - svg.w)/2, right: this.w - svg.w - dx})[align] || 0;
  802. this.Add(svg,dx,dy);
  803. },
  804. Clean: function () {
  805. if (this.h === -SVG.BIGDIMEN) {this.h = this.d = this.l = 0}
  806. return this;
  807. }
  808. });
  809. BBOX.ROW = BBOX.Subclass({
  810. Init: function () {
  811. this.SUPER(arguments).Init.call(this);
  812. this.svg = []; this.sh = this.sd = 0;
  813. },
  814. Check: function (data) {
  815. var svg = data.toSVG(); this.svg.push(svg);
  816. if (data.SVGcanStretch("Vertical")) {svg.mml = data}
  817. if (svg.h > this.sh) {this.sh = svg.h}
  818. if (svg.d > this.sd) {this.sd = svg.d}
  819. },
  820. Stretch: function () {
  821. for (var i = 0, m = this.svg.length; i < m; i++)
  822. {
  823. var svg = this.svg[i], mml = svg.mml;
  824. if (mml) {
  825. svg = mml.SVGstretchV(this.sh,this.sd);
  826. mml.SVGdata.HW = this.sh; mml.SVGdata.D = this.sd;
  827. }
  828. if (svg.ic) {this.ic = svg.ic} else {delete this.ic}
  829. this.Add(svg,this.w,0,true);
  830. }
  831. delete this.svg;
  832. }
  833. });
  834. BBOX.RECT = BBOX.Subclass({
  835. type: "rect", removeable: false,
  836. Init: function (h,d,w,def) {
  837. if (def == null) {def = {stroke:"none"}}
  838. def.width = Math.floor(w); def.height = Math.floor(h+d);
  839. this.SUPER(arguments).Init.call(this,def);
  840. this.w = this.r = w; this.h = this.H = h+d; this.d = this.D = this.l = 0; this.y = -d;
  841. }
  842. });
  843. BBOX.FRAME = BBOX.Subclass({
  844. type: "rect", removeable: false,
  845. Init: function (h,d,w,t,dash,color,def) {
  846. if (def == null) {def = {}}; def.fill = "none";
  847. def["stroke-width"] = t.toFixed(2).replace(/\.?0+$/,"");
  848. def.width = Math.floor(w-t); def.height = Math.floor(h+d-t);
  849. def.transform = "translate("+Math.floor(t/2)+","+Math.floor(-d+t/2)+")";
  850. if (dash === "dashed")
  851. {def["stroke-dasharray"] = [Math.floor(6*SVG.em),Math.floor(6*SVG.em)].join(" ")}
  852. this.SUPER(arguments).Init.call(this,def);
  853. this.w = this.r = w; this.h = this.H = h;
  854. this.d = this.D = d; this.l = 0;
  855. }
  856. });
  857. BBOX.HLINE = BBOX.Subclass({
  858. type: "line", removeable: false,
  859. Init: function (w,t,dash,color,def) {
  860. if (def == null) {def = {}}
  861. if (color && color !== "") {def.stroke = color}
  862. def["stroke-width"] = t.toFixed(2).replace(/\.?0+$/,"");
  863. def.x1 = 0; def.y1 = def.y2 = t/2; def.x2 = Math.floor(w);
  864. if (dash === "dashed") {
  865. var n = Math.floor(w/(6*t)), m = Math.floor(w/(2*n+1));
  866. def["stroke-dasharray"] = m+" "+m;
  867. }
  868. this.SUPER(arguments).Init.call(this,def);
  869. this.w = this.r = w; this.l = 0; this.h = this.H = t; this.d = this.D = 0;
  870. }
  871. });
  872. BBOX.VLINE = BBOX.Subclass({
  873. type: "line", removeable: false,
  874. Init: function (h,t,dash,color,def) {
  875. if (def == null) {def = {}}
  876. if (color && color !== "") {def.stroke = color}
  877. def["stroke-width"] = t.toFixed(2).replace(/\.?0+$/,"");
  878. def.x1 = def.x2 = t/2; def.y1 = 0; def.y2 = Math.floor(h);
  879. if (dash === "dashed") {
  880. var n = Math.floor(h/(6*t)), m = Math.floor(h/(2*n+1));
  881. def["stroke-dasharray"] = m+" "+m;
  882. }
  883. this.SUPER(arguments).Init.call(this,def);
  884. this.w = this.r = t; this.l = 0; this.h = this.H = h; this.d = this.D = 0;
  885. }
  886. });
  887. BBOX.TEXT = BBOX.Subclass({
  888. type: "text", removeable: false,
  889. Init: function (scale,text,def) {
  890. if (!def) {def = {}}; def.stroke = "none";
  891. this.SUPER(arguments).Init.call(this,def);
  892. SVG.addText(this.element,text);
  893. SVG.textSVG.appendChild(this.element);
  894. var bbox = this.element.getBBox();
  895. SVG.textSVG.removeChild(this.element);
  896. scale *= 1000/SVG.em;
  897. this.element.setAttribute("transform","scale("+scale+") matrix(1 0 0 -1 0 0)");
  898. this.w = this.r = bbox.width*scale; this.l = 0;
  899. this.h = this.H = -bbox.y*scale;
  900. this.d = this.D = (bbox.height + bbox.y)*scale;
  901. }
  902. });
  903. BBOX.G = BBOX;
  904. BBOX.NULL = BBOX.Subclass({
  905. Init: function () {
  906. this.SUPER(arguments).Init.apply(this,arguments);
  907. this.Clean();
  908. }
  909. });
  910. var GLYPHS, DEFS; // data for which glyphs are used
  911. BBOX.GLYPH = BBOX.Subclass({
  912. type: "path", removeable: false,
  913. Init: function (scale,id,h,d,w,l,r,p) {
  914. var def, t = SVG.config.blacker;
  915. if (!GLYPHS[id]) {
  916. def = {id:id, "stroke-width":t};
  917. if (p !== "") {def.d = "M"+p+"Z"}
  918. this.SUPER(arguments).Init.call(this,def);
  919. DEFS.appendChild(this.element); GLYPHS[id] = true;
  920. }
  921. def = {}; if (scale !== 1) {def.transform = "scale("+scale+")"}
  922. this.element = SVG.Element("use",def);
  923. this.element.setAttributeNS(XLINKNS,"href","#"+id);
  924. this.h = (h+t) * scale; this.d = (d+t) * scale; this.w = (w+t/2) *scale;
  925. this.l = (l+t/2) * scale; this.r = (r+t/2) * scale;
  926. this.H = Math.max(0,this.h); this.D = Math.max(0,this.d);
  927. this.x = this.y = 0; this.scale = scale;
  928. }
  929. });
  930. HUB.Register.StartupHook("mml Jax Ready",function () {
  931. MML = MathJax.ElementJax.mml;
  932. MML.mbase.Augment({
  933. SVG: BBOX,
  934. toSVG: function () {
  935. this.SVGgetStyles();
  936. var variant = this.SVGgetVariant();
  937. var svg = this.SVG();
  938. svg.scale = this.SVGgetScale(); this.SVGhandleSpace(svg);
  939. for (var i = 0, m = this.data.length; i < m; i++) {
  940. if (this.data[i]) {
  941. var child = svg.Add(this.data[i].toSVG(variant,svg.scale),svg.w,0,true);
  942. if (child.skew) {svg.skew = child.skew}
  943. }
  944. }
  945. svg.Clean(); var text = this.data.join("");
  946. if (svg.skew && text.length !== 1) {delete svg.skew}
  947. if (svg.r > svg.w && text.length === 1 && !variant.noIC)
  948. {svg.ic = svg.r - svg.w; svg.w = svg.r}
  949. this.SVGhandleColor(svg);
  950. this.SVGsaveData(svg);
  951. return svg;
  952. },
  953. SVGchildSVG: function (i) {
  954. return (this.data[i] ? this.data[i].toSVG() : BBOX());
  955. },
  956. SVGdataStretched: function (i,HW,D) {
  957. this.SVGdata = {HW:HW, D:D};
  958. if (!this.data[i]) {return BBOX()}
  959. if (D != null) {return this.data[i].SVGstretchV(HW,D)}
  960. if (HW != null) {return this.data[i].SVGstretchH(HW)}
  961. return this.data[i].toSVG();
  962. },
  963. SVGsaveData: function (svg) {
  964. if (!this.SVGdata) {this.SVGdata = {}}
  965. this.SVGdata.w = svg.w, this.SVGdata.x = svg.x;
  966. this.SVGdata.h = svg.h, this.SVGdata.d = svg.d;
  967. if (svg.X != null) {this.SVGdata.X = svg.X}
  968. if (this["class"]) {svg.removeable = false; SVG.Element(svg.element,{"class":this["class"]})}
  969. // FIXME: if an element is split by linebreaking, the ID will be the same on both parts
  970. // FIXME: if an element has an id, its zoomed copy will have the same ID
  971. if (this.id) {svg.removeable = false; SVG.Element(svg.element,{"id":this.id})}
  972. if (this.href) {
  973. var a = SVG.Element("a",{"class":"mjx-svg-href"});
  974. a.setAttributeNS(XLINKNS,"href",this.href);
  975. a.onclick = this.SVGlink;
  976. SVG.addElement(a,"rect",{width:svg.w, height:svg.h+svg.d, y:-svg.d,
  977. fill:"none", stroke:"none", "pointer-events":"all"});
  978. if (svg.type === "svg") {
  979. // for svg element, put <a> inside the main <g> element
  980. var g = svg.element.firstChild;
  981. while (g.firstChild) {a.appendChild(g.firstChild)}
  982. g.appendChild(a);
  983. } else {
  984. a.appendChild(svg.element); svg.element = a;
  985. }
  986. svg.removeable = false;
  987. }
  988. if (SVG.config.addMMLclasses) {
  989. this.SVGaddClass(svg.element,"mjx-svg-"+this.type);
  990. svg.removeable = false;
  991. }
  992. var style = this.style;
  993. if (style && svg.element) {
  994. svg.element.style.cssText = style;
  995. if (svg.element.style.fontSize) {svg.element.style.fontSize = ""} // handled by scale
  996. svg.element.style.border = svg.element.style.padding = "";
  997. if (svg.removeable) {svg.removeable = svg.element.style.cssText === ""}
  998. }
  999. },
  1000. SVGaddClass: function (node,name) {
  1001. var classes = node.getAttribute("class");
  1002. node.setAttribute("class",(classes ? classes+" " : "")+name);
  1003. },
  1004. //
  1005. // WebKit currently scrolls to the BOTTOM of an svg element if it contains the
  1006. // target of the link, so implement link by hand, to the containing span element.
  1007. //
  1008. SVGlink: function () {
  1009. var href = this.href.animVal;
  1010. if (href.charAt(0) === "#") {
  1011. var target = SVG.hashCheck(document.getElementById(href.substr(1)));
  1012. if (target && target.scrollIntoView)
  1013. {setTimeout(function () {target.parentNode.scrollIntoView(true)},1)}
  1014. }
  1015. document.location = href;
  1016. },
  1017. SVGgetStyles: function () {
  1018. if (this.style) {
  1019. var span = HTML.Element("span");
  1020. span.style.cssText = this.style;
  1021. this.styles = {border:SVG.getBorders(span), padding:SVG.getPadding(span)}
  1022. if (span.style.fontSize) {this.styles.fontSize = span.style.fontSize}
  1023. if (span.style.color) {this.styles.color = span.style.color}
  1024. if (span.style.backgroundColor) {this.styles.background = span.style.backgroundColor}
  1025. if (span.style.fontStyle) {this.styles.fontStyle = span.style.fontStyle}
  1026. if (span.style.fontWeight) {this.styles.fontWeight = span.style.fontWeight}
  1027. if (span.style.fontFamily) {this.styles.fontFamily = span.style.fontFamily}
  1028. if (this.styles.fontWeight && this.styles.fontWeight.match(/^\d+$/))
  1029. {this.styles.fontWeight = (parseInt(this.styles.fontWeight) > 600 ? "bold" : "normal")}
  1030. }
  1031. },
  1032. SVGhandleSpace: function (svg) {
  1033. if (this.useMMLspacing) {
  1034. if (this.type !== "mo") return;
  1035. var values = this.getValues("scriptlevel","lspace","rspace");
  1036. if (values.scriptlevel <= 0 || this.hasValue("lspace") || this.hasValue("rspace")) {
  1037. var mu = this.SVGgetMu(svg);
  1038. values.lspace = Math.max(0,SVG.length2em(values.lspace,mu));
  1039. values.rspace = Math.max(0,SVG.length2em(values.rspace,mu));
  1040. var core = this, parent = this.Parent();
  1041. while (parent && parent.isEmbellished() && parent.Core() === core)
  1042. {core = parent; parent = parent.Parent()}
  1043. if (values.lspace) {svg.x += values.lspace}
  1044. if (values.rspace) {svg.X = values.rspace}
  1045. }
  1046. } else {
  1047. var space = this.texSpacing();
  1048. if (space !== "") {svg.x += SVG.length2em(space,this.SVGgetScale())/svg.scale}
  1049. }
  1050. },
  1051. SVGhandleColor: function (svg) {
  1052. var values = this.getValues("mathcolor","color");
  1053. if (this.styles && this.styles.color && !values.color) {values.color = this.styles.color}
  1054. if (values.color && !this.mathcolor) {values.mathcolor = values.color}
  1055. if (values.mathcolor) {
  1056. SVG.Element(svg.element,{fill:values.mathcolor,stroke:values.mathcolor})
  1057. svg.removeable = false;
  1058. }
  1059. var borders = (this.styles||{}).border, padding = (this.styles||{}).padding,
  1060. bleft = ((borders||{}).left||0), pleft = ((padding||{}).left||0), id;
  1061. values.background = (this.mathbackground || this.background ||
  1062. (this.styles||{}).background || MML.COLOR.TRANSPARENT);
  1063. if (bleft + pleft) {
  1064. //
  1065. // Make a box and move the contents of svg to it,
  1066. // then add it back into svg, but offset by the left amount
  1067. //
  1068. var dup = BBOX(); for (id in svg) {if (svg.hasOwnProperty(id)) {dup[id] = svg[id]}}
  1069. dup.x = 0; dup.y = 0;
  1070. svg.element = SVG.Element("g"); svg.removeable = true;
  1071. svg.Add(dup,bleft+pleft,0);
  1072. }
  1073. //
  1074. // Adjust size by padding and dashed borders (left is taken care of above)
  1075. //
  1076. if (padding) {svg.w += padding.right; svg.h += padding.top; svg.d += padding.bottom}
  1077. if (borders) {svg.w += borders.right; svg.h += borders.top; svg.d += borders.bottom}
  1078. //
  1079. // Add background color
  1080. //
  1081. if (values.background !== MML.COLOR.TRANSPARENT) {
  1082. if (svg.element.nodeName !== "g" && svg.element.nodeName !== "svg") {
  1083. var g = SVG.Element("g"); g.appendChild(svg.element);
  1084. svg.element = g; svg.removeable = true;
  1085. }
  1086. svg.Add(BBOX.RECT(svg.h,svg.d,svg.w,{fill:values.background,stroke:"none"}),0,0,false,true)
  1087. }
  1088. //
  1089. // Add borders
  1090. //
  1091. if (borders) {
  1092. var dd = 5; // fuzz factor to avoid anti-alias problems at edges
  1093. var sides = {
  1094. left: ["V",svg.h+svg.d,-dd,-svg.d],
  1095. right: ["V",svg.h+svg.d,svg.w-borders.right+dd,-svg.d],
  1096. top: ["H",svg.w,0,svg.h-borders.top+dd],
  1097. bottom:["H",svg.w,0,-svg.d-dd]
  1098. }
  1099. for (id in sides) {if (sides.hasOwnProperty(id)) {
  1100. if (borders[id]) {
  1101. var side = sides[id], box = BBOX[side[0]+"LINE"];
  1102. svg.Add(box(side[1],borders[id],borders[id+"Style"],borders[id+"Color"]),side[2],side[3]);
  1103. }
  1104. }}
  1105. }
  1106. },
  1107. SVGhandleVariant: function (variant,scale,text) {
  1108. return SVG.HandleVariant(variant,scale,text);
  1109. },
  1110. SVGgetVariant: function () {
  1111. var values = this.getValues("mathvariant","fontfamily","fontweight","fontstyle");
  1112. var variant = values.mathvariant; if (this.variantForm) {variant = "-TeX-variant"}
  1113. values.hasVariant = this.Get("mathvariant",true); // null if not explicitly specified
  1114. if (!values.hasVariant) {
  1115. values.family = values.fontfamily;
  1116. values.weight = values.fontweight;
  1117. values.style = values.fontstyle;
  1118. }
  1119. if (this.styles) {
  1120. if (!values.style && this.styles.fontStyle) {values.style = this.styles.fontStyle}
  1121. if (!values.weight && this.styles.fontWeight) {values.weight = this.styles.fontWeight}
  1122. if (!values.family && this.styles.fontFamily) {values.family = this.styles.fontFamily}
  1123. }
  1124. if (values.family && !values.hasVariant) {
  1125. if (!values.weight && values.mathvariant.match(/bold/)) {values.weight = "bold"}
  1126. if (!values.style && values.mathvariant.match(/italic/)) {values.style = "italic"}
  1127. variant = {forceFamily: true, font: {"font-family":values.family}};
  1128. if (values.style) {variant.font["font-style"] = values.style}
  1129. if (values.weight) {variant.font["font-weight"] = values.weight}
  1130. return variant;
  1131. }
  1132. if (values.weight === "bold") {
  1133. variant = {
  1134. normal:MML.VARIANT.BOLD, italic:MML.VARIANT.BOLDITALIC,
  1135. fraktur:MML.VARIANT.BOLDFRAKTUR, script:MML.VARIANT.BOLDSCRIPT,
  1136. "sans-serif":MML.VARIANT.BOLDSANSSERIF,
  1137. "sans-serif-italic":MML.VARIANT.SANSSERIFBOLDITALIC
  1138. }[variant]||variant;
  1139. } else if (values.weight === "normal") {
  1140. variant = {
  1141. bold:MML.VARIANT.normal, "bold-italic":MML.VARIANT.ITALIC,
  1142. "bold-fraktur":MML.VARIANT.FRAKTUR, "bold-script":MML.VARIANT.SCRIPT,
  1143. "bold-sans-serif":MML.VARIANT.SANSSERIF,
  1144. "sans-serif-bold-italic":MML.VARIANT.SANSSERIFITALIC
  1145. }[variant]||variant;
  1146. }
  1147. if (values.style === "italic") {
  1148. variant = {
  1149. normal:MML.VARIANT.ITALIC, bold:MML.VARIANT.BOLDITALIC,
  1150. "sans-serif":MML.VARIANT.SANSSERIFITALIC,
  1151. "bold-sans-serif":MML.VARIANT.SANSSERIFBOLDITALIC
  1152. }[variant]||variant;
  1153. } else if (values.style === "normal") {
  1154. variant = {
  1155. italic:MML.VARIANT.NORMAL, "bold-italic":MML.VARIANT.BOLD,
  1156. "sans-serif-italic":MML.VARIANT.SANSSERIF,
  1157. "sans-serif-bold-italic":MML.VARIANT.BOLDSANSSERIF
  1158. }[variant]||variant;
  1159. }
  1160. if (!(variant in SVG.FONTDATA.VARIANT)) {
  1161. // If the mathvariant value is invalid or not supported by this
  1162. // font, fallback to normal. See issue 363.
  1163. variant = "normal";
  1164. }
  1165. return SVG.FONTDATA.VARIANT[variant];
  1166. },
  1167. SVGgetScale: function () {
  1168. var scale = 1,
  1169. values = this.getValues("mathsize","scriptlevel","fontsize");
  1170. if ((this.styles||{}).fontSize && !values.fontsize) {values.fontsize = this.styles.fontSize}
  1171. if (values.fontsize && !this.mathsize) {values.mathsize = values.fontsize}
  1172. if (values.scriptlevel !== 0) {
  1173. if (values.scriptlevel > 2) {values.scriptlevel = 2}
  1174. scale = Math.pow(this.Get("scriptsizemultiplier"),values.scriptlevel);
  1175. values.scriptminsize = SVG.length2em(this.Get("scriptminsize"))/1000;
  1176. if (scale < values.scriptminsize) {scale = values.scriptminsize}
  1177. }
  1178. if (this.isToken) {scale *= SVG.length2em(values.mathsize)/1000}
  1179. return scale;
  1180. },
  1181. SVGgetMu: function (svg) {
  1182. var mu = 1, values = this.getValues("scriptlevel","scriptsizemultiplier");
  1183. if (svg.scale && svg.scale !== 1) {mu = 1/svg.scale}
  1184. if (values.scriptlevel !== 0) {
  1185. if (values.scriptlevel > 2) {values.scriptlevel = 2}
  1186. mu = Math.sqrt(Math.pow(values.scriptsizemultiplier,values.scriptlevel));
  1187. }
  1188. return mu;
  1189. },
  1190. SVGnotEmpty: function (data) {
  1191. while (data) {
  1192. if ((data.type !== "mrow" && data.type !== "texatom") ||
  1193. data.data.length > 1) {return true}
  1194. data = data.data[0];
  1195. }
  1196. return false;
  1197. },
  1198. SVGcanStretch: function (direction) {
  1199. if (this.isEmbellished()) {return this.Core().SVGcanStretch(direction)}
  1200. return false;
  1201. },
  1202. SVGstretchV: function (h,d) {return this.toSVG(h,d)},
  1203. SVGstretchH: function (w) {return this.toSVG(w)},
  1204. SVGlineBreaks: function () {return false}
  1205. },{
  1206. SVGautoload: function () {
  1207. var file = SVG.autoloadDir+"/"+this.type+".js";
  1208. HUB.RestartAfter(AJAX.Require(file));
  1209. },
  1210. SVGautoloadFile: function (name) {
  1211. var file = SVG.autoloadDir+"/"+name+".js";
  1212. HUB.RestartAfter(AJAX.Require(file));
  1213. }
  1214. });
  1215. MML.chars.Augment({
  1216. toSVG: function (variant,scale,remap,chars) {
  1217. var text = this.data.join("").replace(/[\u2061-\u2064]/g,""); // remove invisibles
  1218. if (remap) {text = remap(text,chars)}
  1219. return this.SVGhandleVariant(variant,scale,text);
  1220. }
  1221. });
  1222. MML.entity.Augment({
  1223. toSVG: function (variant,scale,remap,chars) {
  1224. var text = this.toString().replace(/[\u2061-\u2064]/g,""); // remove invisibles
  1225. if (remap) {text = remap(text,chars)}
  1226. return this.SVGhandleVariant(variant,scale,text);
  1227. }
  1228. });
  1229. MML.mo.Augment({
  1230. toSVG: function (HW,D) {
  1231. this.SVGgetStyles();
  1232. var svg = this.svg = this.SVG(); this.SVGhandleSpace(svg);
  1233. if (this.data.length == 0) {svg.Clean(); this.SVGsaveData(svg); return svg}
  1234. //
  1235. // Stretch the operator, if that is requested
  1236. //
  1237. if (D != null) {return this.SVGstretchV(HW,D)}
  1238. else if (HW != null) {return this.SVG.strechH(HW)}
  1239. //
  1240. // Get the variant, and check for operator size
  1241. //
  1242. var scale = this.SVGgetScale(), variant = this.SVGgetVariant();
  1243. var values = this.getValues("largeop","displaystyle");
  1244. if (values.largeop)
  1245. {variant = SVG.FONTDATA.VARIANT[values.displaystyle ? "-largeOp" : "-smallOp"]}
  1246. //
  1247. // Get character translation for superscript and accents
  1248. //
  1249. var parent = this.CoreParent(),
  1250. isScript = (parent && parent.isa(MML.msubsup) && this !== parent.data[0]),
  1251. mapchars = (isScript?this.SVGremapChars:null);
  1252. if (this.data.join("").length === 1 && parent && parent.isa(MML.munderover) &&
  1253. this.CoreText(parent.data[parent.base]).length === 1) {
  1254. var over = parent.data[parent.over], under = parent.data[parent.under];
  1255. if (over && this === over.CoreMO() && parent.Get("accent")) {mapchars = SVG.FONTDATA.REMAPACCENT}
  1256. else if (under && this === under.CoreMO() && parent.Get("accentunder")) {mapchars = SVG.FONTDATA.REMAPACCENTUNDER}
  1257. }
  1258. //
  1259. // Primes must come from another font
  1260. //
  1261. if (isScript && this.data.join("").match(/['`"\u00B4\u2032-\u2037\u2057]/))
  1262. {variant = SVG.FONTDATA.VARIANT["-TeX-variant"]}
  1263. //
  1264. // Typeset contents
  1265. //
  1266. for (var i = 0, m = this.data.length; i < m; i++) {
  1267. if (this.data[i]) {
  1268. var text = this.data[i].toSVG(variant,scale,this.SVGremap,mapchars), x = svg.w;
  1269. if (x === 0 && -text.l > 10*text.w) {x += -text.l} // initial combining character doesn't combine
  1270. svg.Add(text,x,0,true);
  1271. if (text.skew) {svg.skew = text.skew}
  1272. }
  1273. }
  1274. svg.Clean();
  1275. if (this.data.join("").length !== 1) {delete svg.skew}
  1276. //
  1277. // Handle large operator centering
  1278. //
  1279. if (values.largeop) {
  1280. svg.y = (svg.h - svg.d)/2/scale - SVG.TeX.axis_height;
  1281. if (svg.r > svg.w) {svg.ic = svg.r - svg.w; svg.w = svg.r}
  1282. }
  1283. //
  1284. // Finish up
  1285. //
  1286. this.SVGhandleColor(svg);
  1287. this.SVGsaveData(svg);
  1288. return svg;
  1289. },
  1290. CoreParent: function () {
  1291. var parent = this;
  1292. while (parent && parent.isEmbellished() &&
  1293. parent.CoreMO() === this && !parent.isa(MML.math)) {parent = parent.Parent()}
  1294. return parent;
  1295. },
  1296. CoreText: function (parent) {
  1297. if (!parent) {return ""}
  1298. if (parent.isEmbellished()) {return parent.CoreMO().data.join("")}
  1299. while ((parent.isa(MML.mrow) || parent.isa(MML.TeXAtom) ||
  1300. parent.isa(MML.mstyle) || parent.isa(MML.mphantom)) &&
  1301. parent.data.length === 1 && parent.data[0]) {parent = parent.data[0]}
  1302. if (!parent.isToken) {return ""} else {return parent.data.join("")}
  1303. },
  1304. SVGremapChars: {
  1305. '*':"\u2217",
  1306. '"':"\u2033",
  1307. "\u00B0":"\u2218",
  1308. "\u00B2":"2",
  1309. "\u00B3":"3",
  1310. "\u00B4":"\u2032",
  1311. "\u00B9":"1"
  1312. },
  1313. SVGremap: function (text,map) {
  1314. text = text.replace(/-/g,"\u2212");
  1315. if (map) {
  1316. text = text.replace(/'/g,"\u2032").replace(/`/g,"\u2035");
  1317. if (text.length === 1) {text = map[text]||text}
  1318. }
  1319. return text;
  1320. },
  1321. SVGcanStretch: function (direction) {
  1322. if (!this.Get("stretchy")) {return false}
  1323. var c = this.data.join("");
  1324. if (c.length > 1) {return false}
  1325. var parent = this.CoreParent();
  1326. if (parent && parent.isa(MML.munderover) &&
  1327. this.CoreText(parent.data[parent.base]).length === 1) {
  1328. var over = parent.data[parent.over], under = parent.data[parent.under];
  1329. if (over && this === over.CoreMO() && parent.Get("accent")) {c = SVG.FONTDATA.REMAPACCENT[c]||c}
  1330. else if (under && this === under.CoreMO() && parent.Get("accentunder")) {c = SVG.FONTDATA.REMAPACCENTUNDER[c]||c}
  1331. }
  1332. c = SVG.FONTDATA.DELIMITERS[c.charCodeAt(0)];
  1333. var can = (c && c.dir == direction.substr(0,1));
  1334. if (!can) {delete this.svg}
  1335. return can;
  1336. },
  1337. SVGstretchV: function (h,d) {
  1338. var svg = this.svg || this.toSVG();
  1339. var values = this.getValues("symmetric","maxsize","minsize");
  1340. var axis = SVG.TeX.axis_height, mu = this.SVGgetMu(svg), H;
  1341. if (values.symmetric) {H = 2*Math.max(h-axis,d+axis)} else {H = h + d}
  1342. values.maxsize = SVG.length2em(values.maxsize,mu,svg.h+svg.d);
  1343. values.minsize = SVG.length2em(values.minsize,mu,svg.h+svg.d);
  1344. H = Math.max(values.minsize,Math.min(values.maxsize,H));
  1345. svg = SVG.createDelimiter(this.data.join("").charCodeAt(0),H,svg.scale);
  1346. if (values.symmetric) {H = (svg.h + svg.d)/2 + axis}
  1347. else {H = (svg.h + svg.d) * h/(h + d)}
  1348. svg.y = H - svg.h;
  1349. this.SVGhandleSpace(svg);
  1350. this.SVGhandleColor(svg);
  1351. delete this.svg.element;
  1352. this.SVGsaveData(svg);
  1353. return svg;
  1354. },
  1355. SVGstretchH: function (w) {
  1356. var svg = this.svg || this.toSVG(), mu = this.SVGgetMu(svg);
  1357. var values = this.getValues("maxsize","minsize","mathvariant","fontweight");
  1358. // FIXME: should take style="font-weight:bold" into account as well
  1359. if ((values.fontweight === "bold" || parseInt(values.fontweight) >= 600) &&
  1360. !this.Get("mathvariant",true)) {values.mathvariant = MML.VARIANT.BOLD}
  1361. values.maxsize = SVG.length2em(values.maxsize,mu,svg.w);
  1362. values.minsize = SVG.length2em(values.minsize,mu,svg.w);
  1363. w = Math.max(values.minsize,Math.min(values.maxsize,w));
  1364. svg = SVG.createDelimiter(this.data.join("").charCodeAt(0),w,svg.scale,values.mathvariant);
  1365. this.SVGhandleSpace(svg);
  1366. this.SVGhandleColor(svg);
  1367. delete this.svg.element;
  1368. this.SVGsaveData(svg);
  1369. return svg;
  1370. }
  1371. });
  1372. MML.mtext.Augment({
  1373. toSVG: function () {
  1374. this.SVGgetStyles();
  1375. var svg, text, scale = this.SVGgetScale();
  1376. if (this.Parent().type === "merror") {
  1377. // *** FIXME: Make color, style, scale configurable
  1378. svg = this.SVG(); this.SVGhandleSpace(svg);
  1379. text = BBOX.G(); text.Add(BBOX.TEXT(.9*scale,this.data.join(""),{fill:"#C00"}));
  1380. svg.Add(BBOX.RECT(text.h+100,text.d+100,text.w+200,{fill:"#FF8",stroke:"#C00","stroke-width":50}),0,0);
  1381. svg.Add(text,150,0); svg.H += 150; svg.D += 50;
  1382. svg.Clean();
  1383. this.SVGsaveData(svg);
  1384. return svg;
  1385. } else if (SVG.config.mtextFontInherit) {
  1386. svg = this.SVG(); this.SVGhandleSpace(svg);
  1387. var variant = this.SVGgetVariant(), def = {};
  1388. if (variant.bold) {def["font-weight"] = "bold"}
  1389. if (variant.italic) {def["font-style"] = "italic"}
  1390. svg.Add(BBOX.TEXT(scale,this.data.join(""),def)); svg.Clean();
  1391. this.SVGhandleColor(svg);
  1392. this.SVGsaveData(svg);
  1393. return svg;
  1394. } else {
  1395. return this.SUPER(arguments).toSVG.call(this);
  1396. }
  1397. }
  1398. });
  1399. MML.ms.Augment({toSVG: MML.mbase.SVGautoload});
  1400. MML.mglyph.Augment({toSVG: MML.mbase.SVGautoload});
  1401. MML.mspace.Augment({
  1402. toSVG: function () {
  1403. this.SVGgetStyles();
  1404. var values = this.getValues("height","depth","width");
  1405. values.mathbackground = this.mathbackground;
  1406. if (this.background && !this.mathbackground) {values.mathbackground = this.background}
  1407. var svg = this.SVG(), mu = this.SVGgetMu(svg);
  1408. svg.h = SVG.length2em(values.height,mu) / svg.scale;
  1409. svg.d = SVG.length2em(values.depth,mu) / svg.scale;
  1410. svg.w = svg.r = SVG.length2em(values.width,mu) / svg.scale;
  1411. if (svg.w < 0) {svg.x = svg.w; svg.w = svg.r = 0}
  1412. if (svg.h < -svg.d) {svg.d = -svg.h}
  1413. svg.l = 0; svg.Clean();
  1414. this.SVGhandleColor(svg);
  1415. this.SVGsaveData(svg);
  1416. return svg;
  1417. }
  1418. });
  1419. MML.mphantom.Augment({
  1420. toSVG: function (HW,D) {
  1421. this.SVGgetStyles();
  1422. var svg = this.SVG();
  1423. if (this.data[0] != null) {
  1424. this.SVGhandleSpace(svg); svg.Add(this.SVGdataStretched(0,HW,D)); svg.Clean();
  1425. while (svg.element.firstChild) {svg.element.removeChild(svg.element.firstChild)}
  1426. }
  1427. this.SVGhandleColor(svg);
  1428. this.SVGsaveData(svg);
  1429. if (svg.removeable && !svg.element.firstChild) {delete svg.element}
  1430. return svg;
  1431. }
  1432. });
  1433. MML.mpadded.Augment({
  1434. toSVG: function (HW,D) {
  1435. this.SVGgetStyles();
  1436. var svg = this.SVG();
  1437. if (this.data[0] != null) {
  1438. this.SVGhandleSpace(svg);
  1439. var pad = this.SVGdataStretched(0,HW,D), mu = this.SVGgetMu(svg);
  1440. var values = this.getValues("height","depth","width","lspace","voffset"), x = 0, y = 0;
  1441. if (values.lspace) {x = this.SVGlength2em(pad,values.lspace,mu)}
  1442. if (values.voffset) {y = this.SVGlength2em(pad,values.voffset,mu)}
  1443. var h = pad.h, d = pad.d, w = pad.w; // these can change durring the Add()
  1444. svg.Add(pad,x,y); svg.Clean();
  1445. svg.h = h; svg.d = d; svg.w = w; svg.removeable = false;
  1446. if (values.height !== "") {svg.h = this.SVGlength2em(svg,values.height,mu,"h",0)}
  1447. if (values.depth !== "") {svg.d = this.SVGlength2em(svg,values.depth,mu,"d",0)}
  1448. if (values.width !== "") {svg.w = this.SVGlength2em(svg,values.width,mu,"w",0)}
  1449. if (svg.h > svg.H) {svg.H = svg.h}; if (svg.d > svg.D) {svg.D = svg.d}
  1450. }
  1451. this.SVGhandleColor(svg);
  1452. this.SVGsaveData(svg);
  1453. return svg;
  1454. },
  1455. SVGlength2em: function (svg,length,mu,d,m) {
  1456. if (m == null) {m = -SVG.BIGDIMEN}
  1457. var match = String(length).match(/width|height|depth/);
  1458. var size = (match ? svg[match[0].charAt(0)] : (d ? svg[d] : 0));
  1459. var v = SVG.length2em(length,mu,size);
  1460. if (d && String(length).match(/^\s*[-+]/))
  1461. {return Math.max(m,svg[d]+v)} else {return v}
  1462. }
  1463. });
  1464. MML.mrow.Augment({
  1465. SVG: BBOX.ROW,
  1466. toSVG: function () {
  1467. this.SVGgetStyles();
  1468. var svg = this.SVG();
  1469. this.SVGhandleSpace(svg);
  1470. for (var i = 0, m = this.data.length; i < m; i++)
  1471. {if (this.data[i]) {svg.Check(this.data[i])}}
  1472. svg.Stretch(); svg.Clean();
  1473. if (this.SVGlineBreaks(svg)) {svg = this.SVGmultiline(svg)}
  1474. this.SVGhandleColor(svg);
  1475. this.SVGsaveData(svg);
  1476. return svg;
  1477. },
  1478. SVGlineBreaks: function (svg) {
  1479. if (!this.parent.linebreakContainer) {return false}
  1480. return (SVG.config.linebreaks.automatic &&
  1481. svg.w > SVG.linebreakWidth) || this.hasNewline();
  1482. },
  1483. SVGmultiline: function (span) {MML.mbase.SVGautoloadFile("multiline")},
  1484. SVGstretchH: function (w) {
  1485. var svg = this.data[this.core].SVGstretchH(w);
  1486. this.SVGhandleColor(svg);
  1487. this.SVGsaveData(svg);
  1488. return svg;
  1489. },
  1490. SVGstretchV: function (h,d) {
  1491. var svg = this.data[this.core].SVGstretchV(h,d);
  1492. this.SVGhandleColor(svg);
  1493. this.SVGsaveData(svg);
  1494. return svg;
  1495. }
  1496. });
  1497. MML.mstyle.Augment({
  1498. toSVG: function () {
  1499. this.SVGgetStyles();
  1500. var svg = this.SVG();
  1501. if (this.data[0] != null) {
  1502. this.SVGhandleSpace(svg);
  1503. var math = svg.Add(this.data[0].toSVG()); svg.Clean();
  1504. if (math.ic) {svg.ic = math.ic}
  1505. this.SVGhandleColor(svg);
  1506. }
  1507. this.SVGsaveData(svg);
  1508. return svg;
  1509. },
  1510. SVGstretchH: function (w) {
  1511. return (this.data[0] != null ? this.data[0].SVGstretchH(w) : BBOX.NULL());
  1512. },
  1513. SVGstretchV: function (h,d) {
  1514. return (this.data[0] != null ? this.data[0].SVGstretchV(h,d) : BBOX.NULL());
  1515. }
  1516. });
  1517. MML.mfrac.Augment({
  1518. toSVG: function () {
  1519. this.SVGgetStyles();
  1520. var svg = this.SVG(); this.SVGhandleSpace(svg);
  1521. var num = this.SVGchildSVG(0), den = this.SVGchildSVG(1);
  1522. var values = this.getValues("displaystyle","linethickness","numalign","denomalign","bevelled");
  1523. var scale = svg.scale = this.SVGgetScale(), isDisplay = values.displaystyle;
  1524. var a = SVG.TeX.axis_height * scale;
  1525. if (values.bevelled) {
  1526. var delta = (isDisplay ? 400 : 150);
  1527. var H = Math.max(num.h+num.d,den.h+den.d)+2*delta;
  1528. var bevel = SVG.createDelimiter(0x2F,H);
  1529. svg.Add(num,0,(num.d-num.h)/2+a+delta);
  1530. svg.Add(bevel,num.w-delta/2,(bevel.d-bevel.h)/2+a);
  1531. svg.Add(den,num.w+bevel.w-delta,(den.d-den.h)/2+a-delta);
  1532. } else {
  1533. var W = Math.max(num.w,den.w);
  1534. var t = SVG.thickness2em(values.linethickness,scale), p,q, u,v;
  1535. var mt = SVG.TeX.min_rule_thickness/SVG.em * 1000;
  1536. if (isDisplay) {u = SVG.TeX.num1; v = SVG.TeX.denom1}
  1537. else {u = (t === 0 ? SVG.TeX.num3 : SVG.TeX.num2); v = SVG.TeX.denom2}
  1538. u *= scale; v *= scale;
  1539. if (t === 0) {// \atop
  1540. p = Math.max((isDisplay ? 7 : 3) * SVG.TeX.rule_thickness, 2*mt); // force to at least 2 px
  1541. q = (u - num.d) - (den.h - v);
  1542. if (q < p) {u += (p - q)/2; v += (p - q)/2}
  1543. svg.w = W; t = 0;
  1544. } else {// \over
  1545. p = Math.max((isDisplay ? 2 : 0) * mt + t, t/2 + 1.5*mt); // force to be at least 1.5px
  1546. q = (u - num.d) - (a + t/2); if (q < p) {u += p - q}
  1547. q = (a - t/2) - (den.h - v); if (q < p) {v += p - q}
  1548. svg.Add(BBOX.RECT(t/2,t/2,W+2*t),0,a);
  1549. }
  1550. svg.Align(num,values.numalign,t,u);
  1551. svg.Align(den,values.denomalign,t,-v);
  1552. }
  1553. svg.Clean();
  1554. this.SVGhandleColor(svg);
  1555. this.SVGsaveData(svg);
  1556. return svg;
  1557. },
  1558. SVGcanStretch: function (direction) {return false},
  1559. SVGhandleSpace: function (svg) {
  1560. if (!this.texWithDelims) {
  1561. svg.x = (this.useMMLspacing ? 0 : SVG.length2em(this.texSpacing()||0)) + 120;
  1562. svg.X = 120;
  1563. }
  1564. }
  1565. });
  1566. MML.msqrt.Augment({
  1567. toSVG: function () {
  1568. this.SVGgetStyles();
  1569. var svg = this.SVG(); this.SVGhandleSpace(svg);
  1570. var base = this.SVGchildSVG(0), rule, surd;
  1571. var scale = this.SVGgetScale();
  1572. var t = SVG.TeX.rule_thickness * scale, p,q, H, x = 0;
  1573. if (this.Get("displaystyle")) {p = SVG.TeX.x_height * scale} else {p = t}
  1574. q = Math.max(t + p/4,1000*SVG.TeX.min_root_space/SVG.em);
  1575. H = base.h + base.d + q + t;
  1576. surd = SVG.createDelimiter(0x221A,H,scale);
  1577. if (surd.h + surd.d > H) {q = ((surd.h+surd.d) - (H-t)) / 2}
  1578. rule = BBOX.RECT(t,0,base.w);
  1579. H = base.h + q + t;
  1580. x = this.SVGaddRoot(svg,surd,x,surd.h+surd.d-H,scale);
  1581. svg.Add(surd,x,H-surd.h);
  1582. svg.Add(rule,x+surd.w,H-rule.h);
  1583. svg.Add(base,x+surd.w,0);
  1584. svg.Clean();
  1585. svg.h += t; svg.H += t;
  1586. this.SVGhandleColor(svg);
  1587. this.SVGsaveData(svg);
  1588. return svg;
  1589. },
  1590. SVGaddRoot: function (svg,surd,x,d,scale) {return x}
  1591. });
  1592. MML.mroot.Augment({
  1593. toSVG: MML.msqrt.prototype.toSVG,
  1594. SVGaddRoot: function (svg,surd,x,d,scale) {
  1595. var dx = (surd.isMultiChar ? .55 : .65) * surd.w;
  1596. if (this.data[1]) {
  1597. var root = this.data[1].toSVG(); root.x = 0;
  1598. var h = this.SVGrootHeight(surd.h+surd.d,scale,root)-d;
  1599. var w = Math.min(root.w,root.r); // remove extra right-hand padding, if any
  1600. x = Math.max(w,dx);
  1601. svg.Add(root,x-w,h);
  1602. } else {dx = x}
  1603. return x - dx;
  1604. },
  1605. SVGrootHeight: function (d,scale,root) {
  1606. return .45*(d-900*scale) + 600*scale + Math.max(0,root.d-75);
  1607. }
  1608. });
  1609. MML.mfenced.Augment({
  1610. SVG: BBOX.ROW,
  1611. toSVG: function () {
  1612. this.SVGgetStyles();
  1613. var svg = this.SVG();
  1614. this.SVGhandleSpace(svg);
  1615. if (this.data.open) {svg.Check(this.data.open)}
  1616. if (this.data[0] != null) {svg.Check(this.data[0])}
  1617. for (var i = 1, m = this.data.length; i < m; i++) {
  1618. if (this.data[i]) {
  1619. if (this.data["sep"+i]) {svg.Check(this.data["sep"+i])}
  1620. svg.Check(this.data[i]);
  1621. }
  1622. }
  1623. if (this.data.close) {svg.Check(this.data.close)}
  1624. svg.Stretch(); svg.Clean();
  1625. this.SVGhandleColor(svg);
  1626. this.SVGsaveData(svg);
  1627. return svg;
  1628. }
  1629. });
  1630. MML.menclose.Augment({toSVG: MML.mbase.SVGautoload});
  1631. MML.maction.Augment({toSVG: MML.mbase.SVGautoload});
  1632. MML.semantics.Augment({
  1633. toSVG: function () {
  1634. this.SVGgetStyles();
  1635. var svg = this.SVG();
  1636. if (this.data[0] != null) {
  1637. this.SVGhandleSpace(svg);
  1638. svg.Add(this.data[0].toSVG()); svg.Clean();
  1639. } else {svg.Clean()}
  1640. this.SVGsaveData(svg);
  1641. return svg;
  1642. },
  1643. SVGstretchH: function (w) {
  1644. return (this.data[0] != null ? this.data[0].SVGstretchH(w) : BBOX.NULL());
  1645. },
  1646. SVGstretchV: function (h,d) {
  1647. return (this.data[0] != null ? this.data[0].SVGstretchV(h,d) : BBOX.NULL());
  1648. }
  1649. });
  1650. MML.munderover.Augment({
  1651. toSVG: function (HW,D) {
  1652. this.SVGgetStyles();
  1653. var values = this.getValues("displaystyle","accent","accentunder","align");
  1654. if (!values.displaystyle && this.data[this.base] != null &&
  1655. this.data[this.base].CoreMO().Get("movablelimits"))
  1656. {return MML.msubsup.prototype.toSVG.call(this)}
  1657. var svg = this.SVG();
  1658. this.SVGhandleSpace(svg);
  1659. var scale = svg.scale = this.SVGgetScale();
  1660. var boxes = [], stretch = [], box, i, m, W = -SVG.BIGDIMEN, WW = W;
  1661. for (i = 0, m = this.data.length; i < m; i++) {
  1662. if (this.data[i] != null) {
  1663. if (i == this.base) {
  1664. boxes[i] = this.SVGdataStretched(i,HW,D);
  1665. stretch[i] = (D != null || HW == null) && this.data[i].SVGcanStretch("Horizontal");
  1666. } else {
  1667. boxes[i] = this.data[i].toSVG();
  1668. stretch[i] = this.data[i].SVGcanStretch("Horizontal");
  1669. }
  1670. if (boxes[i].w > WW) {WW = boxes[i].w}
  1671. if (!stretch[i] && WW > W) {W = WW}
  1672. }
  1673. }
  1674. if (D == null && HW != null) {W = HW} else if (W == -SVG.BIGDIMEN) {W = WW}
  1675. for (i = WW = 0, m = this.data.length; i < m; i++) {if (this.data[i]) {
  1676. if (stretch[i]) {boxes[i] = this.data[i].SVGstretchH(W)}
  1677. if (boxes[i].w > WW) {WW = boxes[i].w}
  1678. }}
  1679. var t = SVG.TeX.rule_thickness;
  1680. var base = boxes[this.base] || {w:0, h:0, d:0, H:0, D:0, l:0, r:0, scale:scale};
  1681. var x, y, z1, z2, z3, dw, k, delta = 0;
  1682. if (base.ic) {delta = 1.3*base.ic + .05} // adjust faked IC to be more in line with expeted results
  1683. for (i = 0, m = this.data.length; i < m; i++) {
  1684. if (this.data[i] != null) {
  1685. box = boxes[i];
  1686. z3 = SVG.TeX.big_op_spacing5 * scale;
  1687. var accent = (i != this.base && values[this.ACCENTS[i]]);
  1688. if (accent && box.w <= 1) {
  1689. box.x = -box.l;
  1690. boxes[i] = BBOX.G().With({removeable: false});
  1691. boxes[i].Add(box); boxes[i].Clean();
  1692. boxes[i].w = -box.l; box = boxes[i];
  1693. }
  1694. dw = {left:0, center:(WW-box.w)/2, right:WW-box.w}[values.align];
  1695. x = dw; y = 0;
  1696. if (i == this.over) {
  1697. if (accent) {
  1698. k = t * scale; z3 = 0;
  1699. if (base.skew) {x += base.skew}
  1700. } else {
  1701. z1 = SVG.TeX.big_op_spacing1 * scale;
  1702. z2 = SVG.TeX.big_op_spacing3 * scale;
  1703. k = Math.max(z1,z2-Math.max(0,box.d));
  1704. }
  1705. k = Math.max(k,1500/SVG.em);
  1706. x += delta/2; y = base.h + box.d + k;
  1707. box.h += z3; if (box.h > box.H) {box.H = box.h}
  1708. } else if (i == this.under) {
  1709. if (accent) {
  1710. k = 3*t * scale; z3 = 0;
  1711. } else {
  1712. z1 = SVG.TeX.big_op_spacing2 * scale;
  1713. z2 = SVG.TeX.big_op_spacing4 * scale;
  1714. k = Math.max(z1,z2-box.h);
  1715. }
  1716. k = Math.max(k,1500/SVG.em);
  1717. x -= delta/2; y = -(base.d + box.h + k);
  1718. box.d += z3; if (box.d > box.D) {box.D = box.d}
  1719. }
  1720. svg.Add(box,x,y);
  1721. }
  1722. }
  1723. svg.Clean();
  1724. this.SVGhandleColor(svg);
  1725. this.SVGsaveData(svg);
  1726. return svg;
  1727. }
  1728. });
  1729. MML.msubsup.Augment({
  1730. toSVG: function (HW,D) {
  1731. this.SVGgetStyles();
  1732. var svg = this.SVG();
  1733. this.SVGhandleSpace(svg);
  1734. var scale = svg.scale = this.SVGgetScale(), mu = this.SVGgetMu(svg);
  1735. var base = svg.Add(this.SVGdataStretched(this.base,HW,D));
  1736. var sscale = (this.data[this.sup] || this.data[this.sub] || this).SVGgetScale();
  1737. var x_height = SVG.TeX.x_height * scale, s = SVG.TeX.scriptspace * scale;
  1738. var sup, sub;
  1739. if (this.SVGnotEmpty(this.data[this.sup])) {
  1740. sup = this.data[this.sup].toSVG();
  1741. sup.w += s; sup.r = Math.max(sup.w,sup.r);
  1742. }
  1743. if (this.SVGnotEmpty(this.data[this.sub])) {
  1744. sub = this.data[this.sub].toSVG();
  1745. sub.w += s; sub.r = Math.max(sub.w,sub.r);
  1746. }
  1747. var q = SVG.TeX.sup_drop * sscale, r = SVG.TeX.sub_drop * sscale;
  1748. var u = base.h+(base.y||0) - q, v = base.d-(base.y||0) + r, delta = 0, p;
  1749. if (base.ic) {
  1750. base.w -= base.ic; // remove IC (added by mo and mi)
  1751. delta = 1.3*base.ic+.05; // adjust faked IC to be more in line with expeted results
  1752. }
  1753. if (this.data[this.base] &&
  1754. (this.data[this.base].type === "mi" || this.data[this.base].type === "mo")) {
  1755. if (this.data[this.base].data.join("").length === 1 && base.scale === 1 &&
  1756. !base.stretched && !this.data[this.base].Get("largeop")) {u = v = 0}
  1757. }
  1758. var min = this.getValues("subscriptshift","superscriptshift");
  1759. min.subscriptshift = (min.subscriptshift === "" ? 0 : SVG.length2em(min.subscriptshift,mu));
  1760. min.superscriptshift = (min.superscriptshift === "" ? 0 : SVG.length2em(min.superscriptshift,mu));
  1761. if (!sup) {
  1762. if (sub) {
  1763. v = Math.max(v,SVG.TeX.sub1*scale,sub.h-(4/5)*x_height,min.subscriptshift);
  1764. svg.Add(sub,base.w,-v); this.data[this.sub].SVGdata.dy = -v;
  1765. }
  1766. } else {
  1767. if (!sub) {
  1768. values = this.getValues("displaystyle","texprimestyle");
  1769. p = SVG.TeX[(values.displaystyle ? "sup1" : (values.texprimestyle ? "sup3" : "sup2"))];
  1770. u = Math.max(u,p*scale,sup.d+(1/4)*x_height,min.superscriptshift);
  1771. svg.Add(sup,base.w+delta,u);
  1772. this.data[this.sup].SVGdata.dx = delta;
  1773. this.data[this.sup].SVGdata.dy = u;
  1774. } else {
  1775. v = Math.max(v,SVG.TeX.sub2*scale);
  1776. var t = SVG.TeX.rule_thickness * scale;
  1777. if ((u - sup.d) - (sub.h - v) < 3*t) {
  1778. v = 3*t - u + sup.d + sub.h;
  1779. q = (4/5)*x_height - (u - sup.d);
  1780. if (q > 0) {u += q; v -= q}
  1781. }
  1782. svg.Add(sup,base.w+delta,Math.max(u,min.superscriptshift));
  1783. svg.Add(sub,base.w,-Math.max(v,min.subscriptshift));
  1784. this.data[this.sup].SVGdata.dx = delta;
  1785. this.data[this.sup].SVGdata.dy = Math.max(u,min.superscriptshift);
  1786. this.data[this.sub].SVGdata.dy = -Math.max(v,min.subscriptshift);
  1787. }
  1788. }
  1789. svg.Clean();
  1790. this.SVGhandleColor(svg);
  1791. this.SVGsaveData(svg);
  1792. return svg;
  1793. }
  1794. });
  1795. MML.mmultiscripts.Augment({toSVG: MML.mbase.SVGautoload});
  1796. MML.mtable.Augment({toSVG: MML.mbase.SVGautoload});
  1797. MML["annotation-xml"].Augment({toSVG: MML.mbase.SVGautoload});
  1798. MML.math.Augment({
  1799. SVG: BBOX.Subclass({type:"svg", removeable: false}),
  1800. toSVG: function (span,div) {
  1801. if (this.data[0]) {
  1802. this.SVGgetStyles();
  1803. MML.mbase.prototype.displayAlign = HUB.config.displayAlign;
  1804. MML.mbase.prototype.displayIndent = HUB.config.displayIndent;
  1805. //
  1806. // Put content in a <g> with defaults and matrix that flips y axis.
  1807. // Put that in an <svg> with xlink defined.
  1808. //
  1809. var box = BBOX.G({
  1810. stroke:"black", fill:"black", "stroke-width":0,
  1811. transform: "matrix(1 0 0 -1 0 0)"
  1812. }).With({removeable: false});
  1813. box.Add(this.data[0].toSVG(),0,0,true); box.Clean();
  1814. this.SVGhandleColor(box);
  1815. var svg = this.SVG(); svg.element.setAttribute("xmlns:xlink",XLINKNS);
  1816. svg.Add(box); svg.Clean();
  1817. this.SVGsaveData(svg);
  1818. //
  1819. // Style the <svg> to get the right size and placement
  1820. //
  1821. var l = Math.max(-svg.l,0), r = Math.max(svg.r-svg.w,0);
  1822. var style = svg.element.style;
  1823. style.width = SVG.Ex(l+svg.w+r);
  1824. style.height = SVG.Ex(svg.H+svg.D+2*SVG.em);
  1825. style.verticalAlign = SVG.Ex(-svg.D-3*SVG.em); // remove 2 extra pixels added below plus padding
  1826. style.marginLeft = SVG.Ex(-l); style.marginRight = SVG.Ex(-r);
  1827. svg.element.setAttribute("viewBox",(-l)+" "+(-svg.H-SVG.em)+" "+(l+svg.w+r)+" "+(svg.H+svg.D+2*SVG.em));
  1828. svg.element.style.margin="1px 0px"; // 1px above and below to prevent lines from touching
  1829. //
  1830. // If there is extra height or depth, hide that
  1831. //
  1832. if (svg.H > svg.h || svg.D > svg.d) {
  1833. var frame = HTML.Element(
  1834. "span",{style: {display:"inline-block", "white-space":"nowrap", padding:"1px 0px"}, isMathJax:true},[[
  1835. "span",{style: {display:"inline-block", position:"relative", isMathJax:true,
  1836. width:SVG.Ex(svg.w), height:SVG.Ex(svg.h+svg.d),
  1837. "vertical-align":SVG.Ex(-svg.d)}}]]);
  1838. frame.firstChild.appendChild(svg.element); svg.element = frame;
  1839. style.verticalAlign = style.margin = ""; style.position = "absolute";
  1840. style.bottom = SVG.Ex(svg.d-svg.D); style.left = 0;
  1841. }
  1842. //
  1843. // Add it to the MathJax span
  1844. //
  1845. span.appendChild(svg.element); svg.element = null;
  1846. //
  1847. // Handle indentalign and indentshift for single-line displays
  1848. //
  1849. if (!this.isMultiline && this.Get("display") === "block") {
  1850. var values = this.getValues("indentalignfirst","indentshiftfirst","indentalign","indentshift");
  1851. if (values.indentalignfirst !== MML.INDENTALIGN.INDENTALIGN) {values.indentalign = values.indentalignfirst}
  1852. if (values.indentalign === MML.INDENTALIGN.AUTO) {values.indentalign = this.displayAlign}
  1853. div.style.textAlign = values.indentalign;
  1854. if (values.indentshiftfirst !== MML.INDENTSHIFT.INDENTSHIFT) {values.indentshift = values.indentshiftfirst}
  1855. if (values.indentshift === "auto") {values.indentshift = this.displayIndent}
  1856. if (values.indentshift && values.indentalign !== MML.INDENTALIGN.CENTER && !svg.hasIndent) {
  1857. span.style[{left:"marginLeft",right:"marginRight"}[values.indentalign]] =
  1858. SVG.Ex(SVG.length2em(values.indentshift));
  1859. }
  1860. }
  1861. }
  1862. return span;
  1863. }
  1864. });
  1865. MML.TeXAtom.Augment({
  1866. toSVG: function () {
  1867. this.SVGgetStyles();
  1868. var svg = this.SVG();
  1869. this.SVGhandleSpace(svg);
  1870. if (this.data[0] != null) {
  1871. var box = this.data[0].toSVG(), y = 0;
  1872. if (this.texClass === MML.TEXCLASS.VCENTER) {
  1873. // FIXME: should the axis height be scaled?
  1874. y = SVG.TeX.axis_height - (box.h+box.d)/2 + box.d;
  1875. }
  1876. svg.Add(box,0,y);
  1877. svg.ic = box.ic;
  1878. }
  1879. this.SVGhandleColor(svg);
  1880. this.SVGsaveData(svg);
  1881. return svg;
  1882. }
  1883. });
  1884. //
  1885. // Loading isn't complete until the element jax is modified,
  1886. // but can't call loadComplete within the callback for "mml Jax Ready"
  1887. // (it would call SVG's Require routine, asking for the mml jax again)
  1888. // so wait until after the mml jax has finished processing.
  1889. //
  1890. // We also need to wait for the onload handler to run, since the loadComplete
  1891. // will call Config and Startup, which need to modify the body.
  1892. //
  1893. HUB.Register.StartupHook("onLoad",function () {
  1894. setTimeout(MathJax.Callback(["loadComplete",SVG,"jax.js"]),0);
  1895. });
  1896. });
  1897. HUB.Browser.Select({
  1898. Opera: function (browser) {
  1899. SVG.Augment({
  1900. operaZoomRefresh: true // Opera needs a kick to redraw zoomed equations
  1901. });
  1902. }
  1903. });
  1904. HUB.Register.StartupHook("End Cookie", function () {
  1905. if (HUB.config.menuSettings.zoom !== "None")
  1906. {AJAX.Require("[MathJax]/extensions/MathZoom.js")}
  1907. });
  1908. if (!document.createElementNS) {
  1909. //
  1910. // Try to handle SVG in IE8 and below, but fail
  1911. // (but don't crash on loading the file, so no delay for loadComplete)
  1912. //
  1913. if (!document.namespaces.svg) {document.namespaces.add("svg",SVGNS)}
  1914. SVG.Augment({
  1915. Element: function (type,def) {
  1916. var obj = (typeof(type) === "string" ? document.createElement("svg:"+type) : type);
  1917. obj.isMathJax = true;
  1918. if (def) {for (var id in def) {if (def.hasOwnProperty(id)) {obj.setAttribute(id,def[id].toString())}}}
  1919. return obj;
  1920. }
  1921. });
  1922. }
  1923. })(MathJax.Ajax, MathJax.Hub, MathJax.HTML, MathJax.OutputJax.SVG);