mirror of
https://github.com/Smaug123/KaTeX
synced 2025-10-05 11:18:39 +00:00
Associate font metrics with Options, not Style. (#743)
* Associate font metrics with Options, not Style. Font metrics are associated with a given font and size combination. Before KaTeX understood sizing commands, sizes were associated with a Style. That's not true now. So instead of `style.metrics`, use `options.fontMetrics()`, since `options` knows the font and the size. This is a cleanup commit with no visible effects on most tests (there could be some small effect on size + style combinations). It will make other changes possible later.
This commit is contained in:
committed by
Kevin Barabash
parent
ebaa3feab3
commit
f23bf3fe63
@@ -5,6 +5,8 @@
|
||||
* `.reset` functions.
|
||||
*/
|
||||
|
||||
const fontMetrics = require("./fontMetrics");
|
||||
|
||||
const BASESIZE = 6;
|
||||
|
||||
const sizeStyleMap = [
|
||||
@@ -24,6 +26,8 @@ const sizeStyleMap = [
|
||||
];
|
||||
|
||||
const sizeMultipliers = [
|
||||
// fontMetrics.js:getFontMetrics also uses size indexes, so if
|
||||
// you change size indexes, change that function.
|
||||
0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.2, 1.44, 1.728, 2.074, 2.488,
|
||||
];
|
||||
|
||||
@@ -42,6 +46,7 @@ function Options(data) {
|
||||
this.phantom = data.phantom;
|
||||
this.font = data.font;
|
||||
this.sizeMultiplier = sizeMultipliers[this.size - 1];
|
||||
this._fontMetrics = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -180,6 +185,16 @@ Options.prototype.baseSizingClasses = function() {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the font metrics for this size.
|
||||
*/
|
||||
Options.prototype.fontMetrics = function() {
|
||||
if (!this._fontMetrics) {
|
||||
this._fontMetrics = fontMetrics.getFontMetrics(this.size);
|
||||
}
|
||||
return this._fontMetrics;
|
||||
};
|
||||
|
||||
/**
|
||||
* A map of color names to CSS colors.
|
||||
* TODO(emily): Remove this when we have real macros
|
||||
|
15
src/Style.js
15
src/Style.js
@@ -6,20 +6,6 @@
|
||||
* information about them.
|
||||
*/
|
||||
|
||||
const sigmas = require("./fontMetrics.js").sigmas;
|
||||
|
||||
const metrics = [{}, {}, {}];
|
||||
for (const key in sigmas) {
|
||||
if (sigmas.hasOwnProperty(key)) {
|
||||
for (let i = 0; i < 3; i++) {
|
||||
metrics[i][key] = sigmas[key][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < 3; i++) {
|
||||
metrics[i].emPerEx = sigmas.xHeight[i] / sigmas.quad[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* The main style class. Contains a unique id for the style, a size (which is
|
||||
* the same for cramped and uncramped version of a style), and a cramped flag.
|
||||
@@ -28,7 +14,6 @@ function Style(id, size, cramped) {
|
||||
this.id = id;
|
||||
this.size = size;
|
||||
this.cramped = cramped;
|
||||
this.metrics = metrics[size > 0 ? size - 1 : 0];
|
||||
}
|
||||
|
||||
/**
|
||||
|
119
src/buildHTML.js
119
src/buildHTML.js
@@ -12,7 +12,6 @@ const Style = require("./Style");
|
||||
const buildCommon = require("./buildCommon");
|
||||
const delimiter = require("./delimiter");
|
||||
const domTree = require("./domTree");
|
||||
const fontMetrics = require("./fontMetrics");
|
||||
const utils = require("./utils");
|
||||
const stretchy = require("./stretchy");
|
||||
|
||||
@@ -312,7 +311,7 @@ groupTypes.supsub = function(group, options) {
|
||||
let supm;
|
||||
let subm;
|
||||
|
||||
const style = options.style;
|
||||
const metrics = options.fontMetrics();
|
||||
let newOptions;
|
||||
|
||||
// Rule 18a
|
||||
@@ -320,45 +319,45 @@ groupTypes.supsub = function(group, options) {
|
||||
let subShift = 0;
|
||||
|
||||
if (group.value.sup) {
|
||||
newOptions = options.havingStyle(style.sup());
|
||||
newOptions = options.havingStyle(options.style.sup());
|
||||
supm = buildGroup(group.value.sup, newOptions, options);
|
||||
if (!isCharacterBox(group.value.base)) {
|
||||
supShift = base.height - newOptions.style.metrics.supDrop
|
||||
supShift = base.height - newOptions.fontMetrics().supDrop
|
||||
* newOptions.sizeMultiplier / options.sizeMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
if (group.value.sub) {
|
||||
newOptions = options.havingStyle(style.sub());
|
||||
newOptions = options.havingStyle(options.style.sub());
|
||||
subm = buildGroup(group.value.sub, newOptions, options);
|
||||
if (!isCharacterBox(group.value.base)) {
|
||||
subShift = base.depth + newOptions.style.metrics.subDrop
|
||||
subShift = base.depth + newOptions.fontMetrics().subDrop
|
||||
* newOptions.sizeMultiplier / options.sizeMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
// Rule 18c
|
||||
let minSupShift;
|
||||
if (style === Style.DISPLAY) {
|
||||
minSupShift = style.metrics.sup1;
|
||||
} else if (style.cramped) {
|
||||
minSupShift = style.metrics.sup3;
|
||||
if (options.style === Style.DISPLAY) {
|
||||
minSupShift = metrics.sup1;
|
||||
} else if (options.style.cramped) {
|
||||
minSupShift = metrics.sup3;
|
||||
} else {
|
||||
minSupShift = style.metrics.sup2;
|
||||
minSupShift = metrics.sup2;
|
||||
}
|
||||
|
||||
// scriptspace is a font-size-independent size, so scale it
|
||||
// appropriately
|
||||
const multiplier = options.sizeMultiplier;
|
||||
const scriptspace =
|
||||
(0.5 / fontMetrics.metrics.ptPerEm) / multiplier + "em";
|
||||
(0.5 / metrics.ptPerEm) / multiplier + "em";
|
||||
|
||||
let supsub;
|
||||
if (!group.value.sup) {
|
||||
// Rule 18b
|
||||
subShift = Math.max(
|
||||
subShift, style.metrics.sub1,
|
||||
subm.height - 0.8 * style.metrics.xHeight);
|
||||
subShift, metrics.sub1,
|
||||
subm.height - 0.8 * metrics.xHeight);
|
||||
|
||||
supsub = buildCommon.makeVList([
|
||||
{type: "elem", elem: subm},
|
||||
@@ -375,7 +374,7 @@ groupTypes.supsub = function(group, options) {
|
||||
} else if (!group.value.sub) {
|
||||
// Rule 18c, d
|
||||
supShift = Math.max(supShift, minSupShift,
|
||||
supm.depth + 0.25 * style.metrics.xHeight);
|
||||
supm.depth + 0.25 * metrics.xHeight);
|
||||
|
||||
supsub = buildCommon.makeVList([
|
||||
{type: "elem", elem: supm},
|
||||
@@ -384,16 +383,16 @@ groupTypes.supsub = function(group, options) {
|
||||
supsub.children[0].style.marginRight = scriptspace;
|
||||
} else {
|
||||
supShift = Math.max(
|
||||
supShift, minSupShift, supm.depth + 0.25 * style.metrics.xHeight);
|
||||
subShift = Math.max(subShift, style.metrics.sub2);
|
||||
supShift, minSupShift, supm.depth + 0.25 * metrics.xHeight);
|
||||
subShift = Math.max(subShift, metrics.sub2);
|
||||
|
||||
const ruleWidth = fontMetrics.metrics.defaultRuleThickness;
|
||||
const ruleWidth = metrics.defaultRuleThickness;
|
||||
|
||||
// Rule 18e
|
||||
if ((supShift - supm.depth) - (subm.height - subShift) <
|
||||
4 * ruleWidth) {
|
||||
subShift = 4 * ruleWidth - (supShift - supm.depth) + subm.height;
|
||||
const psi = 0.8 * style.metrics.xHeight - (supShift - supm.depth);
|
||||
const psi = 0.8 * metrics.xHeight - (supShift - supm.depth);
|
||||
if (psi > 0) {
|
||||
supShift += psi;
|
||||
subShift -= psi;
|
||||
@@ -455,22 +454,22 @@ groupTypes.genfrac = function(group, options) {
|
||||
let clearance;
|
||||
let denomShift;
|
||||
if (style.size === Style.DISPLAY.size) {
|
||||
numShift = style.metrics.num1;
|
||||
numShift = options.fontMetrics().num1;
|
||||
if (ruleWidth > 0) {
|
||||
clearance = 3 * ruleWidth;
|
||||
} else {
|
||||
clearance = 7 * fontMetrics.metrics.defaultRuleThickness;
|
||||
clearance = 7 * options.fontMetrics().defaultRuleThickness;
|
||||
}
|
||||
denomShift = style.metrics.denom1;
|
||||
denomShift = options.fontMetrics().denom1;
|
||||
} else {
|
||||
if (ruleWidth > 0) {
|
||||
numShift = style.metrics.num2;
|
||||
numShift = options.fontMetrics().num2;
|
||||
clearance = ruleWidth;
|
||||
} else {
|
||||
numShift = style.metrics.num3;
|
||||
clearance = 3 * fontMetrics.metrics.defaultRuleThickness;
|
||||
numShift = options.fontMetrics().num3;
|
||||
clearance = 3 * options.fontMetrics().defaultRuleThickness;
|
||||
}
|
||||
denomShift = style.metrics.denom2;
|
||||
denomShift = options.fontMetrics().denom2;
|
||||
}
|
||||
|
||||
let frac;
|
||||
@@ -489,7 +488,7 @@ groupTypes.genfrac = function(group, options) {
|
||||
], "individualShift", null, options);
|
||||
} else {
|
||||
// Rule 15d
|
||||
const axisHeight = style.metrics.axisHeight;
|
||||
const axisHeight = options.fontMetrics().axisHeight;
|
||||
|
||||
if ((numShift - numerm.depth) - (axisHeight + 0.5 * ruleWidth) <
|
||||
clearance) {
|
||||
@@ -523,9 +522,9 @@ groupTypes.genfrac = function(group, options) {
|
||||
// Rule 15e
|
||||
let delimSize;
|
||||
if (style.size === Style.DISPLAY.size) {
|
||||
delimSize = style.metrics.delim1;
|
||||
delimSize = options.fontMetrics().delim1;
|
||||
} else {
|
||||
delimSize = style.metrics.delim2;
|
||||
delimSize = options.fontMetrics().delim2;
|
||||
}
|
||||
|
||||
let leftDelim;
|
||||
@@ -551,10 +550,10 @@ groupTypes.genfrac = function(group, options) {
|
||||
options);
|
||||
};
|
||||
|
||||
const calculateSize = function(sizeValue, style) {
|
||||
const calculateSize = function(sizeValue, options) {
|
||||
let x = sizeValue.number;
|
||||
if (sizeValue.unit === "ex") {
|
||||
x *= style.metrics.emPerEx;
|
||||
x *= options.fontMetrics().emPerEx;
|
||||
} else if (sizeValue.unit === "mu") {
|
||||
x /= 18;
|
||||
}
|
||||
@@ -568,10 +567,8 @@ groupTypes.array = function(group, options) {
|
||||
let nc = 0;
|
||||
let body = new Array(nr);
|
||||
|
||||
const style = options.style;
|
||||
|
||||
// Horizontal spacing
|
||||
const pt = 1 / fontMetrics.metrics.ptPerEm;
|
||||
const pt = 1 / options.fontMetrics().ptPerEm;
|
||||
const arraycolsep = 5 * pt; // \arraycolsep in article.cls
|
||||
|
||||
// Vertical spacing
|
||||
@@ -610,7 +607,7 @@ groupTypes.array = function(group, options) {
|
||||
|
||||
let gap = 0;
|
||||
if (group.value.rowGaps[r]) {
|
||||
gap = calculateSize(group.value.rowGaps[r].value, style);
|
||||
gap = calculateSize(group.value.rowGaps[r].value, options);
|
||||
if (gap > 0) { // \@argarraycr
|
||||
gap += arstrutDepth;
|
||||
if (depth < gap) {
|
||||
@@ -634,7 +631,7 @@ groupTypes.array = function(group, options) {
|
||||
body[r] = outrow;
|
||||
}
|
||||
|
||||
const offset = totalHeight / 2 + style.metrics.axisHeight;
|
||||
const offset = totalHeight / 2 + options.fontMetrics().axisHeight;
|
||||
const colDescriptions = group.value.cols || [];
|
||||
const cols = [];
|
||||
let colSep;
|
||||
@@ -654,7 +651,7 @@ groupTypes.array = function(group, options) {
|
||||
if (!firstSeparator) {
|
||||
colSep = makeSpan(["arraycolsep"], []);
|
||||
colSep.style.width =
|
||||
fontMetrics.metrics.doubleRuleSep + "em";
|
||||
options.fontMetrics().doubleRuleSep + "em";
|
||||
cols.push(colSep);
|
||||
}
|
||||
|
||||
@@ -829,7 +826,8 @@ groupTypes.op = function(group, options) {
|
||||
// almost on the axis, so these numbers are very small. Note we
|
||||
// don't actually apply this here, but instead it is used either in
|
||||
// the vlist creation or separately when there are no limits.
|
||||
baseShift = (base.height - base.depth) / 2 - style.metrics.axisHeight;
|
||||
baseShift = (base.height - base.depth) / 2 -
|
||||
options.fontMetrics().axisHeight;
|
||||
|
||||
// The slant of the symbol is just its italic correction.
|
||||
slant = base.italic;
|
||||
@@ -852,8 +850,8 @@ groupTypes.op = function(group, options) {
|
||||
supm = buildGroup(supGroup, newOptions, options);
|
||||
|
||||
supKern = Math.max(
|
||||
fontMetrics.metrics.bigOpSpacing1,
|
||||
fontMetrics.metrics.bigOpSpacing3 - supm.depth);
|
||||
options.fontMetrics().bigOpSpacing1,
|
||||
options.fontMetrics().bigOpSpacing3 - supm.depth);
|
||||
}
|
||||
|
||||
if (subGroup) {
|
||||
@@ -861,8 +859,8 @@ groupTypes.op = function(group, options) {
|
||||
subm = buildGroup(subGroup, newOptions, options);
|
||||
|
||||
subKern = Math.max(
|
||||
fontMetrics.metrics.bigOpSpacing2,
|
||||
fontMetrics.metrics.bigOpSpacing4 - subm.height);
|
||||
options.fontMetrics().bigOpSpacing2,
|
||||
options.fontMetrics().bigOpSpacing4 - subm.height);
|
||||
}
|
||||
|
||||
// Build the final group as a vlist of the possible subscript, base,
|
||||
@@ -874,7 +872,7 @@ groupTypes.op = function(group, options) {
|
||||
top = base.height - baseShift;
|
||||
|
||||
finalGroup = buildCommon.makeVList([
|
||||
{type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
|
||||
{type: "kern", size: options.fontMetrics().bigOpSpacing5},
|
||||
{type: "elem", elem: subm},
|
||||
{type: "kern", size: subKern},
|
||||
{type: "elem", elem: base},
|
||||
@@ -892,7 +890,7 @@ groupTypes.op = function(group, options) {
|
||||
{type: "elem", elem: base},
|
||||
{type: "kern", size: supKern},
|
||||
{type: "elem", elem: supm},
|
||||
{type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
|
||||
{type: "kern", size: options.fontMetrics().bigOpSpacing5},
|
||||
], "bottom", bottom, options);
|
||||
|
||||
// See comment above about slants
|
||||
@@ -903,19 +901,19 @@ groupTypes.op = function(group, options) {
|
||||
// subscript) but be safe.
|
||||
return base;
|
||||
} else {
|
||||
bottom = fontMetrics.metrics.bigOpSpacing5 +
|
||||
bottom = options.fontMetrics().bigOpSpacing5 +
|
||||
subm.height + subm.depth +
|
||||
subKern +
|
||||
base.depth + baseShift;
|
||||
|
||||
finalGroup = buildCommon.makeVList([
|
||||
{type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
|
||||
{type: "kern", size: options.fontMetrics().bigOpSpacing5},
|
||||
{type: "elem", elem: subm},
|
||||
{type: "kern", size: subKern},
|
||||
{type: "elem", elem: base},
|
||||
{type: "kern", size: supKern},
|
||||
{type: "elem", elem: supm},
|
||||
{type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
|
||||
{type: "kern", size: options.fontMetrics().bigOpSpacing5},
|
||||
], "bottom", bottom, options);
|
||||
|
||||
// See comment above about slants
|
||||
@@ -1019,7 +1017,7 @@ const makeLineSpan = function(className, options) {
|
||||
const line = makeSpan(
|
||||
[className].concat(baseOptions.sizingClasses(options)),
|
||||
[], options);
|
||||
line.height = fontMetrics.metrics.defaultRuleThickness /
|
||||
line.height = options.fontMetrics().defaultRuleThickness /
|
||||
options.sizeMultiplier;
|
||||
line.maxFontSize = 1.0;
|
||||
return line;
|
||||
@@ -1077,7 +1075,7 @@ groupTypes.sqrt = function(group, options) {
|
||||
|
||||
let phi = ruleWidth;
|
||||
if (options.style.id < Style.TEXT.id) {
|
||||
phi = options.style.metrics.xHeight * options.sizeMultiplier;
|
||||
phi = options.fontMetrics().xHeight * options.sizeMultiplier;
|
||||
}
|
||||
|
||||
// Calculate the clearance between the body and line
|
||||
@@ -1310,16 +1308,15 @@ groupTypes.middle = function(group, options) {
|
||||
groupTypes.rule = function(group, options) {
|
||||
// Make an empty span for the rule
|
||||
const rule = makeSpan(["mord", "rule"], [], options);
|
||||
const style = options.style;
|
||||
|
||||
// Calculate the shift, width, and height of the rule, and account for units
|
||||
let shift = 0;
|
||||
if (group.value.shift) {
|
||||
shift = calculateSize(group.value.shift, style);
|
||||
shift = calculateSize(group.value.shift, options);
|
||||
}
|
||||
|
||||
let width = calculateSize(group.value.width, style);
|
||||
let height = calculateSize(group.value.height, style);
|
||||
let width = calculateSize(group.value.width, options);
|
||||
let height = calculateSize(group.value.height, options);
|
||||
|
||||
// The sizes of rules are absolute, so make it larger if we are in a
|
||||
// smaller style.
|
||||
@@ -1343,11 +1340,10 @@ groupTypes.rule = function(group, options) {
|
||||
groupTypes.kern = function(group, options) {
|
||||
// Make an empty span for the rule
|
||||
const rule = makeSpan(["mord", "rule"], [], options);
|
||||
const style = options.style;
|
||||
|
||||
let dimension = 0;
|
||||
if (group.value.dimension) {
|
||||
dimension = calculateSize(group.value.dimension, style);
|
||||
dimension = calculateSize(group.value.dimension, options);
|
||||
}
|
||||
|
||||
dimension /= options.sizeMultiplier;
|
||||
@@ -1360,7 +1356,6 @@ groupTypes.kern = function(group, options) {
|
||||
groupTypes.accent = function(group, options) {
|
||||
// Accents are handled in the TeXbook pg. 443, rule 12.
|
||||
let base = group.value.base;
|
||||
const style = options.style;
|
||||
|
||||
let supsubGroup;
|
||||
if (group.type === "supsub") {
|
||||
@@ -1415,7 +1410,7 @@ groupTypes.accent = function(group, options) {
|
||||
// calculate the amount of space between the body and the accent
|
||||
const clearance = Math.min(
|
||||
body.height,
|
||||
style.metrics.xHeight);
|
||||
options.fontMetrics().xHeight);
|
||||
|
||||
// Build the accent
|
||||
let accentBody;
|
||||
@@ -1587,9 +1582,9 @@ groupTypes.enclose = function(group, options) {
|
||||
|
||||
if (label === "sout") {
|
||||
img = makeSpan(["stretchy", "sout"]);
|
||||
img.height = fontMetrics.metrics.defaultRuleThickness / scale;
|
||||
img.height = options.fontMetrics().defaultRuleThickness / scale;
|
||||
img.maxFontSize = 1.0;
|
||||
imgShift = -0.5 * options.style.metrics.xHeight;
|
||||
imgShift = -0.5 * options.fontMetrics().xHeight;
|
||||
} else {
|
||||
// Add horizontal padding
|
||||
inner.classes.push((label === "fbox" ? "boxpad" : "cancel-pad"));
|
||||
@@ -1646,14 +1641,14 @@ groupTypes.xArrow = function(group, options) {
|
||||
|
||||
const arrowBody = stretchy.svgSpan(group, options);
|
||||
|
||||
const arrowShift = -style.metrics.axisHeight + arrowBody.depth;
|
||||
const upperShift = -style.metrics.axisHeight - arrowBody.height -
|
||||
const arrowShift = -options.fontMetrics().axisHeight + arrowBody.depth;
|
||||
const upperShift = -options.fontMetrics().axisHeight - arrowBody.height -
|
||||
0.111; // 2 mu. Ref: amsmath.dtx: #7\if0#2\else\mkern#2mu\fi
|
||||
|
||||
// Generate the vlist
|
||||
let vlist;
|
||||
if (group.value.below) {
|
||||
const lowerShift = -style.metrics.axisHeight
|
||||
const lowerShift = -options.fontMetrics().axisHeight
|
||||
+ lowerGroup.height + arrowBody.height
|
||||
+ 0.111;
|
||||
vlist = buildCommon.makeVList([
|
||||
|
@@ -66,7 +66,7 @@ const centerSpan = function(span, options, style) {
|
||||
const newOptions = options.havingBaseStyle(style);
|
||||
const shift =
|
||||
(1 - options.sizeMultiplier / newOptions.sizeMultiplier) *
|
||||
options.style.metrics.axisHeight;
|
||||
options.fontMetrics().axisHeight;
|
||||
|
||||
span.classes.push("delimcenter");
|
||||
span.style.top = shift + "em";
|
||||
@@ -275,7 +275,7 @@ const makeStackedDelim = function(delim, heightTotal, center, options, mode,
|
||||
// that in this context, "center" means that the delimiter should be
|
||||
// centered around the axis in the current style, while normally it is
|
||||
// centered around the axis in textstyle.
|
||||
let axisHeight = options.style.metrics.axisHeight;
|
||||
let axisHeight = options.fontMetrics().axisHeight;
|
||||
if (center) {
|
||||
axisHeight *= options.sizeMultiplier;
|
||||
}
|
||||
@@ -510,11 +510,11 @@ const makeLeftRightDelim = function(delim, height, depth, options, mode,
|
||||
classes) {
|
||||
// We always center \left/\right delimiters, so the axis is always shifted
|
||||
const axisHeight =
|
||||
options.style.metrics.axisHeight * options.sizeMultiplier;
|
||||
options.fontMetrics().axisHeight * options.sizeMultiplier;
|
||||
|
||||
// Taken from TeX source, tex.web, function make_left_right
|
||||
const delimiterFactor = 901;
|
||||
const delimiterExtend = 5.0 / fontMetrics.metrics.ptPerEm;
|
||||
const delimiterExtend = 5.0 / options.fontMetrics().ptPerEm;
|
||||
|
||||
const maxDistFromAxis = Math.max(
|
||||
height - axisHeight, depth + axisHeight);
|
||||
|
@@ -1,7 +1,6 @@
|
||||
/* eslint no-constant-condition:0 */
|
||||
const parseData = require("./parseData");
|
||||
const ParseError = require("./ParseError");
|
||||
const Style = require("./Style");
|
||||
|
||||
const ParseNode = parseData.ParseNode;
|
||||
|
||||
@@ -190,7 +189,7 @@ defineEnvironment([
|
||||
// For now we use the metrics for TEXT style which is what we were
|
||||
// doing before. Before attempting to get the current style we
|
||||
// should look at TeX's behavior especially for \over and matrices.
|
||||
postgap: Style.TEXT.metrics.quad,
|
||||
postgap: 1.0, /* 1em quad */
|
||||
}, {
|
||||
type: "align",
|
||||
align: "l",
|
||||
|
@@ -1,6 +1,3 @@
|
||||
/* eslint no-unused-vars:0 */
|
||||
|
||||
const Style = require("./Style");
|
||||
const cjkRegex = require("./unicodeRegexes").cjkRegex;
|
||||
|
||||
/**
|
||||
@@ -11,8 +8,9 @@ const cjkRegex = require("./unicodeRegexes").cjkRegex;
|
||||
*/
|
||||
|
||||
// In TeX, there are actually three sets of dimensions, one for each of
|
||||
// textstyle, scriptstyle, and scriptscriptstyle. These are provided in the
|
||||
// the arrays below, in that order.
|
||||
// textstyle (size index 5 and higher: >=9pt), scriptstyle (size index 3 and 4:
|
||||
// 7-8pt), and scriptscriptstyle (size index 1 and 2: 5-6pt). These are
|
||||
// provided in the the arrays below, in that order.
|
||||
//
|
||||
// The font metrics are stored in fonts cmsy10, cmsy7, and cmsy5 respsectively.
|
||||
// This was determined by running the following script:
|
||||
@@ -32,7 +30,7 @@ const cjkRegex = require("./unicodeRegexes").cjkRegex;
|
||||
//
|
||||
// The output of each of these commands is quite lengthy. The only part we
|
||||
// care about is the FONTDIMEN section. Each value is measured in EMs.
|
||||
const sigmas = {
|
||||
const sigmasAndXis = {
|
||||
slant: [0.250, 0.250, 0.250], // sigma1
|
||||
space: [0.000, 0.000, 0.000], // sigma2
|
||||
stretch: [0.000, 0.000, 0.000], // sigma3
|
||||
@@ -55,49 +53,28 @@ const sigmas = {
|
||||
delim1: [2.390, 1.700, 1.980], // sigma20
|
||||
delim2: [1.010, 1.157, 1.420], // sigma21
|
||||
axisHeight: [0.250, 0.250, 0.250], // sigma22
|
||||
};
|
||||
|
||||
// These font metrics are extracted from TeX by using
|
||||
// \font\a=cmex10
|
||||
// \showthe\fontdimenX\a
|
||||
// where X is the corresponding variable number. These correspond to the font
|
||||
// parameters of the extension fonts (family 3). See the TeXbook, page 441.
|
||||
const xi1 = 0;
|
||||
const xi2 = 0;
|
||||
const xi3 = 0;
|
||||
const xi4 = 0;
|
||||
const xi5 = 0.431;
|
||||
const xi6 = 1;
|
||||
const xi7 = 0;
|
||||
const xi8 = 0.04;
|
||||
const xi9 = 0.111;
|
||||
const xi10 = 0.166;
|
||||
const xi11 = 0.2;
|
||||
const xi12 = 0.6;
|
||||
const xi13 = 0.1;
|
||||
// These font metrics are extracted from TeX by using tftopl on cmex10.tfm;
|
||||
// they correspond to the font parameters of the extension fonts (family 3).
|
||||
// See the TeXbook, page 441. In AMSTeX, the extension fonts scale; to
|
||||
// match cmex7, we'd use cmex7.tfm values for script and scriptscript
|
||||
// values.
|
||||
defaultRuleThickness: [0.04, 0.04, 0.04], // xi8; cmex7: 0.049
|
||||
bigOpSpacing1: [0.111, 0.111, 0.111], // xi9
|
||||
bigOpSpacing2: [0.166, 0.166, 0.166], // xi10
|
||||
bigOpSpacing3: [0.2, 0.2, 0.2], // xi11
|
||||
bigOpSpacing4: [0.6, 0.6, 0.6], // xi12; cmex7: 0.611
|
||||
bigOpSpacing5: [0.1, 0.1, 0.1], // xi13; cmex7: 0.143
|
||||
|
||||
// This value determines how large a pt is, for metrics which are defined in
|
||||
// terms of pts.
|
||||
// This value is also used in katex.less; if you change it make sure the values
|
||||
// match.
|
||||
const ptPerEm = 10.0;
|
||||
// This value determines how large a pt is, for metrics which are defined
|
||||
// in terms of pts.
|
||||
// This value is also used in katex.less; if you change it make sure the
|
||||
// values match.
|
||||
ptPerEm: [10.0, 10.0, 10.0],
|
||||
|
||||
// The space between adjacent `|` columns in an array definition. From
|
||||
// `\showthe\doublerulesep` in LaTeX.
|
||||
const doubleRuleSep = 2.0 / ptPerEm;
|
||||
|
||||
/**
|
||||
* This is just a mapping from common names to real metrics
|
||||
*/
|
||||
const metrics = {
|
||||
defaultRuleThickness: xi8,
|
||||
bigOpSpacing1: xi9,
|
||||
bigOpSpacing2: xi10,
|
||||
bigOpSpacing3: xi11,
|
||||
bigOpSpacing4: xi12,
|
||||
bigOpSpacing5: xi13,
|
||||
ptPerEm: ptPerEm,
|
||||
doubleRuleSep: doubleRuleSep,
|
||||
// The space between adjacent `|` columns in an array definition. From
|
||||
// `\showthe\doublerulesep` in LaTeX. Equals 2.0 / ptPerEm.
|
||||
doubleRuleSep: [0.2, 0.2, 0.2],
|
||||
};
|
||||
|
||||
// This map contains a mapping from font name and character code to character
|
||||
@@ -271,8 +248,33 @@ const getCharacterMetrics = function(character, style) {
|
||||
}
|
||||
};
|
||||
|
||||
const fontMetricsBySizeIndex = {};
|
||||
|
||||
/**
|
||||
* Get the font metrics for a given size.
|
||||
*/
|
||||
const getFontMetrics = function(size) {
|
||||
let sizeIndex;
|
||||
if (size >= 5) {
|
||||
sizeIndex = 0;
|
||||
} else if (size >= 3) {
|
||||
sizeIndex = 1;
|
||||
} else {
|
||||
sizeIndex = 2;
|
||||
}
|
||||
if (!fontMetricsBySizeIndex[sizeIndex]) {
|
||||
const metrics = fontMetricsBySizeIndex[sizeIndex] = {};
|
||||
for (const key in sigmasAndXis) {
|
||||
if (sigmasAndXis.hasOwnProperty(key)) {
|
||||
metrics[key] = sigmasAndXis[key][sizeIndex];
|
||||
}
|
||||
}
|
||||
metrics.emPerEx = metrics.xHeight / metrics.quad;
|
||||
}
|
||||
return fontMetricsBySizeIndex[sizeIndex];
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
metrics: metrics,
|
||||
sigmas: sigmas,
|
||||
getFontMetrics: getFontMetrics,
|
||||
getCharacterMetrics: getCharacterMetrics,
|
||||
};
|
||||
|
Reference in New Issue
Block a user