jax.js 87 KB

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