This commit is contained in:
Xes
2025-08-14 22:44:47 +02:00
parent 8ce45119b6
commit 791cb748ab
39112 changed files with 975901 additions and 0 deletions

View File

@@ -0,0 +1,92 @@
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/jax/output/SVG/autoload/annotation-xml.js
*
* Implements the SVG output for <annotation-xml> elements.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2013-2020 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
MathJax.Hub.Register.StartupHook("SVG Jax Ready",function () {
var VERSION = "2.7.8";
var MML = MathJax.ElementJax.mml,
SVG = MathJax.OutputJax.SVG;
var BBOX = SVG.BBOX;
BBOX.FOREIGN = BBOX.Subclass({type: "foreignObject", removeable: false});
MML["annotation-xml"].Augment({
toSVG: function () {
var svg = this.SVG(); this.SVGhandleSpace(svg);
var encoding = this.Get("encoding");
for (var i = 0, m = this.data.length; i < m; i++)
{svg.Add(this.data[i].toSVG(encoding),svg.w,0)}
svg.Clean();
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
}
});
MML.xml.Augment({
toSVG: function (encoding) {
//
// Get size of xml content
//
var span = SVG.textSVG.parentNode;
SVG.mathDiv.style.width = "auto"; // Firefox returns offsetWidth = 0 without this
span.insertBefore(this.div,SVG.textSVG);
var w = this.div.offsetWidth, h = this.div.offsetHeight;
var strut = MathJax.HTML.addElement(this.div,"span",{
style:{display:"inline-block", overflow:"hidden", height:h+"px",
width:"1px", marginRight:"-1px"}
});
var d = this.div.offsetHeight - h; h -= d;
this.div.removeChild(strut);
span.removeChild(this.div); SVG.mathDiv.style.width = "";
//
// Create foreignObject element for the content
//
var scale = 1000/SVG.em;
var svg = BBOX.FOREIGN({
y:(-h)+"px", width:w+"px", height:(h+d)+"px",
transform:"scale("+scale+") matrix(1 0 0 -1 0 0)"
});
//
// Add the children to the foreignObject
//
for (var i = 0, m = this.data.length; i < m; i++)
{svg.element.appendChild(this.data[i].cloneNode(true))}
//
// Set the scale and finish up
//
svg.w = w*scale; svg.h = h*scale; svg.d = d*scale;
svg.r = svg.w; svg.l = 0;
svg.Clean();
this.SVGsaveData(svg);
return svg;
}
});
MathJax.Hub.Startup.signal.Post("SVG annotation-xml Ready");
MathJax.Ajax.loadComplete(SVG.autoloadDir+"/annotation-xml.js");
});

View File

