jax.js (137667B)
1 /* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 4 /************************************************************* 5 * 6 * MathJax/jax/output/HTML-CSS/jax.js 7 * 8 * Implements the HTML-CSS OutputJax that displays mathematics 9 * using HTML and CSS to position the characters from math fonts 10 * in their proper locations. 11 * 12 * --------------------------------------------------------------------- 13 * 14 * Copyright (c) 2009-2015 The MathJax Consortium 15 * 16 * Licensed under the Apache License, Version 2.0 (the "License"); 17 * you may not use this file except in compliance with the License. 18 * You may obtain a copy of the License at 19 * 20 * http://www.apache.org/licenses/LICENSE-2.0 21 * 22 * Unless required by applicable law or agreed to in writing, software 23 * distributed under the License is distributed on an "AS IS" BASIS, 24 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 25 * See the License for the specific language governing permissions and 26 * limitations under the License. 27 */ 28 29 (function (AJAX,HUB,HTMLCSS) { 30 var MML, isMobile = HUB.Browser.isMobile; 31 32 var MESSAGE = function () { 33 var data = [].slice.call(arguments,0); 34 data[0][0] = ["HTML-CSS",data[0][0]]; 35 return MathJax.Message.Set.apply(MathJax.Message,data); 36 }; 37 38 var FONTTEST = MathJax.Object.Subclass({ 39 timeout: (isMobile? 15:8)*1000, // timeout for loading web fonts 40 comparisonFont: ["sans-serif","monospace","script","Times","Courier","Arial","Helvetica"], 41 testSize: ["40px","50px","60px","30px","20px"], 42 // 43 // Fedora aliases STIXSizeOneSym to STIX Word, so MathJax thinks STIX is 44 // available, but the fonts aren't actually correct. This is to test if 45 // STIXSizeOneSym has letters in it (so is actually STIX Word). 46 // 47 FedoraSTIXcheck: {family:"STIXSizeOneSym", testString:"abcABC", noStyleChar:true}, 48 49 Init: function () { 50 // 51 // Wrap the Font_Test DIV in a 0x0 DIV so that it takes no room 52 // 53 this.div = MathJax.HTML.addElement(document.body,"div",{style: { 54 position:"absolute", width:0, height:0, overflow:"hidden", 55 padding:0, border:0, margin:0 56 }},[["div",{ 57 id: "MathJax_Font_Test", 58 style: {position:"absolute", visibility:"hidden", top:0, left:0, width: "auto", 59 padding:0, border:0, margin:0, whiteSpace:"nowrap", 60 textAlign:"left", textIndent:0, textTransform:"none", 61 lineHeight:"normal", letterSpacing:"normal", wordSpacing:"normal", 62 fontSize:this.testSize[0], fontWeight:"normal", fontStyle:"normal", 63 fontSizeAdjust:"none"} 64 },[""]]] 65 ).firstChild; 66 this.text = this.div.firstChild; 67 }, 68 69 findFont: function (fonts,pref) { 70 var found = null; 71 if (pref && this.testCollection(pref)) { 72 found = pref; 73 } else { 74 for (var i = 0, m = fonts.length; i < m; i++) { 75 if (fonts[i] === pref) continue; 76 if (this.testCollection(fonts[i])) {found = fonts[i]; break} 77 } 78 } 79 if (found === "STIX" && this.testFont(this.FedoraSTIXcheck)) {found = null} 80 return found; 81 }, 82 83 testCollection: function (name) { 84 var font = {testString: "() {} []"}; 85 font.family = {TeX:"MathJax_Size1", STIX:"STIXSizeOneSym"}[name] || 86 name.replace(/-(Math)?/,"")+"MathJax_Size1"; 87 if (name === "STIX") {font.noStyleChar = true} 88 return this.testFont(font); 89 }, 90 91 testFont: function (font) { 92 if (font.isWebFont && HTMLCSS.FontFaceBug) { 93 this.div.style.fontWeight = this.div.style.fontStyle = "normal"; 94 } else { 95 this.div.style.fontWeight = (font.weight||"normal"); 96 this.div.style.fontStyle = (font.style||"normal"); 97 } 98 // 99 // Hack: Fix up web font names for local access. 100 // (The names for Windows and Mac are different, unlike in the STIX and 101 // TeX fonts, so we have to work out a list of names here.) 102 // 103 // This should be removed when the web fonts are fixed. FIXME 104 // 105 var family = font.familyFixed || font.family; 106 if (!font.isWebFont && !family.match(/^(STIX|MathJax)|'/)) { 107 family = family.replace(/_/g," ").replace(/([a-z])([A-Z])/g,"$1 $2").replace(/ Jax/,"Jax") 108 + "','" + family + "','" + family + "-"; 109 if (font.weight) {family += "Bold"}; if (font.style) {family += "Italic"} 110 if (!font.weight && !font.style) {family += "Regular"} 111 font.familyFixed = family = "'"+family+"'" 112 } 113 114 var W = this.getComparisonWidths(font.testString,font.noStyleChar); 115 var found = null; 116 if (W) { 117 this.div.style.fontFamily = family+","+this.comparisonFont[0]; 118 if (this.div.offsetWidth == W[0]) { 119 this.div.style.fontFamily = family+","+this.comparisonFont[W[2]]; 120 if (this.div.offsetWidth == W[1]) {found = false} 121 } 122 if (found === null && (this.div.offsetWidth != W[3] || this.div.offsetHeight != W[4])) { 123 if (!font.noStyleChar && HTMLCSS.FONTDATA && HTMLCSS.FONTDATA.hasStyleChar) { 124 for (var i = 0, m = this.testSize.length; i < m; i++) 125 {if (this.testStyleChar(font,this.testSize[i])) {found = true; m = 0}} 126 } else {found = true} 127 } 128 } 129 if (HTMLCSS.safariTextNodeBug) {this.div.innerHTML = ""} else {this.text.nodeValue = ""} 130 return found; 131 }, 132 133 styleChar: "\uEFFD", // width encodes style 134 versionChar: "\uEFFE", // width encodes version 135 compChar: "\uEFFF", // "standard" width to compare to 136 137 testStyleChar: function (font,size) { 138 var n = 3 + (font.weight ? 2 : 0) + (font.style ? 4 : 0); 139 var extra = "", dw = 0; 140 var SIZE = this.div.style.fontSize; this.div.style.fontSize = size; 141 if (HTMLCSS.msieItalicWidthBug && font.style === "italic") { 142 this.text.nodeValue = extra = this.compChar; 143 dw = this.div.offsetWidth; 144 } 145 if (HTMLCSS.safariTextNodeBug) {this.div.innerHTML = this.compChar+extra} 146 else {this.text.nodeValue = this.compChar+extra} 147 var W = this.div.offsetWidth-dw; 148 if (HTMLCSS.safariTextNodeBug) {this.div.innerHTML = this.styleChar+extra} 149 else {this.text.nodeValue = this.styleChar+extra} 150 var N = Math.floor((this.div.offsetWidth-dw)/W+.5); 151 if (N === n) { 152 if (HTMLCSS.safariTextNodeBug) {this.div.innerHTML = this.versionChar+extra} 153 else {this.text.nodeValue = this.versionChar+extra} 154 font.version = Math.floor((this.div.offsetWidth-dw)/W+1.5)/2; 155 } 156 this.div.style.fontSize = SIZE; 157 return (N === n); 158 }, 159 160 getComparisonWidths: function (string,noStyleChar) { 161 if (HTMLCSS.FONTDATA && HTMLCSS.FONTDATA.hasStyleChar && !noStyleChar) 162 {string += this.styleChar + " " + this.compChar} 163 if (HTMLCSS.safariTextNodeBug) {this.div.innerHTML = string} 164 else {this.text.nodeValue = string} 165 this.div.style.fontFamily = this.comparisonFont[0]; 166 var W = this.div.offsetWidth; 167 this.div.style.fontFamily = HTMLCSS.webFontDefault; 168 var sW = this.div.offsetWidth, sH = this.div.offsetHeight; 169 for (var i = 1, m = this.comparisonFont.length; i < m; i++) { 170 this.div.style.fontFamily = this.comparisonFont[i]; 171 if (this.div.offsetWidth != W) {return [W,this.div.offsetWidth,i,sW,sH]} 172 } 173 return null; 174 }, 175 176 loadWebFont: function (font) { 177 HUB.Startup.signal.Post("HTML-CSS Jax - Web-Font "+HTMLCSS.fontInUse+"/"+font.directory); 178 var n = MESSAGE(["LoadWebFont","Loading web-font %1",HTMLCSS.fontInUse+"/"+font.directory]); 179 var done = MathJax.Callback({}); // called when font is loaded 180 var callback = MathJax.Callback(["loadComplete",this,font,n,done]); 181 AJAX.timer.start(AJAX,[this.checkWebFont,font,callback],0,this.timeout); 182 return done; 183 }, 184 loadComplete: function (font,n,done,status) { 185 MathJax.Message.Clear(n); 186 if (status === AJAX.STATUS.OK) {this.webFontLoaded = true; done(); return} 187 this.loadError(font); 188 if (HUB.Browser.isFirefox && HTMLCSS.allowWebFonts) { 189 var host = document.location.protocol + "//" + document.location.hostname; 190 if (document.location.port != "") {host += ":" + document.location.port} 191 host += "/"; 192 if (AJAX.fileURL(HTMLCSS.webfontDir).substr(0,host.length) !== host) 193 {this.firefoxFontError(font)} 194 } 195 if (!this.webFontLoaded) {HTMLCSS.loadWebFontError(font,done)} else {done()} 196 }, 197 loadError: function (font) { 198 MESSAGE(["CantLoadWebFont","Can't load web font %1",HTMLCSS.fontInUse+"/"+font.directory],null,2000); 199 HUB.Startup.signal.Post(["HTML-CSS Jax - web font error",HTMLCSS.fontInUse+"/"+font.directory,font]); 200 }, 201 firefoxFontError: function (font) { 202 MESSAGE(["FirefoxCantLoadWebFont","Firefox can't load web fonts from a remote host"],null,3000); 203 HUB.Startup.signal.Post("HTML-CSS Jax - Firefox web fonts on remote host error"); 204 }, 205 206 checkWebFont: function (check,font,callback) { 207 if (check.time(callback)) return; 208 if (HTMLCSS.Font.testFont(font)) {callback(check.STATUS.OK)} 209 else {setTimeout(check,check.delay)} 210 }, 211 212 fontFace: function (name) { 213 var type = HTMLCSS.allowWebFonts; 214 var FONT = HTMLCSS.FONTDATA.FONTS[name]; 215 if (HTMLCSS.msieFontCSSBug && !FONT.family.match(/-Web$/)) {FONT.family += "-Web"} 216 if (FONT.isWebFont) delete FONT.familyFixed; 217 var webfonts = HTMLCSS.webfontDir+"/"+type; 218 var dir = AJAX.fileURL(webfonts); 219 var fullname = name.replace(/-b/,"-B").replace(/-i/,"-I").replace(/-Bold-/,"-Bold"); 220 if (!fullname.match(/-/)) {fullname += "-Regular"} 221 if (type === "svg") {fullname += ".svg#"+fullname} else {fullname += "."+type} 222 var rev = AJAX.fileRev(webfonts+"/"+fullname.replace(/#.*/,"")); 223 var def = { 224 "font-family": FONT.family, 225 src: "url('"+dir+"/"+fullname+rev+"')" 226 }; 227 if (type === "otf") { 228 fullname = fullname.replace(/otf$/,"woff"); 229 rev = AJAX.fileRev(webfonts+"/"+fullname); 230 def.src += " format('opentype')"; 231 dir = AJAX.fileURL(HTMLCSS.webfontDir+"/woff"); // add woff fonts as well 232 def.src = "url('"+dir+"/"+fullname+rev+"') format('woff'), "+def.src; 233 } else if (type !== "eot") {def.src += " format('"+type+"')"} 234 if (!(HTMLCSS.FontFaceBug && FONT.isWebFont)) { 235 if (name.match(/-bold/)) {def["font-weight"] = "bold"} 236 if (name.match(/-italic/)) {def["font-style"] = "italic"} 237 } 238 return def; 239 } 240 }); 241 242 var EVENT, TOUCH, HOVER; // filled in later 243 244 HTMLCSS.Augment({ 245 config: { 246 styles: { 247 ".MathJax": { 248 "display": "inline", 249 "font-style": "normal", 250 "font-weight": "normal", 251 "line-height": "normal", 252 "font-size": "100%", 253 "font-size-adjust":"none", 254 "text-indent": 0, 255 "text-align": "left", 256 "text-transform": "none", 257 "letter-spacing": "normal", 258 "word-spacing": "normal", 259 "word-wrap": "normal", 260 "white-space": "nowrap", 261 "float": "none", 262 "direction": "ltr", 263 "max-width": "none", "max-height": "none", 264 "min-width": 0, "min-height": 0, 265 border: 0, padding: 0, margin: 0 266 }, 267 268 // Focus elements for keyboard tabbing. 269 ".MathJax:focus, body :focus .MathJax": { 270 display:"inline-table" // see issues #1282 and #1338 271 }, 272 273 ".MathJax_Display": { 274 position: "relative", 275 display: "block!important", 276 "text-indent": 0, 277 "max-width": "none", "max-height": "none", 278 "min-width": 0, "min-height": 0, 279 width: "100%" 280 }, 281 282 ".MathJax img, .MathJax nobr, .MathJax a": { 283 border: 0, padding: 0, margin: 0, 284 "max-width": "none", "max-height": "none", 285 "min-width": 0, "min-height": 0, 286 "vertical-align": 0, "line-height": "normal", 287 "text-decoration": "none" 288 }, 289 "img.MathJax_strut": { 290 border:"0!important", padding:"0!important", margin:"0!important", 291 "vertical-align": "0!important" 292 }, 293 294 ".MathJax span": { 295 display: "inline", position: "static", 296 border: 0, padding: 0, margin: 0, 297 "vertical-align": 0, "line-height": "normal", 298 "text-decoration": "none" 299 }, 300 301 ".MathJax nobr": { 302 "white-space": "nowrap!important" 303 }, 304 305 ".MathJax img": { 306 display: "inline!important", 307 "float": "none!important" 308 }, 309 310 ".MathJax *": { 311 transition: "none", 312 "-webkit-transition": "none", 313 "-moz-transition": "none", 314 "-ms-transition": "none", 315 "-o-transition": "none" 316 }, 317 318 ".MathJax_Processing": { 319 visibility: "hidden", position:"fixed", 320 width: 0, height: 0, overflow:"hidden" 321 }, 322 ".MathJax_Processed": {display:"none!important"}, 323 324 ".MathJax_ExBox": { 325 display:"block!important", overflow:"hidden", 326 width:"1px", height:"60ex", 327 "min-height": 0, "max-height":"none" 328 }, 329 ".MathJax .MathJax_EmBox": { 330 display:"block!important", overflow:"hidden", 331 width:"1px", height:"60em", 332 "min-height": 0, "max-height":"none" 333 }, 334 335 ".MathJax .MathJax_HitBox": { 336 cursor: "text", 337 background: "white", 338 opacity:0, filter:"alpha(opacity=0)" 339 }, 340 ".MathJax .MathJax_HitBox *": { 341 filter: "none", opacity:1, background:"transparent" // for IE 342 }, 343 344 "#MathJax_Tooltip": { 345 position: "absolute", left: 0, top: 0, 346 width: "auto", height: "auto", 347 display: "none" 348 }, 349 "#MathJax_Tooltip *": { 350 filter: "none", opacity:1, background:"transparent" // for IE 351 }, 352 353 // 354 // Used for testing web fonts against the default font used while 355 // web fonts are loading 356 // 357 "@font-face": { 358 "font-family": "MathJax_Blank", 359 "src": "url('about:blank')" 360 } 361 362 } 363 }, 364 settings: HUB.config.menuSettings, 365 366 Font: null, // created by Config() below 367 webFontDefault: "MathJax_Blank", 368 allowWebFonts: "otf", // assume browser can use OTF web fonts 369 370 maxStretchyParts: 1000, // limit the number of parts allowed for 371 // stretchy operators. See issue 366. 372 373 fontName: { 374 TeXLocal: "TeX", 375 TeXWeb: ["","TeX"], 376 TeXImage: ["",""], 377 STIXLocal: ["STIX","STIX-Web"], 378 STIXWeb: "STIX-Web", 379 AsanaMathWeb: "Asana-Math", 380 GyrePagellaWeb: "Gyre-Pagella", 381 GyreTermesWeb: "Gyre-Termes", 382 LatinModernWeb: "Latin-Modern", 383 NeoEulerWeb: "Neo-Euler" 384 }, 385 386 fontInUse: "generic", 387 FONTDATA: { 388 TeX_factor: 1, baselineskip: 1.2, lineH: .8, lineD: .2, ffLineH: .8, 389 FONTS: {}, 390 VARIANT: {"normal": {fonts:[]}, "-generic-variant": {}, "-largeOp": {}, "-smallOp": {}}, 391 RANGES: [], DELIMITERS: {}, RULECHAR: 0x2D, REMAP: {} 392 }, 393 394 Config: function () { 395 if (!this.require) {this.require = []} 396 this.Font = FONTTEST(); this.SUPER(arguments).Config.call(this); 397 var settings = this.settings, config = this.config, font = settings.font; 398 if (this.adjustAvailableFonts) {this.adjustAvailableFonts(config.availableFonts)} 399 if (settings.scale) {config.scale = settings.scale} 400 if (font && font !== "Auto" && this.fontName[font]) { 401 config.availableFonts = []; delete config.fonts; 402 if (this.fontName[font] instanceof Array) { 403 config.preferredFont = this.fontName[font][0]; 404 config.webFont = this.fontName[font][1]; 405 } else { 406 config.preferredFont = config.webFont = this.fontName[font]; 407 } 408 if (config.preferredFont) {config.availableFonts[0] = config.preferredFont} 409 } 410 if (config.fonts) { 411 config.availableFonts = config.fonts; 412 config.preferredFont = config.webFont = config.fonts[0]; 413 if (config.webFont === "STIX") {config.webFont += "-Web"} 414 } 415 font = this.Font.findFont(config.availableFonts,config.preferredFont); 416 if (!font && this.allowWebFonts) {font = config.webFont; if (font) {this.webFonts = true}} 417 if (!font && this.config.imageFont) {font = config.imageFont; this.imgFonts = true} 418 if (font) { 419 this.fontInUse = font; this.fontDir += "/" + font; this.webfontDir += "/" + font; 420 this.require.push(this.fontDir+"/fontdata.js"); 421 if (this.imgFonts) { 422 this.require.push(this.directory+"/imageFonts.js"); 423 HUB.Startup.signal.Post("HTML-CSS Jax - using image fonts"); 424 } 425 } else { 426 MESSAGE(["CantFindFontUsing","Can't find a valid font using %1", 427 "["+this.config.availableFonts.join(", ")+"]"],null,3000); 428 HUB.Startup.signal.Post("HTML-CSS Jax - no valid font"); 429 } 430 this.require.push(MathJax.OutputJax.extensionDir+"/MathEvents.js"); 431 }, 432 433 Startup: function () { 434 // Set up event handling 435 EVENT = MathJax.Extension.MathEvents.Event; 436 TOUCH = MathJax.Extension.MathEvents.Touch; 437 HOVER = MathJax.Extension.MathEvents.Hover; 438 this.ContextMenu = EVENT.ContextMenu; 439 this.Mousedown = EVENT.AltContextMenu; 440 this.Mouseover = HOVER.Mouseover; 441 this.Mouseout = HOVER.Mouseout; 442 this.Mousemove = HOVER.Mousemove; 443 444 // Make hidden div for when math is in a display:none block 445 this.hiddenDiv = this.Element("div",{ 446 style:{visibility:"hidden", overflow:"hidden", position:"absolute", top:0, 447 height:"1px", width: "auto", padding:0, border:0, margin:0, 448 textAlign:"left", textIndent:0, textTransform:"none", 449 lineHeight:"normal", letterSpacing:"normal", wordSpacing:"normal"} 450 }); 451 if (!document.body.firstChild) {document.body.appendChild(this.hiddenDiv)} 452 else {document.body.insertBefore(this.hiddenDiv,document.body.firstChild)} 453 this.hiddenDiv = this.addElement(this.hiddenDiv,"div",{id:"MathJax_Hidden"}); 454 455 // Determine pixels per inch 456 var div = this.addElement(this.hiddenDiv,"div",{style:{width:"5in"}}); 457 this.pxPerInch = div.offsetWidth/5; this.hiddenDiv.removeChild(div); 458 459 // Markers used by getW 460 this.startMarker = this.createStrut(this.Element("span"),10,true); 461 this.endMarker = this.addText(this.Element("span"),"x").parentNode; 462 463 // Used in getHD 464 this.HDspan = this.Element("span"); 465 if (this.operaHeightBug) {this.createStrut(this.HDspan,0)} 466 if (this.msieInlineBlockAlignBug) { 467 this.HDimg = this.addElement(this.HDspan,"img",{style:{height:"0px", width:"1px"}}); 468 try {this.HDimg.src = "about:blank"} catch(err) {} 469 } else { 470 this.HDimg = this.createStrut(this.HDspan,0); 471 } 472 473 // Used in preTranslate to get scaling factors 474 this.EmExSpan = this.Element("span", 475 {style:{position:"absolute","font-size-adjust":"none"}}, 476 [ 477 ["span",{className:"MathJax_ExBox"}], 478 ["span",{className:"MathJax"}, 479 [["span",{className:"MathJax_EmBox"}]] 480 ] 481 ] 482 ); 483 484 // Used in preTranslate to get linebreak width 485 this.linebreakSpan = this.Element("span",null, 486 [["hr",{style: {width:"100%", size:1, padding:0, border:0, margin:0}}]]); 487 488 // Set up styles and preload web fonts 489 return AJAX.Styles(this.config.styles,["InitializeHTML",this]); 490 }, 491 492 removeSTIXfonts: function (fonts) { 493 // 494 // Opera doesn't display large chunks of the STIX fonts, and 495 // Safari/Windows doesn't display Plane1, 496 // so disable STIX for these browsers. 497 // 498 // ### FIXME ### Do we need to disable the other web fonts for these? 499 // 500 for (var i = 0, m = fonts.length; i < m; i++) 501 {if (fonts[i] === "STIX") {fonts.splice(i,1); m--; i--;}} 502 if (this.config.preferredFont === "STIX") {this.config.preferredFont = fonts[0]} 503 }, 504 505 PreloadWebFonts: function () { 506 if (!HTMLCSS.allowWebFonts || !HTMLCSS.config.preloadWebFonts) return; 507 for (var i = 0, m = HTMLCSS.config.preloadWebFonts.length; i < m; i++) { 508 var FONT = HTMLCSS.FONTDATA.FONTS[HTMLCSS.config.preloadWebFonts[i]]; 509 if (!FONT.available) {HTMLCSS.Font.testFont(FONT)} 510 } 511 }, 512 513 // 514 // Handle initialization that requires styles to be set up 515 // 516 InitializeHTML: function () { 517 this.PreloadWebFonts(); 518 this.getDefaultExEm(); 519 // 520 // If the defaultEm size is zero, it might be that a web font hasn't 521 // arrived yet, so try to wait for it, but don't wait too long. 522 // 523 if (this.defaultEm) return; 524 var ready = MathJax.Callback(); 525 AJAX.timer.start(AJAX,function (check) { 526 if (check.time(ready)) {HUB.signal.Post(["HTML-CSS Jax - no default em size"]); return} 527 HTMLCSS.getDefaultExEm(); 528 if (HTMLCSS.defaultEm) {ready()} else {setTimeout(check,check.delay)} 529 },this.defaultEmDelay,this.defaultEmTimeout); 530 return ready; 531 }, 532 defaultEmDelay: 100, // initial delay when checking for defaultEm 533 defaultEmTimeout: 1000, // when to stop looking for defaultEm 534 getDefaultExEm: function () { 535 // 536 // Get the default sizes (need styles in place to do this) 537 // 538 document.body.appendChild(this.EmExSpan); 539 document.body.appendChild(this.linebreakSpan); 540 this.defaultEx = this.EmExSpan.firstChild.offsetHeight/60; 541 this.defaultEm = this.EmExSpan.lastChild.firstChild.offsetHeight/60; 542 this.defaultWidth = this.linebreakSpan.firstChild.offsetWidth; 543 document.body.removeChild(this.linebreakSpan); 544 document.body.removeChild(this.EmExSpan); 545 }, 546 547 preTranslate: function (state) { 548 var scripts = state.jax[this.id], i, m = scripts.length, n, 549 script, prev, span, div, test, jax, ex, em, scale, maxwidth, relwidth = false, cwidth, 550 linebreak = this.config.linebreaks.automatic, width = this.config.linebreaks.width; 551 if (linebreak) { 552 relwidth = (width.match(/^\s*(\d+(\.\d*)?%\s*)?container\s*$/) != null); 553 if (relwidth) {width = width.replace(/\s*container\s*/,"")} 554 else {maxwidth = this.defaultWidth} 555 if (width === "") {width = "100%"} 556 } else {maxwidth = 100000} // a big width, so no implicit line breaks 557 // 558 // Loop through the scripts 559 // 560 for (i = 0; i < m; i++) { 561 script = scripts[i]; if (!script.parentNode) continue; 562 // 563 // Remove any existing output 564 // 565 prev = script.previousSibling; 566 if (prev && String(prev.className).match(/^MathJax(_Display)?( MathJax_Processing)?$/)) 567 {prev.parentNode.removeChild(prev)} 568 // 569 // Add the span, and a div if in display mode, 570 // then set the role and mark it as being processed 571 // 572 jax = script.MathJax.elementJax; if (!jax) continue; 573 jax.HTMLCSS = {display: (jax.root.Get("display") === "block")} 574 span = div = this.Element("span",{ 575 className:"MathJax", id:jax.inputID+"-Frame", isMathJax:true, jaxID:this.id, 576 oncontextmenu:EVENT.Menu, onmousedown: EVENT.Mousedown, 577 onmouseover:EVENT.Mouseover, onmouseout:EVENT.Mouseout, 578 onmousemove:EVENT.Mousemove, onclick:EVENT.Click, 579 ondblclick:EVENT.DblClick, 580 // Added for keyboard accessible menu. 581 onkeydown: EVENT.Keydown, tabIndex: HUB.getTabOrder(jax) 582 }); 583 if (HUB.Browser.noContextMenu) { 584 span.ontouchstart = TOUCH.start; 585 span.ontouchend = TOUCH.end; 586 } 587 if (jax.HTMLCSS.display) { 588 div = this.Element("div",{className:"MathJax_Display"}); 589 div.appendChild(span); 590 } else if (this.msieDisappearingBug) {span.style.display = "inline-block"} 591 div.className += " MathJax_Processing"; 592 script.parentNode.insertBefore(div,script); 593 // 594 // Add the test span for determining scales and linebreak widths 595 // 596 script.parentNode.insertBefore(this.EmExSpan.cloneNode(true),script); 597 div.parentNode.insertBefore(this.linebreakSpan.cloneNode(true),div) 598 } 599 // 600 // Determine the scaling factors for each script 601 // (this only requires one reflow rather than a reflow for each equation) 602 // Record any that need to be hidden (don't move them now, since that 603 // would cause reflows). 604 // 605 var hidden = []; 606 for (i = 0; i < m; i++) { 607 script = scripts[i]; if (!script.parentNode) continue; 608 test = script.previousSibling; div = test.previousSibling; 609 jax = script.MathJax.elementJax; if (!jax) continue; 610 ex = test.firstChild.offsetHeight/60; 611 em = test.lastChild.firstChild.offsetHeight/60; 612 cwidth = div.previousSibling.firstChild.offsetWidth; 613 if (relwidth) {maxwidth = cwidth} 614 if (ex === 0 || ex === "NaN") { 615 // can't read width, so move to hidden div for processing 616 hidden.push(div); 617 jax.HTMLCSS.isHidden = true; 618 ex = this.defaultEx; em = this.defaultEm; cwidth = this.defaultWidth; 619 if (relwidth) {maxwidth = cwidth} 620 } 621 scale = (this.config.matchFontHeight ? ex/this.TeX.x_height/em : 1); 622 scale = Math.floor(Math.max(this.config.minScaleAdjust/100,scale)*this.config.scale); 623 jax.HTMLCSS.scale = scale/100; jax.HTMLCSS.fontSize = scale+"%"; 624 jax.HTMLCSS.em = jax.HTMLCSS.outerEm = em; this.em = em * scale/100; jax.HTMLCSS.ex = ex; 625 jax.HTMLCSS.cwidth = cwidth/this.em; 626 jax.HTMLCSS.lineWidth = (linebreak ? this.length2em(width,1,maxwidth/this.em) : 1000000); 627 } 628 for (i = 0, n = hidden.length; i < n; i++) { 629 this.hiddenDiv.appendChild(hidden[i]); 630 this.addElement(this.hiddenDiv,"br"); 631 } 632 // 633 // Remove the test spans used for determining scales and linebreak widths 634 // 635 for (i = 0; i < m; i++) { 636 script = scripts[i]; if (!script.parentNode) continue; 637 test = scripts[i].previousSibling; 638 jax = scripts[i].MathJax.elementJax; if (!jax) continue; 639 span = test.previousSibling; 640 if (!jax.HTMLCSS.isHidden) {span = span.previousSibling} 641 span.parentNode.removeChild(span); 642 test.parentNode.removeChild(test); 643 } 644 // 645 // Set state variables used for displaying equations in chunks 646 // 647 state.HTMLCSSeqn = state.HTMLCSSlast = 0; state.HTMLCSSi = -1; 648 state.HTMLCSSchunk = this.config.EqnChunk; 649 state.HTMLCSSdelay = false; 650 }, 651 652 PHASE: {I: 1, II: 2, III: 3}, // processing phases 653 654 Translate: function (script,state) { 655 if (!script.parentNode) return; 656 657 // 658 // If we are supposed to do a chunk delay, do it 659 // 660 if (state.HTMLCSSdelay) { 661 state.HTMLCSSdelay = false; 662 HUB.RestartAfter(MathJax.Callback.Delay(this.config.EqnChunkDelay)); 663 } 664 665 // 666 // Get the data about the math 667 // 668 var jax = script.MathJax.elementJax, math = jax.root, 669 span = document.getElementById(jax.inputID+"-Frame"), 670 div = (jax.HTMLCSS.display ? (span||{}).parentNode : span); 671 if (!div) return; 672 // 673 // Set the font metrics 674 // 675 this.getMetrics(jax); 676 if (this.scale !== 1) {span.style.fontSize = jax.HTMLCSS.fontSize} 677 // 678 // Typeset the math 679 // 680 this.initImg(span); 681 this.initHTML(math,span); 682 this.savePreview(script); 683 try { 684 math.setTeXclass(); 685 jax.HTMLCSS.span = span; jax.HTMLCSS.div = div; // save for phase II and III 686 math.toHTML(span,div,this.PHASE.I); 687 } catch (err) { 688 if (err.restart) {while (span.firstChild) {span.removeChild(span.firstChild)}} 689 this.restorePreview(script); 690 throw err; 691 } 692 this.restorePreview(script); 693 // 694 // Remove the processing marker, and signal the new math pending 695 // 696 div.className = div.className.split(/ /)[0] + " MathJax_Processed"; 697 HUB.signal.Post(["New Math Pending",jax.inputID]); // FIXME: wait for this? (i.e., restart if returns uncalled callback) 698 // 699 // Check if we should show this chunk of equations 700 // 701 state.HTMLCSSeqn += (state.i - state.HTMLCSSi); state.HTMLCSSi = state.i; 702 if (state.HTMLCSSeqn >= state.HTMLCSSlast + state.HTMLCSSchunk) { 703 this.postTranslate(state,true); 704 state.HTMLCSSchunk = Math.floor(state.HTMLCSSchunk*this.config.EqnChunkFactor); 705 state.HTMLCSSdelay = true; // delay if there are more scripts 706 } 707 return false; 708 }, 709 // 710 // MathML previews can contain the same ID's as the HTML output, 711 // which confuses HTMLspanElement(), so remove the preview temporarily 712 // and restore it after typesetting the math. 713 // 714 savePreview: function (script) { 715 var preview = script.MathJax.preview; 716 if (preview) { 717 script.MathJax.tmpPreview = document.createElement("span"); 718 preview.parentNode.replaceChild(script.MathJax.tmpPreview,preview); 719 } 720 }, 721 restorePreview: function (script) { 722 var tmpPreview = script.MathJax.tmpPreview; 723 if (tmpPreview) { 724 tmpPreview.parentNode.replaceChild(script.MathJax.preview,tmpPreview); 725 delete script.MathJax.tmpPreview; 726 } 727 }, 728 // 729 // Get the jax metric information 730 // 731 getMetrics: function(jax) { 732 var data = jax.HTMLCSS; 733 this.em = MML.mbase.prototype.em = data.em * data.scale; 734 this.outerEm = data.em; 735 this.scale = data.scale; 736 this.cwidth = data.cwidth; 737 this.linebreakWidth = data.lineWidth; 738 }, 739 740 postTranslate: function (state,partial) { 741 var scripts = state.jax[this.id], script, jax, i, m; 742 // 743 // Remove the processed markers so that measuring can occur, 744 // and remove the preview, if any, since the math will now be visible. 745 // 746 for (i = state.HTMLCSSlast, m = state.HTMLCSSeqn; i < m; i++) { 747 script = scripts[i]; 748 if (script && script.MathJax.elementJax) { 749 var div = script.MathJax.elementJax.HTMLCSS.div; 750 div.className = div.className.split(/ /)[0]; 751 if (script.MathJax.preview) {script.MathJax.preview.innerHTML = ""} 752 } 753 } 754 // 755 // Measure the math in this chunk (toHTML phase II) 756 // 757 for (i = state.HTMLCSSlast, m = state.HTMLCSSeqn; i < m; i++) { 758 script = scripts[i]; 759 if (script && script.MathJax.elementJax) { 760 jax = script.MathJax.elementJax; this.getMetrics(jax); 761 jax.root.toHTML(jax.HTMLCSS.span,jax.HTMLCSS.div,this.PHASE.II); 762 } 763 } 764 // 765 // Reveal this chunk of math 766 // 767 for (i = state.HTMLCSSlast, m = state.HTMLCSSeqn; i < m; i++) { 768 script = scripts[i]; 769 if (script && script.MathJax.elementJax) { 770 // 771 // Finish the math with its measured size (toHTML phase III) 772 // 773 jax = script.MathJax.elementJax; this.getMetrics(jax); 774 jax.root.toHTML(jax.HTMLCSS.span,jax.HTMLCSS.div,this.PHASE.III); 775 if (jax.HTMLCSS.isHidden) script.parentNode.insertBefore(jax.HTMLCSS.div,script); 776 delete jax.HTMLCSS.span; delete jax.HTMLCSS.div; 777 // 778 // The math is now fully processed 779 // 780 script.MathJax.state = jax.STATE.PROCESSED; 781 HUB.signal.Post(["New Math",script.MathJax.elementJax.inputID]); // FIXME: wait for this? (i.e., restart if returns uncalled callback) 782 } 783 } 784 if (this.forceReflow) { 785 // WebKit can misplace some elements that should wrap to the next line 786 // but gets them right on a reflow, so force reflow by toggling a stylesheet 787 var sheet = (document.styleSheets||[])[0]||{}; 788 sheet.disabled = true; sheet.disabled = false; 789 } 790 // 791 // Save our place so we know what is revealed 792 // 793 state.HTMLCSSlast = state.HTMLCSSeqn; 794 }, 795 796 getJaxFromMath: function (math) { 797 if (math.parentNode.className === "MathJax_Display") {math = math.parentNode} 798 do {math = math.nextSibling} while (math && math.nodeName.toLowerCase() !== "script"); 799 return HUB.getJaxFor(math); 800 }, 801 getHoverSpan: function (jax,math) {return jax.root.HTMLspanElement()}, 802 getHoverBBox: function (jax,span,math) { 803 var bbox = span.bbox, em = jax.HTMLCSS.outerEm; 804 var BBOX = {w:bbox.w*em, h:bbox.h*em, d:bbox.d*em}; 805 if (bbox.width) {BBOX.width = bbox.width} 806 return BBOX; 807 }, 808 809 Zoom: function (jax,span,math,Mw,Mh) { 810 // 811 // Re-render at larger size 812 // 813 span.className = "MathJax"; 814 span.style.fontSize = jax.HTMLCSS.fontSize; 815 816 // 817 // get em sizes (taken from HTMLCSS.preTranslate) 818 // 819 var emex = span.appendChild(this.EmExSpan.cloneNode(true)); 820 var em = emex.lastChild.firstChild.offsetHeight/60; 821 this.em = MML.mbase.prototype.em = em; 822 this.outerEm = em / jax.HTMLCSS.scale; 823 emex.parentNode.removeChild(emex); 824 this.scale = jax.HTMLCSS.scale; 825 this.linebreakWidth = jax.HTMLCSS.lineWidth; 826 this.cwidth = jax.HTMLCSS.cwidth; 827 828 this.zoomScale = parseInt(HUB.config.menuSettings.zscale) / 100; 829 this.idPostfix = "-zoom"; jax.root.toHTML(span,span); this.idPostfix = ""; 830 this.zoomScale = 1; 831 832 var bbox = jax.root.HTMLspanElement().bbox, width = bbox.width; 833 if (width) { 834 // Handle full-width displayed equations 835 if (bbox.tw) {Mw = bbox.tw*em} 836 if (bbox.w*em < Mw) {Mw = bbox.w*em} 837 span.style.width = Math.floor(Mw-1.5*HTMLCSS.em)+"px"; span.style.display="inline-block"; 838 var id = (jax.root.id||"MathJax-Span-"+jax.root.spanID)+"-zoom"; 839 var child = document.getElementById(id).firstChild; 840 while (child && child.style.width !== width) {child = child.nextSibling} 841 if (child) { 842 var cwidth = child.offsetWidth; child.style.width = "100%"; 843 if (cwidth > Mw) {span.style.width = (cwidth+100)+"px"} 844 } 845 } 846 // 847 // Adjust margins to prevent overlaps at the edges 848 // 849 child = span.firstChild.firstChild.style; 850 if (bbox.H != null && bbox.H > bbox.h) 851 {child.marginTop = HTMLCSS.Em(bbox.H-Math.max(bbox.h,HTMLCSS.FONTDATA.lineH))} 852 if (bbox.D != null && bbox.D > bbox.d) 853 {child.marginBottom = HTMLCSS.Em(bbox.D-Math.max(bbox.d,HTMLCSS.FONTDATA.lineD))} 854 if (bbox.lw < 0) {child.paddingLeft = HTMLCSS.Em(-bbox.lw)} 855 if (bbox.rw > bbox.w) {child.marginRight = HTMLCSS.Em(bbox.rw-bbox.w)} 856 // 857 // Get height and width of zoomed math and original math 858 // 859 span.style.position = "absolute"; 860 if (!width) {math.style.position = "absolute"} 861 var zW = span.offsetWidth, zH = span.offsetHeight, 862 mH = math.offsetHeight, mW = math.offsetWidth; 863 span.style.position = math.style.position = ""; 864 // 865 return {Y:-EVENT.getBBox(span).h, mW:mW, mH:mH, zW:zW, zH:zH}; 866 }, 867 868 initImg: function (span) {}, 869 initHTML: function (math,span) {}, 870 initFont: function (name) { 871 var FONTS = HTMLCSS.FONTDATA.FONTS, AVAIL = HTMLCSS.config.availableFonts; 872 if (AVAIL && AVAIL.length && HTMLCSS.Font.testFont(FONTS[name])) { 873 FONTS[name].available = true; 874 if (FONTS[name].familyFixed) { 875 FONTS[name].family = FONTS[name].familyFixed; 876 delete FONTS[name].familyFixed; 877 } 878 return null; 879 } 880 if (!this.allowWebFonts) {return null} 881 FONTS[name].isWebFont = true; 882 if (HTMLCSS.FontFaceBug) { 883 FONTS[name].family = name; 884 if (HTMLCSS.msieFontCSSBug) {FONTS[name].family += "-Web"} 885 } 886 return AJAX.Styles({"@font-face":this.Font.fontFace(name)}); 887 }, 888 889 Remove: function (jax) { 890 var span = document.getElementById(jax.inputID+"-Frame"); 891 if (span) { 892 if (jax.HTMLCSS.display) {span = span.parentNode} 893 span.parentNode.removeChild(span); 894 } 895 delete jax.HTMLCSS; 896 }, 897 898 getHD: function (span,force) { 899 if (span.bbox && this.config.noReflows && !force) {return {h:span.bbox.h, d:span.bbox.d}} 900 var position = span.style.position; 901 span.style.position = "absolute"; 902 this.HDimg.style.height = "0px"; 903 span.appendChild(this.HDspan); 904 var HD = {h:span.offsetHeight}; 905 this.HDimg.style.height = HD.h+"px"; 906 HD.d = span.offsetHeight - HD.h; HD.h -= HD.d; 907 HD.h /= this.em; HD.d /= this.em; 908 span.removeChild(this.HDspan); 909 span.style.position = position; 910 return HD; 911 }, 912 getW: function (span) { 913 var W, H, w = (span.bbox||{}).w, start = span; 914 if (span.bbox && this.config.noReflows && span.bbox.exactW !== false) { 915 if (!span.bbox.exactW) { 916 if (span.style.paddingLeft) w += this.unEm(span.style.paddingLeft)*(span.scale||1); 917 if (span.style.paddingRight) w += this.unEm(span.style.paddingRight)*(span.scale||1); 918 } 919 return w; 920 } 921 if (span.bbox && span.bbox.exactW) {return w} 922 if ((span.bbox && w >= 0 && !this.initialSkipBug && !this.msieItalicWidthBug) || 923 this.negativeBBoxes || !span.firstChild) { 924 W = span.offsetWidth; H = span.parentNode.offsetHeight; 925 } else if (span.bbox && w < 0 && this.msieNegativeBBoxBug) { 926 W = -span.offsetWidth, H = span.parentNode.offsetHeight; 927 } else { 928 // IE can't deal with a space at the beginning, so put something else first 929 var position = span.style.position; span.style.position = "absolute"; 930 start = this.startMarker; span.insertBefore(start,span.firstChild) 931 span.appendChild(this.endMarker); 932 W = this.endMarker.offsetLeft - start.offsetLeft; 933 span.removeChild(this.endMarker); 934 span.removeChild(start); span.style.position = position 935 } 936 if (H != null) {span.parentNode.HH = H/this.em} 937 return W/this.em; 938 }, 939 Measured: function (span,parent) { 940 var bbox = span.bbox; 941 if (bbox.width == null && bbox.w && !bbox.isMultiline) { 942 var w = this.getW(span); 943 bbox.rw += w - bbox.w; 944 bbox.w = w; bbox.exactW = true; 945 } 946 if (!parent) {parent = span.parentNode} 947 if (!parent.bbox) {parent.bbox = bbox} 948 return span; 949 }, 950 Remeasured: function (span,parent) { 951 parent.bbox = this.Measured(span,parent).bbox; 952 }, 953 MeasureSpans: function (SPANS) { 954 var spans = [], span, i, m, bbox, start, end, W, parent; 955 // 956 // Insert the needed markers 957 // 958 for (i = 0, m = SPANS.length; i < m; i++) { 959 span = SPANS[i]; if (!span) continue; 960 bbox = span.bbox; parent = this.parentNode(span); 961 if (bbox.exactW || bbox.width || bbox.w === 0 || bbox.isMultiline || 962 (this.config.noReflows && bbox.exactW !== false)) { 963 if (!parent.bbox) {parent.bbox = bbox} 964 continue; 965 } 966 if (this.negativeBBoxes || !span.firstChild || (bbox.w >= 0 && !this.initialSkipBug) || 967 (bbox.w < 0 && this.msieNegativeBBoxBug)) { 968 spans.push([span]); 969 } else if (this.initialSkipBug) { 970 start = this.startMarker.cloneNode(true); end = this.endMarker.cloneNode(true); 971 span.insertBefore(start,span.firstChild); span.appendChild(end); 972 spans.push([span,start,end,span.style.position]); span.style.position = "absolute"; 973 } else { 974 end = this.endMarker.cloneNode(true); 975 span.appendChild(end); spans.push([span,null,end]); 976 } 977 } 978 // 979 // Read the widths and heights 980 // 981 for (i = 0, m = spans.length; i < m; i++) { 982 span = spans[i][0]; bbox = span.bbox; parent = this.parentNode(span); 983 if ((bbox.w >= 0 && !this.initialSkipBug) || this.negativeBBoxes || !span.firstChild) { 984 W = span.offsetWidth; parent.HH = parent.offsetHeight/this.em; 985 } else if (bbox.w < 0 && this.msieNegativeBBoxBug) { 986 W = -span.offsetWidth, parent.HH = parent.offsetHeight/this.em; 987 } else { 988 W = spans[i][2].offsetLeft - ((spans[i][1]||{}).offsetLeft||0); 989 } 990 W /= this.em; 991 bbox.rw += W - bbox.w; 992 bbox.w = W; bbox.exactW = true; 993 if (!parent.bbox) {parent.bbox = bbox} 994 } 995 // 996 // Remove markers 997 // 998 for (i = 0, m = spans.length; i < m; i++) { 999 span = spans[i]; 1000 if (span[1]) {span[1].parentNode.removeChild(span[1]), span[0].style.position = span[3]} 1001 if (span[2]) {span[2].parentNode.removeChild(span[2])} 1002 } 1003 }, 1004 1005 Em: function (m) { 1006 if (Math.abs(m) < .0006) {return "0em"} 1007 return m.toFixed(3).replace(/\.?0+$/,"") + "em"; 1008 }, 1009 EmRounded: function (m) { 1010 m = (Math.round(m*HTMLCSS.em)+.05)/HTMLCSS.em; 1011 if (Math.abs(m) < .0006) {return "0em"} 1012 return m.toFixed(3).replace(/\.?0+$/,"") + "em"; 1013 }, 1014 unEm: function (m) { 1015 return parseFloat(m); 1016 }, 1017 Px: function (m) { 1018 m *= this.em; var s = (m < 0? "-" : ""); 1019 return s+Math.abs(m).toFixed(1).replace(/\.?0+$/,"") + "px"; 1020 }, 1021 unPx: function (m) { 1022 return parseFloat(m)/this.em; 1023 }, 1024 Percent: function (m) { 1025 return (100*m).toFixed(1).replace(/\.?0+$/,"") + "%"; 1026 }, 1027 length2em: function (length,mu,size) { 1028 if (typeof(length) !== "string") {length = length.toString()} 1029 if (length === "") {return ""} 1030 if (length === MML.SIZE.NORMAL) {return 1} 1031 if (length === MML.SIZE.BIG) {return 2} 1032 if (length === MML.SIZE.SMALL) {return .71} 1033 if (length === "infinity") {return HTMLCSS.BIGDIMEN} 1034 var factor = this.FONTDATA.TeX_factor, emFactor = (HTMLCSS.zoomScale||1) / HTMLCSS.em; 1035 if (length.match(/mathspace$/)) {return HTMLCSS.MATHSPACE[length]*factor} 1036 var match = length.match(/^\s*([-+]?(?:\.\d+|\d+(?:\.\d*)?))?(pt|em|ex|mu|px|pc|in|mm|cm|%)?/); 1037 var m = parseFloat(match[1]||"1"), unit = match[2]; 1038 if (size == null) {size = 1}; if (mu == null) {mu = 1} 1039 if (unit === "em") {return m * factor} 1040 if (unit === "ex") {return m * HTMLCSS.TeX.x_height * factor} 1041 if (unit === "%") {return m / 100 * size} 1042 if (unit === "px") {return m * emFactor} 1043 if (unit === "pt") {return m / 10 * factor} // 10 pt to an em 1044 if (unit === "pc") {return m * 1.2 * factor} // 12 pt to a pc 1045 if (unit === "in") {return m * this.pxPerInch * emFactor} 1046 if (unit === "cm") {return m * this.pxPerInch * emFactor / 2.54} // 2.54 cm to an inch 1047 if (unit === "mm") {return m * this.pxPerInch * emFactor / 25.4} // 10 mm to a cm 1048 if (unit === "mu") {return m / 18 * factor * mu} // 18mu to an em for the scriptlevel 1049 return m*size; // relative to given size (or 1em as default) 1050 }, 1051 thickness2em: function (length,mu) { 1052 var thick = HTMLCSS.TeX.rule_thickness; 1053 if (length === MML.LINETHICKNESS.MEDIUM) {return thick} 1054 if (length === MML.LINETHICKNESS.THIN) {return .67*thick} 1055 if (length === MML.LINETHICKNESS.THICK) {return 1.67*thick} 1056 return this.length2em(length,mu,thick); 1057 }, 1058 1059 getPadding: function (span) { 1060 var padding = {top:0, right:0, bottom:0, left:0}, has = false; 1061 for (var id in padding) {if (padding.hasOwnProperty(id)) { 1062 var pad = span.style["padding"+id.charAt(0).toUpperCase()+id.substr(1)]; 1063 if (pad) {padding[id] = this.length2em(pad); has = true;} 1064 }} 1065 return (has ? padding : false); 1066 }, 1067 getBorders: function (span) { 1068 var border = {top:0, right:0, bottom:0, left:0}, css = {}, has = false; 1069 for (var id in border) {if (border.hasOwnProperty(id)) { 1070 var ID = "border"+id.charAt(0).toUpperCase()+id.substr(1); 1071 var style = span.style[ID+"Style"]; 1072 if (style) { 1073 has = true; 1074 border[id] = this.length2em(span.style[ID+"Width"]); 1075 css[ID] = [span.style[ID+"Width"],span.style[ID+"Style"],span.style[ID+"Color"]].join(" "); 1076 } 1077 }} 1078 border.css = css; 1079 return (has ? border : false); 1080 }, 1081 setBorders: function (span,borders) { 1082 if (borders) { 1083 for (var id in borders.css) {if (borders.css.hasOwnProperty(id)) { 1084 span.style[id] = borders.css[id]; 1085 }} 1086 } 1087 }, 1088 1089 createStrut: function (span,h,before) { 1090 var strut = this.Element("span",{ 1091 isMathJax: true, 1092 style:{display:"inline-block", overflow:"hidden", height:h+"px", 1093 width:"1px", marginRight:"-1px"} 1094 }); 1095 if (before) {span.insertBefore(strut,span.firstChild)} else {span.appendChild(strut)} 1096 return strut; 1097 }, 1098 createBlank: function (span,w,before) { 1099 var blank = this.Element("span",{ 1100 isMathJax: true, 1101 style: {display:"inline-block", overflow:"hidden", height:"1px", width:this.Em(w)} 1102 }); 1103 if (w < 0) {blank.style.marginRight = blank.style.width; blank.style.width = 0} 1104 if (before) {span.insertBefore(blank,span.firstChild)} else {span.appendChild(blank)} 1105 return blank; 1106 }, 1107 createShift: function (span,w,before) { 1108 var space = this.Element("span",{style:{marginLeft:this.Em(w)}, isMathJax:true}); 1109 if (before) {span.insertBefore(space,span.firstChild)} else {span.appendChild(space)} 1110 return space; 1111 }, 1112 createSpace: function (span,h,d,w,color,isSpace) { 1113 if (h < -d) {d = -h} // make sure h is above d 1114 var H = this.Em(h+d), D = this.Em(-d); 1115 if (this.msieInlineBlockAlignBug) {D = this.Em(HTMLCSS.getHD(span.parentNode,true).d-d)} 1116 if (span.isBox || isSpace) { 1117 var scale = (span.scale == null ? 1 : span.scale); 1118 span.bbox = {exactW: true, h: h*scale, d: d*scale, w: w*scale, rw: w*scale, lw: 0}; 1119 span.style.height = H; span.style.verticalAlign = D; 1120 span.HH = (h+d)*scale; 1121 } else { 1122 span = this.addElement(span,"span",{style: {height:H, verticalAlign:D}, isMathJax:true}); 1123 } 1124 if (w >= 0) { 1125 span.style.width = this.Em(w); 1126 span.style.display = "inline-block"; 1127 span.style.overflow = "hidden"; // for IE in quirks mode 1128 } else { 1129 if (this.msieNegativeSpaceBug) {span.style.height = ""} 1130 span.style.marginLeft = this.Em(w); 1131 if (HTMLCSS.safariNegativeSpaceBug && span.parentNode.firstChild == span) 1132 {this.createBlank(span,0,true)} 1133 } 1134 if (color && color !== MML.COLOR.TRANSPARENT) { 1135 span.style.backgroundColor = color; 1136 span.style.position = "relative"; // make sure it covers earlier items 1137 } 1138 return span; 1139 }, 1140 createRule: function (span,h,d,w,color) { 1141 if (h < -d) {d = -h} // make sure h is above d 1142 var min = HTMLCSS.TeX.min_rule_thickness, f = 1; 1143 // If rule is very thin, make it at least min_rule_thickness so it doesn't disappear 1144 if (w > 0 && w*this.em < min) {w = min/this.em} 1145 if (h+d > 0 && (h+d)*this.em < min) {f = 1/(h+d)*(min/this.em); h *= f; d *= f} 1146 if (!color) {color = "solid"} else {color = "solid "+color} 1147 var style = {display: "inline-block", overflow:"hidden", verticalAlign:this.Em(-d)}; 1148 if (w > h+d) { 1149 style.borderTop = this.Px(h+d)+" "+color; 1150 style.width = this.Em(w); 1151 style.height = (this.msieRuleBug && h+d > 0 ? this.Em(h+d) : 0); 1152 } else { 1153 style.borderLeft = this.Px(w)+" "+color; 1154 style.width = (this.msieRuleBug && w > 0 ? this.Em(w) : 0); 1155 style.height = this.Em(h+d); 1156 } 1157 var rule = this.addElement(span,"span",{ 1158 style: style, noAdjust:true, HH:h+d, isMathJax:true, 1159 bbox: {h:h, d:d, w:w, rw:w, lw:0, exactW:true} 1160 }); 1161 if (span.isBox || span.className == "mspace") {span.bbox = rule.bbox, span.HH = h+d} 1162 return rule; 1163 }, 1164 createFrame: function (span,h,d,w,t,style) { 1165 if (h < -d) {d = -h} // make sure h is above d 1166 var T = 2*t; 1167 if (this.msieFrameSizeBug) {if (w < T) {w = T}; if (h+d < T) {h = T-d}} 1168 if (this.msieBorderWidthBug) {T = 0} 1169 var H = this.Em(h+d-T), D = this.Em(-d-t), W = this.Em(w-T); 1170 var B = this.Px(t)+" "+style; 1171 var frame = this.addElement(span,"span",{ 1172 style: {border: B, display:"inline-block", overflow:"hidden", width:W, height:H}, 1173 bbox: {h:h, d:d, w:w, rw:w, lw:0, exactW:true}, noAdjust: true, HH:h+d, isMathJax:true 1174 }); 1175 if (D) {frame.style.verticalAlign = D} 1176 return frame; 1177 }, 1178 1179 // 1180 // Find parent span (skipping over <a> tags) 1181 // 1182 parentNode: function (span) { 1183 var parent = span.parentNode; 1184 if (parent.nodeName.toLowerCase() === "a") {parent = parent.parentNode} 1185 return parent; 1186 }, 1187 1188 createStack: function (span,nobbox,w) { 1189 if (this.msiePaddingWidthBug) {this.createStrut(span,0)} 1190 var relativeW = String(w).match(/%$/); 1191 var W = (!relativeW && w != null ? w : 0); 1192 span = this.addElement(span,"span",{ 1193 noAdjust: true, HH: 0, isMathJax: true, 1194 style: {display:"inline-block", position:"relative", 1195 width:(relativeW ? "100%" : this.Em(W)), height:0} 1196 }); 1197 if (!nobbox) { 1198 span.parentNode.bbox = span.bbox = { 1199 exactW: true, 1200 h: -this.BIGDIMEN, d: -this.BIGDIMEN, 1201 w:W, lw: this.BIGDIMEN, rw: (!relativeW && w != null ? w : -this.BIGDIMEN) 1202 }; 1203 if (relativeW) {span.bbox.width = w} 1204 } 1205 return span; 1206 }, 1207 createBox: function (span,w) { 1208 var box = this.addElement(span,"span",{style:{position:"absolute"}, isBox: true, isMathJax:true}); 1209 if (w != null) {box.style.width = w} 1210 return box; 1211 }, 1212 addBox: function (span,box) { 1213 box.style.position = "absolute"; box.isBox = box.isMathJax = true; 1214 return span.appendChild(box); 1215 }, 1216 placeBox: function (span,x,y,noclip) { 1217 span.isMathJax = true; 1218 var parent = HTMLCSS.parentNode(span), bbox = span.bbox, BBOX = parent.bbox; 1219 if (this.msiePlaceBoxBug) {this.addText(span,this.NBSP)} 1220 if (this.imgSpaceBug) {this.addText(span,this.imgSpace)} 1221 // Place the box 1222 var HH, dx = 0; 1223 if (span.HH != null) {HH = span.HH} 1224 else if (bbox) {HH = Math.max(3,bbox.h+bbox.d)} 1225 else {HH = span.offsetHeight/this.em} 1226 if (!span.noAdjust) { 1227 HH += 1; 1228 HH = Math.round(HH*this.em)/this.em; // make this an integer number of pixels (for Chrome) 1229 if (this.msieInlineBlockAlignBug) { 1230 this.addElement(span,"img",{ 1231 className:"MathJax_strut", border:0, src:"about:blank", isMathJax:true, 1232 style:{width:0,height:this.Em(HH)} 1233 }); 1234 } else { 1235 this.addElement(span,"span",{ 1236 isMathJax: true, style:{display:"inline-block",width:0,height:this.Em(HH)} 1237 }); 1238 if (HTMLCSS.chromeHeightBug) 1239 {HH -= (span.lastChild.offsetHeight - Math.round(HH*this.em))/this.em} 1240 } 1241 } 1242 // Clip so that bbox doesn't include extra height and depth 1243 if (bbox) { 1244 if (this.initialSkipBug) { 1245 if (bbox.lw < 0) {dx = bbox.lw; HTMLCSS.createBlank(span,-dx,true)} 1246 if (bbox.rw > bbox.w) {HTMLCSS.createBlank(span,bbox.rw-bbox.w+.1)} 1247 } 1248 if (!this.msieClipRectBug && !bbox.noclip && !noclip) { 1249 var dd = 3/this.em; 1250 var H = (bbox.H == null ? bbox.h : bbox.H), D = (bbox.D == null ? bbox.d : bbox.D); 1251 var t = HH - H - dd, b = HH + D + dd, l = -1000, r = bbox.rw+1000; 1252 span.style.clip = "rect("+this.Em(t)+" "+this.Em(r)+" "+this.Em(b)+" "+this.Em(l)+")"; 1253 } 1254 } 1255 // Place the box 1256 span.style.top = this.Em(-y-HH); 1257 span.style.left = this.Em(x+dx); 1258 // Update the bounding box 1259 if (bbox && BBOX) { 1260 if (bbox.H != null && (BBOX.H == null || bbox.H + y > BBOX.H)) {BBOX.H = bbox.H + y} 1261 if (bbox.D != null && (BBOX.D == null || bbox.D - y > BBOX.D)) {BBOX.D = bbox.D - y} 1262 if (bbox.h + y > BBOX.h) {BBOX.h = bbox.h + y} 1263 if (bbox.d - y > BBOX.d) {BBOX.d = bbox.d - y} 1264 if (BBOX.H != null && BBOX.H <= BBOX.h) {delete BBOX.H} 1265 if (BBOX.D != null && BBOX.D <= BBOX.d) {delete BBOX.D} 1266 if (bbox.w + x > BBOX.w) { 1267 BBOX.w = bbox.w + x; 1268 if (BBOX.width == null) {parent.style.width = this.Em(BBOX.w)} 1269 } 1270 if (bbox.rw + x > BBOX.rw) {BBOX.rw = bbox.rw + x} 1271 if (bbox.lw + x < BBOX.lw) {BBOX.lw = bbox.lw + x} 1272 if (bbox.width != null && !bbox.isFixed) { 1273 if (BBOX.width == null) { 1274 parent.style.width = BBOX.width = "100%"; 1275 if (bbox.minWidth) {parent.style.minWidth = BBOX.minWidth = bbox.minWidth} 1276 } 1277 span.style.width = bbox.width; 1278 } 1279 if (bbox.tw) {BBOX.tw = bbox.tw} 1280 } 1281 }, 1282 alignBox: function (span,align,y,dx) { 1283 if (dx == null) {dx = 0} 1284 this.placeBox(span,dx,y); // set y position (and left aligned) 1285 if (this.msiePlaceBoxBug) { 1286 // 1287 // placeBox() adds an extra , so remove it here. 1288 // 1289 var node = span.lastChild; 1290 while (node && node.nodeName !== "#text") {node = node.previousSibling} 1291 if (node) {span.removeChild(node)} 1292 } 1293 var bbox = span.bbox; if (bbox.isMultiline) return; 1294 var isRelative = bbox.width != null && !bbox.isFixed; 1295 var r = 0, c = dx-bbox.w/2, l = "50%"; 1296 if (this.initialSkipBug) {r = bbox.w-bbox.rw-.1; c += bbox.lw} 1297 if (this.msieMarginScaleBug) {c = (c*this.em) + "px"} else {c = this.Em(c)} 1298 if (isRelative) { 1299 c = (dx === 0 ? "" : this.Em(dx)); 1300 l = (50 - parseFloat(bbox.width)/2) + "%"; 1301 } 1302 HUB.Insert(span.style,({ 1303 right: {left:"", right: this.Em(r-dx)}, 1304 center: {left:l, marginLeft: c} 1305 })[align]); 1306 }, 1307 setStackWidth: function (span,w) { 1308 if (typeof(w) === "number") { 1309 span.style.width = this.Em(Math.max(0,w)); 1310 var bbox = span.bbox; if (bbox) {bbox.w = w; bbox.exactW = true}; 1311 bbox = span.parentNode.bbox; if (bbox) {bbox.w = w; bbox.exactW = true}; 1312 } else { 1313 span.style.width = span.parentNode.style.width = "100%"; 1314 if (span.bbox) {span.bbox.width = w} 1315 if (span.parentNode.bbox) {span.parentNode.bbox.width = w} 1316 } 1317 }, 1318 1319 createDelimiter: function (span,code,HW,scale,font) { 1320 if (!code) { 1321 span.bbox = {h:0, d:0, w:this.TeX.nulldelimiterspace, lw: 0}; 1322 span.bbox.rw = span.bbox.w; 1323 this.createSpace(span,span.bbox.h,span.bbox.d,span.bbox.w); 1324 return; 1325 } 1326 if (!scale) {scale = 1}; 1327 if (!(HW instanceof Array)) {HW = [HW,HW]} 1328 var hw = HW[1]; HW = HW[0]; 1329 var delim = {alias: code}; 1330 while (delim.alias) { 1331 code = delim.alias; delim = this.FONTDATA.DELIMITERS[code]; 1332 if (!delim) {delim = {HW: [0,this.FONTDATA.VARIANT[MML.VARIANT.NORMAL]]}} 1333 } 1334 if (delim.load) {HUB.RestartAfter(AJAX.Require(this.fontDir+"/fontdata-"+delim.load+".js"))} 1335 for (var i = 0, m = delim.HW.length; i < m; i++) { 1336 if (delim.HW[i][0]*scale >= HW-.01 || (i == m-1 && !delim.stretch)) { 1337 if (delim.HW[i][2]) {scale *= delim.HW[i][2]} 1338 if (delim.HW[i][3]) {code = delim.HW[i][3]} 1339 var chr = this.addElement(span,"span"); 1340 this.createChar(chr,[code,delim.HW[i][1]],scale,font); 1341 span.bbox = chr.bbox; 1342 span.offset = .65 * span.bbox.w; 1343 span.scale = scale; 1344 return; 1345 } 1346 } 1347 if (delim.stretch) {this["extendDelimiter"+delim.dir](span,hw,delim.stretch,scale,font)} 1348 }, 1349 extendDelimiterV: function (span,H,delim,scale,font) { 1350 var stack = this.createStack(span,true); 1351 var top = this.createBox(stack), bot = this.createBox(stack); 1352 this.createChar(top,(delim.top||delim.ext),scale,font); 1353 this.createChar(bot,(delim.bot||delim.ext),scale,font); 1354 var ext = {bbox:{w:0,lw:0,rw:0}}, mid = ext, EXT; 1355 var h = top.bbox.h + top.bbox.d + bot.bbox.h + bot.bbox.d; 1356 var y = -top.bbox.h; this.placeBox(top,0,y,true); y -= top.bbox.d; 1357 if (delim.mid) { 1358 mid = this.createBox(stack); this.createChar(mid,delim.mid,scale,font); 1359 h += mid.bbox.h + mid.bbox.d; 1360 } 1361 if (delim.min && H < h*delim.min) {H = h*delim.min} 1362 if (H > h) { 1363 ext = this.Element("span"); this.createChar(ext,delim.ext,scale,font); 1364 var eH = ext.bbox.h + ext.bbox.d, eh = eH - .05, n, N, k = (delim.mid ? 2 : 1); 1365 N = n = Math.min(Math.ceil((H-h)/(k*eh)), this.maxStretchyParts); 1366 if (!delim.fullExtenders) {eh = (H-h)/(k*n)} 1367 var dy = (n/(n+1))*(eH - eh); eh = eH - dy; y += dy + eh - ext.bbox.h; 1368 while (k-- > 0) { 1369 while (n-- > 0) { 1370 if (!this.msieCloneNodeBug) {EXT = ext.cloneNode(true)} 1371 else {EXT = this.Element("span"); this.createChar(EXT,delim.ext,scale,font)} 1372 EXT.bbox = ext.bbox; 1373 y -= eh; this.placeBox(this.addBox(stack,EXT),0,y,true); 1374 } 1375 y += dy - ext.bbox.d; 1376 if (delim.mid && k) { 1377 this.placeBox(mid,0,y-mid.bbox.h,true); n = N; 1378 y += -(mid.bbox.h + mid.bbox.d) + dy + eh - ext.bbox.h; 1379 } 1380 } 1381 } else { 1382 y += (h - H)/2; 1383 if (delim.mid) {this.placeBox(mid,0,y-mid.bbox.h,true); y += -(mid.bbox.h + mid.bbox.d)} 1384 y += (h - H)/2; 1385 } 1386 this.placeBox(bot,0,y-bot.bbox.h,true); y -= bot.bbox.h + bot.bbox.d; 1387 span.bbox = { 1388 w: Math.max(top.bbox.w,ext.bbox.w,bot.bbox.w,mid.bbox.w), 1389 lw: Math.min(top.bbox.lw,ext.bbox.lw,bot.bbox.lw,mid.bbox.lw), 1390 rw: Math.max(top.bbox.rw,ext.bbox.rw,bot.bbox.rw,mid.bbox.rw), 1391 h: 0, d: -y, exactW: true 1392 } 1393 span.scale = scale; 1394 span.offset = .55 * span.bbox.w; 1395 span.isMultiChar = true; 1396 this.setStackWidth(stack,span.bbox.w); 1397 }, 1398 extendDelimiterH: function (span,W,delim,scale,font) { 1399 var stack = this.createStack(span,true); 1400 var left = this.createBox(stack), right = this.createBox(stack); 1401 this.createChar(left,(delim.left||delim.rep),scale,font); 1402 this.createChar(right,(delim.right||delim.rep),scale,font); 1403 var rep = this.Element("span"); this.createChar(rep,delim.rep,scale,font); 1404 var mid = {bbox: {h:-this.BIGDIMEN, d:-this.BIGDIMEN}}, REP; 1405 this.placeBox(left,-left.bbox.lw,0,true); 1406 var w = (left.bbox.rw - left.bbox.lw) + (right.bbox.rw - right.bbox.lw) - .05, 1407 x = left.bbox.rw - left.bbox.lw - .025, dx; 1408 if (delim.mid) { 1409 mid = this.createBox(stack); this.createChar(mid,delim.mid,scale,font); 1410 w += mid.bbox.w; 1411 } 1412 if (delim.min && W < w*delim.min) {W = w*delim.min} 1413 if (W > w) { 1414 var rW = rep.bbox.rw-rep.bbox.lw, rw = rW - .05, n, N, k = (delim.mid ? 2 : 1); 1415 N = n = Math.min(Math.ceil((W-w)/(k*rw)), this.maxStretchyParts); 1416 if (!delim.fillExtenders) {rw = (W-w)/(k*n)} 1417 dx = (n/(n+1))*(rW - rw); rw = rW - dx; x -= rep.bbox.lw + dx; 1418 while (k-- > 0) { 1419 while (n-- > 0) { 1420 if (!this.cloneNodeBug) {REP = rep.cloneNode(true)} 1421 else {REP = this.Element("span"); this.createChar(REP,delim.rep,scale,font)} 1422 REP.bbox = rep.bbox; 1423 this.placeBox(this.addBox(stack,REP),x,0,true); x += rw; 1424 } 1425 if (delim.mid && k) {this.placeBox(mid,x,0,true); x += mid.bbox.w - dx; n = N} 1426 } 1427 } else { 1428 x -= (w - W)/2; 1429 if (delim.mid) {this.placeBox(mid,x,0,true); x += mid.bbox.w}; 1430 x -= (w - W)/2; 1431 } 1432 this.placeBox(right,x,0,true); 1433 span.bbox = { 1434 w: x+right.bbox.rw, lw: 0, rw: x+right.bbox.rw, 1435 h: Math.max(left.bbox.h,rep.bbox.h,right.bbox.h,mid.bbox.h), 1436 d: Math.max(left.bbox.d,rep.bbox.d,right.bbox.d,mid.bbox.d), 1437 exactW: true 1438 } 1439 span.scale = scale; 1440 span.isMultiChar = true; 1441 this.setStackWidth(stack,span.bbox.w); 1442 }, 1443 createChar: function (span,data,scale,font) { 1444 span.isMathJax = true; 1445 var SPAN = span, text = "", variant = {fonts: [data[1]], noRemap:true}; 1446 if (font && font === MML.VARIANT.BOLD) {variant.fonts = [data[1]+"-bold",data[1]]} 1447 if (typeof(data[1]) !== "string") {variant = data[1]} 1448 if (data[0] instanceof Array) { 1449 for (var i = 0, m = data[0].length; i < m; i++) {text += String.fromCharCode(data[0][i])} 1450 } else {text = String.fromCharCode(data[0])} 1451 if (data[4]) {scale *= data[4]} 1452 if (scale !== 1 || data[3]) { 1453 SPAN = this.addElement(span,"span",{style:{fontSize: this.Percent(scale)}, scale:scale, isMathJax:true}); 1454 this.handleVariant(SPAN,variant,text); 1455 span.bbox = SPAN.bbox; 1456 } else {this.handleVariant(span,variant,text)} 1457 if (data[2]) {span.style.marginLeft = this.Em(data[2])} // x offset 1458 if (data[3]) { // y offset 1459 span.firstChild.style.verticalAlign = this.Em(data[3]); 1460 span.bbox.h += data[3]; if (span.bbox.h < 0) {span.bbox.h = 0} 1461 } 1462 if (data[5]) {span.bbox.h += data[5]} // extra height 1463 if (data[6]) {span.bbox.d += data[6]} // extra depth 1464 // Handle combining characters by adding a non-breaking space so it shows up 1465 if (this.AccentBug && span.bbox.w === 0) {SPAN.firstChild.nodeValue += this.NBSP} 1466 }, 1467 positionDelimiter: function (span,h) { 1468 h -= span.bbox.h; span.bbox.d -= h; span.bbox.h += h; 1469 if (h) { 1470 if (this.safariVerticalAlignBug || this.konquerorVerticalAlignBug || 1471 (this.operaVerticalAlignBug && span.isMultiChar)) { 1472 if (span.firstChild.style.display === "" && span.style.top !== "") 1473 {span = span.firstChild; h -= HTMLCSS.unEm(span.style.top)} 1474 span.style.position = "relative"; 1475 span.style.top = this.Em(-h); 1476 } else { 1477 span.style.verticalAlign = this.Em(h); 1478 if (HTMLCSS.ffVerticalAlignBug) { 1479 HTMLCSS.createRule(span.parentNode,span.bbox.h,0,0); 1480 delete span.parentNode.bbox; 1481 } 1482 } 1483 } 1484 }, 1485 1486 handleVariant: function (span,variant,text) { 1487 var newtext = "", n, c, font, VARIANT, SPAN = span, force = !!span.style.fontFamily; 1488 if (text.length === 0) return; 1489 if (!span.bbox) { 1490 span.bbox = { 1491 w: 0, h: -this.BIGDIMEN, d: -this.BIGDIMEN, 1492 rw: -this.BIGDIMEN, lw: this.BIGDIMEN 1493 }; 1494 } 1495 if (!variant) {variant = this.FONTDATA.VARIANT[MML.VARIANT.NORMAL]} 1496 VARIANT = variant; 1497 for (var i = 0, m = text.length; i < m; i++) { 1498 variant = VARIANT; 1499 n = text.charCodeAt(i); c = text.charAt(i); 1500 if (n >= 0xD800 && n < 0xDBFF) { 1501 i++; n = (((n-0xD800)<<10)+(text.charCodeAt(i)-0xDC00))+0x10000; 1502 if (this.FONTDATA.RemapPlane1) { 1503 var nv = this.FONTDATA.RemapPlane1(n,variant); 1504 n = nv.n; variant = nv.variant; 1505 } 1506 } else { 1507 var id, M, RANGES = this.FONTDATA.RANGES; 1508 for (id = 0, M = RANGES.length; id < M; id++) { 1509 if (RANGES[id].name === "alpha" && variant.noLowerCase) continue; 1510 var N = variant["offset"+RANGES[id].offset]; 1511 if (N && n >= RANGES[id].low && n <= RANGES[id].high) { 1512 if (RANGES[id].remap && RANGES[id].remap[n]) { 1513 n = N + RANGES[id].remap[n]; 1514 } else { 1515 n = n - RANGES[id].low + N; 1516 if (RANGES[id].add) {n += RANGES[id].add} 1517 } 1518 if (variant["variant"+RANGES[id].offset]) 1519 {variant = this.FONTDATA.VARIANT[variant["variant"+RANGES[id].offset]]} 1520 break; 1521 } 1522 } 1523 } 1524 if (variant.remap && variant.remap[n]) { 1525 n = variant.remap[n]; 1526 if (variant.remap.variant) {variant = this.FONTDATA.VARIANT[variant.remap.variant]} 1527 } else if (this.FONTDATA.REMAP[n] && !variant.noRemap) { 1528 n = this.FONTDATA.REMAP[n]; 1529 } 1530 if (n instanceof Array) {variant = this.FONTDATA.VARIANT[n[1]]; n = n[0]} 1531 if (typeof(n) === "string") { 1532 text = n+text.substr(i+1); 1533 m = text.length; i = -1; 1534 continue; 1535 } 1536 font = this.lookupChar(variant,n); c = font[n]; 1537 if (force || (!this.checkFont(font,SPAN.style) && !c[5].img)) { 1538 if (newtext.length) {this.addText(SPAN,newtext); newtext = ""}; 1539 var addSpan = !!SPAN.style.fontFamily || !!span.style.fontStyle || 1540 !!span.style.fontWeight || !font.directory || force; force = false; 1541 if (SPAN !== span) {addSpan = !this.checkFont(font,span.style); SPAN = span} 1542 if (addSpan) {SPAN = this.addElement(span,"span",{isMathJax:true, subSpan:true})} 1543 this.handleFont(SPAN,font,SPAN !== span); 1544 } 1545 newtext = this.handleChar(SPAN,font,c,n,newtext); 1546 if (!(c[5]||{}).space) { 1547 if (c[0]/1000 > span.bbox.h) {span.bbox.h = c[0]/1000} 1548 if (c[1]/1000 > span.bbox.d) {span.bbox.d = c[1]/1000} 1549 } 1550 if (span.bbox.w + c[3]/1000 < span.bbox.lw) {span.bbox.lw = span.bbox.w + c[3]/1000} 1551 if (span.bbox.w + c[4]/1000 > span.bbox.rw) {span.bbox.rw = span.bbox.w + c[4]/1000} 1552 span.bbox.w += c[2]/1000; 1553 if ((c[5]||{}).isUnknown) span.bbox.exactW = false; // force measurement 1554 } 1555 if (newtext.length) {this.addText(SPAN,newtext)} 1556 if (span.scale && span.scale !== 1) { 1557 span.bbox.h *= span.scale; span.bbox.d *= span.scale; 1558 span.bbox.w *= span.scale; span.bbox.lw *= span.scale; span.bbox.rw *= span.scale; 1559 } 1560 if (text.length == 1 && font.skew && font.skew[n]) {span.bbox.skew = font.skew[n]} 1561 }, 1562 checkFont: function (font,style) { 1563 var weight = (style.fontWeight||"normal"); 1564 if (weight.match(/^\d+$/)) {weight = (parseInt(weight) >= 600 ? "bold" : "normal")} 1565 return (font.family.replace(/'/g,"") === style.fontFamily.replace(/'/g,"") && 1566 (font.style||"normal") === (style.fontStyle||"normal") && 1567 (font.weight||"normal") === weight); 1568 }, 1569 1570 handleFont: function (span,font,force) { 1571 span.style.fontFamily = font.family; 1572 if (!font.directory) 1573 {span.style.fontSize = Math.floor(HTMLCSS.config.scale/HTMLCSS.scale+.5) + "%"} 1574 if (!(HTMLCSS.FontFaceBug && font.isWebFont)) { 1575 var style = font.style || "normal", weight = font.weight || "normal"; 1576 if (style !== "normal" || force) {span.style.fontStyle = style} 1577 if (weight !== "normal" || force) {span.style.fontWeight = weight} 1578 } 1579 }, 1580 1581 handleChar: function (span,font,c,n,text) { 1582 var C = c[5]; 1583 if (C.space) { 1584 if (text.length) {this.addText(span,text)} 1585 HTMLCSS.createShift(span,c[2]/1000); 1586 return ""; 1587 } 1588 if (C.img) {return this.handleImg(span,font,c,n,text)} 1589 if (C.isUnknown && this.FONTDATA.DELIMITERS[n]) { 1590 if (text.length) {this.addText(span,text)} 1591 var scale = span.scale; 1592 HTMLCSS.createDelimiter(span,n,0,1,font); 1593 if (this.FONTDATA.DELIMITERS[n].dir === "V") { 1594 span.style.verticalAlign = this.Em(span.bbox.d); 1595 span.bbox.h += span.bbox.d; span.bbox.d = 0; 1596 } 1597 span.scale = scale; 1598 c[0] = span.bbox.h*1000; c[1] = span.bbox.d*1000; 1599 c[2] = span.bbox.w*1000; c[3] = span.bbox.lw*1000; c[4] = span.bbox.rw*1000; 1600 return ""; 1601 } 1602 if (C.c == null) { 1603 if (n <= 0xFFFF) {C.c = String.fromCharCode(n)} else { 1604 var N = n - 0x10000; 1605 C.c = String.fromCharCode((N>>10)+0xD800) 1606 + String.fromCharCode((N&0x3FF)+0xDC00); 1607 } 1608 } 1609 if (HTMLCSS.ffFontOptimizationBug && c[4] - c[2] > 125) 1610 {span.style.textRendering = "optimizeLegibility"} 1611 if (C.rfix) {this.addText(span,text+C.c); HTMLCSS.createShift(span,C.rfix/1000); return ""} 1612 if (c[2] || !this.msieAccentBug || text.length) {return text + C.c} 1613 // Handle IE accent clipping bug 1614 HTMLCSS.createShift(span,c[3]/1000); 1615 HTMLCSS.createShift(span,(c[4]-c[3])/1000); 1616 this.addText(span,C.c); 1617 HTMLCSS.createShift(span,-c[4]/1000); 1618 return ""; 1619 }, 1620 handleImg: function (span,font,c,n,text) {return text}, // replaced by imageFont extension 1621 1622 lookupChar: function (variant,n) { 1623 var i, m; 1624 if (!variant.FONTS) { 1625 var FONTS = this.FONTDATA.FONTS; 1626 var fonts = (variant.fonts || this.FONTDATA.VARIANT.normal.fonts); 1627 if (!(fonts instanceof Array)) {fonts = [fonts]} 1628 if (variant.fonts != fonts) {variant.fonts = fonts} 1629 variant.FONTS = []; 1630 for (i = 0, m = fonts.length; i < m; i++) { 1631 if (FONTS[fonts[i]]) { 1632 variant.FONTS.push(FONTS[fonts[i]]); 1633 FONTS[fonts[i]].name = fonts[i]; // FIXME: should really be in the font files 1634 } 1635 } 1636 } 1637 for (i = 0, m = variant.FONTS.length; i < m; i++) { 1638 var font = variant.FONTS[i]; 1639 if (typeof(font) === "string") { 1640 delete variant.FONTS; this.loadFont(font); 1641 } 1642 if (font[n]) { 1643 if (font[n].length === 5) {font[n][5] = {}} 1644 if (HTMLCSS.allowWebFonts && !font.available) 1645 {this.loadWebFont(font)} else {return font} 1646 } else {this.findBlock(font,n)} 1647 } 1648 return this.unknownChar(variant,n); 1649 }, 1650 1651 unknownChar: function (variant,n) { 1652 var unknown = (variant.defaultFont || {family:HTMLCSS.config.undefinedFamily}); 1653 if (variant.bold) {unknown.weight = "bold"}; if (variant.italic) {unknown.style = "italic"} 1654 if (!unknown[n]) {unknown[n] = [800,200,500,0,500,{isUnknown:true}]} // [h,d,w,lw,rw,{data}] 1655 HUB.signal.Post(["HTML-CSS Jax - unknown char",n,variant]); 1656 return unknown; 1657 }, 1658 1659 findBlock: function (font,c) { 1660 if (font.Ranges) { 1661 // FIXME: do binary search? 1662 for (var i = 0, m = font.Ranges.length; i < m; i++) { 1663 if (c < font.Ranges[i][0]) return; 1664 if (c <= font.Ranges[i][1]) { 1665 var file = font.Ranges[i][2]; 1666 for (var j = font.Ranges.length-1; j >= 0; j--) 1667 {if (font.Ranges[j][2] == file) {font.Ranges.splice(j,1)}} 1668 this.loadFont(font.directory+"/"+file+".js"); 1669 } 1670 } 1671 } 1672 }, 1673 1674 loadFont: function (file) { 1675 var queue = MathJax.Callback.Queue(); 1676 queue.Push(["Require",AJAX,this.fontDir+"/"+file]); 1677 if (this.imgFonts) { 1678 if (!MathJax.isPacked) {file = file.replace(/\/([^\/]*)$/,HTMLCSS.imgPacked+"/$1")} 1679 queue.Push(["Require",AJAX,this.webfontDir+"/png/"+file]); 1680 } 1681 HUB.RestartAfter(queue.Push({})); 1682 }, 1683 1684 loadWebFont: function (font) { 1685 font.available = font.isWebFont = true; 1686 if (HTMLCSS.FontFaceBug) { 1687 font.family = font.name; 1688 if (HTMLCSS.msieFontCSSBug) {font.family += "-Web"} 1689 } 1690 HUB.RestartAfter(this.Font.loadWebFont(font)); 1691 }, 1692 loadWebFontError: function (font,done) { 1693 // 1694 // After the first web font fails to load, switch to image fonts, if possible 1695 // otherwise, give up on web fonts all together 1696 // 1697 HUB.Startup.signal.Post("HTML-CSS Jax - disable web fonts"); 1698 font.isWebFont = false; 1699 if (this.config.imageFont && this.config.imageFont === this.fontInUse) { 1700 this.imgFonts = true; 1701 HUB.Startup.signal.Post("HTML-CSS Jax - switch to image fonts"); 1702 HUB.Startup.signal.Post("HTML-CSS Jax - using image fonts"); 1703 MESSAGE(["WebFontNotAvailable","Web-Fonts not available -- using image fonts instead"],null,3000); 1704 AJAX.Require(this.directory+"/imageFonts.js",done); 1705 } else { 1706 this.allowWebFonts = false; 1707 done(); 1708 } 1709 }, 1710 1711 Element: MathJax.HTML.Element, 1712 addElement: MathJax.HTML.addElement, 1713 TextNode: MathJax.HTML.TextNode, 1714 addText: MathJax.HTML.addText, 1715 ucMatch: MathJax.HTML.ucMatch, 1716 1717 BIGDIMEN: 10000000, 1718 ID: 0, idPostfix: "", 1719 GetID: function () {this.ID++; return this.ID}, 1720 1721 MATHSPACE: { 1722 veryverythinmathspace: 1/18, 1723 verythinmathspace: 2/18, 1724 thinmathspace: 3/18, 1725 mediummathspace: 4/18, 1726 thickmathspace: 5/18, 1727 verythickmathspace: 6/18, 1728 veryverythickmathspace: 7/18, 1729 negativeveryverythinmathspace: -1/18, 1730 negativeverythinmathspace: -2/18, 1731 negativethinmathspace: -3/18, 1732 negativemediummathspace: -4/18, 1733 negativethickmathspace: -5/18, 1734 negativeverythickmathspace: -6/18, 1735 negativeveryverythickmathspace: -7/18 1736 }, 1737 1738 TeX: { 1739 x_height: .430554, 1740 quad: 1, 1741 num1: .676508, 1742 num2: .393732, 1743 num3: .44373, 1744 denom1: .685951, 1745 denom2: .344841, 1746 sup1: .412892, 1747 sup2: .362892, 1748 sup3: .288888, 1749 sub1: .15, 1750 sub2: .247217, 1751 sup_drop: .386108, 1752 sub_drop: .05, 1753 delim1: 2.39, 1754 delim2: 1.0, 1755 axis_height: .25, 1756 rule_thickness: .06, 1757 big_op_spacing1: .111111, 1758 big_op_spacing2: .166666, 1759 big_op_spacing3: .2, 1760 big_op_spacing4: .6, 1761 big_op_spacing5: .1, 1762 1763 scriptspace: .1, 1764 nulldelimiterspace: .12, 1765 delimiterfactor: 901, 1766 delimitershortfall: .3, 1767 1768 min_rule_thickness: 1.25 // in pixels 1769 }, 1770 1771 NBSP: "\u00A0", 1772 1773 rfuzz: 0 // adjustment to rule placements in roots 1774 }); 1775 1776 MathJax.Hub.Register.StartupHook("mml Jax Ready",function () { 1777 1778 MML = MathJax.ElementJax.mml; 1779 1780 MML.mbase.Augment({ 1781 toHTML: function (span) { 1782 span = this.HTMLcreateSpan(span); if (this.type != "mrow") {span = this.HTMLhandleSize(span)} 1783 for (var i = 0, m = this.data.length; i < m; i++) 1784 {if (this.data[i]) {this.data[i].toHTML(span)}} 1785 var stretchy = this.HTMLcomputeBBox(span); 1786 var h = span.bbox.h, d = span.bbox.d, stretched = false, bbox; 1787 for (i = 0, m = stretchy.length; i < m; i++) { 1788 bbox = stretchy[i].HTMLspanElement().bbox; 1789 if (stretchy[i].forceStretch || bbox.h !== h || bbox.d !== d) 1790 {stretchy[i].HTMLstretchV(span,h,d); stretched = true} 1791 else if (stretchy[i].needsBBox) stretched = true; 1792 } 1793 if (stretched) {this.HTMLcomputeBBox(span,true)} 1794 if (this.HTMLlineBreaks(span)) {span = this.HTMLmultiline(span)} 1795 this.HTMLhandleSpace(span); 1796 this.HTMLhandleColor(span); 1797 if (this.data.length === 1 && this.data[0]) { 1798 // copy skew data from accented character 1799 bbox = this.data[0].HTMLspanElement().bbox; 1800 if (bbox.skew) span.bbox.skew = bbox.skew; 1801 } 1802 return span; 1803 }, 1804 HTMLlineBreaks: function () {return false}, 1805 HTMLmultiline: function () {MML.mbase.HTMLautoloadFile("multiline")}, 1806 HTMLcomputeBBox: function (span,full,i,m) { 1807 if (i == null) {i = 0}; if (m == null) {m = this.data.length} 1808 var BBOX = span.bbox = {exactW: true}, stretchy = []; 1809 while (i < m) { 1810 var core = this.data[i]; if (!core) continue; 1811 if (!full && core.HTMLcanStretch("Vertical")) { 1812 stretchy.push(core); 1813 core = (core.CoreMO()||core); 1814 stretchy[stretchy.length-1].needsBBox = (core !== this.data[i]); 1815 } 1816 this.HTMLcombineBBoxes(core,BBOX); i++; 1817 } 1818 this.HTMLcleanBBox(BBOX); 1819 return stretchy; 1820 }, 1821 HTMLcombineBBoxes: function (core,BBOX) { 1822 if (BBOX.w == null) {this.HTMLemptyBBox(BBOX)} 1823 var child = (core.bbox ? core : core.HTMLspanElement()); 1824 if (!child || !child.bbox) return; 1825 var bbox = child.bbox; 1826 if (bbox.d > BBOX.d) {BBOX.d = bbox.d} 1827 if (bbox.h > BBOX.h) {BBOX.h = bbox.h} 1828 if (bbox.D != null && bbox.D > BBOX.D) {BBOX.D = bbox.D} 1829 if (bbox.H != null && bbox.H > BBOX.H) {BBOX.H = bbox.H} 1830 if (child.style.paddingLeft) {BBOX.w += HTMLCSS.unEm(child.style.paddingLeft)*(child.scale||1)} 1831 if (BBOX.w + bbox.lw < BBOX.lw) {BBOX.lw = BBOX.w + bbox.lw} 1832 if (BBOX.w + bbox.rw > BBOX.rw) {BBOX.rw = BBOX.w + bbox.rw} 1833 BBOX.w += bbox.w; 1834 if (child.style.paddingRight) {BBOX.w += HTMLCSS.unEm(child.style.paddingRight)*(child.scale||1)} 1835 if (bbox.width) {BBOX.width = bbox.width; BBOX.minWidth = bbox.minWidth} 1836 if (bbox.tw) {BBOX.tw = bbox.tw} 1837 if (bbox.ic) {BBOX.ic = bbox.ic} else {delete BBOX.ic} 1838 if (BBOX.exactW && !bbox.exactW) {BBOX.exactW = bbox.exactW} 1839 }, 1840 HTMLemptyBBox: function (BBOX) { 1841 BBOX.h = BBOX.d = BBOX.H = BBOX.D = BBOX.rw = -HTMLCSS.BIGDIMEN; 1842 BBOX.w = 0; BBOX.lw = HTMLCSS.BIGDIMEN; 1843 return BBOX; 1844 }, 1845 HTMLcleanBBox: function (BBOX) { 1846 if (BBOX.h === this.BIGDIMEN) 1847 {BBOX.h = BBOX.d = BBOX.H = BBOX.D = BBOX.w = BBOX.rw = BBOX.lw = 0} 1848 if (BBOX.D <= BBOX.d) {delete BBOX.D}; if (BBOX.H <= BBOX.h) {delete BBOX.H} 1849 }, 1850 HTMLzeroBBox: function () {return {h:0, d:0, w:0, lw: 0, rw:0}}, 1851 HTMLcanStretch: function (direction) { 1852 if (this.isEmbellished()) { 1853 var core = this.Core(); 1854 if (core && core !== this) {return core.HTMLcanStretch(direction)} 1855 } 1856 return false; 1857 }, 1858 HTMLstretchH: function (box,W) {return this.HTMLspanElement()}, 1859 HTMLstretchV: function (box,h,d) {return this.HTMLspanElement()}, 1860 HTMLnotEmpty: function (data) { 1861 while (data) { 1862 if ((data.type !== "mrow" && data.type !== "texatom") || 1863 data.data.length > 1) {return true} 1864 data = data.data[0]; 1865 } 1866 return false; 1867 }, 1868 1869 HTMLmeasureChild: function (n,box) { 1870 if (this.data[n]) {HTMLCSS.Measured(this.data[n].toHTML(box),box)} 1871 else {box.bbox = this.HTMLzeroBBox()} 1872 }, 1873 HTMLboxChild: function (n,box) { 1874 if (!this.data[n]) {this.SetData(n,MML.mrow())} 1875 return this.data[n].toHTML(box); 1876 }, 1877 1878 HTMLcreateSpan: function (span) { 1879 if (this.spanID) { 1880 var SPAN = this.HTMLspanElement(); 1881 if (SPAN && (SPAN.parentNode === span || (SPAN.parentNode||{}).parentNode === span)) { 1882 while (SPAN.firstChild) {SPAN.removeChild(SPAN.firstChild)} 1883 SPAN.bbox = this.HTMLzeroBBox(); 1884 SPAN.scale = 1; SPAN.isMultChar = SPAN.HH = null; 1885 SPAN.style.cssText = ""; 1886 return SPAN; 1887 } 1888 } 1889 if (this.href) {span = HTMLCSS.addElement(span,"a",{href:this.href, isMathJax:true})} 1890 span = HTMLCSS.addElement(span,"span",{className: this.type, isMathJax:true}); 1891 if (HTMLCSS.imgHeightBug) {span.style.display = "inline-block"} 1892 if (this["class"]) {span.className += " "+this["class"]} 1893 if (!this.spanID) {this.spanID = HTMLCSS.GetID()} 1894 span.id = (this.id || "MathJax-Span-"+this.spanID) + HTMLCSS.idPostfix; 1895 span.bbox = this.HTMLzeroBBox(); this.styles = {}; 1896 if (this.style) { 1897 span.style.cssText = this.style; 1898 if (span.style.fontSize) {this.mathsize = span.style.fontSize; span.style.fontSize = ""} 1899 this.styles = {border:HTMLCSS.getBorders(span), padding:HTMLCSS.getPadding(span)} 1900 if (this.styles.border) {span.style.border = ""} // IE needs "0px none"? 1901 if (this.styles.padding) {span.style.padding = ""} 1902 } 1903 if (this.href) {span.parentNode.bbox = span.bbox} 1904 this.HTMLaddAttributes(span); 1905 return span; 1906 }, 1907 HTMLaddAttributes: function(span) { 1908 // 1909 // Copy RDFa, aria, and other tags from the MathML to the HTML-CSS 1910 // output spans. Don't copy those in the MML.nocopyAttributes list, 1911 // the ignoreMMLattributes configuration list, or anything that 1912 // already exists as a property of the span (e.g., no "onlick", etc.) 1913 // If a name in the ignoreMMLattributes object is set to false, then 1914 // the attribute WILL be copied. 1915 // 1916 if (this.attrNames) { 1917 var copy = this.attrNames, skip = MML.nocopyAttributes, ignore = HUB.config.ignoreMMLattributes; 1918 var defaults = (this.type === "mstyle" ? MML.math.prototype.defaults : this.defaults); 1919 for (var i = 0, m = copy.length; i < m; i++) { 1920 var id = copy[i]; 1921 if (ignore[id] == false || (!skip[id] && !ignore[id] && 1922 defaults[id] == null && typeof(span[id]) === "undefined")) { 1923 span.setAttribute(id,this.attr[id]) 1924 } 1925 } 1926 } 1927 }, 1928 HTMLspanElement: function () { 1929 if (!this.spanID) {return null} 1930 return document.getElementById((this.id||"MathJax-Span-"+this.spanID)+HTMLCSS.idPostfix); 1931 }, 1932 1933 HTMLhandleVariant: function (span,variant,text) {HTMLCSS.handleVariant(span,variant,text)}, 1934 1935 HTMLhandleSize: function (span) { 1936 if (!span.scale) { 1937 span.scale = this.HTMLgetScale(); 1938 if (span.scale !== 1) {span.style.fontSize = HTMLCSS.Percent(span.scale)} 1939 } 1940 return span; 1941 }, 1942 1943 HTMLhandleDir: function (span) { 1944 var dir = this.Get("dir",true); // only get value if not the default 1945 if (dir) {span.dir = dir} 1946 return span; 1947 }, 1948 1949 HTMLhandleColor: function (span) { 1950 var values = this.getValues("mathcolor","color"); 1951 if (this.mathbackground) {values.mathbackground = this.mathbackground} 1952 if (this.background) {values.background = this.background} 1953 if (this.style && span.style.backgroundColor) { 1954 values.mathbackground = span.style.backgroundColor; 1955 span.style.backgroundColor = "transparent"; 1956 } 1957 var borders = (this.styles||{}).border, padding = (this.styles||{}).padding; 1958 if (values.color && !this.mathcolor) {values.mathcolor = values.color} 1959 if (values.background && !this.mathbackground) {values.mathbackground = values.background} 1960 if (values.mathcolor) {span.style.color = values.mathcolor} 1961 if ((values.mathbackground && values.mathbackground !== MML.COLOR.TRANSPARENT) || 1962 borders || padding) { 1963 var bbox = span.bbox, dd = (bbox.exact ? 0 : 1/HTMLCSS.em), lW = 0, rW = 0, 1964 lpad = span.style.paddingLeft, rpad = span.style.paddingRight; 1965 if (this.isToken) {lW = bbox.lw; rW = bbox.rw - bbox.w} 1966 if (lpad !== "") {lW += HTMLCSS.unEm(lpad)*(span.scale||1)} 1967 if (rpad !== "") {rW -= HTMLCSS.unEm(rpad)*(span.scale||1)} 1968 var dw = (HTMLCSS.PaddingWidthBug || bbox.keepPadding || bbox.exactW ? 0 : rW - lW); 1969 var W = Math.max(0,HTMLCSS.getW(span) + dw); 1970 var H = bbox.h + bbox.d, D = -bbox.d, lp = 0, rp = 0; 1971 if (W > 0) {W += 2*dd; lW -= dd}; if (H > 0) {H += 2*dd; D -= dd}; rW = -W-lW; 1972 if (borders) { 1973 rW -= borders.right; D -= borders.bottom; lp += borders.left; rp += borders.right; 1974 bbox.h += borders.top; bbox.d += borders.bottom; 1975 bbox.w += borders.left + borders.right; 1976 bbox.lw -= borders.left; bbox.rw += borders.right; 1977 } 1978 if (padding) { 1979 H += padding.top + padding.bottom; W += padding.left + padding.right; 1980 rW -= padding.right; D -= padding.bottom; lp += padding.left; rp += padding.right; 1981 bbox.h += padding.top; bbox.d += padding.bottom; 1982 bbox.w += padding.left + padding.right; 1983 bbox.lw -= padding.left; bbox.rw += padding.right; 1984 } 1985 if (rp) {span.style.paddingRight = HTMLCSS.Em(rp)} 1986 var frame = HTMLCSS.Element("span",{ 1987 id:"MathJax-Color-"+this.spanID+HTMLCSS.idPostfix, isMathJax: true, 1988 style:{display:"inline-block", backgroundColor:values.mathbackground, 1989 width: HTMLCSS.Em(W), height:HTMLCSS.Em(H), verticalAlign: HTMLCSS.Em(D), 1990 marginLeft: HTMLCSS.Em(lW), marginRight: HTMLCSS.Em(rW)} 1991 }); 1992 HTMLCSS.setBorders(frame,borders); 1993 if (bbox.width) {frame.style.width = bbox.width; frame.style.marginRight = "-"+bbox.width} 1994 if (HTMLCSS.msieInlineBlockAlignBug) { 1995 // FIXME: handle variable width background 1996 frame.style.position = "relative"; frame.style.width = frame.style.height = 0; 1997 frame.style.verticalAlign = frame.style.marginLeft = frame.style.marginRight = ""; 1998 frame.style.border = frame.style.padding = ""; 1999 if (borders && HTMLCSS.msieBorderWidthBug) 2000 {H += borders.top + borders.bottom; W += borders.left + borders.right} 2001 frame.style.width = HTMLCSS.Em(lp+dd); 2002 HTMLCSS.placeBox(HTMLCSS.addElement(frame,"span",{ 2003 noAdjust: true, isMathJax: true, 2004 style: {display:"inline-block", position:"absolute", overflow:"hidden", 2005 background:(values.mathbackground||"transparent"), 2006 width: HTMLCSS.Em(W), height: HTMLCSS.Em(H)} 2007 }),lW,bbox.h+dd); 2008 HTMLCSS.setBorders(frame.firstChild,borders); 2009 } 2010 span.parentNode.insertBefore(frame,span); 2011 if (HTMLCSS.msieColorPositionBug) {span.style.position = "relative"} 2012 return frame; 2013 } 2014 return null; 2015 }, 2016 HTMLremoveColor: function () { 2017 var color = document.getElementById("MathJax-Color-"+this.spanID+HTMLCSS.idPostfix); 2018 if (color) {color.parentNode.removeChild(color)} 2019 }, 2020 2021 HTMLhandleSpace: function (span) { 2022 if (this.useMMLspacing) { 2023 if (this.type !== "mo") return; 2024 var values = this.getValues("scriptlevel","lspace","rspace"); 2025 if (values.scriptlevel <= 0 || this.hasValue("lspace") || this.hasValue("rspace")) { 2026 var mu = this.HTMLgetMu(span); 2027 values.lspace = Math.max(0,HTMLCSS.length2em(values.lspace,mu)); 2028 values.rspace = Math.max(0,HTMLCSS.length2em(values.rspace,mu)); 2029 var core = this, parent = this.Parent(); 2030 while (parent && parent.isEmbellished() && parent.Core() === core) 2031 {core = parent; parent = parent.Parent(); span = core.HTMLspanElement()} 2032 if (values.lspace) {span.style.paddingLeft = HTMLCSS.Em(values.lspace)} 2033 if (values.rspace) {span.style.paddingRight = HTMLCSS.Em(values.rspace)} 2034 } 2035 } else { 2036 var space = this.texSpacing(); 2037 if (space !== "") { 2038 this.HTMLgetScale(); 2039 space = HTMLCSS.length2em(space,this.scale)/(span.scale||1)*this.mscale; 2040 if (span.style.paddingLeft) {space += HTMLCSS.unEm(span.style.paddingLeft)} 2041 span.style.paddingLeft = HTMLCSS.Em(space); 2042 } 2043 } 2044 }, 2045 2046 HTMLgetScale: function () { 2047 if (this.scale) {return this.scale * this.mscale} 2048 var scale = 1, values = this.getValues("scriptlevel","fontsize"); 2049 values.mathsize = (this.isToken ? this : this.Parent()).Get("mathsize"); 2050 if (this.style) { 2051 var span = this.HTMLspanElement(); 2052 if (span.style.fontSize != "") {values.fontsize = span.style.fontSize} 2053 } 2054 if (values.fontsize && !this.mathsize) {values.mathsize = values.fontsize} 2055 if (values.scriptlevel !== 0) { 2056 if (values.scriptlevel > 2) {values.scriptlevel = 2} 2057 scale = Math.pow(this.Get("scriptsizemultiplier"),values.scriptlevel); 2058 values.scriptminsize = HTMLCSS.length2em(this.Get("scriptminsize")); 2059 if (scale < values.scriptminsize) {scale = values.scriptminsize} 2060 } 2061 this.scale = scale; this.mscale = HTMLCSS.length2em(values.mathsize); 2062 return scale * this.mscale; 2063 }, 2064 HTMLgetMu: function (span) { 2065 var mu = 1, values = this.getValues("scriptlevel","scriptsizemultiplier"); 2066 if (span.scale && span.scale !== 1) {mu = 1/span.scale} 2067 if (values.scriptlevel !== 0) { 2068 if (values.scriptlevel > 2) {values.scriptlevel = 2} 2069 mu = Math.sqrt(Math.pow(values.scriptsizemultiplier,values.scriptlevel)); 2070 } 2071 return mu; 2072 }, 2073 2074 HTMLgetVariant: function () { 2075 var values = this.getValues("mathvariant","fontfamily","fontweight","fontstyle"); 2076 values.hasVariant = this.Get("mathvariant",true); // null if not explicitly specified 2077 if (!values.hasVariant) { 2078 values.family = values.fontfamily; 2079 values.weight = values.fontweight; 2080 values.style = values.fontstyle; 2081 } 2082 if (this.style) { 2083 var span = this.HTMLspanElement(); 2084 if (!values.family && span.style.fontFamily) {values.family = span.style.fontFamily} 2085 if (!values.weight && span.style.fontWeight) {values.weight = span.style.fontWeight} 2086 if (!values.style && span.style.fontStyle) {values.style = span.style.fontStyle} 2087 } 2088 if (values.weight && values.weight.match(/^\d+$/)) 2089 {values.weight = (parseInt(values.weight) > 600 ? "bold" : "normal")} 2090 var variant = values.mathvariant; if (this.variantForm) {variant = "-"+HTMLCSS.fontInUse+"-variant"} 2091 if (values.family && !values.hasVariant) { 2092 if (!values.weight && values.mathvariant.match(/bold/)) {values.weight = "bold"} 2093 if (!values.style && values.mathvariant.match(/italic/)) {values.style = "italic"} 2094 return {FONTS:[], fonts:[], noRemap:true, 2095 defaultFont: {family:values.family, style:values.style, weight:values.weight}}; 2096 } 2097 if (values.weight === "bold") { 2098 variant = { 2099 normal:MML.VARIANT.BOLD, italic:MML.VARIANT.BOLDITALIC, 2100 fraktur:MML.VARIANT.BOLDFRAKTUR, script:MML.VARIANT.BOLDSCRIPT, 2101 "sans-serif":MML.VARIANT.BOLDSANSSERIF, 2102 "sans-serif-italic":MML.VARIANT.SANSSERIFBOLDITALIC 2103 }[variant]||variant; 2104 } else if (values.weight === "normal") { 2105 variant = { 2106 bold:MML.VARIANT.normal, "bold-italic":MML.VARIANT.ITALIC, 2107 "bold-fraktur":MML.VARIANT.FRAKTUR, "bold-script":MML.VARIANT.SCRIPT, 2108 "bold-sans-serif":MML.VARIANT.SANSSERIF, 2109 "sans-serif-bold-italic":MML.VARIANT.SANSSERIFITALIC 2110 }[variant]||variant; 2111 } 2112 if (values.style === "italic") { 2113 variant = { 2114 normal:MML.VARIANT.ITALIC, bold:MML.VARIANT.BOLDITALIC, 2115 "sans-serif":MML.VARIANT.SANSSERIFITALIC, 2116 "bold-sans-serif":MML.VARIANT.SANSSERIFBOLDITALIC 2117 }[variant]||variant; 2118 } else if (values.style === "normal") { 2119 variant = { 2120 italic:MML.VARIANT.NORMAL, "bold-italic":MML.VARIANT.BOLD, 2121 "sans-serif-italic":MML.VARIANT.SANSSERIF, 2122 "sans-serif-bold-italic":MML.VARIANT.BOLDSANSSERIF 2123 }[variant]||variant; 2124 } 2125 if (!(variant in HTMLCSS.FONTDATA.VARIANT)) { 2126 // If the mathvariant value is invalid or not supported by this 2127 // font, fallback to normal. See issue 363. 2128 variant = "normal"; 2129 } 2130 return HTMLCSS.FONTDATA.VARIANT[variant]; 2131 }, 2132 2133 HTMLdrawBBox: function (span) { 2134 var bbox = span.bbox; 2135 var box = HTMLCSS.Element("span", 2136 {style:{"font-size":span.style.fontSize, display:"inline-block", 2137 opacity:.25,"margin-left":HTMLCSS.Em(-bbox.w)}},[ 2138 ["span",{style:{ 2139 height:HTMLCSS.Em(bbox.h),width:HTMLCSS.Em(bbox.w), 2140 "background-color":"red", display:"inline-block" 2141 }}], 2142 ["span",{style:{ 2143 height:HTMLCSS.Em(bbox.d),width:HTMLCSS.Em(bbox.w), 2144 "margin-left":HTMLCSS.Em(-bbox.w),"vertical-align":HTMLCSS.Em(-bbox.d), 2145 "background-color":"green", display:"inline-block" 2146 }}] 2147 ]); 2148 if (span.nextSibling) {span.parentNode.insertBefore(box,span.nextSibling)} 2149 else {span.parentNode.appendChild(box)} 2150 } 2151 2152 },{ 2153 HTMLautoload: function () { 2154 var file = HTMLCSS.autoloadDir+"/"+this.type+".js"; 2155 HUB.RestartAfter(AJAX.Require(file)); 2156 }, 2157 HTMLautoloadFile: function (name) { 2158 var file = HTMLCSS.autoloadDir+"/"+name+".js"; 2159 HUB.RestartAfter(AJAX.Require(file)); 2160 }, 2161 2162 HTMLstretchH: function (box,w) { 2163 this.HTMLremoveColor(); 2164 return this.toHTML(box,w); 2165 }, 2166 2167 HTMLstretchV: function (box,h,d) { 2168 this.HTMLremoveColor(); 2169 return this.toHTML(box,h,d); 2170 } 2171 }); 2172 2173 MML.chars.Augment({ 2174 toHTML: function (span,variant,remap,chars) { 2175 var text = this.data.join("").replace(/[\u2061-\u2064]/g,""); // remove invisibles 2176 if (remap) {text = remap(text,chars)} 2177 if (variant.fontInherit) { 2178 var scale = Math.floor(HTMLCSS.config.scale/HTMLCSS.scale+.5) + "%"; 2179 HTMLCSS.addElement(span,"span",{style:{"font-size":scale}},[text]); 2180 if (variant.bold) {span.lastChild.style.fontWeight = "bold"} 2181 if (variant.italic) {span.lastChild.style.fontStyle = "italic"} 2182 span.bbox = null; 2183 var HD = HTMLCSS.getHD(span), W = HTMLCSS.getW(span); 2184 span.bbox = {h:HD.h, d:HD.d, w:W, lw:0, rw:W, exactW: true}; 2185 } else { 2186 this.HTMLhandleVariant(span,variant,text); 2187 } 2188 } 2189 }); 2190 MML.entity.Augment({ 2191 toHTML: function (span,variant,remap,chars) { 2192 var text = this.toString().replace(/[\u2061-\u2064]/g,""); // remove invisibles 2193 if (remap) {text = remap(text,chars)} 2194 if (variant.fontInherit) { 2195 var scale = Math.floor(HTMLCSS.config.scale/HTMLCSS.scale+.5) + "%"; 2196 HTMLCSS.addElement(span,"span",{style:{"font-size":scale}},[text]); 2197 if (variant.bold) {span.lastChild.style.fontWeight = "bold"} 2198 if (variant.italic) {span.lastChild.style.fontStyle = "italic"} 2199 delete span.bbox; 2200 var HD = HTMLCSS.getHD(span), W = HTMLCSS.getW(span); 2201 span.bbox = {h:HD.h, d:HD.d, w:W, lw:0, rw:W, exactW: true}; 2202 } else { 2203 this.HTMLhandleVariant(span,variant,text); 2204 } 2205 } 2206 }); 2207 2208 MML.mi.Augment({ 2209 toHTML: function (span) { 2210 span = this.HTMLhandleSize(this.HTMLcreateSpan(span)); span.bbox = null; 2211 var variant = this.HTMLgetVariant(); 2212 for (var i = 0, m = this.data.length; i < m; i++) 2213 {if (this.data[i]) {this.data[i].toHTML(span,variant)}} 2214 if (!span.bbox) {span.bbox = this.HTMLzeroBBox()} 2215 var text = this.data.join(""), bbox = span.bbox; 2216 if (bbox.skew && text.length !== 1) {delete bbox.skew} 2217 if (bbox.rw > bbox.w && text.length === 1 && !variant.noIC) { 2218 bbox.ic = bbox.rw - bbox.w; 2219 HTMLCSS.createBlank(span,bbox.ic/this.mscale); 2220 bbox.w = bbox.rw; 2221 } 2222 this.HTMLhandleSpace(span); 2223 this.HTMLhandleColor(span); 2224 this.HTMLhandleDir(span); 2225 return span; 2226 } 2227 }); 2228 2229 MML.mn.Augment({ 2230 toHTML: function (span) { 2231 span = this.HTMLhandleSize(this.HTMLcreateSpan(span)); span.bbox = null; 2232 var variant = this.HTMLgetVariant(); 2233 for (var i = 0, m = this.data.length; i < m; i++) 2234 {if (this.data[i]) {this.data[i].toHTML(span,variant)}} 2235 if (!span.bbox) {span.bbox = this.HTMLzeroBBox()} 2236 if (this.data.join("").length !== 1) {delete span.bbox.skew} 2237 this.HTMLhandleSpace(span); 2238 this.HTMLhandleColor(span); 2239 this.HTMLhandleDir(span); 2240 return span; 2241 } 2242 }); 2243 2244 MML.mo.Augment({ 2245 toHTML: function (span) { 2246 span = this.HTMLhandleSize(this.HTMLcreateSpan(span)); 2247 if (this.data.length == 0) {return span} else {span.bbox = null} 2248 var text = this.data.join(""); 2249 // 2250 // Get the variant, and check for operator size 2251 // 2252 var variant = this.HTMLgetVariant(); 2253 var values = this.getValues("largeop","displaystyle"); 2254 if (values.largeop) 2255 {variant = HTMLCSS.FONTDATA.VARIANT[values.displaystyle ? "-largeOp" : "-smallOp"]} 2256 // 2257 // Get character translation for superscript and accents 2258 // 2259 var parent = this.CoreParent(), 2260 isScript = (parent && parent.isa(MML.msubsup) && this !== parent.data[parent.base]), 2261 mapchars = (isScript?this.remapChars:null); 2262 if (text.length === 1 && parent && parent.isa(MML.munderover) && 2263 this.CoreText(parent.data[parent.base]).length === 1) { 2264 var over = parent.data[parent.over], under = parent.data[parent.under]; 2265 if (over && this === over.CoreMO() && parent.Get("accent")) {mapchars = HTMLCSS.FONTDATA.REMAPACCENT} 2266 else if (under && this === under.CoreMO() && parent.Get("accentunder")) {mapchars = HTMLCSS.FONTDATA.REMAPACCENTUNDER} 2267 } 2268 // 2269 // STIX and TeX fonts need quotes from variant font 2270 // 2271 if (isScript && text.match(/['`"\u00B4\u2032-\u2037\u2057]/)) 2272 {variant = HTMLCSS.FONTDATA.VARIANT["-"+HTMLCSS.fontInUse+"-variant"]} 2273 // 2274 // Typeset contents 2275 // 2276 for (var i = 0, m = this.data.length; i < m; i++) 2277 {if (this.data[i]) {this.data[i].toHTML(span,variant,this.remap,mapchars)}} 2278 if (!span.bbox) {span.bbox = this.HTMLzeroBBox()} 2279 if (text.length !== 1) {delete span.bbox.skew} 2280 // 2281 // Handle combining characters by adding a non-breaking space and removing that width 2282 // 2283 if (HTMLCSS.AccentBug && span.bbox.w === 0 && text.length === 1 && span.firstChild) { 2284 span.firstChild.nodeValue += HTMLCSS.NBSP; 2285 HTMLCSS.createSpace(span,0,0,-span.offsetWidth/HTMLCSS.em); 2286 } 2287 // 2288 // Handle large operator centering 2289 // 2290 if (values.largeop) { 2291 var a = HTMLCSS.TeX.axis_height * this.scale * this.mscale 2292 var p = (span.bbox.h - span.bbox.d)/2 - a; 2293 if (HTMLCSS.safariVerticalAlignBug && span.lastChild.nodeName === "IMG") { 2294 span.lastChild.style.verticalAlign = 2295 HTMLCSS.Em(HTMLCSS.unEm(span.lastChild.style.verticalAlign||0)/HTMLCSS.em-p/span.scale); 2296 } else if (HTMLCSS.konquerorVerticalAlignBug && span.lastChild.nodeName === "IMG") { 2297 span.style.position = "relative"; 2298 span.lastChild.style.position="relative"; 2299 span.lastChild.style.top = HTMLCSS.Em(p/span.scale); 2300 } else { 2301 span.style.verticalAlign = HTMLCSS.Em(-p/span.scale); 2302 } 2303 span.bbox.h -= p; span.bbox.d += p; 2304 if (span.bbox.rw > span.bbox.w) { 2305 span.bbox.ic = span.bbox.rw-span.bbox.w; 2306 HTMLCSS.createBlank(span,span.bbox.ic/this.mscale); 2307 span.bbox.w = span.bbox.rw; 2308 } 2309 } 2310 // 2311 // Finish up 2312 // 2313 this.HTMLhandleSpace(span); 2314 this.HTMLhandleColor(span); 2315 this.HTMLhandleDir(span); 2316 return span; 2317 }, 2318 HTMLcanStretch: function (direction) { 2319 if (!this.Get("stretchy")) {return false} 2320 var c = this.data.join(""); 2321 if (c.length > 1) {return false} 2322 var parent = this.CoreParent(); 2323 if (parent && parent.isa(MML.munderover) && 2324 this.CoreText(parent.data[parent.base]).length === 1) { 2325 var over = parent.data[parent.over], under = parent.data[parent.under]; 2326 if (over && this === over.CoreMO() && parent.Get("accent")) {c = HTMLCSS.FONTDATA.REMAPACCENT[c]||c} 2327 else if (under && this === under.CoreMO() && parent.Get("accentunder")) {c = HTMLCSS.FONTDATA.REMAPACCENTUNDER[c]||c} 2328 } 2329 c = HTMLCSS.FONTDATA.DELIMITERS[c.charCodeAt(0)]; 2330 var stretch = (c && c.dir === direction.substr(0,1)); 2331 this.forceStretch = (stretch && (this.Get("minsize",true) || this.Get("maxsize",true))); 2332 return stretch; 2333 }, 2334 HTMLstretchV: function (box,h,d) { 2335 this.HTMLremoveColor(); 2336 var values = this.getValues("symmetric","maxsize","minsize"); 2337 var span = this.HTMLspanElement(), mu = this.HTMLgetMu(span), H; 2338 var scale = this.HTMLgetScale(), axis = HTMLCSS.TeX.axis_height * scale; 2339 if (values.symmetric) {H = 2*Math.max(h-axis,d+axis)} else {H = h + d} 2340 values.maxsize = HTMLCSS.length2em(values.maxsize,mu,span.bbox.h+span.bbox.d); 2341 values.minsize = HTMLCSS.length2em(values.minsize,mu,span.bbox.h+span.bbox.d); 2342 H = Math.max(values.minsize,Math.min(values.maxsize,H)); 2343 if (H != values.minsize) 2344 {H = [Math.max(H*HTMLCSS.TeX.delimiterfactor/1000,H-HTMLCSS.TeX.delimitershortfall),H]} 2345 span = this.HTMLcreateSpan(box); // clear contents and attributes 2346 HTMLCSS.createDelimiter(span,this.data.join("").charCodeAt(0),H,scale); 2347 if (values.symmetric) {H = (span.bbox.h + span.bbox.d)/2 + axis} 2348 else {H = (span.bbox.h + span.bbox.d) * h/(h + d)} 2349 HTMLCSS.positionDelimiter(span,H); 2350 this.HTMLhandleSpace(span); // add in lspace/rspace, if any 2351 this.HTMLhandleColor(span); 2352 return span; 2353 }, 2354 HTMLstretchH: function (box,W) { 2355 this.HTMLremoveColor(); 2356 var values = this.getValues("maxsize","minsize","mathvariant","fontweight"); 2357 // FIXME: should take style="font-weight:bold" into account as well 2358 if ((values.fontweight === "bold" || parseInt(values.fontweight) >= 600) && 2359 !this.Get("mathvariant",true)) {values.mathvariant = MML.VARIANT.BOLD} 2360 var span = this.HTMLspanElement(), mu = this.HTMLgetMu(span), scale = span.scale; 2361 values.maxsize = HTMLCSS.length2em(values.maxsize,mu,span.bbox.w); 2362 values.minsize = HTMLCSS.length2em(values.minsize,mu,span.bbox.w); 2363 W = Math.max(values.minsize,Math.min(values.maxsize,W)); 2364 span = this.HTMLcreateSpan(box); // clear contents and attributes 2365 HTMLCSS.createDelimiter(span,this.data.join("").charCodeAt(0),W,scale,values.mathvariant); 2366 this.HTMLhandleSpace(span); // add in lspace/rspace, if any 2367 this.HTMLhandleColor(span); 2368 return span; 2369 } 2370 }); 2371 2372 MML.mtext.Augment({ 2373 toHTML: function (span) { 2374 span = this.HTMLhandleSize(this.HTMLcreateSpan(span)); 2375 var variant = this.HTMLgetVariant(); 2376 // Avoid setting the font style for error text or if mtextFontInherit is set 2377 if (HTMLCSS.config.mtextFontInherit || this.Parent().type === "merror") { 2378 var vname = this.Get("mathvariant"); 2379 if (vname === "monospace") {span.className += " MJX-monospace"} 2380 else if (vname.match(/sans-serif/)) {span.className += " MJX-sans-serif"} 2381 variant = {bold:variant.bold, italic:variant.italic, fontInherit: true}; 2382 } 2383 for (var i = 0, m = this.data.length; i < m; i++) 2384 {if (this.data[i]) {this.data[i].toHTML(span,variant)}} 2385 if (!span.bbox) {span.bbox = this.HTMLzeroBBox()} 2386 if (this.data.join("").length !== 1) {delete span.bbox.skew} 2387 this.HTMLhandleSpace(span); 2388 this.HTMLhandleColor(span); 2389 this.HTMLhandleDir(span); 2390 return span; 2391 } 2392 }); 2393 MML.merror.Augment({ 2394 toHTML: function (span) { 2395 // 2396 // Width doesn't include padding and border, so use an extra inline block 2397 // element to capture it. 2398 // 2399 var SPAN = MathJax.HTML.addElement(span,"span",{style:{display:"inline-block"}}); 2400 span = this.SUPER(arguments).toHTML.call(this,SPAN); 2401 var HD = HTMLCSS.getHD(SPAN), W = HTMLCSS.getW(SPAN); 2402 SPAN.bbox = {h:HD.h, d:HD.d, w:W, lw:0, rw:W, exactW: true}; 2403 SPAN.id = span.id; span.id = null; 2404 return SPAN; 2405 } 2406 }); 2407 2408 MML.ms.Augment({toHTML: MML.mbase.HTMLautoload}); 2409 2410 MML.mglyph.Augment({toHTML: MML.mbase.HTMLautoload}); 2411 2412 MML.mspace.Augment({ 2413 toHTML: function (span) { 2414 span = this.HTMLcreateSpan(span); 2415 var values = this.getValues("height","depth","width"); 2416 var mu = this.HTMLgetMu(span); this.HTMLgetScale(); 2417 values.mathbackground = this.mathbackground; 2418 if (this.background && !this.mathbackground) {values.mathbackground = this.background} 2419 var h = HTMLCSS.length2em(values.height,mu) * this.mscale, 2420 d = HTMLCSS.length2em(values.depth,mu) * this.mscale, 2421 w = HTMLCSS.length2em(values.width,mu) * this.mscale; 2422 HTMLCSS.createSpace(span,h,d,w,values.mathbackground,true); 2423 return span; 2424 } 2425 }); 2426 2427 MML.mphantom.Augment({ 2428 toHTML: function (span,HW,D) { 2429 span = this.HTMLcreateSpan(span); 2430 if (this.data[0] != null) { 2431 var box = this.data[0].toHTML(span); 2432 if (D != null) {HTMLCSS.Remeasured(this.data[0].HTMLstretchV(span,HW,D),span)} 2433 else if (HW != null) {HTMLCSS.Remeasured(this.data[0].HTMLstretchH(span,HW),span)} 2434 else {box = HTMLCSS.Measured(box,span)} 2435 span.bbox = {w: box.bbox.w, h: box.bbox.h, d: box.bbox.d, lw: 0, rw: 0, exactW: true}; 2436 for (var i = 0, m = span.childNodes.length; i < m; i++) 2437 {span.childNodes[i].style.visibility = "hidden"} 2438 } 2439 this.HTMLhandleSpace(span); 2440 this.HTMLhandleColor(span); 2441 return span; 2442 }, 2443 HTMLstretchH: MML.mbase.HTMLstretchH, 2444 HTMLstretchV: MML.mbase.HTMLstretchV 2445 }); 2446 2447 MML.mpadded.Augment({ 2448 toHTML: function (span,HW,D) { 2449 span = this.HTMLcreateSpan(span); 2450 if (this.data[0] != null) { 2451 var stack = HTMLCSS.createStack(span,true); 2452 var box = HTMLCSS.createBox(stack); 2453 var child = this.data[0].toHTML(box); 2454 if (D != null) {HTMLCSS.Remeasured(this.data[0].HTMLstretchV(box,HW,D),box)} 2455 else if (HW != null) {HTMLCSS.Remeasured(this.data[0].HTMLstretchH(box,HW),box)} 2456 else {HTMLCSS.Measured(child,box)} 2457 var values = this.getValues("height","depth","width","lspace","voffset"), 2458 x = 0, y = 0, mu = this.HTMLgetMu(span); 2459 this.HTMLgetScale(); 2460 if (values.lspace) {x = this.HTMLlength2em(box,values.lspace,mu)} 2461 if (values.voffset) {y = this.HTMLlength2em(box,values.voffset,mu)} 2462 HTMLCSS.placeBox(box,x,y); x /= this.mscale; y /= this.mscale; 2463 span.bbox = { 2464 h: box.bbox.h, d: box.bbox.d, w: box.bbox.w, exactW: true, 2465 lw: box.bbox.lw+x, rw: box.bbox.rw+x, 2466 H: Math.max((box.bbox.H == null ? -HTMLCSS.BIGDIMEN : box.bbox.H+y),box.bbox.h+y), 2467 D: Math.max((box.bbox.D == null ? -HTMLCSS.BIGDIMEN : box.bbox.D-y),box.bbox.d-y) 2468 }; 2469 if (values.height !== "") {span.bbox.h = this.HTMLlength2em(box,values.height,mu,"h",0)} 2470 if (values.depth !== "") {span.bbox.d = this.HTMLlength2em(box,values.depth,mu,"d",0)} 2471 if (values.width !== "") {span.bbox.w = this.HTMLlength2em(box,values.width,mu,"w",0)} 2472 if (span.bbox.H <= span.bbox.h) {delete span.bbox.H} 2473 if (span.bbox.D <= span.bbox.d) {delete span.bbox.D} 2474 var dimen = /^\s*(\d+(\.\d*)?|\.\d+)\s*(pt|em|ex|mu|px|pc|in|mm|cm)\s*$/ 2475 span.bbox.exact = !!((this.data[0] && this.data[0].data.length == 0) || 2476 dimen.exec(values.height) || dimen.exec(values.width) || dimen.exec(values.depth)); 2477 HTMLCSS.setStackWidth(stack,span.bbox.w); 2478 } 2479 this.HTMLhandleSpace(span); 2480 this.HTMLhandleColor(span); 2481 return span; 2482 }, 2483 HTMLlength2em: function (span,length,mu,d,m) { 2484 if (m == null) {m = -HTMLCSS.BIGDIMEN} 2485 var match = String(length).match(/width|height|depth/); 2486 var size = (match ? span.bbox[match[0].charAt(0)] : (d ? span.bbox[d] : 0)); 2487 var v = HTMLCSS.length2em(length,mu,size/this.mscale) * this.mscale; 2488 if (d && String(length).match(/^\s*[-+]/)) 2489 {return Math.max(m,span.bbox[d]+v)} else {return v} 2490 }, 2491 HTMLstretchH: MML.mbase.HTMLstretchH, 2492 HTMLstretchV: MML.mbase.HTMLstretchV 2493 }); 2494 2495 MML.mrow.Augment({ 2496 HTMLlineBreaks: function (span) { 2497 if (!this.parent.linebreakContainer) {return false} 2498 return (HTMLCSS.config.linebreaks.automatic && 2499 span.bbox.w > HTMLCSS.linebreakWidth) || this.hasNewline(); 2500 }, 2501 HTMLstretchH: function (box,w) { 2502 this.HTMLremoveColor(); 2503 var span = this.HTMLspanElement(); 2504 this.data[this.core].HTMLstretchH(span,w); 2505 this.HTMLcomputeBBox(span,true); 2506 this.HTMLhandleColor(span); 2507 return span; 2508 }, 2509 HTMLstretchV: function (box,h,d) { 2510 this.HTMLremoveColor(); 2511 var span = this.HTMLspanElement(); 2512 this.data[this.core].HTMLstretchV(span,h,d); 2513 this.HTMLcomputeBBox(span,true); 2514 this.HTMLhandleColor(span); 2515 return span; 2516 } 2517 }); 2518 2519 MML.mstyle.Augment({ 2520 toHTML: function (span,HW,D) { 2521 span = this.HTMLcreateSpan(span); 2522 if (this.data[0] != null) { 2523 var SPAN = this.data[0].toHTML(span); 2524 if (D != null) {this.data[0].HTMLstretchV(span,HW,D)} 2525 else if (HW != null) {this.data[0].HTMLstretchH(span,HW)} 2526 span.bbox = SPAN.bbox; 2527 } 2528 this.HTMLhandleSpace(span); 2529 this.HTMLhandleColor(span); 2530 return span; 2531 }, 2532 HTMLstretchH: MML.mbase.HTMLstretchH, 2533 HTMLstretchV: MML.mbase.HTMLstretchV 2534 }); 2535 2536 MML.mfrac.Augment({ 2537 toHTML: function (span) { 2538 span = this.HTMLcreateSpan(span); 2539 var frac = HTMLCSS.createStack(span); 2540 var num = HTMLCSS.createBox(frac), den = HTMLCSS.createBox(frac); 2541 HTMLCSS.MeasureSpans([this.HTMLboxChild(0,num),this.HTMLboxChild(1,den)]); 2542 var values = this.getValues("displaystyle","linethickness","numalign","denomalign","bevelled"); 2543 var scale = this.HTMLgetScale(), isDisplay = values.displaystyle; 2544 var a = HTMLCSS.TeX.axis_height * scale; 2545 if (values.bevelled) { 2546 var delta = (isDisplay ? .4 : .15); 2547 var H = Math.max(num.bbox.h+num.bbox.d,den.bbox.h+den.bbox.d)+2*delta; 2548 var bevel = HTMLCSS.createBox(frac); 2549 HTMLCSS.createDelimiter(bevel,0x2F,H); 2550 HTMLCSS.placeBox(num,0,(num.bbox.d-num.bbox.h)/2+a+delta); 2551 HTMLCSS.placeBox(bevel,num.bbox.w-delta/2,(bevel.bbox.d-bevel.bbox.h)/2+a); 2552 HTMLCSS.placeBox(den,num.bbox.w+bevel.bbox.w-delta,(den.bbox.d-den.bbox.h)/2+a-delta); 2553 } else { 2554 var W = Math.max(num.bbox.w,den.bbox.w); 2555 var t = HTMLCSS.thickness2em(values.linethickness,this.scale)*this.mscale, p,q, u,v; 2556 var mt = HTMLCSS.TeX.min_rule_thickness/this.em; 2557 if (isDisplay) {u = HTMLCSS.TeX.num1; v = HTMLCSS.TeX.denom1} 2558 else {u = (t === 0 ? HTMLCSS.TeX.num3 : HTMLCSS.TeX.num2); v = HTMLCSS.TeX.denom2} 2559 u *= scale; v *= scale; 2560 if (t === 0) {// \atop 2561 p = Math.max((isDisplay ? 7 : 3) * HTMLCSS.TeX.rule_thickness, 2*mt); // force to at least 2 px 2562 q = (u - num.bbox.d) - (den.bbox.h - v); 2563 if (q < p) {u += (p - q)/2; v += (p - q)/2} 2564 } else {// \over 2565 p = Math.max((isDisplay ? 2 : 0) * mt + t, t/2 + 1.5*mt); // force to be at least 1.5px 2566 q = (u - num.bbox.d) - (a + t/2); if (q < p) {u += p - q} 2567 q = (a - t/2) - (den.bbox.h - v); if (q < p) {v += p - q} 2568 var rule = HTMLCSS.createBox(frac); 2569 HTMLCSS.createRule(rule,t,0,W+2*t); 2570 HTMLCSS.placeBox(rule,0,a-t/2); 2571 } 2572 HTMLCSS.alignBox(num,values.numalign,u); 2573 HTMLCSS.alignBox(den,values.denomalign,-v); 2574 } 2575 this.HTMLhandleSpace(span); 2576 this.HTMLhandleColor(span); 2577 return span; 2578 }, 2579 HTMLcanStretch: function (direction) {return false}, 2580 HTMLhandleSpace: function (span) { 2581 if (!this.texWithDelims && !this.useMMLspacing) { 2582 // 2583 // Add nulldelimiterspace around the fraction 2584 // (TeXBook pg 150 and Appendix G rule 15e) 2585 // 2586 var space = HTMLCSS.TeX.nulldelimiterspace * this.mscale; 2587 var style = span.childNodes[HTMLCSS.msiePaddingWidthBug ? 1 : 0].style; 2588 style.marginLeft = style.marginRight = HTMLCSS.Em(space); 2589 span.bbox.w += 2*space; span.bbox.rw += 2*space; 2590 } 2591 this.SUPER(arguments).HTMLhandleSpace.call(this,span); 2592 } 2593 }); 2594 2595 MML.msqrt.Augment({ 2596 toHTML: function (span) { 2597 span = this.HTMLcreateSpan(span); 2598 var sqrt = HTMLCSS.createStack(span); 2599 var base = HTMLCSS.createBox(sqrt), 2600 rule = HTMLCSS.createBox(sqrt), 2601 surd = HTMLCSS.createBox(sqrt); 2602 var scale = this.HTMLgetScale(); 2603 var t = HTMLCSS.TeX.rule_thickness * scale, p,q, H, W; 2604 if (this.Get("displaystyle")) {p = HTMLCSS.TeX.x_height * scale} else {p = t} 2605 q = Math.max(t + p/4,1.5*HTMLCSS.TeX.min_rule_thickness/this.em); // force to be at least 1px 2606 var BASE = this.HTMLboxChild(0,base); 2607 H = BASE.bbox.h + BASE.bbox.d + q + t; 2608 HTMLCSS.createDelimiter(surd,0x221A,H,scale); 2609 HTMLCSS.MeasureSpans([BASE,surd]); 2610 W = BASE.bbox.w; 2611 var x = 0; 2612 if (surd.isMultiChar || (HTMLCSS.AdjustSurd && HTMLCSS.imgFonts)) {surd.bbox.w *= .95} 2613 if (surd.bbox.h + surd.bbox.d > H) {q = ((surd.bbox.h+surd.bbox.d) - (H-t))/2} 2614 var ruleC = HTMLCSS.FONTDATA.DELIMITERS[HTMLCSS.FONTDATA.RULECHAR]; 2615 if (!ruleC || W < ruleC.HW[0][0]*scale || scale < .75) { 2616 HTMLCSS.createRule(rule,0,t,W); 2617 } else { 2618 HTMLCSS.createDelimiter(rule,HTMLCSS.FONTDATA.RULECHAR,W,scale); 2619 } 2620 H = BASE.bbox.h + q + t; 2621 q = H*HTMLCSS.rfuzz; if (surd.isMultiChar) {q = HTMLCSS.rfuzz} 2622 x = this.HTMLaddRoot(sqrt,surd,x,surd.bbox.h+surd.bbox.d-H,scale); 2623 HTMLCSS.placeBox(surd,x,H-surd.bbox.h); 2624 HTMLCSS.placeBox(rule,x+surd.bbox.w,H-rule.bbox.h+q); 2625 HTMLCSS.placeBox(base,x+surd.bbox.w,0); 2626 this.HTMLhandleSpace(span); 2627 this.HTMLhandleColor(span); 2628 return span; 2629 }, 2630 HTMLaddRoot: function (sqrt,surd,x,d,scale) {return x} 2631 }); 2632 2633 MML.mroot.Augment({ 2634 toHTML: MML.msqrt.prototype.toHTML, 2635 HTMLaddRoot: function (sqrt,surd,x,d,scale) { 2636 var box = HTMLCSS.createBox(sqrt); 2637 if (this.data[1]) { 2638 var root = this.data[1].toHTML(box); 2639 root.style.paddingRight = root.style.paddingLeft = ""; // remove extra padding, if any 2640 HTMLCSS.Measured(root,box); 2641 } else {box.bbox = this.HTMLzeroBBox()} 2642 var h = this.HTMLrootHeight(surd.bbox.h+surd.bbox.d,scale,box)-d; 2643 var w = Math.min(box.bbox.w,box.bbox.rw); // remove extra right-hand padding, if any 2644 x = Math.max(w,surd.offset); 2645 HTMLCSS.placeBox(box,x-w,h); 2646 return x - surd.offset; 2647 }, 2648 HTMLrootHeight: function (d,scale,root) { 2649 return .45*(d-.9*scale)+.6*scale + Math.max(0,root.bbox.d-.075); 2650 } 2651 }); 2652 2653 MML.mfenced.Augment({ 2654 toHTML: function (span) { 2655 span = this.HTMLcreateSpan(span); 2656 if (this.data.open) {this.data.open.toHTML(span)} 2657 if (this.data[0] != null) {this.data[0].toHTML(span)} 2658 for (var i = 1, m = this.data.length; i < m; i++) { 2659 if (this.data[i]) { 2660 if (this.data["sep"+i]) {this.data["sep"+i].toHTML(span)} 2661 this.data[i].toHTML(span); 2662 } 2663 } 2664 if (this.data.close) {this.data.close.toHTML(span)} 2665 var stretchy = this.HTMLcomputeBBox(span); 2666 var h = span.bbox.h, d = span.bbox.d; 2667 for (i = 0, m = stretchy.length; i < m; i++) {stretchy[i].HTMLstretchV(span,h,d)} 2668 if (stretchy.length) {this.HTMLcomputeBBox(span,true)} 2669 this.HTMLhandleSpace(span); 2670 this.HTMLhandleColor(span); 2671 return span; 2672 }, 2673 HTMLcomputeBBox: function (span,full) { 2674 var BBOX = span.bbox = {}, stretchy = []; 2675 this.HTMLcheckStretchy(this.data.open,BBOX,stretchy,full); 2676 this.HTMLcheckStretchy(this.data[0],BBOX,stretchy,full); 2677 for (var i = 1, m = this.data.length; i < m; i++) { 2678 if (this.data[i]) { 2679 this.HTMLcheckStretchy(this.data["sep"+i],BBOX,stretchy,full); 2680 this.HTMLcheckStretchy(this.data[i],BBOX,stretchy,full); 2681 } 2682 } 2683 this.HTMLcheckStretchy(this.data.close,BBOX,stretchy,full); 2684 this.HTMLcleanBBox(BBOX); 2685 return stretchy; 2686 }, 2687 HTMLcheckStretchy: function (core,BBOX,stretchy,full) { 2688 if (core) { 2689 if (!full && core.HTMLcanStretch("Vertical")) 2690 {stretchy.push(core); core = (core.CoreMO()||core)} 2691 this.HTMLcombineBBoxes(core,BBOX); 2692 } 2693 } 2694 }); 2695 2696 MML.menclose.Augment({toHTML: MML.mbase.HTMLautoload}); 2697 MML.maction.Augment({toHTML: MML.mbase.HTMLautoload}); 2698 2699 MML.semantics.Augment({ 2700 toHTML: function (span,HW,D) { 2701 span = this.HTMLcreateSpan(span); 2702 if (this.data[0] != null) { 2703 var SPAN = this.data[0].toHTML(span); 2704 if (D != null) {this.data[0].HTMLstretchV(span,HW,D)} 2705 else if (HW != null) {this.data[0].HTMLstretchH(span,HW)} 2706 span.bbox = SPAN.bbox; 2707 } 2708 this.HTMLhandleSpace(span); 2709 return span; 2710 }, 2711 HTMLstretchH: MML.mbase.HTMLstretchH, 2712 HTMLstretchV: MML.mbase.HTMLstretchV 2713 }); 2714 2715 MML.munderover.Augment({ 2716 toHTML: function (span,HW,D) { 2717 var values = this.getValues("displaystyle","accent","accentunder","align"); 2718 var base = this.data[this.base]; 2719 if (!values.displaystyle && base != null && 2720 (base.movablelimits || base.CoreMO().Get("movablelimits"))) 2721 {return MML.msubsup.prototype.toHTML.call(this,span)} 2722 span = this.HTMLcreateSpan(span); var scale = this.HTMLgetScale(); 2723 var stack = HTMLCSS.createStack(span); 2724 var boxes = [], children = [], stretch = [], box, i, m; 2725 for (i = 0, m = this.data.length; i < m; i++) { 2726 if (this.data[i] != null) { 2727 box = boxes[i] = HTMLCSS.createBox(stack); 2728 children[i] = this.data[i].toHTML(box); 2729 if (i == this.base) { 2730 if (D != null) {this.data[this.base].HTMLstretchV(box,HW,D)} 2731 else if (HW != null) {this.data[this.base].HTMLstretchH(box,HW)} 2732 stretch[i] = (D == null && HW != null ? false : 2733 this.data[i].HTMLcanStretch("Horizontal")); 2734 } else { 2735 stretch[i] = this.data[i].HTMLcanStretch("Horizontal"); 2736 children[i].style.paddingLeft = children[i].style.paddingRight = ""; 2737 } 2738 } 2739 } 2740 HTMLCSS.MeasureSpans(children); 2741 var W = -HTMLCSS.BIGDIMEN, WW = W; 2742 for (i = 0, m = this.data.length; i < m; i++) { 2743 if (this.data[i]) { 2744 if (boxes[i].bbox.w > WW) {WW = boxes[i].bbox.w} 2745 if (!stretch[i] && WW > W) {W = WW} 2746 } 2747 } 2748 if (D == null && HW != null) {W = HW} else if (W == -HTMLCSS.BIGDIMEN) {W = WW} 2749 for (i = WW = 0, m = this.data.length; i < m; i++) {if (this.data[i]) { 2750 box = boxes[i]; 2751 if (stretch[i]) { 2752 box.bbox = this.data[i].HTMLstretchH(box,W).bbox; 2753 if (i !== this.base) 2754 {children[i].style.paddingLeft = children[i].style.paddingRight = ""} 2755 } 2756 if (box.bbox.w > WW) {WW = box.bbox.w} 2757 }} 2758 var t = HTMLCSS.TeX.rule_thickness * this.mscale, factor = HTMLCSS.FONTDATA.TeX_factor; 2759 var x, y, z1, z2, z3, dw, k, delta = 0; 2760 base = boxes[this.base] || {bbox: this.HTMLzeroBBox()}; 2761 if (base.bbox.ic) {delta = 1.3*base.bbox.ic + .05} // adjust faked IC to be more in line with expeted results 2762 for (i = 0, m = this.data.length; i < m; i++) { 2763 if (this.data[i] != null) { 2764 box = boxes[i]; 2765 z3 = HTMLCSS.TeX.big_op_spacing5 * scale; 2766 var accent = (i != this.base && values[this.ACCENTS[i]]); 2767 if (accent && box.bbox.w <= 1/HTMLCSS.em+.0001) { // images can get the width off by 1px 2768 box.bbox.w = box.bbox.rw - box.bbox.lw; box.bbox.noclip = true; 2769 if (box.bbox.lw) 2770 {box.insertBefore(HTMLCSS.createSpace(box.parentNode,0,0,-box.bbox.lw),box.firstChild)} 2771 HTMLCSS.createBlank(box,0,0,box.bbox.rw+.1); 2772 } 2773 dw = {left:0, center:(WW-box.bbox.w)/2, right:WW-box.bbox.w}[values.align]; 2774 x = dw; y = 0; 2775 if (i == this.over) { 2776 if (accent) { 2777 k = Math.max(t * scale * factor,2.5/this.em); z3 = 0; 2778 if (base.bbox.skew) { 2779 x += base.bbox.skew; span.bbox.skew = base.bbox.skew; 2780 if (x+box.bbox.w > WW) {span.bbox.skew += (WW-box.bbox.w-x)/2} 2781 } 2782 } else { 2783 z1 = HTMLCSS.TeX.big_op_spacing1 * scale * factor; 2784 z2 = HTMLCSS.TeX.big_op_spacing3 * scale * factor; 2785 k = Math.max(z1,z2-Math.max(0,box.bbox.d)); 2786 } 2787 k = Math.max(k,1.5/this.em); // force to be at least 1.5px 2788 x += delta/2; y = base.bbox.h + box.bbox.d + k; 2789 box.bbox.h += z3; 2790 } else if (i == this.under) { 2791 if (accent) { 2792 k = 3*t * scale * factor; z3 = 0; 2793 } else { 2794 z1 = HTMLCSS.TeX.big_op_spacing2 * scale * factor; 2795 z2 = HTMLCSS.TeX.big_op_spacing4 * scale * factor; 2796 k = Math.max(z1,z2-box.bbox.h); 2797 } 2798 k = Math.max(k,1.5/this.em); // force to be at least 1.5px 2799 x -= delta/2; y = -(base.bbox.d + box.bbox.h + k); 2800 box.bbox.d += z3; 2801 } 2802 HTMLCSS.placeBox(box,x,y); 2803 } 2804 } 2805 this.HTMLhandleSpace(span); 2806 this.HTMLhandleColor(span); 2807 return span; 2808 }, 2809 HTMLstretchH: MML.mbase.HTMLstretchH, 2810 HTMLstretchV: MML.mbase.HTMLstretchV 2811 }); 2812 2813 MML.msubsup.Augment({ 2814 toHTML: function (span,HW,D) { 2815 span = this.HTMLcreateSpan(span); 2816 var scale = this.HTMLgetScale(), mu = this.HTMLgetMu(span); 2817 var stack = HTMLCSS.createStack(span), values, children = []; 2818 var base = HTMLCSS.createBox(stack); 2819 if (this.data[this.base]) { 2820 children.push(this.data[this.base].toHTML(base)); 2821 if (D != null) {this.data[this.base].HTMLstretchV(base,HW,D)} 2822 else if (HW != null) {this.data[this.base].HTMLstretchH(base,HW)} 2823 } else {base.bbox = this.HTMLzeroBBox()} 2824 var x_height = HTMLCSS.TeX.x_height * scale, 2825 s = HTMLCSS.TeX.scriptspace * scale * .75; // FIXME: .75 can be removed when IC is right? 2826 var sup, sub; 2827 if (this.HTMLnotEmpty(this.data[this.sup])) 2828 {sup = HTMLCSS.createBox(stack); children.push(this.data[this.sup].toHTML(sup))} 2829 if (this.HTMLnotEmpty(this.data[this.sub])) 2830 {sub = HTMLCSS.createBox(stack); children.push(this.data[this.sub].toHTML(sub))} 2831 HTMLCSS.MeasureSpans(children); 2832 if (sup) {sup.bbox.w += s; sup.bbox.rw = Math.max(sup.bbox.w,sup.bbox.rw)} 2833 if (sub) {sub.bbox.w += s; sub.bbox.rw = Math.max(sub.bbox.w,sub.bbox.rw)} 2834 HTMLCSS.placeBox(base,0,0); 2835 var sscale = scale; 2836 if (sup) { 2837 sscale = this.data[this.sup].HTMLgetScale(); 2838 } else if (sub) { 2839 sscale = this.data[this.sub].HTMLgetScale(); 2840 } 2841 var q = HTMLCSS.TeX.sup_drop * sscale, r = HTMLCSS.TeX.sub_drop * sscale; 2842 var u = base.bbox.h - q, v = base.bbox.d + r, delta = 0, p; 2843 if (base.bbox.ic) { 2844 base.bbox.w -= base.bbox.ic; // remove IC (added by mo and mi) 2845 delta = 1.3*base.bbox.ic + .05; // adjust faked IC to be more in line with expected results 2846 } 2847 if (this.data[this.base] && HW == null && D == null && 2848 (this.data[this.base].type === "mi" || this.data[this.base].type === "mo")) { 2849 if (this.data[this.base].data.join("").length === 1 && children[0].scale === 1 && 2850 !this.data[this.base].Get("largeop")) {u = v = 0} 2851 } 2852 var min = this.getValues("subscriptshift","superscriptshift"); 2853 min.subscriptshift = (min.subscriptshift === "" ? 0 : HTMLCSS.length2em(min.subscriptshift,mu)); 2854 min.superscriptshift = (min.superscriptshift === "" ? 0 : HTMLCSS.length2em(min.superscriptshift,mu)); 2855 if (!sup) { 2856 if (sub) { 2857 v = Math.max(v,HTMLCSS.TeX.sub1*scale,sub.bbox.h-(4/5)*x_height,min.subscriptshift); 2858 HTMLCSS.placeBox(sub,base.bbox.w,-v,sub.bbox); 2859 } 2860 } else { 2861 if (!sub) { 2862 values = this.getValues("displaystyle","texprimestyle"); 2863 p = HTMLCSS.TeX[(values.displaystyle ? "sup1" : (values.texprimestyle ? "sup3" : "sup2"))]; 2864 u = Math.max(u,p*scale,sup.bbox.d+(1/4)*x_height,min.superscriptshift); 2865 HTMLCSS.placeBox(sup,base.bbox.w+delta,u,sup.bbox); 2866 } else { 2867 v = Math.max(v,HTMLCSS.TeX.sub2*scale); 2868 var t = HTMLCSS.TeX.rule_thickness * scale; 2869 if ((u - sup.bbox.d) - (sub.bbox.h - v) < 3*t) { 2870 v = 3*t - u + sup.bbox.d + sub.bbox.h; 2871 q = (4/5)*x_height - (u - sup.bbox.d); 2872 if (q > 0) {u += q; v -= q} 2873 } 2874 HTMLCSS.placeBox(sup,base.bbox.w+delta,Math.max(u,min.superscriptshift)); 2875 HTMLCSS.placeBox(sub,base.bbox.w,-Math.max(v,min.subscriptshift)); 2876 } 2877 } 2878 this.HTMLhandleSpace(span); 2879 this.HTMLhandleColor(span); 2880 return span; 2881 }, 2882 HTMLstretchH: MML.mbase.HTMLstretchH, 2883 HTMLstretchV: MML.mbase.HTMLstretchV 2884 }); 2885 2886 MML.mmultiscripts.Augment({toHTML: MML.mbase.HTMLautoload}); 2887 2888 MML.mtable.Augment({toHTML: MML.mbase.HTMLautoload}); 2889 2890 MML["annotation-xml"].Augment({toHTML: MML.mbase.HTMLautoload}); 2891 MML.annotation.Augment({toHTML: function (span) {return this.HTMLcreateSpan(span)}}); 2892 2893 MML.math.Augment({ 2894 toHTML: function (span,node,phase) { 2895 var stack, box, html, math, SPAN = span; 2896 // 2897 // Phase I lays out the math, but doesn't measure the final math yet 2898 // (that is done for a chunk at a time, to avoid reflows) 2899 // 2900 if (!phase || phase === HTMLCSS.PHASE.I) { 2901 var nobr = HTMLCSS.addElement(span,"nobr",{isMathJax: true}); 2902 span = this.HTMLcreateSpan(nobr); 2903 var alttext = this.Get("alttext"); 2904 if (alttext && !span.getAttribute("aria-label")) span.setAttribute("aria-label",alttext); 2905 if (!span.getAttribute("role")) span.setAttribute("role","math"); 2906 stack = HTMLCSS.createStack(span); box = HTMLCSS.createBox(stack); 2907 // Move font-size from outer span to stack to avoid line separation 2908 // problem in strict HTML mode 2909 stack.style.fontSize = nobr.parentNode.style.fontSize; nobr.parentNode.style.fontSize = ""; 2910 if (this.data[0] != null) { 2911 MML.mbase.prototype.displayAlign = HUB.config.displayAlign; 2912 MML.mbase.prototype.displayIndent = HUB.config.displayIndent; 2913 if (String(HUB.config.displayIndent).match(/^0($|[a-z%])/i)) 2914 MML.mbase.prototype.displayIndent = "0"; 2915 html = this.data[0].toHTML(box); html.bbox.exactW = false; // force remeasure just to be sure 2916 } 2917 } else { 2918 span = span.firstChild.firstChild; 2919 if (this.href) span = span.firstChild; 2920 stack = span.firstChild; 2921 if (stack.style.position !== "relative") stack = stack.nextSibling; 2922 box = stack.firstChild; 2923 html = box.firstChild; 2924 } 2925 // 2926 // Phase II measures the math (this is done for each one in the chunk at once) 2927 // 2928 math = ((!phase || phase === HTMLCSS.PHASE.II) ? HTMLCSS.Measured(html,box) : html); 2929 // 2930 // Phase III finishes the layout using the measured math 2931 // 2932 if (!phase || phase === HTMLCSS.PHASE.III) { 2933 HTMLCSS.placeBox(box,0,0); 2934 // 2935 // Get width right if minimum font size is set: 2936 // Round to nearest pixel (plus a small amount), and convert back to outer-em's. 2937 // Add the width to the span (outside the MathJax class, so uses outer em size, 2938 // which makes it work even when minimum font size is in effect). 2939 // 2940 span.style.width = HTMLCSS.Em(Math.max(0,Math.round(math.bbox.w*this.em)+.25)/HTMLCSS.outerEm); 2941 span.style.display = "inline-block"; 2942 // 2943 // Adjust bbox to match outer em-size 2944 // 2945 var p = 1/HTMLCSS.em, f = HTMLCSS.em / HTMLCSS.outerEm; HTMLCSS.em /= f; 2946 span.bbox.h *= f; span.bbox.d *= f; span.bbox.w *= f; 2947 span.bbox.lw *= f; span.bbox.rw *= f; 2948 if (span.bbox.H) {span.bbox.H *= f} 2949 if (span.bbox.D) {span.bbox.D *= f} 2950 if (math && math.bbox.width != null) { 2951 span.style.minWidth = (math.bbox.minWidth || span.style.width); 2952 span.style.width = math.bbox.width; 2953 box.style.width = stack.style.width = SPAN.style.width = "100%"; 2954 } 2955 // 2956 // Add color (if any) 2957 // 2958 var color = this.HTMLhandleColor(span); 2959 // 2960 // Make math span be the correct height and depth 2961 // 2962 if (math) {HTMLCSS.createRule(span,(math.bbox.h+p)*f,(math.bbox.d+p)*f,0)} 2963 // 2964 // Handle indentalign and indentshift for single-line display equations 2965 // 2966 if (!this.isMultiline && this.Get("display") === "block" && span.bbox.width == null) { 2967 var values = this.getValues("indentalignfirst","indentshiftfirst","indentalign","indentshift"); 2968 if (values.indentalignfirst !== MML.INDENTALIGN.INDENTALIGN) {values.indentalign = values.indentalignfirst} 2969 if (values.indentalign === MML.INDENTALIGN.AUTO) {values.indentalign = this.displayAlign} 2970 if (values.indentshiftfirst !== MML.INDENTSHIFT.INDENTSHIFT) {values.indentshift = values.indentshiftfirst} 2971 if (values.indentshift === "auto") {values.indentshift = "0"} 2972 var shift = HTMLCSS.length2em(values.indentshift,1,HTMLCSS.scale*HTMLCSS.cwidth); 2973 if (this.displayIndent !== "0") { 2974 var indent = HTMLCSS.length2em(this.displayIndent,1,HTMLCSS.scale*HTMLCSS.cwidth); 2975 shift += (values.indentalign === MML.INDENTALIGN.RIGHT ? -indent : indent); 2976 } 2977 node.style.textAlign = values.indentalign; 2978 // ### FIXME: make percentage widths respond to changes in container 2979 if (shift) { 2980 HUB.Insert(span.style,({ 2981 left: {marginLeft: HTMLCSS.Em(shift)}, 2982 right: {marginRight: HTMLCSS.Em(-shift)}, 2983 center: {marginLeft: HTMLCSS.Em(shift), marginRight: HTMLCSS.Em(-shift)} 2984 })[values.indentalign]); 2985 // 2986 // Move the background color, of any 2987 // 2988 if (color) { 2989 var L = parseFloat(color.style.marginLeft||"0")+shift, 2990 R = parseFloat(color.style.marginRight||"0")-shift; 2991 color.style.marginLeft = HTMLCSS.Em(L); 2992 color.style.marginRight = 2993 HTMLCSS.Em(R + (values.indentalign === "right" ? 2994 span.bbox.w+shift - span.bbox.w : 0)); 2995 if (HTMLCSS.msieColorBug && values.indentalign === "right") { 2996 if (parseFloat(color.style.marginLeft) > 0) { 2997 var padding = MathJax.HTML.addElement(color.parentNode,"span"); 2998 padding.style.marginLeft = HTMLCSS.Em(R+Math.min(0,span.bbox.w+shift)); 2999 color.nextSibling.style.marginRight = "0em"; 3000 } 3001 color.nextSibling.style.marginLeft = "0em"; 3002 color.style.marginRight = color.style.marginLeft = "0em"; 3003 } 3004 } 3005 } 3006 } 3007 } 3008 return span; 3009 }, 3010 HTMLspanElement: MML.mbase.prototype.HTMLspanElement 3011 }); 3012 3013 MML.TeXAtom.Augment({ 3014 toHTML: function (span,HW,D) { 3015 span = this.HTMLcreateSpan(span); 3016 if (this.data[0] != null) { 3017 if (this.texClass === MML.TEXCLASS.VCENTER) { 3018 var stack = HTMLCSS.createStack(span); 3019 var box = HTMLCSS.createBox(stack); 3020 var child = this.data[0].toHTML(box); 3021 if (D != null) {HTMLCSS.Remeasured(this.data[0].HTMLstretchV(box,HW,D),box)} 3022 else if (HW != null) {HTMLCSS.Remeasured(this.data[0].HTMLstretchH(box,HW),box)} 3023 else {HTMLCSS.Measured(child,box)} 3024 var a = HTMLCSS.TeX.axis_height * this.HTMLgetScale(); 3025 HTMLCSS.placeBox(box,0,a-(box.bbox.h+box.bbox.d)/2+box.bbox.d); 3026 } else { 3027 var html = this.data[0].toHTML(span,HW,D); 3028 if (D != null) {html = this.data[0].HTMLstretchV(box,HW,D)} 3029 else if (HW != null) {html = this.data[0].HTMLstretchH(box,HW)} 3030 span.bbox = html.bbox; 3031 } 3032 } 3033 this.HTMLhandleSpace(span); 3034 this.HTMLhandleColor(span); 3035 return span; 3036 }, 3037 HTMLstretchH: MML.mbase.HTMLstretchH, 3038 HTMLstretchV: MML.mbase.HTMLstretchV 3039 }); 3040 3041 // 3042 // Loading isn't complete until the element jax is modified, 3043 // but can't call loadComplete within the callback for "mml Jax Ready" 3044 // (it would call HTMLCSS's Require routine, asking for the mml jax again) 3045 // so wait until after the mml jax has finished processing. 3046 // 3047 // We also need to wait for the onload handler to run, since the loadComplete 3048 // will call Config and Startup, which need to modify the body. 3049 // 3050 HUB.Register.StartupHook("onLoad",function () { 3051 setTimeout(MathJax.Callback(["loadComplete",HTMLCSS,"jax.js"]),0); 3052 }); 3053 }); 3054 3055 HUB.Register.StartupHook("End Config",function () { 3056 3057 // 3058 // Handle browser-specific setup 3059 // 3060 HUB.Browser.Select({ 3061 MSIE: function (browser) { 3062 var mode = (document.documentMode || 0); 3063 var isIE7 = browser.versionAtLeast("7.0"); 3064 var isIE8 = browser.versionAtLeast("8.0") && mode > 7; 3065 var quirks = (document.compatMode === "BackCompat"); 3066 if (mode < 9) { 3067 // IE doesn't do mouse events on trasparent objects, 3068 // so give a background color, but opacity makes it transparent 3069 HTMLCSS.config.styles[".MathJax .MathJax_HitBox"]["background-color"] = "white"; 3070 HTMLCSS.config.styles[".MathJax .MathJax_HitBox"].opacity = 0 3071 HTMLCSS.config.styles[".MathJax .MathJax_HitBox"].filter = "alpha(opacity=0)"; 3072 } 3073 // FIXME: work out tests for these? 3074 HTMLCSS.Augment({ 3075 PaddingWidthBug: true, 3076 msieAccentBug: true, 3077 msieColorBug: (mode < 8), // negative margin-right doesn't work to position color 3078 msieColorPositionBug: true, // needs position:relative to put color behind text 3079 msieRelativeWidthBug: quirks, 3080 msieDisappearingBug: (mode >= 8), // inline math disappears 3081 msieMarginScaleBug: (mode < 8), // relative margins are not scaled properly by font-size 3082 msiePaddingWidthBug: true, 3083 msieBorderWidthBug: quirks, 3084 msieFrameSizeBug: (mode <= 8), // crashes if size of box isn't big enough for border 3085 msieInlineBlockAlignBug: (!isIE8 || quirks), 3086 msiePlaceBoxBug: (isIE8 && !quirks), 3087 msieClipRectBug: !isIE8, 3088 msieNegativeSpaceBug: quirks, 3089 msieRuleBug: (mode < 7), // rules need to be measured 3090 cloneNodeBug: (isIE8 && browser.version === "8.0"), 3091 msieItalicWidthBug: true, // can't measure boxes ending in italics correctly 3092 initialSkipBug: (mode < 8), // confused by initial left-margin values 3093 msieNegativeBBoxBug: (mode >= 8), // negative bboxes have positive widths 3094 msieIE6: !isIE7, 3095 msieItalicWidthBug: true, 3096 FontFaceBug: (mode < 9), 3097 msieFontCSSBug: browser.isIE9, 3098 allowWebFonts: (mode >= 9 ? "woff" : "eot") 3099 }); 3100 }, 3101 3102 Firefox: function (browser) { 3103 var webFonts = false; 3104 if (browser.versionAtLeast("3.5")) { 3105 var root = String(document.location).replace(/[^\/]*$/,""); 3106 if (document.location.protocol !== "file:" || HUB.config.root.match(/^https?:\/\//) || 3107 (HUB.config.root+"/").substr(0,root.length) === root) {webFonts = "otf"} 3108 } 3109 HTMLCSS.Augment({ 3110 ffVerticalAlignBug: !browser.versionAtLeast("20.0"), // not sure when this bug was fixed 3111 AccentBug: true, 3112 allowWebFonts: webFonts, 3113 ffFontOptimizationBug: true 3114 }); 3115 }, 3116 3117 Safari: function (browser) { 3118 var v3p0 = browser.versionAtLeast("3.0"); 3119 var v3p1 = browser.versionAtLeast("3.1"); 3120 var trueSafari = navigator.appVersion.match(/ Safari\/\d/) && 3121 navigator.appVersion.match(/ Version\/\d/) && 3122 navigator.vendor.match(/Apple/); 3123 var android = (navigator.appVersion.match(/ Android (\d+)\.(\d+)/)); 3124 var forceImages = (v3p1 && browser.isMobile && ( 3125 (navigator.platform.match(/iPad|iPod|iPhone/) && !browser.versionAtLeast("5.0")) || 3126 (android != null && (android[1] < 2 || (android[1] == 2 && android[2] < 2))) 3127 )); 3128 HTMLCSS.Augment({ 3129 config: { 3130 styles: { 3131 ".MathJax img, .MathJax nobr, .MathJax a": { 3132 // "none" seems to work like "0px" when width is initially 0 3133 "max-width": "5000em", "max-height": "5000em" 3134 } 3135 } 3136 }, 3137 Em: ((browser.webkit||0) >= 538 ? HTMLCSS.EmRounded : HTMLCSS.Em), // issue #931 3138 rfuzz: .011, 3139 AccentBug: true, 3140 AdjustSurd: true, 3141 negativeBBoxes: true, 3142 safariNegativeSpaceBug: true, 3143 safariVerticalAlignBug: !v3p1, 3144 safariTextNodeBug: !v3p0, 3145 forceReflow: true, 3146 FontFaceBug: true, 3147 allowWebFonts: (v3p1 && !forceImages ? "otf" : false) 3148 }); 3149 if (trueSafari) { 3150 HTMLCSS.Augment({ 3151 webFontDefault: (browser.isMobile ? "sans-serif" : "serif") 3152 }); 3153 } 3154 if (browser.isPC) { 3155 HTMLCSS.Augment({ 3156 adjustAvailableFonts: HTMLCSS.removeSTIXfonts, // can't access plane1 3157 checkWebFontsTwice: true // bug in Safari/Win that doesn't update font test div properly 3158 }); 3159 } 3160 if (forceImages) { 3161 // Force image mode for iOS prior to 4.2 and Droid prior to 2.2 3162 var config = HUB.config["HTML-CSS"]; 3163 if (config) {config.availableFonts = []; config.preferredFont = null} 3164 else {HUB.config["HTML-CSS"] = {availableFonts: [], preferredFont: null}} 3165 } 3166 }, 3167 3168 Chrome: function (browser) { 3169 HTMLCSS.Augment({ 3170 Em: HTMLCSS.EmRounded, // vertical alignment needs help (since around v20) 3171 cloneNodeBug: true, // Chrome gets heights wrong with the cloned ones 3172 rfuzz: -.02, 3173 AccentBug: true, 3174 AdjustSurd: true, 3175 FontFaceBug: browser.versionAtLeast("32.0"), // Chrome 32 fails on bold-italic (#735) 3176 negativeBBoxes: true, 3177 safariNegativeSpaceBug: true, 3178 safariWebFontSerif: [""], 3179 forceReflow: true, 3180 allowWebFonts: (browser.versionAtLeast("4.0") ? "otf" : "svg") 3181 }); 3182 }, 3183 3184 Opera: function (browser) { 3185 browser.isMini = (navigator.appVersion.match("Opera Mini") != null); 3186 HTMLCSS.config.styles[".MathJax .merror"]["vertical-align"] = null; 3187 HTMLCSS.config.styles[".MathJax span"]["z-index"] = 0; 3188 HTMLCSS.Augment({ 3189 operaHeightBug: true, 3190 operaVerticalAlignBug: true, 3191 operaFontSizeBug: browser.versionAtLeast("10.61"), 3192 initialSkipBug: true, 3193 FontFaceBug: true, 3194 PaddingWidthBug: true, 3195 allowWebFonts: (browser.versionAtLeast("10.0") && !browser.isMini ? "otf" : false), 3196 adjustAvailableFonts: HTMLCSS.removeSTIXfonts 3197 }); 3198 }, 3199 3200 Konqueror: function (browser) { 3201 HTMLCSS.Augment({ 3202 konquerorVerticalAlignBug: true 3203 }); 3204 } 3205 }); 3206 3207 }); 3208 3209 MathJax.Hub.Register.StartupHook("End Cookie", function () { 3210 if (HUB.config.menuSettings.zoom !== "None") 3211 {AJAX.Require("[MathJax]/extensions/MathZoom.js")} 3212 }); 3213 3214 })(MathJax.Ajax, MathJax.Hub, MathJax.OutputJax["HTML-CSS"]);