Handle undefined characters (these need measurement,so cause reflows).
This commit is contained in:
parent
29efa89877
commit
563dd09fa7
|
@ -36,7 +36,9 @@
|
||||||
var SCRIPTFACTOR = Math.sqrt(1/2),
|
var SCRIPTFACTOR = Math.sqrt(1/2),
|
||||||
AXISHEIGHT = .25,
|
AXISHEIGHT = .25,
|
||||||
STRUTHEIGHT = 1,
|
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 = {
|
var STYLES = {
|
||||||
".MathJax_CHTML_Display": {
|
".MathJax_CHTML_Display": {
|
||||||
|
@ -102,6 +104,17 @@
|
||||||
".MJXc-space2": {"margin-left":".222em"},
|
".MJXc-space2": {"margin-left":".222em"},
|
||||||
".MJXc-space3": {"margin-left":".278em"},
|
".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"},
|
||||||
|
|
||||||
/*********************************/
|
/*********************************/
|
||||||
|
|
||||||
"mjx-mtable": {"vertical-align":AXISHEIGHT+"em", "margin":"0 .125em"},
|
"mjx-mtable": {"vertical-align":AXISHEIGHT+"em", "margin":"0 .125em"},
|
||||||
|
@ -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) {
|
getUnicode: function (string) {
|
||||||
var n = string.text.charCodeAt(string.i); string.i++;
|
var n = string.text.charCodeAt(string.i); string.i++;
|
||||||
if (n >= 0xD800 && n < 0xDBFF) {
|
if (n >= 0xD800 && n < 0xDBFF) {
|
||||||
|
@ -447,6 +471,12 @@
|
||||||
}
|
}
|
||||||
return n;
|
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) {
|
getCharList: function (variant,n) {
|
||||||
var id, M, list = [], cache = variant.cache, N = n;
|
var id, M, list = [], cache = variant.cache, N = n;
|
||||||
if (cache[n]) return cache[n];
|
if (cache[n]) return cache[n];
|
||||||
|
@ -489,6 +519,12 @@
|
||||||
cache[N] = list;
|
cache[N] = list;
|
||||||
return 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) {
|
lookupChar: function (variant,n) {
|
||||||
while (variant) {
|
while (variant) {
|
||||||
for (var i = 0, m = variant.fonts.length; i < m; i++) {
|
for (var i = 0, m = variant.fonts.length; i < m; i++) {
|
||||||
|
@ -500,13 +536,7 @@
|
||||||
if (C.length === 5) C[5] = {};
|
if (C.length === 5) C[5] = {};
|
||||||
if (C.c == null) {
|
if (C.c == null) {
|
||||||
C[0] /= 1000; C[1] /= 1000; C[2] /= 1000; C[3] /= 1000; C[4] /= 1000;
|
C[0] /= 1000; C[1] /= 1000; C[2] /= 1000; C[3] /= 1000; C[4] /= 1000;
|
||||||
if (n <= 0xFFFF) {
|
C.c = this.unicodeChar(n);
|
||||||
C.c = String.fromCharCode(n);
|
|
||||||
} else {
|
|
||||||
var N = n - 0x10000;
|
|
||||||
C.c = String.fromCharCode((N>>10)+0xD800)
|
|
||||||
+ String.fromCharCode((N&0x3FF)+0xDC00);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (C[5].space) return {type:"space", w:C[2], font:font};
|
if (C[5].space) return {type:"space", w:C[2], font:font};
|
||||||
return {type:"char", font:font, n:n};
|
return {type:"char", font:font, n:n};
|
||||||
|
@ -516,59 +546,115 @@
|
||||||
}
|
}
|
||||||
return this.unknownChar(variant,n);
|
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) {
|
addCharList: function (node,list,bbox) {
|
||||||
var text = "", className;
|
var state = {text:"", className:null};
|
||||||
for (var i = 0, m = list.length; i < m; i++) {
|
for (var i = 0, m = list.length; i < m; i++) {
|
||||||
var item = list[i];
|
var item = list[i];
|
||||||
switch (item.type) {
|
if (this.charList[item.type]) (this.charList[item.type])(item,node,bbox,state,m);
|
||||||
case "char":
|
|
||||||
var font = item.font;
|
|
||||||
if (className && font.className !== className) {
|
|
||||||
HTML.addElement(node,"span",{className:className},[text]);
|
|
||||||
text = ""; className = null;
|
|
||||||
}
|
}
|
||||||
|
if (state.text !== "") {
|
||||||
|
if (node.childNodes.length) {
|
||||||
|
HTML.addElement(node,"span",{className:state.className},[state.text]);
|
||||||
|
} else {
|
||||||
|
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];
|
var C = font[item.n];
|
||||||
text += C.c; className = font.className;
|
state.text += C.c; state.className = font.className;
|
||||||
if (bbox.h < C[0]) bbox.t = bbox.h = C[0];
|
if (bbox.h < C[0]) bbox.t = bbox.h = C[0];
|
||||||
if (bbox.d < C[1]) bbox.b = bbox.d = C[1];
|
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.l > bbox.w+C[3]) bbox.l = bbox.w+C[3];
|
||||||
if (bbox.r < bbox.w+C[4]) bbox.r = bbox.w+C[4];
|
if (bbox.r < bbox.w+C[4]) bbox.r = bbox.w+C[4];
|
||||||
bbox.w += C[2];
|
bbox.w += C[2];
|
||||||
if (m == 1 && font.skew && font.skew[item.n]) bbox.skew = font.skew[item.n];
|
if (m == 1 && font.skew && font.skew[item.n]) bbox.skew = font.skew[item.n];
|
||||||
if (C[5].rfix) {
|
if (C[5].rfix) this.flushText(node,state).style.marginRight = CHTML.Em(C[5].rfix/1000);
|
||||||
HTML.addElement(node,"span",{
|
},
|
||||||
className:className, style:{"margin-right":CHTML.Em(C[5].rfix/1000)}
|
//
|
||||||
},[text]);
|
// Space characters (not actually in the fonts)
|
||||||
text = ""; className = null;
|
//
|
||||||
}
|
space: function (item,node,bbox,state) {
|
||||||
break;
|
|
||||||
|
|
||||||
case "space":
|
|
||||||
if (item.w) {
|
if (item.w) {
|
||||||
if (text === "") className = item.font.className;
|
if (state.text === "") state.className = item.font.className;
|
||||||
HTML.addElement(node,"span",{
|
this.flushText(node,state).style.marginRight = CHTML.Em(item.w);
|
||||||
className:className, style:{"margin-right":CHTML.Em(item.w)}
|
|
||||||
},[text]);
|
|
||||||
text = ""; className = null;
|
|
||||||
bbox.w += item.w;
|
bbox.w += item.w;
|
||||||
}
|
}
|
||||||
break;
|
},
|
||||||
}
|
//
|
||||||
}
|
// An unknown character (one not in the font data)
|
||||||
if (text !== "") {
|
//
|
||||||
if (node.childNodes.length) {
|
unknown: function (item,node,bbox,state) {
|
||||||
HTML.addElement(node,"span",{className:className},[text]);
|
this.char(item,node,bbox,state,0);
|
||||||
} else {
|
node = this.flushText(node,state);
|
||||||
HTML.addText(node,text);
|
node.style.lineHeight = "normal";
|
||||||
node.className = className;
|
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) {
|
handleText: function (node,text,variant,bbox) {
|
||||||
if (node.childNodes.length === 0) {
|
if (node.childNodes.length === 0) {
|
||||||
HTML.addElement(node,"mjx-char");
|
HTML.addElement(node,"mjx-char");
|
||||||
|
@ -585,7 +671,7 @@
|
||||||
this.addCharList(node.firstChild,list,bbox);
|
this.addCharList(node.firstChild,list,bbox);
|
||||||
this.cleanBBox(bbox);
|
this.cleanBBox(bbox);
|
||||||
bbox.h += HFUZZ; bbox.d += DFUZZ; bbox.t += HFUZZ; bbox.b += DFUZZ;
|
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);
|
node.firstChild.style[bbox.d < 0 ? "marginBottom": "paddingBottom"] = this.Em(bbox.d);
|
||||||
return bbox;
|
return bbox;
|
||||||
},
|
},
|
||||||
|
@ -1060,6 +1146,7 @@
|
||||||
bbox.ic = bbox.r - bbox.w; bbox.w = bbox.r;
|
bbox.ic = bbox.r - bbox.w; bbox.w = bbox.r;
|
||||||
node.style.paddingRight = CHTML.Em(bbox.ic);
|
node.style.paddingRight = CHTML.Em(bbox.ic);
|
||||||
}
|
}
|
||||||
|
return node;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user