commit 7aab884fd040e94e55c27c7d8117f12d7360e135
parent 41df4b5cfaee974e36e40e7633d1d39d4a34fa56
Author: Davide P. Cervone <dpvc@union.edu>
Date: Mon, 21 Jul 2014 10:06:35 -0400
Merge pull request #874 from pkra/nodejs
merging @dpvc's Nodejs branch into develop.
Diffstat:
4 files changed, 81 insertions(+), 34 deletions(-)
diff --git a/unpacked/jax/input/MathML/jax.js b/unpacked/jax/input/MathML/jax.js
@@ -282,8 +282,11 @@
parseDOM: function (string) {return this.parser.parseFromString(string,"text/xml")},
parseMS: function (string) {return (this.parser.loadXML(string) ? this.parser : null)},
parseDIV: function (string) {
- this.div.innerHTML = string.replace(/<([a-z]+)([^>]*)\/>/g,"<$1$2></$1>");
- return this.div;
+ this.div.innerHTML =
+ "<div>"+string.replace(/<([a-z]+)([^>]*)\/>/g,"<$1$2></$1>")+"</div>";
+ var doc = this.div.firstChild;
+ this.div.innerHTML = "";
+ return doc;
},
parseError: function (string) {return null},
createMSParser: function() {
diff --git a/unpacked/jax/output/HTML-CSS/jax.js b/unpacked/jax/output/HTML-CSS/jax.js
@@ -520,7 +520,7 @@
if (this.defaultEm) return;
var ready = MathJax.Callback();
AJAX.timer.start(AJAX,function (check) {
- if (check.time(ready)) {HUB.signal.Post("HTML-CSS Jax - no default em size"); return}
+ if (check.time(ready)) {HUB.signal.Post(["HTML-CSS Jax - no default em size"]); return}
HTMLCSS.getDefaultExEm();
if (HTMLCSS.defaultEm) {ready()} else {setTimeout(check,check.delay)}
},this.defaultEmDelay,this.defaultEmTimeout);
diff --git a/unpacked/jax/output/SVG/config.js b/unpacked/jax/output/SVG/config.js
@@ -41,6 +41,8 @@ MathJax.OutputJax.SVG = MathJax.OutputJax({
undefinedFamily: "STIXGeneral,'Arial Unicode MS',serif", // fonts to use for missing characters
addMMLclasses: false, // keep MathML structure and use CSS classes to mark elements
+ useFontCache: true, // use <use> elements to re-use font paths rather than repeat paths every time
+ useGlobalCache: true, // store fonts in a global <defs> for use in all equations, or one in each equation
EqnChunk: (MathJax.Hub.Browser.isMobile ? 10: 50),
// number of equations to process before showing them
@@ -82,6 +84,10 @@ MathJax.OutputJax.SVG = MathJax.OutputJax({
".MathJax_SVG .MJX-sans-serif": {
"font-family": "sans-serif"
},
+
+ //
+ // For tooltips
+ //
"#MathJax_SVG_Tooltip": {
"background-color": "InfoBackground", color: "InfoText",
border: "1px solid black",
diff --git a/unpacked/jax/output/SVG/jax.js b/unpacked/jax/output/SVG/jax.js
@@ -153,8 +153,8 @@
this.textSVG = this.Element("svg");
// Global defs for font glyphs
- DEFS = this.addElement(this.addElement(this.hiddenDiv.parentNode,"svg"),"defs",{id:"MathJax_SVG_glyphs"});
- GLYPHS = {};
+ BBOX.GLYPH.defs = this.addElement(this.addElement(this.hiddenDiv.parentNode,"svg"),
+ "defs",{id:"MathJax_SVG_glyphs"});
// Used in preTranslate to get scaling factors
this.ExSpan = HTML.Element("span",
@@ -166,7 +166,7 @@
this.linebreakSpan = HTML.Element("span",null,
[["hr",{style: {width:"auto", size:1, padding:0, border:0, margin:0}}]]);
- // Set up styles
+ // Set up styles
return AJAX.Styles(this.config.styles,["InitializeSVG",this]);
},
@@ -298,7 +298,8 @@
//
var jax = script.MathJax.elementJax, math = jax.root,
span = document.getElementById(jax.inputID+"-Frame"),
- div = (jax.SVG.display ? (span||{}).parentNode : span);
+ div = (jax.SVG.display ? (span||{}).parentNode : span),
+ localCache = (SVG.config.useFontCache && !SVG.config.useGlobalCache);
if (!div) return;
//
// Set the font metrics
@@ -310,10 +311,12 @@
//
this.mathDiv = div;
span.appendChild(this.textSVG);
+ if (localCache) {SVG.resetGlyphs()}
this.initSVG(math,span);
math.setTeXclass();
try {math.toSVG(span,div)} catch (err) {
if (err.restart) {while (span.firstChild) {span.removeChild(span.firstChild)}}
+ if (localCache) {BBOX.GLYPH.n--}
throw err;
}
span.removeChild(this.textSVG);
@@ -375,13 +378,28 @@
//
state.SVGlast = state.SVGeqn;
},
+
+ resetGlyphs: function (reset) {
+ if (this.config.useFontCache) {
+ var GLYPH = BBOX.GLYPH;
+ if (this.config.useGlobalCache) {
+ GLYPH.defs = document.getElementById("MathJax_SVG_glyphs");
+ GLYPH.defs.innerHTML = "";
+ } else {
+ GLYPH.defs = this.Element("defs");
+ GLYPH.n++;
+ }
+ GLYPH.glyphs = {};
+ if (reset) {GLYPH.n = 0}
+ }
+ },
//
// Return the containing HTML element rather than the SVG element, since
// most browsers can't position to an SVG element properly.
//
hashCheck: function (target) {
- if (target && target.nodeName === "g")
+ if (target && target.nodeName.toLowerCase() === "g")
{do {target = target.parentNode} while (target && target.firstChild.nodeName !== "svg")}
return target;
},
@@ -465,6 +483,10 @@
Percent: function (m) {
return (100*m).toFixed(1).replace(/\.?0+$/,"") + "%";
},
+ Fixed: function (m,n) {
+ if (Math.abs(m) < .0006) {return "0"}
+ return m.toFixed(n||3).replace(/\.?0+$/,"");
+ },
length2em: function (length,mu,size) {
if (typeof(length) !== "string") {length = length.toString()}
if (length === "") {return ""}
@@ -815,8 +837,8 @@
if (dx) {svg.x += dx}; if (dy) {svg.y += dy};
if (svg.element) {
if (svg.removeable && svg.element.childNodes.length === 1 && svg.n === 1) {
- var child = svg.element.firstChild;
- if (child.nodeName === "use" || child.nodeName === "rect") {
+ var child = svg.element.firstChild, nodeName = child.nodeName.toLowerCase();
+ if (nodeName === "use" || nodeName === "rect") {
svg.element = child; svg.scale = svg.childScale;
var x = svg.childX, y = svg.childY;
svg.x += x; svg.y += y;
@@ -828,13 +850,12 @@
if (Math.abs(svg.x) < 1 && Math.abs(svg.y) < 1) {
svg.remove = svg.removeable;
} else {
- if (svg.element.nodeName === "g") {
+ nodeName = svg.element.nodeName.toLowerCase();
+ if (nodeName === "g") {
if (!svg.element.firstChild) {svg.remove = svg.removeable}
else {svg.element.setAttribute("transform","translate("+Math.floor(svg.x)+","+Math.floor(svg.y)+")")}
- } else if (svg.element.nodeName === "line" ||
- svg.element.nodeName === "polygon" ||
- svg.element.nodeName === "path" ||
- svg.element.nodeName === "a") {
+ } else if (nodeName === "line" || nodeName === "polygon" ||
+ nodeName === "path" || nodeName === "a") {
svg.element.setAttribute("transform","translate("+Math.floor(svg.x)+","+Math.floor(svg.y)+")");
} else {
svg.element.setAttribute("x",Math.floor(svg.x/svg.scale));
@@ -930,7 +951,7 @@
type: "rect", removeable: false,
Init: function (h,d,w,t,dash,color,def) {
if (def == null) {def = {}}; def.fill = "none";
- def["stroke-width"] = t.toFixed(2).replace(/\.?0+$/,"");
+ def["stroke-width"] = SVG.Fixed(t,2);
def.width = Math.floor(w-t); def.height = Math.floor(h+d-t);
def.transform = "translate("+Math.floor(t/2)+","+Math.floor(-d+t/2)+")";
if (dash === "dashed")
@@ -946,7 +967,7 @@
Init: function (w,t,dash,color,def) {
if (def == null) {def = {"stroke-linecap":"square"}}
if (color && color !== "") {def.stroke = color}
- def["stroke-width"] = t.toFixed(2).replace(/\.?0+$/,"");
+ def["stroke-width"] = SVG.Fixed(t,2);
def.x1 = def.y1 = def.y2 = Math.floor(t/2); def.x2 = Math.floor(w-t/2);
if (dash === "dashed") {
var n = Math.floor(Math.max(0,w-t)/(6*t)), m = Math.floor(Math.max(0,w-t)/(2*n+1));
@@ -966,7 +987,7 @@
Init: function (h,t,dash,color,def) {
if (def == null) {def = {"stroke-linecap":"square"}}
if (color && color !== "") {def.stroke = color}
- def["stroke-width"] = t.toFixed(2).replace(/\.?0+$/,"");
+ def["stroke-width"] = SVG.Fixed(t,2);
def.x1 = def.x2 = def.y1 = Math.floor(t/2); def.y2 = Math.floor(h-t/2);
if (dash === "dashed") {
var n = Math.floor(Math.max(0,h-t)/(6*t)), m = Math.floor(Math.max(0,h-t)/(2*n+1));
@@ -1007,26 +1028,34 @@
}
});
- var GLYPHS, DEFS; // data for which glyphs are used
-
BBOX.GLYPH = BBOX.Subclass({
type: "path", removeable: false,
Init: function (scale,id,h,d,w,l,r,p) {
- var def, t = SVG.config.blacker;
- if (!GLYPHS[id]) {
- def = {id:id, "stroke-width":t};
+ var def, t = SVG.config.blacker, GLYPH = BBOX.GLYPH;
+ var cache = SVG.config.useFontCache;
+ var transform = (scale === 1 ? null : "scale("+SVG.Fixed(scale)+")");
+ if (cache && !SVG.config.useGlobalCache) {id = "E"+GLYPH.n+"-"+id}
+ if (!cache || !GLYPH.glyphs[id]) {
+ def = {"stroke-width":t};
+ if (cache) {def.id = id} else if (transform) {def.transform = transform}
if (p !== "") {def.d = "M"+p+"Z"}
this.SUPER(arguments).Init.call(this,def);
- DEFS.appendChild(this.element); GLYPHS[id] = true;
+ if (cache) {GLYPH.defs.appendChild(this.element); GLYPH.glyphs[id] = true;}
+ }
+ if (cache) {
+ def = {}; if (transform) {def.transform = transform}
+ this.element = SVG.Element("use",def);
+ this.element.setAttributeNS(XLINKNS,"href","#"+id);
}
- def = {}; if (scale !== 1) {def.transform = "scale("+scale+")"}
- this.element = SVG.Element("use",def);
- this.element.setAttributeNS(XLINKNS,"href","#"+id);
this.h = (h+t) * scale; this.d = (d+t) * scale; this.w = (w+t/2) *scale;
this.l = (l+t/2) * scale; this.r = (r+t/2) * scale;
this.H = Math.max(0,this.h); this.D = Math.max(0,this.d);
this.x = this.y = 0; this.scale = scale;
}
+ },{
+ glyphs: {}, // which glpyhs have been used
+ defs: null, // the SVG <defs> element where glyphs are stored
+ n: 0 // the ID for local <defs> for self-contained SVG elements
});
HUB.Register.StartupHook("mml Jax Ready",function () {
@@ -1197,7 +1226,8 @@
// Add background color
//
if (values.background !== MML.COLOR.TRANSPARENT) {
- if (svg.element.nodeName !== "g" && svg.element.nodeName !== "svg") {
+ var nodeName = svg.element.nodeName.toLowerCase();
+ if (nodeName !== "g" && nodeName !== "svg") {
var g = SVG.Element("g"); g.appendChild(svg.element);
svg.element = g; svg.removeable = true;
}
@@ -1988,6 +2018,10 @@
MML.math.Augment({
SVG: BBOX.Subclass({type:"svg", removeable: false}),
toSVG: function (span,div) {
+ var CONFIG = SVG.config;
+ //
+ // All the data should be in an inferrerd row
+ //
if (this.data[0]) {
this.SVGgetStyles();
MML.mbase.prototype.displayAlign = HUB.config.displayAlign;
@@ -2002,7 +2036,10 @@
}).With({removeable: false});
box.Add(this.data[0].toSVG(),0,0,true); box.Clean();
this.SVGhandleColor(box);
- var svg = this.SVG(); svg.element.setAttribute("xmlns:xlink",XLINKNS);
+ var svg = this.SVG();
+ svg.element.setAttribute("xmlns:xlink",XLINKNS);
+ if (CONFIG.useFontCache && !CONFIG.useGlobalCache)
+ {svg.element.appendChild(BBOX.GLYPH.defs)}
svg.Add(box); svg.Clean();
this.SVGsaveData(svg);
//
@@ -2021,11 +2058,12 @@
//
var l = Math.max(-svg.l,0), r = Math.max(svg.r-svg.w,0);
var style = svg.element.style;
- style.width = SVG.Ex(l+svg.w+r);
- style.height = SVG.Ex(svg.H+svg.D+2*SVG.em);
+ svg.element.setAttribute("width",SVG.Ex(l+svg.w+r));
+ svg.element.setAttribute("height",SVG.Ex(svg.H+svg.D+2*SVG.em));
style.verticalAlign = SVG.Ex(-svg.D-3*SVG.em); // remove 2 extra pixels added below plus padding
style.marginLeft = SVG.Ex(-l); style.marginRight = SVG.Ex(-r);
- svg.element.setAttribute("viewBox",(-l)+" "+(-svg.H-SVG.em)+" "+(l+svg.w+r)+" "+(svg.H+svg.D+2*SVG.em));
+ svg.element.setAttribute("viewBox",SVG.Fixed(-l,1)+" "+SVG.Fixed(-svg.H-SVG.em,1)+" "+
+ SVG.Fixed(l+svg.w+r,1)+" "+SVG.Fixed(svg.H+svg.D+2*SVG.em,1));
svg.element.style.margin="1px 0px"; // 1px above and below to prevent lines from touching
//
// If there is extra height or depth, hide that
@@ -2033,9 +2071,9 @@
if (svg.H > svg.h || svg.D > svg.d) {
var frame = HTML.Element(
"span",{style: {display:"inline-block", "white-space":"nowrap", padding:"1px 0px"}, isMathJax:true},[[
- "span",{style: {display:"inline-block", position:"relative", isMathJax:true,
+ "span",{style: {display:"inline-block", position:"relative",
width:SVG.Ex(svg.w), height:SVG.Ex(svg.h+svg.d),
- "vertical-align":SVG.Ex(-svg.d)}}]]);
+ "vertical-align":SVG.Ex(-svg.d)}, isMathJax:true}]]);
frame.firstChild.appendChild(svg.element); svg.element = frame;
style.verticalAlign = style.margin = ""; style.position = "absolute";
style.bottom = SVG.Ex(svg.d-svg.D); style.left = 0;