|
|
|
|
|
|
|
|
|
|
|
|
|
var domTree = require("./domTree"); |
|
var fontMetrics = require("./fontMetrics"); |
|
var symbols = require("./symbols"); |
|
var utils = require("./utils"); |
|
|
|
var greekCapitals = [ |
|
"\\Gamma", |
|
"\\Delta", |
|
"\\Theta", |
|
"\\Lambda", |
|
"\\Xi", |
|
"\\Pi", |
|
"\\Sigma", |
|
"\\Upsilon", |
|
"\\Phi", |
|
"\\Psi", |
|
"\\Omega", |
|
]; |
|
|
|
var dotlessLetters = [ |
|
"\u0131", |
|
"\u0237", |
|
]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
var makeSymbol = function(value, style, mode, color, classes) { |
|
|
|
if (symbols[mode][value] && symbols[mode][value].replace) { |
|
value = symbols[mode][value].replace; |
|
} |
|
|
|
var metrics = fontMetrics.getCharacterMetrics(value, style); |
|
|
|
var symbolNode; |
|
if (metrics) { |
|
symbolNode = new domTree.symbolNode( |
|
value, metrics.height, metrics.depth, metrics.italic, metrics.skew, |
|
classes); |
|
} else { |
|
|
|
typeof console !== "undefined" && console.warn( |
|
"No character metrics for '" + value + "' in style '" + |
|
style + "'"); |
|
symbolNode = new domTree.symbolNode(value, 0, 0, 0, 0, classes); |
|
} |
|
|
|
if (color) { |
|
symbolNode.style.color = color; |
|
} |
|
|
|
return symbolNode; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
var mathsym = function(value, mode, color, classes) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
if (value === "\\" || symbols[mode][value].font === "main") { |
|
return makeSymbol(value, "Main-Regular", mode, color, classes); |
|
} else { |
|
return makeSymbol( |
|
value, "AMS-Regular", mode, color, classes.concat(["amsrm"])); |
|
} |
|
}; |
|
|
|
|
|
|
|
|
|
var mathDefault = function(value, mode, color, classes, type) { |
|
if (type === "mathord") { |
|
return mathit(value, mode, color, classes); |
|
} else if (type === "textord") { |
|
return makeSymbol( |
|
value, "Main-Regular", mode, color, classes.concat(["mathrm"])); |
|
} else { |
|
throw new Error("unexpected type: " + type + " in mathDefault"); |
|
} |
|
}; |
|
|
|
|
|
|
|
|
|
var mathit = function(value, mode, color, classes) { |
|
if (/[0-9]/.test(value.charAt(0)) || |
|
|
|
|
|
utils.contains(dotlessLetters, value) || |
|
utils.contains(greekCapitals, value)) { |
|
return makeSymbol( |
|
value, "Main-Italic", mode, color, classes.concat(["mainit"])); |
|
} else { |
|
return makeSymbol( |
|
value, "Math-Italic", mode, color, classes.concat(["mathit"])); |
|
} |
|
}; |
|
|
|
|
|
|
|
|
|
var makeOrd = function(group, options, type) { |
|
var mode = group.mode; |
|
var value = group.value; |
|
if (symbols[mode][value] && symbols[mode][value].replace) { |
|
value = symbols[mode][value].replace; |
|
} |
|
|
|
var classes = ["mord"]; |
|
var color = options.getColor(); |
|
|
|
var font = options.font; |
|
if (font) { |
|
if (font === "mathit" || utils.contains(dotlessLetters, value)) { |
|
return mathit(value, mode, color, classes); |
|
} else { |
|
var fontName = fontMap[font].fontName; |
|
if (fontMetrics.getCharacterMetrics(value, fontName)) { |
|
return makeSymbol( |
|
value, fontName, mode, color, classes.concat([font])); |
|
} else { |
|
return mathDefault(value, mode, color, classes, type); |
|
} |
|
} |
|
} else { |
|
return mathDefault(value, mode, color, classes, type); |
|
} |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
var sizeElementFromChildren = function(elem) { |
|
var height = 0; |
|
var depth = 0; |
|
var maxFontSize = 0; |
|
|
|
if (elem.children) { |
|
for (var i = 0; i < elem.children.length; i++) { |
|
if (elem.children[i].height > height) { |
|
height = elem.children[i].height; |
|
} |
|
if (elem.children[i].depth > depth) { |
|
depth = elem.children[i].depth; |
|
} |
|
if (elem.children[i].maxFontSize > maxFontSize) { |
|
maxFontSize = elem.children[i].maxFontSize; |
|
} |
|
} |
|
} |
|
|
|
elem.height = height; |
|
elem.depth = depth; |
|
elem.maxFontSize = maxFontSize; |
|
}; |
|
|
|
|
|
|
|
|
|
var makeSpan = function(classes, children, color) { |
|
var span = new domTree.span(classes, children); |
|
|
|
sizeElementFromChildren(span); |
|
|
|
if (color) { |
|
span.style.color = color; |
|
} |
|
|
|
return span; |
|
}; |
|
|
|
|
|
|
|
|
|
var makeFragment = function(children) { |
|
var fragment = new domTree.documentFragment(children); |
|
|
|
sizeElementFromChildren(fragment); |
|
|
|
return fragment; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
var makeFontSizer = function(options, fontSize) { |
|
var fontSizeInner = makeSpan([], [new domTree.symbolNode("\u200b")]); |
|
fontSizeInner.style.fontSize = |
|
(fontSize / options.style.sizeMultiplier) + "em"; |
|
|
|
var fontSizer = makeSpan( |
|
["fontsize-ensurer", "reset-" + options.size, "size5"], |
|
[fontSizeInner]); |
|
|
|
return fontSizer; |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var makeVList = function(children, positionType, positionData, options) { |
|
var depth; |
|
var currPos; |
|
var i; |
|
if (positionType === "individualShift") { |
|
var oldChildren = children; |
|
children = [oldChildren[0]]; |
|
|
|
|
|
|
|
depth = -oldChildren[0].shift - oldChildren[0].elem.depth; |
|
currPos = depth; |
|
for (i = 1; i < oldChildren.length; i++) { |
|
var diff = -oldChildren[i].shift - currPos - |
|
oldChildren[i].elem.depth; |
|
var size = diff - |
|
(oldChildren[i - 1].elem.height + |
|
oldChildren[i - 1].elem.depth); |
|
|
|
currPos = currPos + diff; |
|
|
|
children.push({type: "kern", size: size}); |
|
children.push(oldChildren[i]); |
|
} |
|
} else if (positionType === "top") { |
|
|
|
|
|
var bottom = positionData; |
|
for (i = 0; i < children.length; i++) { |
|
if (children[i].type === "kern") { |
|
bottom -= children[i].size; |
|
} else { |
|
bottom -= children[i].elem.height + children[i].elem.depth; |
|
} |
|
} |
|
depth = bottom; |
|
} else if (positionType === "bottom") { |
|
depth = -positionData; |
|
} else if (positionType === "shift") { |
|
depth = -children[0].elem.depth - positionData; |
|
} else if (positionType === "firstBaseline") { |
|
depth = -children[0].elem.depth; |
|
} else { |
|
depth = 0; |
|
} |
|
|
|
|
|
var maxFontSize = 0; |
|
for (i = 0; i < children.length; i++) { |
|
if (children[i].type === "elem") { |
|
maxFontSize = Math.max(maxFontSize, children[i].elem.maxFontSize); |
|
} |
|
} |
|
var fontSizer = makeFontSizer(options, maxFontSize); |
|
|
|
|
|
var realChildren = []; |
|
currPos = depth; |
|
for (i = 0; i < children.length; i++) { |
|
if (children[i].type === "kern") { |
|
currPos += children[i].size; |
|
} else { |
|
var child = children[i].elem; |
|
|
|
var shift = -child.depth - currPos; |
|
currPos += child.height + child.depth; |
|
|
|
var childWrap = makeSpan([], [fontSizer, child]); |
|
childWrap.height -= shift; |
|
childWrap.depth += shift; |
|
childWrap.style.top = shift + "em"; |
|
|
|
realChildren.push(childWrap); |
|
} |
|
} |
|
|
|
|
|
|
|
var baselineFix = makeSpan( |
|
["baseline-fix"], [fontSizer, new domTree.symbolNode("\u200b")]); |
|
realChildren.push(baselineFix); |
|
|
|
var vlist = makeSpan(["vlist"], realChildren); |
|
|
|
|
|
vlist.height = Math.max(currPos, vlist.height); |
|
vlist.depth = Math.max(-depth, vlist.depth); |
|
return vlist; |
|
}; |
|
|
|
|
|
var sizingMultiplier = { |
|
size1: 0.5, |
|
size2: 0.7, |
|
size3: 0.8, |
|
size4: 0.9, |
|
size5: 1.0, |
|
size6: 1.2, |
|
size7: 1.44, |
|
size8: 1.73, |
|
size9: 2.07, |
|
size10: 2.49, |
|
}; |
|
|
|
|
|
|
|
var spacingFunctions = { |
|
"\\qquad": { |
|
size: "2em", |
|
className: "qquad", |
|
}, |
|
"\\quad": { |
|
size: "1em", |
|
className: "quad", |
|
}, |
|
"\\enspace": { |
|
size: "0.5em", |
|
className: "enspace", |
|
}, |
|
"\\;": { |
|
size: "0.277778em", |
|
className: "thickspace", |
|
}, |
|
"\\:": { |
|
size: "0.22222em", |
|
className: "mediumspace", |
|
}, |
|
"\\,": { |
|
size: "0.16667em", |
|
className: "thinspace", |
|
}, |
|
"\\!": { |
|
size: "-0.16667em", |
|
className: "negativethinspace", |
|
}, |
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var fontMap = { |
|
|
|
"mathbf": { |
|
variant: "bold", |
|
fontName: "Main-Bold", |
|
}, |
|
"mathrm": { |
|
variant: "normal", |
|
fontName: "Main-Regular", |
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
"mathbb": { |
|
variant: "double-struck", |
|
fontName: "AMS-Regular", |
|
}, |
|
"mathcal": { |
|
variant: "script", |
|
fontName: "Caligraphic-Regular", |
|
}, |
|
"mathfrak": { |
|
variant: "fraktur", |
|
fontName: "Fraktur-Regular", |
|
}, |
|
"mathscr": { |
|
variant: "script", |
|
fontName: "Script-Regular", |
|
}, |
|
"mathsf": { |
|
variant: "sans-serif", |
|
fontName: "SansSerif-Regular", |
|
}, |
|
"mathtt": { |
|
variant: "monospace", |
|
fontName: "Typewriter-Regular", |
|
}, |
|
}; |
|
|
|
module.exports = { |
|
fontMap: fontMap, |
|
makeSymbol: makeSymbol, |
|
mathsym: mathsym, |
|
makeSpan: makeSpan, |
|
makeFragment: makeFragment, |
|
makeVList: makeVList, |
|
makeOrd: makeOrd, |
|
sizingMultiplier: sizingMultiplier, |
|
spacingFunctions: spacingFunctions, |
|
}; |
|
|