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