jax.js 92 KB

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