diff --git a/unpacked/jax/output/CommonHTML/jax.js b/unpacked/jax/output/CommonHTML/jax.js index 1d3c91574..8e0807b83 100644 --- a/unpacked/jax/output/CommonHTML/jax.js +++ b/unpacked/jax/output/CommonHTML/jax.js @@ -36,7 +36,9 @@ var SCRIPTFACTOR = Math.sqrt(1/2), AXISHEIGHT = .25, STRUTHEIGHT = 1, - HFUZZ = .025, DFUZZ = .025; // adjustments to bounding box of character boxes + AFUZZ = .08, HFUZZ = .025, DFUZZ = .025; // adjustments to bounding box of character boxes + + var UNKNOWNFAMILY = "STIXGeneral,'Cambria Math','Arial Unicode MS',serif"; var STYLES = { ".MathJax_CHTML_Display": { @@ -101,6 +103,17 @@ ".MJXc-space1": {"margin-left":".167em"}, ".MJXc-space2": {"margin-left":".222em"}, ".MJXc-space3": {"margin-left":".278em"}, + + ".MJXc-TeX-unknown": {"font-family":UNKNOWNFAMILY}, + "mjx-chartest": { + display:"block", + position:"absolute", top:0, + "line-height":"normal", + "font-size":"500%", + "font-family":UNKNOWNFAMILY + }, + "mjx-chartest mjx-char": {display:"inline"}, + "mjx-chartest mjx-box": {"padding-top": "500px"}, /*********************************/ @@ -439,6 +452,17 @@ /********************************************************/ + // + // Get a unicode character by number (even when it takes two character) + // + unicodeChar: function (n) { + if (n < 0xFFFF) return String.fromCharCode(n); + n -= 0x10000; + return String.fromCharCode((n>>10)+0xD800) + String.fromCharCode((N&0x3FF)+0xDC00); + }, + // + // Get the unicode number of a (possibly multi-character) string + // getUnicode: function (string) { var n = string.text.charCodeAt(string.i); string.i++; if (n >= 0xD800 && n < 0xDBFF) { @@ -447,6 +471,12 @@ } return n; }, + // + // Get the list of actions for a given character in a given variant + // (processing remaps, multi-character results, and so on). Results are + // cached so that future lookups for the same variant/n pair will not + // require looking through the data again. + // getCharList: function (variant,n) { var id, M, list = [], cache = variant.cache, N = n; if (cache[n]) return cache[n]; @@ -489,6 +519,12 @@ cache[N] = list; return list; }, + // + // After all remapping has been done, look up a character + // in the fonts for a given variant, chaining to other + // variants as needed. Return an undefined character if + // it isnt' found in the given variant. + // lookupChar: function (variant,n) { while (variant) { for (var i = 0, m = variant.fonts.length; i < m; i++) { @@ -500,13 +536,7 @@ if (C.length === 5) C[5] = {}; if (C.c == null) { C[0] /= 1000; C[1] /= 1000; C[2] /= 1000; C[3] /= 1000; C[4] /= 1000; - if (n <= 0xFFFF) { - C.c = String.fromCharCode(n); - } else { - var N = n - 0x10000; - C.c = String.fromCharCode((N>>10)+0xD800) - + String.fromCharCode((N&0x3FF)+0xDC00); - } + C.c = this.unicodeChar(n); } if (C[5].space) return {type:"space", w:C[2], font:font}; return {type:"char", font:font, n:n}; @@ -516,59 +546,115 @@ } return this.unknownChar(variant,n); }, - unknownChar: function (variant,n) {}, + // + // Create a fake font entry for an unknown character. + // + unknownChar: function (variant,n) { + HUB.signal.Post(["CommonHTML Jax - unknown char",n,variant]); + var c = this.unicodeChar(n); + var HDW = this.getHDW(c); var a = (HDW.h-HDW.d)/2+AFUZZ; // ### FIXME: is this really the axis of the surrounding text? + var unknown = {type:"unknown", n:n, font:{className:"MJXc-TeX-unknown"}}; + unknown.font[n] = [.8,.2,HDW.w,0,HDW.w,{a:a, A:HDW.h-a, d:HDW.d}]; + unknown.font[n].c = c + return unknown; + }, + // + // Get the height, depth and width of a character + // (height and depth are of the font, not the character). + // WARNING: causes reflow of the page! + // + getHDW: function (c) { + var test1 = HTML.addElement(document.body,"mjx-chartest",{},[["mjx-char",{},[c]]]); + var test2 = HTML.addElement(document.body,"mjx-chartest",{},[["mjx-char",{},[c,["mjx-box"]]]]); + var em = window.parseFloat(window.getComputedStyle(test1).fontSize); + var d = (test2.offsetHeight-500)/em; + var w = test1.offsetWidth/em, h = test1.offsetHeight/em - d; + document.body.removeChild(test1); + document.body.removeChild(test2); + return {h:h, d:d, w:w} + }, /********************************************************/ + // + // Process a character list into a given node and return + // the updated bounding box. + // addCharList: function (node,list,bbox) { - var text = "", className; + var state = {text:"", className:null}; for (var i = 0, m = list.length; i < m; i++) { var item = list[i]; - switch (item.type) { - case "char": - var font = item.font; - if (className && font.className !== className) { - HTML.addElement(node,"span",{className:className},[text]); - text = ""; className = null; - } - var C = font[item.n]; - text += C.c; className = font.className; - if (bbox.h < C[0]) bbox.t = bbox.h = C[0]; - if (bbox.d < C[1]) bbox.b = bbox.d = C[1]; - if (bbox.l > bbox.w+C[3]) bbox.l = bbox.w+C[3]; - if (bbox.r < bbox.w+C[4]) bbox.r = bbox.w+C[4]; - bbox.w += C[2]; - if (m == 1 && font.skew && font.skew[item.n]) bbox.skew = font.skew[item.n]; - if (C[5].rfix) { - HTML.addElement(node,"span",{ - className:className, style:{"margin-right":CHTML.Em(C[5].rfix/1000)} - },[text]); - text = ""; className = null; - } - break; - - case "space": - if (item.w) { - if (text === "") className = item.font.className; - HTML.addElement(node,"span",{ - className:className, style:{"margin-right":CHTML.Em(item.w)} - },[text]); - text = ""; className = null; - bbox.w += item.w; - } - break; - } + if (this.charList[item.type]) (this.charList[item.type])(item,node,bbox,state,m); } - if (text !== "") { + if (state.text !== "") { if (node.childNodes.length) { - HTML.addElement(node,"span",{className:className},[text]); + HTML.addElement(node,"span",{className:state.className},[state.text]); } else { - HTML.addText(node,text); - node.className = className; + HTML.addText(node,state.text); + node.className = state.className; } } }, + // + // The various item types are processed by these + // functions. + // + charList: { + // + // Character from the known fonts + // + char: function (item,node,bbox,state,m) { + var font = item.font; + if (state.className && font.className !== state.className) this.flushText(node,state); + var C = font[item.n]; + state.text += C.c; state.className = font.className; + if (bbox.h < C[0]) bbox.t = bbox.h = C[0]; + if (bbox.d < C[1]) bbox.b = bbox.d = C[1]; + if (bbox.l > bbox.w+C[3]) bbox.l = bbox.w+C[3]; + if (bbox.r < bbox.w+C[4]) bbox.r = bbox.w+C[4]; + bbox.w += C[2]; + if (m == 1 && font.skew && font.skew[item.n]) bbox.skew = font.skew[item.n]; + if (C[5].rfix) this.flushText(node,state).style.marginRight = CHTML.Em(C[5].rfix/1000); + }, + // + // Space characters (not actually in the fonts) + // + space: function (item,node,bbox,state) { + if (item.w) { + if (state.text === "") state.className = item.font.className; + this.flushText(node,state).style.marginRight = CHTML.Em(item.w); + bbox.w += item.w; + } + }, + // + // An unknown character (one not in the font data) + // + unknown: function (item,node,bbox,state) { + this.char(item,node,bbox,state,0); + node = this.flushText(node,state); + node.style.lineHeight = "normal"; + var C = item.font[item.n]; + node.style.marginTop = CHTML.Em(-C[5].A-HFUZZ); + node.style.marginBottom = CHTML.Em(-C[5].d-DFUZZ); + node.style.width = CHTML.Em(C[2]); + if (!bbox.a || C[5].a > bbox.a) bbox.a = C[5].a; + }, + // + // Put the pending text into a box of the class, and + // reset the data about the text. + // + flushText: function (node,state) { + node = HTML.addElement(node,"mjx-charbox",{className:state.className},[state.text]); + state.text = ""; state.className = null; + return node; + } + }, + // + // Add the given text (in the given variant) into the given node, and + // update the bounding box of the result. Make sure the node's DOM + // bounding box matches the contents. + // handleText: function (node,text,variant,bbox) { if (node.childNodes.length === 0) { HTML.addElement(node,"mjx-char"); @@ -585,7 +671,7 @@ this.addCharList(node.firstChild,list,bbox); this.cleanBBox(bbox); bbox.h += HFUZZ; bbox.d += DFUZZ; bbox.t += HFUZZ; bbox.b += DFUZZ; - node.firstChild.style[bbox.h < 0 ? "marginTop" : "paddingTop"] = this.Em(bbox.h); + node.firstChild.style[bbox.h < 0 ? "marginTop" : "paddingTop"] = this.Em(bbox.h-(bbox.a||0)); node.firstChild.style[bbox.d < 0 ? "marginBottom": "paddingBottom"] = this.Em(bbox.d); return bbox; }, @@ -1060,6 +1146,7 @@ bbox.ic = bbox.r - bbox.w; bbox.w = bbox.r; node.style.paddingRight = CHTML.Em(bbox.ic); } + return node; } });