@@ -0,0 +1,201 @@
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/jax/output/SVG/autoload/maction.js
*
* Implements the SVG output for <maction> elements.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2011-2020 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
MathJax.Hub.Register.StartupHook("SVG Jax Ready",function () {
var VERSION = "2.7.8";
var MML = MathJax.ElementJax.mml,
SVG = MathJax.OutputJax["SVG"];
var currentTip, hover, clear;
//
// Add configuration for tooltips
//
var CONFIG = SVG.config.tooltip = MathJax.Hub.Insert({
delayPost: 600, delayClear: 600,
offsetX: 10, offsetY: 5
},SVG.config.tooltip||{});
MML.maction.Augment({
SVGtooltip: MathJax.HTML.addElement(document.body,"div",{id:"MathJax_SVG_Tooltip"}),
toSVG: function (HW,D) {
this.SVGgetStyles();
var svg = this.SVG();
var selected = this.selected();
if (selected.type == "null") {this.SVGsaveData(svg);return svg;}
svg.Add(this.SVGdataStretched(this.Get("selection")-1,HW,D));
svg.removeable = false;
this.SVGhandleHitBox(svg);
this.SVGhandleSpace(svg);
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
},
SVGhandleHitBox: function (svg) {
var frame = SVG.Element("rect",
{width:svg.w, height:svg.h+svg.d, y:-svg.d, fill:"none", "pointer-events":"all"});
svg.element.insertBefore(frame,svg.element.firstChild);
var type = this.Get("actiontype");
if (this.SVGaction[type])
{this.SVGaction[type].call(this,svg,svg.element,this.Get("selection"))}
},
SVGstretchH: MML.mbase.prototype.SVGstretchH,
SVGstretchV: MML.mbase.prototype.SVGstretchV,
//
// Implementations for the various actions
//
SVGaction: {
toggle: function (svg,frame,selection) {
this.selection = selection;
SVG.Element(frame,{cursor:"pointer"});
frame.onclick = MathJax.Callback(["SVGclick",this]);
},
statusline: function (svg,frame,selection) {
frame.onmouseover = MathJax.Callback(["SVGsetStatus",this]),
frame.onmouseout = MathJax.Callback(["SVGclearStatus",this]);
frame.onmouseover.autoReset = frame.onmouseout.autoReset = true;
},
tooltip: function(svg,frame,selection) {
frame.onmouseover = MathJax.Callback(["SVGtooltipOver",this]),
frame.onmouseout = MathJax.Callback(["SVGtooltipOut",this]);
frame.onmouseover.autoReset = frame.onmouseout.autoReset = true;
}
},
//
// Handle a click on the maction element
// (remove the original rendering and rerender)
//
SVGclick: function (event) {
this.selection++;
if (this.selection > this.data.length) {this.selection = 1}
var math = this; while (math.type !== "math") {math = math.inherit}
var jax = MathJax.Hub.getJaxFor(math.inputID); //, hover = !!jax.hover;
jax.Update();
/*
* if (hover) {
* var span = document.getElementById(jax.inputID+"-Span");
* MathJax.Extension.MathEvents.Hover.Hover(jax,span);
* }
*/
return MathJax.Extension.MathEvents.Event.False(event);
},
//
// Set/Clear the window status message
//
SVGsetStatus: function (event) {
// FIXME: Do something better with non-token elements
this.messageID = MathJax.Message.Set
((this.data[1] && this.data[1].isToken) ?
this.data[1].data.join("") : this.data[1].toString());
},
SVGclearStatus: function (event) {
if (this.messageID) {MathJax.Message.Clear(this.messageID,0)}
delete this.messageID;
},
//
// Handle tooltips
//
SVGtooltipOver: function (event) {
if (!event) {event = window.event}
if (clear) {clearTimeout(clear); clear = null}
if (hover) {clearTimeout(hover)}
var x = event.pageX; var y = event.pageY;
if (x == null) {
x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
var callback = MathJax.Callback(["SVGtooltipPost",this,x+CONFIG.offsetX,y+CONFIG.offsetY])
hover = setTimeout(callback,CONFIG.delayPost);
},
SVGtooltipOut: function (event) {
if (hover) {clearTimeout(hover); hover = null}
if (clear) {clearTimeout(clear)}
var callback = MathJax.Callback(["SVGtooltipClear",this,80]);
clear = setTimeout(callback,CONFIG.delayClear);
},
SVGtooltipPost: function (x,y) {
hover = null; if (clear) {clearTimeout(clear); clear = null}
//
// Get the tip div and show it at the right location, then clear its contents
//
var tip = this.SVGtooltip;
tip.style.display = "block"; tip.style.opacity = "";
if (this === currentTip) return;
tip.style.left = x+"px"; tip.style.top = y+"px";
tip.innerHTML = ''; var span = MathJax.HTML.addElement(tip,"span");
//
// Get the sizes from the jax (FIXME: should calculate again?)
//
var math = this; while (math.type !== "math") {math = math.inherit}
var jax = MathJax.Hub.getJaxFor(math.inputID);
this.em = MML.mbase.prototype.em = jax.SVG.em; this.ex = jax.SVG.ex;
this.linebreakWidth = jax.SVG.lineWidth; this.cwidth = jax.SVG.cwidth;
//
// Make a new math element and temporarily move the tooltip to it
// Display the math containing the tip, but check for errors
// Then put the tip back into the maction element
//
var mml = this.data[1];
math = MML.math(mml);
try {math.toSVG(span,tip)} catch(err) {
this.SetData(1,mml); tip.style.display = "none";
if (!err.restart) {throw err}
MathJax.Callback.After(["SVGtooltipPost",this,x,y],err.restart);
return;
}
this.SetData(1,mml);
currentTip = this;
},
SVGtooltipClear: function (n) {
var tip = this.SVGtooltip;
if (n <= 0) {
tip.style.display = "none";
tip.style.opacity = "";
clear = null;
} else {
tip.style.opacity = n/100;
clear = setTimeout(MathJax.Callback(["SVGtooltipClear",this,n-20]),50);
}
}
});
MathJax.Hub.Startup.signal.Post("SVG maction Ready");
MathJax.Ajax.loadComplete(SVG.autoloadDir+"/maction.js");
});

View File

@@ -0,0 +1,233 @@
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/jax/output/SVG/autoload/menclose.js
*
* Implements the SVG output for <menclose> elements.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2011-2020 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
MathJax.Hub.Register.StartupHook("SVG Jax Ready",function () {
var VERSION = "2.7.8";
var MML = MathJax.ElementJax.mml,
SVG = MathJax.OutputJax.SVG,
BBOX = SVG.BBOX;
BBOX.ELLIPSE = BBOX.Subclass({
type: "ellipse", removeable: false,
Init: function (h,d,w,t,color,def) {
if (def == null) {def = {}}; def.fill = "none";
if (color) {def.stroke = color}
def["stroke-width"] = t.toFixed(2).replace(/\.?0+$/,"");
def.cx = Math.floor(w/2); def.cy = Math.floor((h+d)/2-d);
def.rx = Math.floor((w-t)/2); def.ry = Math.floor((h+d-t)/2);
this.SUPER(arguments).Init.call(this,def);
this.w = this.r = w; this.h = this.H = h;
this.d = this.D = d; this.l = 0;
}
});
BBOX.DLINE = BBOX.Subclass({
type: "line", removeable: false,
Init: function (h,d,w,t,color,updown,def) {
if (def == null) {def = {}}; def.fill = "none";
if (color) {def.stroke = color}
def["stroke-width"] = t.toFixed(2).replace(/\.?0+$/,"");
if (updown == "up") {
def.x1 = Math.floor(t/2); def.y1 = Math.floor(t/2-d);
def.x2 = Math.floor(w-t/2); def.y2 = Math.floor(h-t/2);
} else {
def.x1 = Math.floor(t/2); def.y1 = Math.floor(h-t/2);
def.x2 = Math.floor(w-t/2); def.y2 = Math.floor(t/2-d);
}
this.SUPER(arguments).Init.call(this,def);
this.w = this.r = w; this.h = this.H = h;
this.d = this.D = d; this.l = 0;
}
});
BBOX.FPOLY = BBOX.Subclass({
type: "polygon", removeable: false,
Init: function (points,color,def) {
if (def == null) {def = {}}
if (color) {def.fill = color}
var P = [], mx = 100000000, my = mx, Mx = -mx, My = Mx;
for (var i = 0, m = points.length; i < m; i++) {
var x = points[i][0], y = points[i][1];
if (x > Mx) {Mx = x}; if (x < mx) {mx = x}
if (y > My) {My = y}; if (y < my) {my = y}
P.push(Math.floor(x)+","+Math.floor(y));
}
def.points = P.join(" ");
this.SUPER(arguments).Init.call(this,def);
this.w = this.r = Mx; this.h = this.H = My;
this.d = this.D = -my; this.l = -mx;
}
});
BBOX.PPATH = BBOX.Subclass({
type: "path", removeable: false,
Init: function (h,d,w,p,t,color,def) {
if (def == null) {def = {}}; def.fill = "none";
if (color) {def.stroke = color}
def["stroke-width"] = t.toFixed(2).replace(/\.?0+$/,"");
def.d = p;
this.SUPER(arguments).Init.call(this,def);
this.w = this.r = w; this.h = this.H = h+d;
this.d = this.D = this.l = 0; this.y = -d;
}
});
MML.menclose.Augment({
toSVG: function (HW,DD) {
this.SVGgetStyles();
var svg = this.SVG(), scale = this.SVGgetScale(svg);
this.SVGhandleSpace(svg);
var base = this.SVGdataStretched(0,HW,DD);
var values = this.getValues("notation","thickness","padding","mathcolor","color");
if (values.color && !this.mathcolor) {values.mathcolor = values.color}
if (values.thickness == null) {values.thickness = ".075em"}
if (values.padding == null) {values.padding = ".2em"}
var mu = this.SVGgetMu(svg);
var p = SVG.length2em(values.padding,mu,1/SVG.em) * scale; // padding for enclosure
var t = SVG.length2em(values.thickness,mu,1/SVG.em); // thickness of lines
t = Math.max(1/SVG.em,t); // see issue #414
var H = base.h+p+t, D = base.d+p+t, W = base.w+2*(p+t);
var dx = 0, w, h, i, m, borders = [false,false,false,false];
// perform some reduction e.g. eliminate duplicate notations.
var nl = MathJax.Hub.SplitList(values.notation), notation = {};
for (i = 0, m = nl.length; i < m; i++) notation[nl[i]] = true;
if (notation[MML.NOTATION.UPDIAGONALARROW]) notation[MML.NOTATION.UPDIAGONALSTRIKE] = false;
for (var n in notation) {
if (!notation.hasOwnProperty(n) || !notation[n]) continue;
switch (n) {
case MML.NOTATION.BOX:
borders = [true,true,true,true];
break;
case MML.NOTATION.ROUNDEDBOX:
svg.Add(BBOX.FRAME(H,D,W,t,"solid",values.mathcolor,
{rx:Math.floor(Math.min(H+D-t,W-t)/4)}));
break;
case MML.NOTATION.CIRCLE:
svg.Add(BBOX.ELLIPSE(H,D,W,t,values.mathcolor));
break;
case MML.NOTATION.ACTUARIAL:
borders[0] = true;
case MML.NOTATION.RIGHT:
borders[1] = true;
break;
case MML.NOTATION.LEFT:
borders[3] = true;
break;
case MML.NOTATION.TOP:
borders[0] = true;
break;
case MML.NOTATION.BOTTOM:
borders[2] = true;
break;
case MML.NOTATION.VERTICALSTRIKE:
svg.Add(BBOX.VLINE(H+D,t,"solid",values.mathcolor),(W-t)/2,-D);
break;
case MML.NOTATION.HORIZONTALSTRIKE:
svg.Add(BBOX.HLINE(W,t,"solid",values.mathcolor),0,(H+D-t)/2-D);
break;
case MML.NOTATION.UPDIAGONALSTRIKE:
svg.Add(BBOX.DLINE(H,D,W,t,values.mathcolor,"up"));
break;
case MML.NOTATION.UPDIAGONALARROW:
var l = Math.sqrt(W*W + (H+D)*(H+D)), f = 1/l * 10/SVG.em * t/.075;
w = W * f; h = (H+D) * f; var x = .4*h;
svg.Add(BBOX.DLINE(H-.5*h,D,W-.5*w,t,values.mathcolor,"up"));
svg.Add(BBOX.FPOLY(
[[x+w,h], [x-.4*h,.4*w], [x+.3*w,.3*h], [x+.4*h,-.4*w], [x+w,h]],
values.mathcolor),W-w-x,H-h);
break;
case MML.NOTATION.DOWNDIAGONALSTRIKE:
svg.Add(BBOX.DLINE(H,D,W,t,values.mathcolor,"down"));
break;
case MML.NOTATION.PHASORANGLE:
borders[2] = true; W -= 2*p; p = (H+D)/2; W += p;
svg.Add(BBOX.DLINE(H,D,p,t,values.mathcolor,"up"));
break;
case MML.NOTATION.MADRUWB:
borders[1] = borders[2] = true;
break;
case MML.NOTATION.RADICAL:
svg.Add(BBOX.PPATH(H,D,W,
"M "+this.SVGxy(t/2,.4*(H+D)) +
" L "+this.SVGxy(p,t/2) +
" L "+this.SVGxy(2*p,H+D-t/2) +
" L "+this.SVGxy(W,H+D-t/2),
t,values.mathcolor),0,t);
dx = p;
break;
case MML.NOTATION.LONGDIV:
svg.Add(BBOX.PPATH(H,D,W,
"M "+this.SVGxy(t/2,t/2) +
" a "+this.SVGxy(p,(H+D)/2-2*t) + " 0 0,1 " + this.SVGxy(t/2,H+D-t) +
" L "+this.SVGxy(W,H+D-t/2),
t,values.mathcolor),0,t/2);
dx = p;
break;
}
}
var sides = [["H",W,0,H-t],["V",H+D,W-t,-D],["H",W,0,-D],["V",H+D,0,-D]];
for (i = 0; i < 4; i++) {
if (borders[i]) {
var side = sides[i];
svg.Add(BBOX[side[0]+"LINE"](side[1],t,"solid",values.mathcolor),side[2],side[3]);
}
}
svg.Add(base,dx+p+t,0,false,true);
svg.Clean();
this.SVGhandleSpace(svg);
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
},
SVGxy: function (x,y) {return Math.floor(x)+","+Math.floor(y)}
});
MathJax.Hub.Startup.signal.Post("SVG menclose Ready");
MathJax.Ajax.loadComplete(SVG.autoloadDir+"/menclose.js");
});

View File

@@ -0,0 +1,107 @@
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/jax/output/SVG/autoload/mglyph.js
*
* Implements the SVG output for <mglyph> elements.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2011-2020 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
MathJax.Hub.Register.StartupHook("SVG Jax Ready",function () {
var VERSION = "2.7.8";
var MML = MathJax.ElementJax.mml,
SVG = MathJax.OutputJax.SVG,
BBOX = SVG.BBOX,
LOCALE = MathJax.Localization;
var XLINKNS = "http://www.w3.org/1999/xlink";
BBOX.MGLYPH = BBOX.Subclass({
type: "image", removeable: false,
Init: function (img,w,h,align,mu,scale,def) {
if (def == null) {def = {}}
var W = img.width*1000/SVG.em, H = img.height*1000/SVG.em;
var WW = W, HH = H, y = 0;
if (w !== "") {W = SVG.length2em(w,mu,WW) * scale; H = (WW ? W/WW * HH : 0)}
if (h !== "") {H = SVG.length2em(h,mu,HH) * scale; if (w === "") {W = (HH ? H/HH * WW : 0)}}
if (align !== "" && align.match(/\d/)) {y = SVG.length2em(align,mu) * scale; def.y = -y}
def.height = Math.floor(H); def.width = Math.floor(W);
def.transform = "translate(0,"+H+") matrix(1 0 0 -1 0 0)";
def.preserveAspectRatio = "none";
this.SUPER(arguments).Init.call(this,def);
this.element.setAttributeNS(XLINKNS,"href",img.SRC);
this.w = this.r = W; this.h = this.H = H + y;
this.d = this.D = -y; this.l = 0;
}
});
MML.mglyph.Augment({
toSVG: function (variant,scale) {
this.SVGgetStyles(); var svg = this.SVG(), img, err;
this.SVGhandleSpace(svg);
var values = this.getValues("src","width","height","valign","alt");
if (values.src === "") {
values = this.getValues("index","fontfamily");
if (values.index) {
if (!scale) {scale = this.SVGgetScale()}
var def = {}; if (values.fontfamily) {def["font-family"] = values.fontfamily}
svg.Add(BBOX.TEXT(scale,String.fromCharCode(values.index),def));
}
} else {
if (!this.img) {this.img = MML.mglyph.GLYPH[values.src]}
if (!this.img) {
this.img = MML.mglyph.GLYPH[values.src] = {img: new Image(), status: "pending"};
img = this.img.img;
img.onload = MathJax.Callback(["SVGimgLoaded",this]);
img.onerror = MathJax.Callback(["SVGimgError",this]);
img.src = img.SRC = values.src;
MathJax.Hub.RestartAfter(img.onload);
}
if (this.img.status !== "OK") {
err = MML.Error(
LOCALE._(["MathML","BadMglyph"],"Bad mglyph: %1",values.src),
{mathsize:"75%"});
this.Append(err); svg = err.toSVG(); this.data.pop();
} else {
var mu = this.SVGgetMu(svg);
var SCALE = this.SVGgetScale();
svg.Add(BBOX.MGLYPH(this.img.img,values.width,values.height,values.valign,mu,SCALE,
{'aria-label':values.alt}));
}
}
svg.Clean();
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
},
SVGimgLoaded: function (event,status) {
if (typeof(event) === "string") {status = event}
this.img.status = (status || "OK")
},
SVGimgError: function () {this.img.img.onload("error")}
},{
GLYPH: {} // global list of all loaded glyphs
});
MathJax.Hub.Startup.signal.Post("SVG mglyph Ready");
MathJax.Ajax.loadComplete(SVG.autoloadDir+"/mglyph.js");
});

View File

@@ -0,0 +1,130 @@
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/jax/output/SVG/autoload/mmultiscripts.js
*
* Implements the SVG output for <mmultiscripts> elements.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2011-2020 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
MathJax.Hub.Register.StartupHook("SVG Jax Ready",function () {
var VERSION = "2.7.8";
var MML = MathJax.ElementJax.mml,
SVG = MathJax.OutputJax.SVG;
MML.mmultiscripts.Augment({
toSVG: function (HW,D) {
this.SVGgetStyles();
var svg = this.SVG(), scale = this.SVGgetScale(svg); this.SVGhandleSpace(svg);
var base = (this.data[this.base] ? this.SVGdataStretched(this.base,HW,D) : SVG.BBOX.G().Clean());
var x_height = SVG.TeX.x_height * scale,
s = SVG.TeX.scriptspace * scale * .75; // FIXME: .75 can be removed when IC is right?
var BOX = this.SVGgetScripts(s);
var sub = BOX[0], sup = BOX[1], presub = BOX[2], presup = BOX[3];
var sscale = (this.data[1]||this).SVGgetScale();
var q = SVG.TeX.sup_drop * sscale, r = SVG.TeX.sub_drop * sscale;
var u = base.h - q, v = base.d + r, delta = 0, p;
if (base.ic) {delta = base.ic}
if (this.data[this.base] &&
(this.data[this.base].type === "mi" || this.data[this.base].type === "mo")) {
if (SVG.isChar(this.data[this.base].data.join("")) && base.scale === 1 &&
!base.stretched && !this.data[this.base].Get("largeop")) {u = v = 0}
}
var min = this.getValues("subscriptshift","superscriptshift"), mu = this.SVGgetMu(svg);
min.subscriptshift = (min.subscriptshift === "" ? 0 : SVG.length2em(min.subscriptshift,mu));
min.superscriptshift = (min.superscriptshift === "" ? 0 : SVG.length2em(min.superscriptshift,mu));
var dx = 0;
if (presub) {dx = presub.w+delta} else if (presup) {dx = presup.w-delta}
svg.Add(base,Math.max(0,dx),0);
if (!sup && !presup) {
v = Math.max(v,SVG.TeX.sub1*scale,min.subscriptshift);
if (sub) {v = Math.max(v,sub.h-(4/5)*x_height)}
if (presub) {v = Math.max(v,presub.h-(4/5)*x_height)}
if (sub) {svg.Add(sub,dx+base.w+s-delta,-v)}
if (presub) {svg.Add(presub,0,-v)}
} else {
if (!sub && !presub) {
var values = this.getValues("displaystyle","texprimestyle");
p = SVG.TeX[(values.displaystyle ? "sup1" : (values.texprimestyle ? "sup3" : "sup2"))];
u = Math.max(u,p*scale,min.superscriptshift);
if (sup) {u = Math.max(u,sup.d+(1/4)*x_height)}
if (presup) {u = Math.max(u,presup.d+(1/4)*x_height)}
if (sup) {svg.Add(sup,dx+base.w+s,u)}
if (presup) {svg.Add(presup,0,u)}
} else {
v = Math.max(v,SVG.TeX.sub2*scale);
var t = SVG.TeX.rule_thickness * scale;
var h = (sub||presub).h, d = (sup||presup).d;
if (presub) {h = Math.max(h,presub.h)}
if (presup) {d = Math.max(d,presup.d)}
if ((u - d) - (h - v) < 3*t) {
v = 3*t - u + d + h; q = (4/5)*x_height - (u - d);
if (q > 0) {u += q; v -= q}
}
u = Math.max(u,min.superscriptshift); v = Math.max(v,min.subscriptshift);
if (sup) {svg.Add(sup,dx+base.w+s,u)}
if (presup) {svg.Add(presup,dx+delta-presup.w,u)}
if (sub) {svg.Add(sub,dx+base.w+s-delta,-v)}
if (presub) {svg.Add(presub,dx-presub.w,-v)}
}
}
svg.Clean();
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
var data = this.SVGdata;
data.dx = dx; data.s = s; data.u = u, data.v = v; data.delta = delta;
return svg;
},
SVGgetScripts: function (s) {
var sup, sub, BOX = [];
var i = 1, m = this.data.length, W = 0;
for (var k = 0; k < 4; k += 2) {
while (i < m && (this.data[i]||{}).type !== "mprescripts") {
var box = [null,null,null,null];
for (var j = k; j < k+2; j++) {
if (this.data[i] && this.data[i].type !== "none" && this.data[i].type !== "mprescripts") {
if (!BOX[j]) {BOX[j] = SVG.BBOX.G()}
box[j] = this.data[i].toSVG();
}
if ((this.data[i]||{}).type !== "mprescripts") i++;
}
var isPre = (k === 2);
if (isPre) W += Math.max((box[k]||{w:0}).w,(box[k+1]||{w:0}).w);
if (box[k]) BOX[k].Add(box[k].With({x:W-(isPre?box[k].w:0)}));
if (box[k+1]) BOX[k+1].Add(box[k+1].With({x:W-(isPre?box[k+1].w:0)}));
sub = BOX[k]||{w:0}; sup = BOX[k+1]||{w:0};
sub.w = sup.w = W = Math.max(sub.w,sup.w);
}
i++; W = 0;
}
for (j = 0; j < 4; j++) {if (BOX[j]) {BOX[j].w += s; BOX[j].Clean()}}
return BOX;
}
});
MathJax.Hub.Startup.signal.Post("SVG mmultiscripts Ready");
MathJax.Ajax.loadComplete(SVG.autoloadDir+"/mmultiscripts.js");
});

View File

@@ -0,0 +1,55 @@
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/jax/output/SVG/autoload/ms.js
*
* Implements the SVG output for <ms> elements.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2011-2020 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
MathJax.Hub.Register.StartupHook("SVG Jax Ready",function () {
var VERSION = "2.7.8";
var MML = MathJax.ElementJax.mml,
SVG = MathJax.OutputJax.SVG;
MML.ms.Augment({
toSVG: function () {
this.SVGgetStyles();
var svg = this.SVG(); this.SVGhandleSpace(svg);
var values = this.getValues("lquote","rquote","mathvariant");
if (!this.hasValue("lquote") || values.lquote === '"') values.lquote = "\u201C";
if (!this.hasValue("rquote") || values.rquote === '"') values.rquote = "\u201D";
if (values.lquote === "\u201C" && values.mathvariant === "monospace") values.lquote = '"';
if (values.rquote === "\u201D" && values.mathvariant === "monospace") values.rquote = '"';
var variant = this.SVGgetVariant(), scale = this.SVGgetScale();
var text = values.lquote+this.data.join("")+values.rquote; // FIXME: handle mglyph?
svg.Add(this.SVGhandleVariant(variant,scale,text));
svg.Clean();
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
}
});
MathJax.Hub.Startup.signal.Post("SVG ms Ready");
MathJax.Ajax.loadComplete(SVG.autoloadDir+"/ms.js");
});

View File

@@ -0,0 +1,389 @@
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/jax/output/SVG/autoload/mtable.js
*
* Implements the SVG output for <mtable> elements.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2011-2020 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
MathJax.Hub.Register.StartupHook("SVG Jax Ready",function () {
var VERSION = "2.7.8";
var MML = MathJax.ElementJax.mml,
SVG = MathJax.OutputJax.SVG,
BBOX = SVG.BBOX;
MML.mtable.Augment({
toSVG: function (span) {
this.SVGgetStyles();
var svg = this.SVG(), scale = this.SVGgetScale(svg);
if (this.data.length === 0) {this.SVGsaveData(svg);return svg}
var values = this.getValues("columnalign","rowalign","columnspacing","rowspacing",
"columnwidth","equalcolumns","equalrows",
"columnlines","rowlines","frame","framespacing",
"align","useHeight","width","side","minlabelspacing");
// Handle relative width as fixed width in relation to container
if (values.width.match(/%$/))
{svg.width = values.width = SVG.Em((SVG.cwidth/1000)*(parseFloat(values.width)/100))}
var mu = this.SVGgetMu(svg);
var LABEL = -1;
var H = [], D = [], W = [], A = [], C = [], i, j, J = -1,
m, M, s, row, cell, mo, HD;
var LH = SVG.FONTDATA.lineH * scale * values.useHeight,
LD = SVG.FONTDATA.lineD * scale * values.useHeight;
//
// Create cells and measure columns and rows
//
for (i = 0, m = this.data.length; i < m; i++) {
row = this.data[i]; s = (row.type === "mlabeledtr" ? LABEL : 0);
A[i] = []; H[i] = LH; D[i] = LD;
for (j = s, M = row.data.length + s; j < M; j++) {
if (W[j] == null) {
if (j > J) {J = j}
C[j] = BBOX.G();
W[j] = -SVG.BIGDIMEN;
}
cell = row.data[j-s];
A[i][j] = cell.toSVG();
// if (row.data[j-s].isMultiline) {A[i][j].style.width = "100%"}
if (cell.isEmbellished()) {
mo = cell.CoreMO();
var min = mo.Get("minsize",true);
if (min) {
if (mo.SVGcanStretch("Vertical")) {
HD = mo.SVGdata.h + mo.SVGdata.d;
if (HD) {
min = SVG.length2em(min,mu,HD);
if (min*mo.SVGdata.h/HD > H[i]) {H[i] = min*mo.SVGdata.h/HD}
if (min*mo.SVGdata.d/HD > D[i]) {D[i] = min*mo.SVGdata.d/HD}
}
} else if (mo.SVGcanStretch("Horizontal")) {
min = SVG.length2em(min,mu,mo.SVGdata.w);
if (min > W[j]) {W[j] = min}
}
}
}
if (A[i][j].h > H[i]) {H[i] = A[i][j].h}
if (A[i][j].d > D[i]) {D[i] = A[i][j].d}
if (A[i][j].w > W[j]) {W[j] = A[i][j].w}
}
}
//
// Determine spacing and alignment
//
var SPLIT = MathJax.Hub.SplitList;
var CSPACE = SPLIT(values.columnspacing),
RSPACE = SPLIT(values.rowspacing),
CALIGN = SPLIT(values.columnalign),
RALIGN = SPLIT(values.rowalign),
CLINES = SPLIT(values.columnlines),
RLINES = SPLIT(values.rowlines),
CWIDTH = SPLIT(values.columnwidth),
RCALIGN = [];
for (i = 0, m = CSPACE.length; i < m; i++) {CSPACE[i] = SVG.length2em(CSPACE[i],mu)}
for (i = 0, m = RSPACE.length; i < m; i++) {RSPACE[i] = SVG.length2em(RSPACE[i],mu)}
while (CSPACE.length < J) {CSPACE.push(CSPACE[CSPACE.length-1])}
while (CALIGN.length <= J) {CALIGN.push(CALIGN[CALIGN.length-1])}
while (CLINES.length < J) {CLINES.push(CLINES[CLINES.length-1])}
while (CWIDTH.length <= J) {CWIDTH.push(CWIDTH[CWIDTH.length-1])}
while (RSPACE.length < A.length) {RSPACE.push(RSPACE[RSPACE.length-1])}
while (RALIGN.length <= A.length) {RALIGN.push(RALIGN[RALIGN.length-1])}
while (RLINES.length < A.length) {RLINES.push(RLINES[RLINES.length-1])}
if (C[LABEL]) {
CALIGN[LABEL] = (values.side.substr(0,1) === "l" ? "left" : "right");
CSPACE[LABEL] = -W[LABEL];
}
//
// Override row data
//
for (i = 0, m = A.length; i < m; i++) {
row = this.data[i]; RCALIGN[i] = [];
if (row.rowalign) {RALIGN[i] = row.rowalign}
if (row.columnalign) {
RCALIGN[i] = SPLIT(row.columnalign);
while (RCALIGN[i].length <= J) {RCALIGN[i].push(RCALIGN[i][RCALIGN[i].length-1])}
}
}
//
// Handle equal heights
//
if (values.equalrows) {
// FIXME: should really be based on row align (below is for baseline)
var Hm = Math.max.apply(Math,H), Dm = Math.max.apply(Math,D);
for (i = 0, m = A.length; i < m; i++)
{s = ((Hm + Dm) - (H[i] + D[i])) / 2; H[i] += s; D[i] += s}
}
// FIXME: do background colors for entire cell (include half the intercolumn space?)
//
// Determine array total height
//
HD = H[0] + D[A.length-1];
for (i = 0, m = A.length-1; i < m; i++)
{HD += Math.max(0,D[i]+H[i+1]+RSPACE[i])}
//
// Determine frame and line sizes
//
var fx = 0, fy = 0, fW, fH = HD;
if (values.frame !== "none" ||
(values.columnlines+values.rowlines).match(/solid|dashed/)) {
var frameSpacing = SPLIT(values.framespacing);
if (frameSpacing.length != 2) {
// invalid attribute value: use the default.
frameSpacing = SPLIT(this.defaults.framespacing);
}
fx = SVG.length2em(frameSpacing[0],mu);
fy = SVG.length2em(frameSpacing[1],mu);
fH = HD + 2*fy; // fW waits until svg.w is determined
}
//
// Compute alignment
//
var Y, fY, n = "";
if (typeof(values.align) !== "string") {values.align = String(values.align)}
if (values.align.match(/(top|bottom|center|baseline|axis)( +(-?\d+))?/))
{n = RegExp.$3||""; values.align = RegExp.$1} else {values.align = this.defaults.align}
if (n !== "") {
//
// Find the height of the given row
//
n = parseInt(n);
if (n < 0) {n = A.length + 1 + n}
if (n < 1) {n = 1} else if (n > A.length) {n = A.length}
Y = 0; fY = -(HD + fy) + H[0];
for (i = 0, m = n-1; i < m; i++) {
// FIXME: Should handle values.align for final row
var dY = Math.max(0,D[i]+H[i+1]+RSPACE[i]);
Y += dY; fY += dY;
}
} else {
Y = ({
top: -(H[0] + fy),
bottom: HD + fy - H[0],
center: HD/2 - H[0],
baseline: HD/2 - H[0],
axis: HD/2 + SVG.TeX.axis_height*scale - H[0]
})[values.align];
fY = ({
top: -(HD + 2*fy),
bottom: 0,
center: -(HD/2 + fy),
baseline: -(HD/2 + fy),
axis: SVG.TeX.axis_height*scale - HD/2 - fy
})[values.align];
}
var WW, WP = 0, Wt = 0, Wp = 0, p = 0, f = 0, P = [], F = [], Wf = 1;
//
if (values.equalcolumns && values.width !== "auto") {
//
// Handle equalcolumns for percent-width and fixed-width tables
//
// Get total width minus column spacing
WW = SVG.length2em(values.width,mu);
for (i = 0, m = Math.min(J,CSPACE.length); i < m; i++) {WW -= CSPACE[i]}
// Determine individual column widths
WW /= J;
for (i = 0, m = Math.min(J+1,CWIDTH.length); i < m; i++) {W[i] = WW}
} else {
//
// Get column widths for fit and percentage columns
//
// Calculate the natural widths and percentage widths,
// while keeping track of the fit and percentage columns
for(i = 0, m = Math.min(J+1,CWIDTH.length); i < m; i++) {
if (CWIDTH[i] === "auto") {Wt += W[i]}
else if (CWIDTH[i] === "fit") {F[f] = i; f++; Wt += W[i]}
else if (CWIDTH[i].match(/%$/))
{P[p] = i; p++; Wp += W[i]; WP += SVG.length2em(CWIDTH[i],mu,1)}
else {W[i] = SVG.length2em(CWIDTH[i],mu); Wt += W[i]}
}
// Get the full width (excluding inter-column spacing)
if (values.width === "auto") {
if (WP > .98) {Wf = Wp/(Wt+Wp); WW = Wt + Wp} else {WW = Wt / (1-WP)}
} else {
WW = Math.max(Wt + Wp, SVG.length2em(values.width,mu));
for (i = 0, m = Math.min(J,CSPACE.length); i < m; i++) {WW -= CSPACE[i]}
}
// Determine the relative column widths
for (i = 0, m = P.length; i < m; i++) {
W[P[i]] = SVG.length2em(CWIDTH[P[i]],mu,WW*Wf); Wt += W[P[i]];
}
// Stretch fit columns, if any, otherwise stretch (or shrink) everything
if (Math.abs(WW - Wt) > .01) {
if (f && WW > Wt) {
WW = (WW - Wt) / f; for (i = 0, m = F.length; i < m; i++) {W[F[i]] += WW}
} else {WW = WW/Wt; for (j = 0; j <= J; j++) {W[j] *= WW}}
}
//
// Handle equal columns
//
if (values.equalcolumns) {
var Wm = Math.max.apply(Math,W);
for (j = 0; j <= J; j++) {W[j] = Wm}
}
}
//
// Lay out array columns
//
var y = Y, dy, align; s = (C[LABEL] ? LABEL : 0);
for (j = s; j <= J; j++) {
C[j].w = W[j];
for (i = 0, m = A.length; i < m; i++) {
if (A[i][j]) {
s = (this.data[i].type === "mlabeledtr" ? LABEL : 0);
cell = this.data[i].data[j-s];
if (cell.SVGcanStretch("Horizontal")) {
A[i][j] = cell.SVGstretchH(W[j]);
} else if (cell.SVGcanStretch("Vertical")) {
mo = cell.CoreMO();
var symmetric = mo.symmetric; mo.symmetric = false;
A[i][j] = cell.SVGstretchV(H[i],D[i]);
mo.symmetric = symmetric;
}
align = cell.rowalign||this.data[i].rowalign||RALIGN[i];
dy = ({top: H[i] - A[i][j].h,
bottom: A[i][j].d - D[i],
center: ((H[i]-D[i]) - (A[i][j].h-A[i][j].d))/2,
baseline: 0, axis: 0})[align] || 0; // FIXME: handle axis better?
align = (cell.columnalign||RCALIGN[i][j]||CALIGN[j])
C[j].Align(A[i][j],align,0,y+dy);
}
if (i < A.length-1) {y -= Math.max(0,D[i]+H[i+1]+RSPACE[i])}
}
y = Y;
}
//
// Place the columns and add column lines
//
var lw = 1.5*SVG.em;
var x = fx - lw/2;
for (j = 0; j <= J; j++) {
svg.Add(C[j],x,0); x += W[j] + CSPACE[j];
if (CLINES[j] !== "none" && j < J && j !== LABEL)
{svg.Add(BBOX.VLINE(fH,lw,CLINES[j]),x-CSPACE[j]/2,fY)}
}
svg.w += fx; svg.d = -fY; svg.h = fH+fY;
fW = svg.w;
//
// Add frame
//
if (values.frame !== "none") {
svg.Add(BBOX.HLINE(fW,lw,values.frame),0,fY+fH-lw);
svg.Add(BBOX.HLINE(fW,lw,values.frame),0,fY);
svg.Add(BBOX.VLINE(fH,lw,values.frame),0,fY);
svg.Add(BBOX.VLINE(fH,lw,values.frame),fW-lw,fY);
}
//
// Add row lines
//
y = Y - lw/2;
for (i = 0, m = A.length-1; i < m; i++) {
dy = Math.max(0,D[i]+H[i+1]+RSPACE[i]);
if (RLINES[i] !== MML.LINES.NONE && RLINES[i] !== "")
{svg.Add(BBOX.HLINE(fW,lw,RLINES[i]),0,y-D[i]-(dy-D[i]-H[i+1])/2)}
y -= dy;
}
//
// Finish the table
//
svg.Clean();
this.SVGhandleSpace(svg);
this.SVGhandleColor(svg);
//
// Place the labels, if any
//
if (C[LABEL]) {
svg.tw = Math.max(svg.w,svg.r) - Math.min(0,svg.l);
var indent = this.getValues("indentalignfirst","indentshiftfirst","indentalign","indentshift");
if (indent.indentalignfirst !== MML.INDENTALIGN.INDENTALIGN) {indent.indentalign = indent.indentalignfirst}
if (indent.indentalign === MML.INDENTALIGN.AUTO) {indent.indentalign = this.displayAlign}
if (indent.indentshiftfirst !== MML.INDENTSHIFT.INDENTSHIFT) {indent.indentshift = indent.indentshiftfirst}
if (indent.indentshift === "auto" || indent.indentshift === "") {indent.indentshift = "0"}
var shift = SVG.length2em(indent.indentshift,mu,SVG.cwidth);
var labelspace = SVG.length2em(values.minlabelspacing,mu,SVG.cwidth);
var labelW = labelspace + C[LABEL].w, labelshift = 0, tw = svg.w;
var dIndent = SVG.length2em(this.displayIndent,mu,SVG.cwidth);
s = (CALIGN[LABEL] === MML.INDENTALIGN.RIGHT ? -1 : 1);
if (indent.indentalign === MML.INDENTALIGN.CENTER) {
var dx = (SVG.cwidth-tw)/2; shift += dIndent;
if (labelW + s*labelshift > dx + s*shift) {
indent.indentalign = CALIGN[LABEL];
shift = s*(labelW + s*labelshift); tw += labelW + Math.max(0,shift);
}
} else if (CALIGN[LABEL] === indent.indentalign) {
if (dIndent < 0) {labelshift = s*dIndent; dIndent = 0}
shift += s*dIndent; if (labelW > s*shift) shift = s*labelW; shift += labelshift;
tw += s*shift;
} else {
shift -= s*dIndent;
if (tw - s*shift + labelW > SVG.cwidth) {
shift = s*(tw + labelW - SVG.cwidth);
if (s*shift > 0) {tw = SVG.cwidth + s*shift; shift = 0}
}
}
var eqn = svg; svg = this.SVG();
svg.hasIndent = true;
svg.w = svg.r = Math.max(tw,SVG.cwidth);
svg.Align(C[LABEL],CALIGN[LABEL],0,0,labelshift);
svg.Align(eqn,indent.indentalign,0,0,shift);
svg.tw = tw;
}
this.SVGsaveData(svg);
return svg;
},
SVGhandleSpace: function (svg) {
if (!this.hasFrame && !svg.width) {svg.x = svg.X = 167}
this.SUPER(arguments).SVGhandleSpace.call(this,svg);
}
});
MML.mtd.Augment({
toSVG: function (HW,D) {
var svg = this.svg = this.SVG();
if (this.data[0]) {
svg.Add(this.SVGdataStretched(0,HW,D));
svg.Clean();
}
this.SVGhandleColor(svg);
this.SVGsaveData(svg);
return svg;
}
});
MathJax.Hub.Startup.signal.Post("SVG mtable Ready");
MathJax.Ajax.loadComplete(SVG.autoloadDir+"/mtable.js");
});

View File

@@ -0,0 +1,733 @@
/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*************************************************************
*
* MathJax/jax/output/SVG/autoload/multiline.js
*
* Implements the SVG output for <mrow>'s that contain line breaks.
*
* ---------------------------------------------------------------------
*
* Copyright (c) 2011-2020 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
MathJax.Hub.Register.StartupHook("SVG Jax Ready",function () {
var VERSION = "2.7.8";
var MML = MathJax.ElementJax.mml,
SVG = MathJax.OutputJax.SVG,
BBOX = SVG.BBOX;
//
// Fake node used for testing end-of-line potential breakpoint
//
var MO = MML.mo().With({SVGdata: {w: 0, x:0}});
//
// Penalties for the various line breaks
//
var PENALTY = {
newline: 0,
nobreak: 1000000,
goodbreak: [-200],
badbreak: [+200],
auto: [0],
maxwidth: 1.33, // stop looking for breaks after this time the line-break width
toobig: 800,
nestfactor: 400,
spacefactor: -100,
spaceoffset: 2,
spacelimit: 1, // spaces larger than this get a penalty boost
fence: 500,
close: 500
};
var ENDVALUES = {linebreakstyle: "after"};
/**************************************************************************/
MML.mrow.Augment({
//
// Handle breaking an mrow into separate lines
//
SVGmultiline: function (svg) {
//
// Find the parent element and mark it as multiline
//
var parent = this;
while (parent.inferred || (parent.parent && parent.parent.type === "mrow" &&
parent.isEmbellished())) {parent = parent.parent}
var isTop = ((parent.type === "math" && parent.Get("display") === "block") ||
parent.type === "mtd");
parent.isMultiline = true;
//
// Default values for the line-breaking parameters
//
var VALUES = this.getValues(
"linebreak","linebreakstyle","lineleading","linebreakmultchar",
"indentalign","indentshift",
"indentalignfirst","indentshiftfirst",
"indentalignlast","indentshiftlast"
);
if (VALUES.linebreakstyle === MML.LINEBREAKSTYLE.INFIXLINEBREAKSTYLE)
{VALUES.linebreakstyle = this.Get("infixlinebreakstyle")}
VALUES.lineleading = SVG.length2em(VALUES.lineleading,1,0.5);
//
// Start with a fresh SVG element
// and make it full width if we are breaking to a specific width
// in the top-level math element
//
svg = this.SVG();
if (parent.type === "math") {
if (SVG.linebreakWidth < SVG.BIGDIMEN) {svg.w = SVG.linebreakWidth}
else {svg.w = SVG.cwidth}
}
var state = {
n: 0, Y: 0,
scale: this.scale || 1,
isTop: isTop,
values: {},
VALUES: VALUES
},
align = this.SVGgetAlign(state,{}),
shift = this.SVGgetShift(state,{},align),
start = [],
end = {
index:[], penalty:PENALTY.nobreak,
w:0, W:shift, shift:shift, scanW:shift,
nest: 0
},
broken = false;
//
// Break the expression at its best line breaks
//
while (this.SVGbetterBreak(end,state,true) &&
(end.scanW >= SVG.linebreakWidth || end.penalty === PENALTY.newline)) {
this.SVGaddLine(svg,start,end.index,state,end.values,broken);
start = end.index.slice(0); broken = true;
align = this.SVGgetAlign(state,end.values);
shift = this.SVGgetShift(state,end.values,align);
if (align === MML.INDENTALIGN.CENTER) {shift = 0}
end.W = end.shift = end.scanW = shift; end.penalty = PENALTY.nobreak;
}
state.isLast = true;
this.SVGaddLine(svg,start,[],state,ENDVALUES,broken);
this.SVGhandleSpace(svg);
this.SVGhandleColor(svg);
svg.isMultiline = true;
this.SVGsaveData(svg);
return svg;
}
});
/**************************************************************************/
MML.mbase.Augment({
SVGlinebreakPenalty: PENALTY,
/****************************************************************/
//
// Locate the next linebreak that is better than the current one
//
SVGbetterBreak: function (info,state,toplevel) {
if (this.isToken) {return false} // FIXME: handle breaking of token elements
if (this.isEmbellished()) {
info.embellished = this;
return this.CoreMO().SVGbetterBreak(info,state);
}
if (this.linebreakContainer) {return false}
//
// Get the current breakpoint position and other data
//
var index = info.index.slice(0), i = info.index.shift(),
m = this.data.length, W, w, scanW, broken = (info.index.length > 0), better = false;
if (i == null) {i = -1}; if (!broken) {i++; info.W += info.w; info.w = 0}
scanW = info.scanW = info.W; info.nest++;
//
// Look through the line for breakpoints,
// (as long as we are not too far past the breaking width)
//
while (i < m && (info.scanW < PENALTY.maxwidth*SVG.linebreakWidth || info.w === 0)) {
if (this.data[i]) {
if (this.data[i].SVGbetterBreak(info,state)) {
better = true; index = [i].concat(info.index); W = info.W; w = info.w;
if (info.penalty === PENALTY.newline) {
info.index = index;
if (info.nest) {info.nest--}
return true;
}
}
scanW = (broken ? info.scanW : this.SVGaddWidth(i,info,scanW));
}
info.index = []; i++; broken = false;
}
//
// Check if end-of-line is a better breakpoint
//
if (toplevel && better) {
MO.parent = this.parent; MO.inherit = this.inherit;
if (MO.SVGbetterBreak(info,state)) {better = false; index = info.index}
}
if (info.nest) {info.nest--}
info.index = index;
if (better) {info.W = W}
return better;
},
SVGaddWidth: function (i,info,scanW) {
if (this.data[i]) {
var svg = this.data[i].SVGdata;
scanW += svg.w + svg.x; if (svg.X) {scanW += svg.X}
info.W = info.scanW = scanW; info.w = 0;
}
return scanW;
},
/****************************************************************/
//
// Create a new line and move the required elements into it
// Position it using proper alignment and indenting
//
SVGaddLine: function (svg,start,end,state,values,broken) {
//
// Create a box for the line, with empty BBox
// fill it with the proper elements,
// and clean up the bbox
//
var line = BBOX();
state.first = broken; state.last = true;
this.SVGmoveLine(start,end,line,state,values);
line.Clean();
//
// Get the alignment and shift values
//
var align = this.SVGgetAlign(state,values),
shift = this.SVGgetShift(state,values,align);
//
// Set the Y offset based on previous depth, leading, and current height
//
if (state.n > 0) {
var LHD = SVG.FONTDATA.baselineskip * state.scale;
var leading = (state.values.lineleading == null ? state.VALUES : state.values).lineleading * state.scale;
state.Y -= Math.max(LHD,state.d + line.h + leading);
}
//
// Place the new line
//
if (line.w + shift > svg.w) svg.w = line.w + shift;
svg.Align(line,align,0,state.Y,shift);
//
// Save the values needed for the future
//
state.d = line.d; state.values = values; state.n++;
},
/****************************************************************/
//
// Get alignment and shift values from the given data
//
SVGgetAlign: function (state,values) {
var cur = values, prev = state.values, def = state.VALUES, align;
if (state.n === 0) {align = cur.indentalignfirst || prev.indentalignfirst || def.indentalignfirst}
else if (state.isLast) {align = prev.indentalignlast || def.indentalignlast}
else {align = prev.indentalign || def.indentalign}
if (align === MML.INDENTALIGN.INDENTALIGN) {align = prev.indentalign || def.indentalign}
if (align === MML.INDENTALIGN.AUTO) {align = (state.isTop ? this.displayAlign : MML.INDENTALIGN.LEFT)}
return align;
},
SVGgetShift: function (state,values,align) {
var cur = values, prev = state.values, def = state.VALUES, shift;
if (state.n === 0) {shift = cur.indentshiftfirst || prev.indentshiftfirst || def.indentshiftfirst}
else if (state.isLast) {shift = prev.indentshiftlast || def.indentshiftlast}
else {shift = prev.indentshift || def.indentshift}
if (shift === MML.INDENTSHIFT.INDENTSHIFT) {shift = prev.indentshift || def.indentshift}
if (shift === "auto" || shift === "") {shift = "0"}
shift = SVG.length2em(shift,1,SVG.cwidth);
if (state.isTop && this.displayIndent !== "0") {
var indent = SVG.length2em(this.displayIndent,1,SVG.cwidth);
shift += (align === MML.INDENTALIGN.RIGHT ? -indent: indent);
}
return shift;
},
/****************************************************************/
//
// Move the selected elements into the new line,
// moving whole items when possible, and parts of ones
// that are split by a line break.
//
SVGmoveLine: function (start,end,svg,state,values) {
var i = start[0], j = end[0];
if (i == null) {i = -1}; if (j == null) {j = this.data.length-1}
if (i === j && start.length > 1) {
//
// If starting and ending in the same element move the subpiece to the new line
//
this.data[i].SVGmoveSlice(start.slice(1),end.slice(1),svg,state,values,"paddingLeft");
} else {
//
// Otherwise, move the remainder of the initial item
// and any others up to the last one
//
var last = state.last; state.last = false;
while (i < j) {
if (this.data[i]) {
if (start.length <= 1) {this.data[i].SVGmove(svg,state,values)}
else {this.data[i].SVGmoveSlice(start.slice(1),[],svg,state,values,"paddingLeft")}
}
i++; state.first = false; start = [];
}
//
// If the last item is complete, move it,
// otherwise move the first part of it up to the split
//
state.last = last;
if (this.data[i]) {
if (end.length <= 1) {this.data[i].SVGmove(svg,state,values)}
else {this.data[i].SVGmoveSlice([],end.slice(1),svg,state,values,"paddingRight")}
}
}
},
/****************************************************************/
//
// Split an element and copy the selected items into the new part
//
SVGmoveSlice: function (start,end,svg,state,values,padding) {
//
// Create a new container for the slice of the element
// Move the selected portion into the slice
//
var slice = BBOX();
this.SVGmoveLine(start,end,slice,state,values);
slice.Clean();
if (this.href) {this.SVGaddHref(slice)}
this.SVGhandleColor(slice);
if (start.length == 0) this.SVGhandleSpace(slice);
svg.Add(slice,svg.w,0,true);
return slice;
},
/****************************************************************/
//
// Move an element from its original position to its new location in
// a split element or the new line's position
//
SVGmove: function (line,state,values) {
// FIXME: handle linebreakstyle === "duplicate"
// FIXME: handle linebreakmultchar
if (!(state.first || state.last) ||
(state.first && state.values.linebreakstyle === MML.LINEBREAKSTYLE.BEFORE) ||
(state.last && values.linebreakstyle === MML.LINEBREAKSTYLE.AFTER)) {
//
// Recreate output
// Remove padding (if first, remove at leftt, if last remove at right)
// Add to line
//
var svg = this.toSVG(this.SVGdata.HW,this.SVGdata.D);
if (state.first || state.nextIsFirst) {svg.x = 0}
if (state.last && svg.X) {svg.X = 0}
line.Add(svg,line.w,0,true);
}
if (state.first && svg && svg.w === 0) {state.nextIsFirst = true}
else {delete state.nextIsFirst}
}
});
/**************************************************************************/
MML.mfenced.Augment({
SVGbetterBreak: function (info,state) {
//
// Get the current breakpoint position and other data
//
var index = info.index.slice(0), i = info.index.shift(),
m = this.data.length, W, w, scanW, broken = (info.index.length > 0), better = false;
if (i == null) {i = -1}; if (!broken) {i++; info.W += info.w; info.w = 0}
scanW = info.scanW = info.W; info.nest++;
//
// Create indices that include the delimiters and separators
//
if (!this.dataI) {
this.dataI = [];
if (this.data.open) {this.dataI.push("open")}
if (m) {this.dataI.push(0)}
for (var j = 1; j < m; j++) {
if (this.data["sep"+j]) {this.dataI.push("sep"+j)}
this.dataI.push(j);
}
if (this.data.close) {this.dataI.push("close")}
}
m = this.dataI.length;
//
// Look through the line for breakpoints, including the open, close, and separators
// (as long as we are not too far past the breaking width)
//
while (i < m && (info.scanW < PENALTY.maxwidth*SVG.linebreakWidth || info.w === 0)) {
var k = this.dataI[i];
if (this.data[k]) {
if (this.data[k].SVGbetterBreak(info,state)) {
better = true; index = [i].concat(info.index); W = info.W; w = info.w;
if (info.penalty === PENALTY.newline) {
info.index = index;
if (info.nest) {info.nest--}
return true;
}
}
scanW = (broken ? info.scanW : this.SVGaddWidth(i,info,scanW));
}
info.index = []; i++; broken = false;
}
if (info.nest) {info.nest--}
info.index = index;
if (better) {info.W = W; info.w = w}
return better;
},
SVGmoveLine: function (start,end,svg,state,values) {
var i = start[0], j = end[0];
if (i == null) {i = -1}; if (j == null) {j = this.dataI.length-1}
if (i === j && start.length > 1) {
//
// If starting and ending in the same element move the subpiece to the new line
//
this.data[this.dataI[i]].SVGmoveSlice(start.slice(1),end.slice(1),svg,state,values,"paddingLeft");
} else {
//
// Otherwise, move the remainder of the initial item
// and any others (including open and separators) up to the last one
//
var last = state.last; state.last = false; var k = this.dataI[i];
while (i < j) {
if (this.data[k]) {
if (start.length <= 1) {this.data[k].SVGmove(svg,state,values)}
else {this.data[k].SVGmoveSlice(start.slice(1),[],svg,state,values,"paddingLeft")}
}
i++; k = this.dataI[i]; state.first = false; start = [];
}
//
// If the last item is complete, move it
//
state.last = last;
if (this.data[k]) {
if (end.length <= 1) {this.data[k].SVGmove(svg,state,values)}
else {this.data[k].SVGmoveSlice([],end.slice(1),svg,state,values,"paddingRight")}
}
}
}
});
/**************************************************************************/
MML.msubsup.Augment({
SVGbetterBreak: function (info,state) {
if (!this.data[this.base]) {return false}
//
// Get the current breakpoint position and other data
//
var index = info.index.slice(0), i = info.index.shift(),
W, w, scanW, broken = (info.index.length > 0), better = false;
if (!broken) {info.W += info.w; info.w = 0}
scanW = info.scanW = info.W;
//
// Record the width of the base and the super- and subscripts
//
if (i == null) {this.SVGdata.dw = this.SVGdata.w - this.data[this.base].SVGdata.w}
//
// Check if the base can be broken
//
if (this.data[this.base].SVGbetterBreak(info,state)) {
better = true; index = [this.base].concat(info.index); W = info.W; w = info.w;
if (info.penalty === PENALTY.newline) {better = broken = true}
}
//
// Add in the base if it is unbroken, and add the scripts
//
if (!broken) {this.SVGaddWidth(this.base,info,scanW)}
info.scanW += this.SVGdata.dw; info.W = info.scanW;
info.index = []; if (better) {info.W = W; info.w = w; info.index = index}
return better;
},
SVGmoveLine: function (start,end,svg,state,values) {
//
// Move the proper part of the base
//
if (this.data[this.base]) {
if (start.length > 1) {
this.data[this.base].SVGmoveSlice(start.slice(1),end.slice(1),svg,state,values,"paddingLeft");
} else {
if (end.length <= 1) {this.data[this.base].SVGmove(svg,state,values)}
else {this.data[this.base].SVGmoveSlice([],end.slice(1),svg,state,values,"paddingRight")}
}
}
//
// If this is the end, check for super and subscripts, and move those
// by moving the stack that contains them, and shifting by the amount of the
// base that has been removed. Remove the empty base box from the stack.
//
if (end.length === 0) {
var sup = this.data[this.sup], sub = this.data[this.sub], w = svg.w, data;
var ic = (this.data[this.base].SVGdata || {}).ic || 0;
if (sup) {data = sup.SVGdata||{}; svg.Add(sup.toSVG(),w+(data.dx||0)-ic,data.dy)}
if (sub) {data = sub.SVGdata||{}; svg.Add(sub.toSVG(),w+(data.dx||0)-ic,data.dy)}
}
}
});
/**************************************************************************/
MML.mmultiscripts.Augment({
SVGbetterBreak: function (info,state) {
if (!this.data[this.base]) {return false}
//
// Get the current breakpoint position and other data
//
var index = info.index.slice(0); info.index.shift();
var W, w, scanW, broken = (info.index.length > 0), better = false;
if (!broken) {info.W += info.w; info.w = 0}
info.scanW = info.W;
//
// The width of the postscripts
//
var dw = this.SVGdata.w - this.data[this.base].SVGdata.w - this.SVGdata.dx;
//
// Add in the prescripts
//
info.scanW += this.SVGdata.dx; scanW = info.scanW;
//
// Check if the base can be broken (but don't break between prescripts and base)
//
if (this.data[this.base].SVGbetterBreak(info,state)) {
better = true; index = [this.base].concat(info.index); W = info.W; w = info.w;
if (info.penalty === PENALTY.newline) {better = broken = true}
}
//
// Add in the base if it is unbroken, and add the postscripts
//
if (!broken) {this.SVGaddWidth(this.base,info,scanW)}
info.scanW += dw; info.W = info.scanW;
info.index = []; if (better) {info.W = W; info.w = w; info.index = index}
return better;
},
SVGmoveLine: function (start,end,svg,state,values) {
var dx, data = this.SVGdata;
//
// If this is the start, move the prescripts, if any.
//
if (start.length < 1) {
this.scriptBox = this.SVGgetScripts(this.SVGdata.s);
var presub = this.scriptBox[2], presup = this.scriptBox[3]; dx = svg.w + data.dx;
if (presup) {svg.Add(presup,dx+data.delta-presup.w,data.u)}
if (presub) {svg.Add(presub,dx-presub.w,-data.v)}
}
//
// Move the proper part of the base
//
if (this.data[this.base]) {
if (start.length > 1) {
this.data[this.base].SVGmoveSlice(start.slice(1),end.slice(1),svg,state,values,"paddingLeft");
} else {
if (end.length <= 1) {this.data[this.base].SVGmove(svg,state,values)}
else {this.data[this.base].SVGmoveSlice([],end.slice(1),svg,state,values,"paddingRight")}
}
}
//
// If this is the end, move the postscripts, if any.
//
if (end.length === 0) {
var sub = this.scriptBox[0], sup = this.scriptBox[1]; dx = svg.w + data.s;
if (sup) {svg.Add(sup,dx,data.u)}
if (sub) {svg.Add(sub,dx-data.delta,-data.v)}
delete this.scriptBox;
}
}
});
/**************************************************************************/
MML.mo.Augment({
//
// Override the method for checking line breaks to properly handle <mo>
//
SVGbetterBreak: function (info,state) {
if (info.values && info.values.last === this) {return false}
var values = this.getValues(
"linebreak","linebreakstyle","lineleading","linebreakmultchar",
"indentalign","indentshift",
"indentalignfirst","indentshiftfirst",
"indentalignlast","indentshiftlast",
"texClass", "fence"
);
if (values.linebreakstyle === MML.LINEBREAKSTYLE.INFIXLINEBREAKSTYLE)
{values.linebreakstyle = this.Get("infixlinebreakstyle")}
//
// Adjust nesting by TeX class (helps output that does not include
// mrows for nesting, but can leave these unbalanced.
//
if (values.texClass === MML.TEXCLASS.OPEN) {info.nest++}
if (values.texClass === MML.TEXCLASS.CLOSE && info.nest) {info.nest--}
//
// Get the default penalty for this location
//
var W = info.scanW, mo = info.embellished; delete info.embellished;
if (!mo || !mo.SVGdata) {mo = this}
var svg = mo.SVGdata, w = svg.w + svg.x;
if (values.linebreakstyle === MML.LINEBREAKSTYLE.AFTER) {W += w; w = 0}
if (W - info.shift === 0 && values.linebreak !== MML.LINEBREAK.NEWLINE)
{return false} // don't break at zero width (FIXME?)
var offset = SVG.linebreakWidth - W;
// adjust offest for explicit first-line indent and align
if (state.n === 0 && (values.indentshiftfirst !== state.VALUES.indentshiftfirst ||
values.indentalignfirst !== state.VALUES.indentalignfirst)) {
var align = this.SVGgetAlign(state,values),
shift = this.SVGgetShift(state,values,align);
offset += (info.shift - shift);
}
//
var penalty = Math.floor(offset / SVG.linebreakWidth * 1000);
if (penalty < 0) {penalty = PENALTY.toobig - 3*penalty}
if (values.fence) {penalty += PENALTY.fence}
if ((values.linebreakstyle === MML.LINEBREAKSTYLE.AFTER &&
values.texClass === MML.TEXCLASS.OPEN) ||
values.texClass === MML.TEXCLASS.CLOSE) {penalty += PENALTY.close}
penalty += info.nest * PENALTY.nestfactor;
//
// Get the penalty for this type of break and
// use it to modify the default penalty
//
var linebreak = PENALTY[values.linebreak||MML.LINEBREAK.AUTO]||0;
if (!MathJax.Object.isArray(linebreak)) {
// for breaks past the width, keep original penalty for newline
if (linebreak || offset >= 0) {penalty = linebreak * info.nest}
} else {penalty = Math.max(1,penalty + linebreak[0] * info.nest)}
//
// If the penalty is no better than the current one, return false
// Otherwise save the data for this breakpoint and return true
//
if (penalty >= info.penalty) {return false}
info.penalty = penalty; info.values = values; info.W = W; info.w = w;
values.lineleading = SVG.length2em(values.lineleading,1,state.VALUES.lineleading);
values.last = this;
return true;
}
});
/**************************************************************************/
MML.mspace.Augment({
//
// Override the method for checking line breaks to properly handle <mspace>
//
SVGbetterBreak: function (info,state) {
if (info.values && info.values.last === this) {return false}
var values = this.getValues("linebreak");
var linebreakValue = values.linebreak;
if (!linebreakValue || this.hasDimAttr()) {
// The MathML spec says that the linebreak attribute should be ignored
// if any dimensional attribute is set.
linebreakValue = MML.LINEBREAK.AUTO;
}
//
// Get the default penalty for this location
//
var W = info.scanW, svg = this.SVGdata, w = svg.w + svg.x;
if (W - info.shift === 0) {return false} // don't break at zero width (FIXME?)
var offset = SVG.linebreakWidth - W;
//
var penalty = Math.floor(offset / SVG.linebreakWidth * 1000);
if (penalty < 0) {penalty = PENALTY.toobig - 3*penalty}
penalty += info.nest * PENALTY.nestfactor;
//
// Get the penalty for this type of break and
// use it to modify the default penalty
//
var linebreak = PENALTY[linebreakValue]||0;
if (linebreakValue === MML.LINEBREAK.AUTO && w >= PENALTY.spacelimit*1000 &&
!this.mathbackground && !this.backrgound)
{linebreak = [(w/1000+PENALTY.spaceoffset)*PENALTY.spacefactor]}
if (!MathJax.Object.isArray(linebreak)) {
// for breaks past the width, keep original penalty for newline
if (linebreak || offset >= 0) {penalty = linebreak * info.nest}
} else {penalty = Math.max(1,penalty + linebreak[0] * info.nest)}
//
// If the penalty is no better than the current one, return false
// Otherwise save the data for this breakpoint and return true
//
if (penalty >= info.penalty) {return false}
info.penalty = penalty; info.values = values; info.W = W; info.w = w;
values.lineleading = state.VALUES.lineleading;
values.linebreakstyle = "before"; values.last = this;
return true;
}
});
//
// Hook into the mathchoice extension
//
MathJax.Hub.Register.StartupHook("TeX mathchoice Ready",function () {
MML.TeXmathchoice.Augment({
SVGbetterBreak: function (info,state) {
return this.Core().SVGbetterBreak(info,state);
},
SVGmoveLine: function (start,end,svg,state,values) {
return this.Core().SVGmoveSlice(start,end,svg,state,values);
}
});
});
//
// Have maction process only the selected item
//
MML.maction.Augment({
SVGbetterBreak: function (info,state) {
return this.Core().SVGbetterBreak(info,state);
},
SVGmoveLine: function (start,end,svg,state,values) {
return this.Core().SVGmoveSlice(start,end,svg,state,values);
},
});
//
// Have semantics only do the first element
// (FIXME: do we need to do anything special about annotation-xml?)
//
MML.semantics.Augment({
SVGbetterBreak: function (info,state) {
return (this.data[0] ? this.data[0].SVGbetterBreak(info,state) : false);
},
SVGmoveLine: function (start,end,svg,state,values) {
return (this.data[0] ? this.data[0].SVGmoveSlice(start,end,svg,state,values) : null);
}
});
/**************************************************************************/
MathJax.Hub.Startup.signal.Post("SVG multiline Ready");
MathJax.Ajax.loadComplete(SVG.autoloadDir+"/multiline.js");
});