Fix interaction between styles and sizes. (#719)

* Fix interaction between styles and sizes by implementing styles as sizes.

Rather than having both `textstyle` CSS classes and `size5` CSS classes
affect the font size (and step on each other), implement sizes more the
way TeX does: a command like `\displaystyle` changes the current size.

This is actually a simplification, since now only `size` affects the size.
Simplifies CSS and computation. Many screenshotter tests change; they
change to be more like TeX. For instance, `\sqrt` fixes some
discrepancies in size treatment.

Also:

Remove the `Options.withX()` methods in favor of `.havingX()`, which
might return the same `options`.

Remove `Style.cls()` and `Style.reset()`.

Remove `Options.reset()`. You should never modify an `Options`; they
should change only by the `havingX()` methods.

* Implement TeX sizing for scriptsize/scriptscriptsize.

At every size level. Also make the sizes match TeX to the last decimal.

* Review comments.
This commit is contained in:
Eddie Kohler
2017-06-27 20:55:14 -04:00
committed by Kevin Barabash
parent 4f57d53f6e
commit b866cd5224
29 changed files with 347 additions and 410 deletions

View File

@@ -5,33 +5,43 @@
* `.reset` functions.
*/
const BASESIZE = 6;
const sizeStyleMap = [
// Each element contains [textsize, scriptsize, scriptscriptsize].
// The size mappings are taken from TeX with \normalsize=10pt.
[1, 1, 1], // size1: [5, 5, 5] \tiny
[2, 1, 1], // size2: [6, 5, 5]
[3, 1, 1], // size3: [7, 5, 5] \scriptsize
[4, 2, 1], // size4: [8, 6, 5] \footnotesize
[5, 2, 1], // size5: [9, 6, 5] \small
[6, 3, 1], // size6: [10, 7, 5] \normalsize
[7, 4, 2], // size7: [12, 8, 6] \large
[8, 6, 3], // size8: [14.4, 10, 7] \Large
[9, 7, 6], // size9: [17.28, 12, 10] \LARGE
[10, 8, 7], // size10: [20.74, 14.4, 12] \huge
[11, 10, 9], // size11: [24.88, 20.74, 17.28] \HUGE
];
const sizeMultipliers = [
0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.2, 1.44, 1.728, 2.074, 2.488,
];
/**
* This is the main options class. It contains the style, size, color, and font
* of the current parse level. It also contains the style and size of the parent
* parse level, so size changes can be handled efficiently.
* This is the main options class. It contains the current style, size, color,
* and font.
*
* Each of the `.with*` and `.reset` functions passes its current style and size
* as the parentStyle and parentSize of the new options class, so parent
* handling is taken care of automatically.
* Options objects should not be modified. To create a new Options with
* different properties, call a `.having*` method.
*/
function Options(data) {
this.style = data.style;
this.color = data.color;
this.size = data.size;
this.size = data.size || BASESIZE;
this.textSize = data.textSize || this.size;
this.phantom = data.phantom;
this.font = data.font;
if (data.parentStyle === undefined) {
this.parentStyle = data.style;
} else {
this.parentStyle = data.parentStyle;
}
if (data.parentSize === undefined) {
this.parentSize = data.size;
} else {
this.parentSize = data.parentSize;
}
this.sizeMultiplier = sizeMultipliers[this.size - 1];
}
/**
@@ -42,9 +52,8 @@ Options.prototype.extend = function(extension) {
const data = {
style: this.style,
size: this.size,
textSize: this.textSize,
color: this.color,
parentStyle: this.style,
parentSize: this.size,
phantom: this.phantom,
font: this.font,
};
@@ -58,22 +67,66 @@ Options.prototype.extend = function(extension) {
return new Options(data);
};
function sizeAtStyle(size, style) {
return style.size < 2 ? size : sizeStyleMap[size - 1][style.size - 1];
}
/**
* Create a new options object with the given style.
* Return an options object with the given style. If `this.style === style`,
* returns `this`.
*/
Options.prototype.withStyle = function(style) {
return this.extend({
style: style,
});
Options.prototype.havingStyle = function(style) {
if (this.style === style) {
return this;
} else {
return this.extend({
style: style,
size: sizeAtStyle(this.textSize, style),
});
}
};
/**
* Create a new options object with the given size.
* Return an options object with a cramped version of the current style. If
* the current style is cramped, returns `this`.
*/
Options.prototype.withSize = function(size) {
return this.extend({
size: size,
});
Options.prototype.havingCrampedStyle = function() {
return this.havingStyle(this.style.cramp());
};
/**
* Return an options object with the given size and in at least `\textstyle`.
* Returns `this` if appropriate.
*/
Options.prototype.havingSize = function(size) {
if (this.size === size && this.textSize === size) {
return this;
} else {
return this.extend({
style: this.style.text(),
size: size,
textSize: size,
});
}
};
/**
* Like `this.havingSize(BASESIZE).havingStyle(style)`. If `style` is omitted,
* changes to at least `\textstyle`.
*/
Options.prototype.havingBaseStyle = function(style) {
style = style || this.style.text();
const wantSize = sizeAtStyle(BASESIZE, style);
if (this.size === wantSize && this.textSize === BASESIZE
&& this.style === style) {
return this;
} else {
return this.extend({
style: style,
size: wantSize,
baseSize: BASESIZE,
});
}
};
/**
@@ -104,11 +157,27 @@ Options.prototype.withFont = function(font) {
};
/**
* Create a new options object with the same style, size, and color. This is
* used so that parent style and size changes are handled correctly.
* Return the CSS sizing classes required to switch from enclosing options
* `oldOptions` to `this`. Returns an array of classes.
*/
Options.prototype.reset = function() {
return this.extend({});
Options.prototype.sizingClasses = function(oldOptions) {
if (oldOptions.size !== this.size) {
return ["sizing", "reset-size" + oldOptions.size, "size" + this.size];
} else {
return [];
}
};
/**
* Return the CSS sizing classes required to switch to the base size. Like
* `this.havingSize(BASESIZE).sizingClasses(this)`.
*/
Options.prototype.baseSizingClasses = function() {
if (this.size !== BASESIZE) {
return ["sizing", "reset-size" + this.size, "size" + BASESIZE];
} else {
return [];
}
};
/**
@@ -186,4 +255,9 @@ Options.prototype.getColor = function() {
}
};
/**
* The base size index.
*/
Options.BASESIZE = BASESIZE;
module.exports = Options;

View File

@@ -390,8 +390,8 @@ Parser.prototype.parseAtom = function() {
// A list of the size-changing functions, for use in parseImplicitGroup
const sizeFuncs = [
"\\tiny", "\\scriptsize", "\\footnotesize", "\\small", "\\normalsize",
"\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge",
"\\tiny", "\\sixptsize", "\\scriptsize", "\\footnotesize", "\\small",
"\\normalsize", "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge",
];
// A list of the style-changing functions, for use in parseImplicitGroup
@@ -483,7 +483,7 @@ Parser.prototype.parseImplicitGroup = function() {
const body = this.parseExpression(false);
return new ParseNode("sizing", {
// Figure out what size to use based on the list of functions above
size: "size" + (utils.indexOf(sizeFuncs, func) + 1),
size: utils.indexOf(sizeFuncs, func) + 1,
value: body,
}, this.mode);
} else if (utils.contains(styleFuncs, func)) {

View File

@@ -22,15 +22,12 @@ for (let i = 0; i < 3; 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), a cramped flag, and a
* size multiplier, which gives the size difference between a style and
* textstyle.
* the same for cramped and uncramped version of a style), and a cramped flag.
*/
function Style(id, size, multiplier, cramped) {
function Style(id, size, cramped) {
this.id = id;
this.size = size;
this.cramped = cramped;
this.sizeMultiplier = multiplier;
this.metrics = metrics[size > 0 ? size - 1 : 0];
}
@@ -73,17 +70,10 @@ Style.prototype.cramp = function() {
};
/**
* HTML class name, like "displaystyle cramped"
* Get a text or display version of this style.
*/
Style.prototype.cls = function() {
return sizeNames[this.size] + (this.cramped ? " cramped" : " uncramped");
};
/**
* HTML Reset class name, like "reset-textstyle"
*/
Style.prototype.reset = function() {
return resetNames[this.size];
Style.prototype.text = function() {
return styles[text[this.id]];
};
/**
@@ -103,32 +93,16 @@ const Sc = 5;
const SS = 6;
const SSc = 7;
// String names for the different sizes
const sizeNames = [
"displaystyle textstyle",
"textstyle",
"scriptstyle",
"scriptscriptstyle",
];
// Reset names for the different sizes
const resetNames = [
"reset-textstyle",
"reset-textstyle",
"reset-scriptstyle",
"reset-scriptscriptstyle",
];
// Instances of the different styles
const styles = [
new Style(D, 0, 1.0, false),
new Style(Dc, 0, 1.0, true),
new Style(T, 1, 1.0, false),
new Style(Tc, 1, 1.0, true),
new Style(S, 2, 0.7, false),
new Style(Sc, 2, 0.7, true),
new Style(SS, 3, 0.5, false),
new Style(SSc, 3, 0.5, true),
new Style(D, 0, false),
new Style(Dc, 0, true),
new Style(T, 1, false),
new Style(Tc, 1, true),
new Style(S, 2, false),
new Style(Sc, 2, true),
new Style(SS, 3, false),
new Style(SSc, 3, true),
];
// Lookup tables for switching from one style to another
@@ -137,6 +111,7 @@ const sub = [Sc, Sc, Sc, Sc, SSc, SSc, SSc, SSc];
const fracNum = [T, Tc, S, Sc, SS, SSc, SS, SSc];
const fracDen = [Tc, Tc, Sc, Sc, SSc, SSc, SSc, SSc];
const cramp = [Dc, Dc, Tc, Tc, Sc, Sc, SSc, SSc];
const text = [D, Dc, T, Tc, T, Tc, T, Tc];
// We only export some of the styles. Also, we don't export the `Style` class so
// no more styles can be generated.

View File

@@ -63,6 +63,7 @@ const makeSymbol = function(value, fontFamily, mode, options, classes) {
}
if (options) {
symbolNode.maxFontSize = options.sizeMultiplier;
if (options.style.isTight()) {
symbolNode.classes.push("mtight");
}
@@ -239,11 +240,10 @@ const makeFragment = function(children) {
*/
const makeFontSizer = function(options, fontSize) {
const fontSizeInner = makeSpan([], [new domTree.symbolNode("\u200b")]);
fontSizeInner.style.fontSize =
(fontSize / options.style.sizeMultiplier) + "em";
fontSizeInner.style.fontSize = fontSize + "em";
const fontSizer = makeSpan(
["fontsize-ensurer", "reset-" + options.size, "size5"],
["fontsize-ensurer"].concat(options.baseSizingClasses()),
[fontSizeInner]);
return fontSizer;
@@ -378,20 +378,6 @@ const makeVList = function(children, positionType, positionData, options) {
return vlist;
};
// A table of size -> font size for the different sizing functions
const 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,
};
// A map of spacing functions to their attributes, like size and corresponding
// CSS class
const spacingFunctions = {
@@ -486,6 +472,5 @@ module.exports = {
makeVList: makeVList,
makeOrd: makeOrd,
prependChildren: prependChildren,
sizingMultiplier: sizingMultiplier,
spacingFunctions: spacingFunctions,
};

View File

@@ -216,10 +216,8 @@ const isCharacterBox = function(group) {
};
const makeNullDelimiter = function(options, classes) {
return makeSpan(classes.concat([
"sizing", "reset-" + options.size, "size5",
options.style.reset(), Style.TEXT.cls(),
"nulldelimiter"]));
const moreClasses = ["nulldelimiter"].concat(options.baseSizingClasses());
return makeSpan(classes.concat(moreClasses));
};
/**
@@ -267,9 +265,8 @@ groupTypes.punct = function(group, options) {
};
groupTypes.ordgroup = function(group, options) {
return makeSpan(
["mord", options.style.cls()],
buildExpression(group.value, options.reset(), true),
return makeSpan(["mord"],
buildExpression(group.value, options, true),
options
);
};
@@ -283,7 +280,7 @@ groupTypes.text = function(group, options) {
i--;
}
}
return makeSpan(["mord", "text", newOptions.style.cls()],
return makeSpan(["mord", "text"],
inner, newOptions);
};
@@ -311,43 +308,33 @@ groupTypes.supsub = function(group, options) {
return groupTypes[group.value.base.type](group, options);
}
const base = buildGroup(group.value.base, options.reset());
let supmid;
let submid;
let sup;
let sub;
const base = buildGroup(group.value.base, options);
let supm;
let subm;
const style = options.style;
let newOptions;
// Rule 18a
let supShift = 0;
let subShift = 0;
if (group.value.sup) {
newOptions = options.withStyle(style.sup());
sup = buildGroup(group.value.sup, newOptions);
supmid = makeSpan([style.reset(), style.sup().cls()],
[sup], newOptions);
newOptions = options.havingStyle(style.sup());
supm = buildGroup(group.value.sup, newOptions, options);
if (!isCharacterBox(group.value.base)) {
supShift = base.height - newOptions.style.metrics.supDrop
* newOptions.sizeMultiplier / options.sizeMultiplier;
}
}
if (group.value.sub) {
newOptions = options.withStyle(style.sub());
sub = buildGroup(group.value.sub, newOptions);
submid = makeSpan([style.reset(), style.sub().cls()],
[sub], newOptions);
}
// Rule 18a
let supShift;
let subShift;
if (isCharacterBox(group.value.base)) {
supShift = 0;
subShift = 0;
} else {
const supstyle = style.sup();
supShift = base.height - supstyle.metrics.supDrop
* supstyle.sizeMultiplier;
const substyle = style.sub();
subShift = base.depth + substyle.metrics.subDrop
* substyle.sizeMultiplier;
newOptions = options.havingStyle(style.sub());
subm = buildGroup(group.value.sub, newOptions, options);
if (!isCharacterBox(group.value.base)) {
subShift = base.depth + newOptions.style.metrics.subDrop
* newOptions.sizeMultiplier / options.sizeMultiplier;
}
}
// Rule 18c
@@ -362,8 +349,7 @@ groupTypes.supsub = function(group, options) {
// scriptspace is a font-size-independent size, so scale it
// appropriately
const multiplier = Style.TEXT.sizeMultiplier *
style.sizeMultiplier;
const multiplier = options.sizeMultiplier;
const scriptspace =
(0.5 / fontMetrics.metrics.ptPerEm) / multiplier + "em";
@@ -372,10 +358,10 @@ groupTypes.supsub = function(group, options) {
// Rule 18b
subShift = Math.max(
subShift, style.metrics.sub1,
sub.height - 0.8 * style.metrics.xHeight);
subm.height - 0.8 * style.metrics.xHeight);
supsub = buildCommon.makeVList([
{type: "elem", elem: submid},
{type: "elem", elem: subm},
], "shift", subShift, options);
supsub.children[0].style.marginRight = scriptspace;
@@ -389,25 +375,25 @@ groupTypes.supsub = function(group, options) {
} else if (!group.value.sub) {
// Rule 18c, d
supShift = Math.max(supShift, minSupShift,
sup.depth + 0.25 * style.metrics.xHeight);
supm.depth + 0.25 * style.metrics.xHeight);
supsub = buildCommon.makeVList([
{type: "elem", elem: supmid},
{type: "elem", elem: supm},
], "shift", -supShift, options);
supsub.children[0].style.marginRight = scriptspace;
} else {
supShift = Math.max(
supShift, minSupShift, sup.depth + 0.25 * style.metrics.xHeight);
supShift, minSupShift, supm.depth + 0.25 * style.metrics.xHeight);
subShift = Math.max(subShift, style.metrics.sub2);
const ruleWidth = fontMetrics.metrics.defaultRuleThickness;
// Rule 18e
if ((supShift - sup.depth) - (sub.height - subShift) <
if ((supShift - supm.depth) - (subm.height - subShift) <
4 * ruleWidth) {
subShift = 4 * ruleWidth - (supShift - sup.depth) + sub.height;
const psi = 0.8 * style.metrics.xHeight - (supShift - sup.depth);
subShift = 4 * ruleWidth - (supShift - supm.depth) + subm.height;
const psi = 0.8 * style.metrics.xHeight - (supShift - supm.depth);
if (psi > 0) {
supShift += psi;
subShift -= psi;
@@ -415,8 +401,8 @@ groupTypes.supsub = function(group, options) {
}
supsub = buildCommon.makeVList([
{type: "elem", elem: submid, shift: subShift},
{type: "elem", elem: supmid, shift: -supShift},
{type: "elem", elem: subm, shift: subShift},
{type: "elem", elem: supm, shift: -supShift},
], "individualShift", null, options);
// See comment above about subscripts not being shifted
@@ -450,23 +436,19 @@ groupTypes.genfrac = function(group, options) {
const dstyle = style.fracDen();
let newOptions;
newOptions = options.withStyle(nstyle);
const numer = buildGroup(group.value.numer, newOptions);
const numerreset = makeSpan([style.reset(), nstyle.cls()],
[numer], newOptions);
newOptions = options.havingStyle(nstyle);
const numerm = buildGroup(group.value.numer, newOptions, options);
newOptions = options.withStyle(dstyle);
const denom = buildGroup(group.value.denom, newOptions);
const denomreset = makeSpan([style.reset(), dstyle.cls()],
[denom], newOptions);
newOptions = options.havingStyle(dstyle);
const denomm = buildGroup(group.value.denom, newOptions, options);
let ruleWidth;
let rule;
if (group.value.hasBarLine) {
ruleWidth = fontMetrics.metrics.defaultRuleThickness /
options.style.sizeMultiplier;
rule = makeLineSpan("frac-line", options);
} else {
ruleWidth = 0;
rule = null;
}
const ruleWidth = rule ? rule.height : 0;
// Rule 15b
let numShift;
@@ -495,53 +477,48 @@ groupTypes.genfrac = function(group, options) {
if (ruleWidth === 0) {
// Rule 15c
const candidateClearance =
(numShift - numer.depth) - (denom.height - denomShift);
(numShift - numerm.depth) - (denomm.height - denomShift);
if (candidateClearance < clearance) {
numShift += 0.5 * (clearance - candidateClearance);
denomShift += 0.5 * (clearance - candidateClearance);
}
frac = buildCommon.makeVList([
{type: "elem", elem: denomreset, shift: denomShift},
{type: "elem", elem: numerreset, shift: -numShift},
{type: "elem", elem: denomm, shift: denomShift},
{type: "elem", elem: numerm, shift: -numShift},
], "individualShift", null, options);
} else {
// Rule 15d
const axisHeight = style.metrics.axisHeight;
if ((numShift - numer.depth) - (axisHeight + 0.5 * ruleWidth) <
if ((numShift - numerm.depth) - (axisHeight + 0.5 * ruleWidth) <
clearance) {
numShift +=
clearance - ((numShift - numer.depth) -
clearance - ((numShift - numerm.depth) -
(axisHeight + 0.5 * ruleWidth));
}
if ((axisHeight - 0.5 * ruleWidth) - (denom.height - denomShift) <
if ((axisHeight - 0.5 * ruleWidth) - (denomm.height - denomShift) <
clearance) {
denomShift +=
clearance - ((axisHeight - 0.5 * ruleWidth) -
(denom.height - denomShift));
(denomm.height - denomShift));
}
const mid = makeSpan(
[options.style.reset(), Style.TEXT.cls(), "frac-line"]);
// Manually set the height of the line because its height is
// created in CSS
mid.height = ruleWidth;
const midShift = -(axisHeight - 0.5 * ruleWidth);
frac = buildCommon.makeVList([
{type: "elem", elem: denomreset, shift: denomShift},
{type: "elem", elem: mid, shift: midShift},
{type: "elem", elem: numerreset, shift: -numShift},
{type: "elem", elem: denomm, shift: denomShift},
{type: "elem", elem: rule, shift: midShift},
{type: "elem", elem: numerm, shift: -numShift},
], "individualShift", null, options);
}
// Since we manually change the style sometimes (with \dfrac or \tfrac),
// account for the possible size change here.
frac.height *= style.sizeMultiplier / options.style.sizeMultiplier;
frac.depth *= style.sizeMultiplier / options.style.sizeMultiplier;
newOptions = options.havingStyle(style);
frac.height *= newOptions.sizeMultiplier / options.sizeMultiplier;
frac.depth *= newOptions.sizeMultiplier / options.sizeMultiplier;
// Rule 15e
let delimSize;
@@ -558,18 +535,18 @@ groupTypes.genfrac = function(group, options) {
} else {
leftDelim = delimiter.customSizedDelim(
group.value.leftDelim, delimSize, true,
options.withStyle(style), group.mode, ["mopen"]);
options.havingStyle(style), group.mode, ["mopen"]);
}
if (group.value.rightDelim == null) {
rightDelim = makeNullDelimiter(options, ["mclose"]);
} else {
rightDelim = delimiter.customSizedDelim(
group.value.rightDelim, delimSize, true,
options.withStyle(style), group.mode, ["mclose"]);
options.havingStyle(style), group.mode, ["mclose"]);
}
return makeSpan(
["mord", options.style.reset(), style.cls()],
["mord"].concat(newOptions.sizingClasses(options)),
[leftDelim, makeSpan(["mfrac"], [frac]), rightDelim],
options);
};
@@ -770,18 +747,18 @@ groupTypes.spacing = function(group, options) {
groupTypes.llap = function(group, options) {
const inner = makeSpan(
["inner"], [buildGroup(group.value.body, options.reset())]);
["inner"], [buildGroup(group.value.body, options)]);
const fix = makeSpan(["fix"], []);
return makeSpan(
["mord", "llap", options.style.cls()], [inner, fix], options);
["mord", "llap"], [inner, fix], options);
};
groupTypes.rlap = function(group, options) {
const inner = makeSpan(
["inner"], [buildGroup(group.value.body, options.reset())]);
["inner"], [buildGroup(group.value.body, options)]);
const fix = makeSpan(["fix"], []);
return makeSpan(
["mord", "rlap", options.style.cls()], [inner, fix], options);
["mord", "rlap"], [inner, fix], options);
};
groupTypes.op = function(group, options) {
@@ -831,7 +808,7 @@ groupTypes.op = function(group, options) {
// 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 * style.sizeMultiplier;
style.metrics.axisHeight * options.sizeMultiplier;
// The slant of the symbol is just its italic correction.
slant = base.italic;
@@ -857,33 +834,29 @@ groupTypes.op = function(group, options) {
// in a new span so it is an inline, and works.
base = makeSpan([], [base]);
let supmid;
let supm;
let supKern;
let submid;
let subm;
let subKern;
let newOptions;
// We manually have to handle the superscripts and subscripts. This,
// aside from the kern calculations, is copied from supsub.
if (supGroup) {
newOptions = options.withStyle(style.sup());
const sup = buildGroup(supGroup, newOptions);
supmid = makeSpan([style.reset(), style.sup().cls()],
[sup], newOptions);
newOptions = options.havingStyle(style.sup());
supm = buildGroup(supGroup, newOptions, options);
supKern = Math.max(
fontMetrics.metrics.bigOpSpacing1,
fontMetrics.metrics.bigOpSpacing3 - sup.depth);
fontMetrics.metrics.bigOpSpacing3 - supm.depth);
}
if (subGroup) {
newOptions = options.withStyle(style.sub());
const sub = buildGroup(subGroup, newOptions);
submid = makeSpan([style.reset(), style.sub().cls()],
[sub], newOptions);
newOptions = options.havingStyle(style.sub());
subm = buildGroup(subGroup, newOptions, options);
subKern = Math.max(
fontMetrics.metrics.bigOpSpacing2,
fontMetrics.metrics.bigOpSpacing4 - sub.height);
fontMetrics.metrics.bigOpSpacing4 - subm.height);
}
// Build the final group as a vlist of the possible subscript, base,
@@ -896,7 +869,7 @@ groupTypes.op = function(group, options) {
finalGroup = buildCommon.makeVList([
{type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
{type: "elem", elem: submid},
{type: "elem", elem: subm},
{type: "kern", size: subKern},
{type: "elem", elem: base},
], "top", top, options);
@@ -912,7 +885,7 @@ groupTypes.op = function(group, options) {
finalGroup = buildCommon.makeVList([
{type: "elem", elem: base},
{type: "kern", size: supKern},
{type: "elem", elem: supmid},
{type: "elem", elem: supm},
{type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
], "bottom", bottom, options);
@@ -925,17 +898,17 @@ groupTypes.op = function(group, options) {
return base;
} else {
bottom = fontMetrics.metrics.bigOpSpacing5 +
submid.height + submid.depth +
subm.height + subm.depth +
subKern +
base.depth + baseShift;
finalGroup = buildCommon.makeVList([
{type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
{type: "elem", elem: submid},
{type: "elem", elem: subm},
{type: "kern", size: subKern},
{type: "elem", elem: base},
{type: "kern", size: supKern},
{type: "elem", elem: supmid},
{type: "elem", elem: supm},
{type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
], "bottom", bottom, options);
@@ -1034,29 +1007,33 @@ groupTypes.katex = function(group, options) {
["mord", "katex-logo"], [k, a, t, e, x], options);
};
const makeLineSpan = function(className, options) {
const baseOptions = options.havingBaseStyle();
const line = makeSpan(
[className].concat(baseOptions.sizingClasses(options)),
[], options);
line.height = fontMetrics.metrics.defaultRuleThickness /
options.sizeMultiplier;
line.maxFontSize = 1.0;
return line;
};
groupTypes.overline = function(group, options) {
// Overlines are handled in the TeXbook pg 443, Rule 9.
const style = options.style;
// Build the inner group in the cramped style.
const innerGroup = buildGroup(group.value.body,
options.withStyle(style.cramp()));
const ruleWidth = fontMetrics.metrics.defaultRuleThickness /
style.sizeMultiplier;
options.havingCrampedStyle());
// Create the line above the body
const line = makeSpan(
[style.reset(), Style.TEXT.cls(), "overline-line"]);
line.height = ruleWidth;
line.maxFontSize = 1.0;
const line = makeLineSpan("overline-line", options);
// Generate the vlist, with the appropriate kerns
const vlist = buildCommon.makeVList([
{type: "elem", elem: innerGroup},
{type: "kern", size: 3 * ruleWidth},
{type: "kern", size: 3 * line.height},
{type: "elem", elem: line},
{type: "kern", size: ruleWidth},
{type: "kern", size: line.height},
], "firstBaseline", null, options);
return makeSpan(["mord", "overline"], [vlist], options);
@@ -1064,24 +1041,17 @@ groupTypes.overline = function(group, options) {
groupTypes.underline = function(group, options) {
// Underlines are handled in the TeXbook pg 443, Rule 10.
const style = options.style;
// Build the inner group.
const innerGroup = buildGroup(group.value.body, options);
const ruleWidth = fontMetrics.metrics.defaultRuleThickness /
style.sizeMultiplier;
// Create the line above the body
const line = makeSpan([style.reset(), Style.TEXT.cls(), "underline-line"]);
line.height = ruleWidth;
line.maxFontSize = 1.0;
const line = makeLineSpan("underline-line", options);
// Generate the vlist, with the appropriate kerns
const vlist = buildCommon.makeVList([
{type: "kern", size: ruleWidth},
{type: "kern", size: line.height},
{type: "elem", elem: line},
{type: "kern", size: 3 * ruleWidth},
{type: "kern", size: 3 * line.height},
{type: "elem", elem: innerGroup},
], "top", innerGroup.height, options);
@@ -1090,32 +1060,24 @@ groupTypes.underline = function(group, options) {
groupTypes.sqrt = function(group, options) {
// Square roots are handled in the TeXbook pg. 443, Rule 11.
const style = options.style;
// First, we do the same steps as in overline to build the inner group
// and line
const inner = buildGroup(
group.value.body, options.withStyle(style.cramp()));
const inner = buildGroup(group.value.body, options.havingCrampedStyle());
const ruleWidth = fontMetrics.metrics.defaultRuleThickness /
style.sizeMultiplier;
const line = makeSpan(
[style.reset(), Style.TEXT.cls(), "sqrt-line"], [],
options);
line.height = ruleWidth;
line.maxFontSize = 1.0;
const line = makeLineSpan("sqrt-line", options);
const ruleWidth = line.height;
let phi = ruleWidth;
if (style.id < Style.TEXT.id) {
phi = style.metrics.xHeight;
if (options.style.id < Style.TEXT.id) {
phi = options.style.metrics.xHeight * options.sizeMultiplier;
}
// Calculate the clearance between the body and line
let lineClearance = ruleWidth + phi / 4;
const innerHeight = (inner.height + inner.depth) * style.sizeMultiplier;
const minDelimiterHeight = innerHeight + lineClearance + ruleWidth;
const minDelimiterHeight = (inner.height + inner.depth +
lineClearance + ruleWidth) * options.sizeMultiplier;
// Create a \surd delimiter of the required minimum size
const delim = makeSpan(["sqrt-sign"], [
@@ -1161,12 +1123,8 @@ groupTypes.sqrt = function(group, options) {
// Handle the optional root index
// The index is always in scriptscript style
const newOptions = options.withStyle(Style.SCRIPTSCRIPT);
const root = buildGroup(group.value.index, newOptions);
const rootWrap = makeSpan(
[style.reset(), Style.SCRIPTSCRIPT.cls()],
[root],
newOptions);
const newOptions = options.havingStyle(Style.SCRIPTSCRIPT);
const rootm = buildGroup(group.value.index, newOptions, options);
// Figure out the height and depth of the inner part
const innerRootHeight = Math.max(delim.height, body.height);
@@ -1178,7 +1136,7 @@ groupTypes.sqrt = function(group, options) {
// Build a VList with the superscript shifted up correctly
const rootVList = buildCommon.makeVList(
[{type: "elem", elem: rootWrap}],
[{type: "elem", elem: rootm}],
"shift", -toShift, options);
// Add a class surrounding it so we can add on the appropriate
// kerning
@@ -1189,35 +1147,37 @@ groupTypes.sqrt = function(group, options) {
}
};
groupTypes.sizing = function(group, options) {
// Handle sizing operators like \Huge. Real TeX doesn't actually allow
// these functions inside of math expressions, so we do some special
// handling.
const inner = buildExpression(group.value.value,
options.withSize(group.value.size), false);
// Compute the correct maxFontSize.
const style = options.style;
const fontSize = buildCommon.sizingMultiplier[group.value.size] *
style.sizeMultiplier;
function sizingGroup(value, options, baseOptions) {
const inner = buildExpression(value, options, false);
const multiplier = options.sizeMultiplier / baseOptions.sizeMultiplier;
// Add size-resetting classes to the inner list and set maxFontSize
// manually. Handle nested size changes.
for (let i = 0; i < inner.length; i++) {
const pos = utils.indexOf(inner[i].classes, "sizing");
if (pos < 0) {
inner[i].classes.push("sizing", "reset-" + options.size,
group.value.size, style.cls());
inner[i].maxFontSize = fontSize;
} else if (inner[i].classes[pos + 1] === "reset-" + group.value.size) {
Array.prototype.push.apply(inner[i].classes,
options.sizingClasses(baseOptions));
} else if (inner[i].classes[pos + 1] === "reset-size" + options.size) {
// This is a nested size change: e.g., inner[i] is the "b" in
// `\Huge a \small b`. Override the old size (the `reset-` class)
// but not the new size.
inner[i].classes[pos + 1] = "reset-" + options.size;
inner[i].classes[pos + 1] = "reset-size" + baseOptions.size;
}
inner[i].height *= multiplier;
inner[i].depth *= multiplier;
}
return buildCommon.makeFragment(inner);
}
groupTypes.sizing = function(group, options) {
// Handle sizing operators like \Huge. Real TeX doesn't actually allow
// these functions inside of math expressions, so we do some special
// handling.
const newOptions = options.havingSize(group.value.size);
return sizingGroup(group.value.value, newOptions, options);
};
groupTypes.styling = function(group, options) {
@@ -1232,25 +1192,8 @@ groupTypes.styling = function(group, options) {
};
const newStyle = styleMap[group.value.style];
const newOptions = options.withStyle(newStyle);
// Build the inner expression in the new style.
const inner = buildExpression(
group.value.value, newOptions, false);
// Add style-resetting classes to the inner list. Handle nested changes.
for (let i = 0; i < inner.length; i++) {
const pos = utils.indexOf(inner[i].classes, newStyle.reset());
if (pos < 0) {
inner[i].classes.push(options.style.reset(), newStyle.cls());
} else {
// This is a nested style change, as `\textstyle a\scriptstyle b`.
// Only override the old style (the reset class).
inner[i].classes[pos] = options.style.reset();
}
}
return new buildCommon.makeFragment(inner);
const newOptions = options.havingStyle(newStyle);
return sizingGroup(group.value.value, newOptions, options);
};
groupTypes.font = function(group, options) {
@@ -1275,7 +1218,7 @@ groupTypes.delimsizing = function(group, options) {
groupTypes.leftright = function(group, options) {
// Build the inner expression
const inner = buildExpression(group.value.body, options.reset(), true);
const inner = buildExpression(group.value.body, options, true);
let innerHeight = 0;
let innerDepth = 0;
@@ -1291,13 +1234,11 @@ groupTypes.leftright = function(group, options) {
}
}
const style = options.style;
// The size of delimiters is the same, regardless of what style we are
// in. Thus, to correctly calculate the size of delimiter we need around
// a group, we scale down the inner size based on the size.
innerHeight *= style.sizeMultiplier;
innerDepth *= style.sizeMultiplier;
innerHeight *= options.sizeMultiplier;
innerDepth *= options.sizeMultiplier;
let leftDelim;
if (group.value.left === ".") {
@@ -1343,8 +1284,7 @@ groupTypes.leftright = function(group, options) {
// Add it to the end of the expression.
inner.push(rightDelim);
return makeSpan(
["minner", style.cls()], inner, options);
return makeSpan(["minner"], inner, options);
};
groupTypes.middle = function(group, options) {
@@ -1376,9 +1316,9 @@ groupTypes.rule = function(group, options) {
// The sizes of rules are absolute, so make it larger if we are in a
// smaller style.
shift /= style.sizeMultiplier;
width /= style.sizeMultiplier;
height /= style.sizeMultiplier;
shift /= options.sizeMultiplier;
width /= options.sizeMultiplier;
height /= options.sizeMultiplier;
// Style the rule to the right size
rule.style.borderRightWidth = width + "em";
@@ -1403,7 +1343,7 @@ groupTypes.kern = function(group, options) {
dimension = calculateSize(group.value.dimension, style);
}
dimension /= style.sizeMultiplier;
dimension /= options.sizeMultiplier;
rule.style.marginLeft = dimension + "em";
@@ -1436,13 +1376,11 @@ groupTypes.accent = function(group, options) {
// Rerender the supsub group with its new base, and store that
// result.
supsubGroup = buildGroup(
supsub, options.reset());
supsubGroup = buildGroup(supsub, options);
}
// Build the base group
const body = buildGroup(
base, options.withStyle(style.cramp()));
const body = buildGroup(base, options.havingCrampedStyle());
// Does the accent need to shift for the skew of a character?
const mustShift = group.value.isShifty && isCharacterBox(base);
@@ -1458,8 +1396,7 @@ groupTypes.accent = function(group, options) {
// innermost character. To do that, we find the innermost character:
const baseChar = getBaseElem(base);
// Then, we render its group to get the symbol inside it
const baseGroup = buildGroup(
baseChar, options.withStyle(style.cramp()));
const baseGroup = buildGroup(baseChar, options.havingCrampedStyle());
// Finally, we pull the skew off of the symbol.
skew = baseGroup.skew;
// Note that we now throw away baseGroup, because the layers we
@@ -1543,28 +1480,23 @@ groupTypes.horizBrace = function(group, options) {
const hasSupSub = (group.type === "supsub");
let supSubGroup;
let newOptions;
let supSubReset;
if (hasSupSub) {
// Ref: LaTeX source2e: }}}}\limits}
// i.e. LaTeX treats the brace similar to an op and passes it
// with \limits, so we need to assign supsub style.
if (group.value.sup) {
newOptions = options.withStyle(style.sup());
supSubGroup = buildGroup(group.value.sup, newOptions);
supSubReset = makeSpan([style.reset(), style.sup().cls()],
[supSubGroup], newOptions);
newOptions = options.havingStyle(style.sup());
supSubGroup = buildGroup(group.value.sup, newOptions, options);
} else {
newOptions = options.withStyle(style.sub());
supSubGroup = buildGroup(group.value.sub, newOptions);
supSubReset = makeSpan([style.reset(), style.sub().cls()],
[supSubGroup], newOptions);
newOptions = options.havingStyle(style.sub());
supSubGroup = buildGroup(group.value.sub, newOptions, options);
}
group = group.value.base;
}
// Build the base group
const body = buildGroup(
group.value.base, options.withStyle(style.cramp()));
group.value.base, options.havingStyle(style.cramp()));
// Create the stretchy element
const braceBody = stretchy.svgSpan(group, options);
@@ -1603,14 +1535,14 @@ groupTypes.horizBrace = function(group, options) {
vlist = buildCommon.makeVList([
{type: "elem", elem: vSpan},
{type: "kern", size: 0.2},
{type: "elem", elem: supSubReset},
{type: "elem", elem: supSubGroup},
], "firstBaseline", null, options);
} else {
vlist = buildCommon.makeVList([
{type: "elem", elem: supSubReset},
{type: "elem", elem: supSubGroup},
{type: "kern", size: 0.2},
{type: "elem", elem: vSpan},
], "bottom", vSpan.depth + 0.2 + supSubReset.height,
], "bottom", vSpan.depth + 0.2 + supSubGroup.height,
options);
}
}
@@ -1638,10 +1570,10 @@ groupTypes.accentUnder = function(group, options) {
groupTypes.enclose = function(group, options) {
// \cancel, \bcancel, \xcancel, \sout, \fbox
const inner = buildGroup(group.value.body, options.reset());
const inner = buildGroup(group.value.body, options);
const label = group.value.label.substr(1);
const scale = options.style.sizeMultiplier;
const scale = options.sizeMultiplier;
let img;
let pad = 0;
let imgShift = 0;
@@ -1695,19 +1627,14 @@ groupTypes.xArrow = function(group, options) {
// Build the argument groups in the appropriate style.
// Ref: amsmath.dtx: \hbox{$\scriptstyle\mkern#3mu{#6}\mkern#4mu$}%
let newOptions = options.withStyle(style.sup());
const upperGroup = buildGroup(group.value.body, newOptions);
const upperGroupWrap = makeSpan([style.reset(), style.sup().cls()],
[upperGroup], newOptions);
let newOptions = options.havingStyle(style.sup());
const upperGroup = buildGroup(group.value.body, newOptions, options);
let lowerGroup;
let lowerGroupWrap;
if (group.value.below) {
// Build the lower group
newOptions = options.withStyle(style.sub());
lowerGroup = buildGroup(group.value.below, newOptions);
lowerGroupWrap = makeSpan([style.reset(), style.sub().cls()],
[lowerGroup], newOptions);
newOptions = options.havingStyle(style.sub());
lowerGroup = buildGroup(group.value.below, newOptions, options);
}
const arrowBody = stretchy.svgSpan(group, options);
@@ -1720,16 +1647,16 @@ groupTypes.xArrow = function(group, options) {
let vlist;
if (group.value.below) {
const lowerShift = -style.metrics.axisHeight
+ lowerGroupWrap.height + arrowBody.height
+ lowerGroup.height + arrowBody.height
+ 0.111;
vlist = buildCommon.makeVList([
{type: "elem", elem: upperGroupWrap, shift: upperShift},
{type: "elem", elem: upperGroup, shift: upperShift},
{type: "elem", elem: arrowBody, shift: arrowShift},
{type: "elem", elem: lowerGroupWrap, shift: lowerShift},
{type: "elem", elem: lowerGroup, shift: lowerShift},
], "individualShift", null, options);
} else {
vlist = buildCommon.makeVList([
{type: "elem", elem: upperGroupWrap, shift: upperShift},
{type: "elem", elem: upperGroup, shift: upperShift},
{type: "elem", elem: arrowBody, shift: arrowShift},
], "individualShift", null, options);
}
@@ -1763,31 +1690,23 @@ groupTypes.mclass = function(group, options) {
* function for it. It also handles the interaction of size and style changes
* between parents and children.
*/
const buildGroup = function(group, options) {
const buildGroup = function(group, options, baseOptions) {
if (!group) {
return makeSpan();
}
if (groupTypes[group.type]) {
// Call the groupTypes function
const groupNode = groupTypes[group.type](group, options);
let multiplier;
// If the style changed between the parent and the current group,
// account for the size difference
if (options.style !== options.parentStyle) {
multiplier = options.style.sizeMultiplier /
options.parentStyle.sizeMultiplier;
groupNode.height *= multiplier;
groupNode.depth *= multiplier;
}
let groupNode = groupTypes[group.type](group, options);
// If the size changed between the parent and the current group, account
// for that size difference.
if (options.size !== options.parentSize) {
multiplier = buildCommon.sizingMultiplier[options.size] /
buildCommon.sizingMultiplier[options.parentSize];
if (baseOptions && options.size !== baseOptions.size) {
groupNode = makeSpan(options.sizingClasses(baseOptions),
[groupNode], options);
const multiplier = options.sizeMultiplier /
baseOptions.sizeMultiplier;
groupNode.height *= multiplier;
groupNode.depth *= multiplier;
@@ -1811,7 +1730,7 @@ const buildHTML = function(tree, options) {
// Build the expression contained in the tree
const expression = buildExpression(tree, options, true);
const body = makeSpan(["base", options.style.cls()], expression, options);
const body = makeSpan(["base"], expression, options);
// Add struts, which ensure that the top of the HTML element falls at the
// height of the expression, and the bottom of the HTML element falls at the

View File

@@ -480,7 +480,8 @@ groupTypes.styling = function(group, options) {
};
groupTypes.sizing = function(group, options) {
const inner = buildExpression(group.value.value, options);
const newOptions = options.havingSize(group.value.size);
const inner = buildExpression(group.value.value, newOptions);
const node = new mathMLTree.MathNode("mstyle", inner);
@@ -489,8 +490,7 @@ groupTypes.sizing = function(group, options) {
// in, so we can't reset the size to normal before changing it. Now
// that we're passing an options parameter we should be able to fix
// this.
node.setAttribute(
"mathsize", buildCommon.sizingMultiplier[group.value.size] + "em");
node.setAttribute("mathsize", newOptions.sizeMultiplier + "em");
return node;
};

View File

@@ -18,7 +18,6 @@ const buildTree = function(tree, expression, settings) {
// Setup the default options
const options = new Options({
style: startStyle,
size: "size5",
});
// `buildHTML` sometimes messes with the parse tree (like turning bins ->

View File

@@ -44,33 +44,36 @@ const getMetrics = function(symbol, font) {
}
};
/**
* Builds a symbol in the given font size (note size is an integer)
*/
const mathrmSize = function(value, size, mode, options) {
return buildCommon.makeSymbol(value, "Size" + size + "-Regular",
mode, options);
};
/**
* Puts a delimiter span in a given style, and adds appropriate height, depth,
* and maxFontSizes.
*/
const styleWrap = function(delim, toStyle, options, classes) {
classes = classes || [];
const newOptions = options.havingBaseStyle(toStyle);
const span = makeSpan(
classes.concat(["style-wrap", options.style.reset(), toStyle.cls()]),
(classes || []).concat(newOptions.sizingClasses(options)),
[delim], options);
const multiplier = toStyle.sizeMultiplier / options.style.sizeMultiplier;
span.height *= multiplier;
span.depth *= multiplier;
span.maxFontSize = toStyle.sizeMultiplier;
span.height *= newOptions.sizeMultiplier / options.sizeMultiplier;
span.depth *= newOptions.sizeMultiplier / options.sizeMultiplier;
span.maxFontSize = newOptions.sizeMultiplier;
return span;
};
const centerSpan = function(span, options, style) {
const newOptions = options.havingBaseStyle(style);
const shift =
(1 - options.sizeMultiplier / newOptions.sizeMultiplier) *
options.style.metrics.axisHeight;
span.classes.push("delimcenter");
span.style.top = shift + "em";
span.height -= shift;
span.depth += shift;
};
/**
* Makes a small delimiter. This is a delimiter that comes in the Main-Regular
* font, but is restyled to either be in textstyle, scriptstyle, or
@@ -78,42 +81,33 @@ const styleWrap = function(delim, toStyle, options, classes) {
*/
const makeSmallDelim = function(delim, style, center, options, mode, classes) {
const text = buildCommon.makeSymbol(delim, "Main-Regular", mode, options);
const span = styleWrap(text, style, options, classes);
if (center) {
const shift =
(1 - options.style.sizeMultiplier / style.sizeMultiplier) *
options.style.metrics.axisHeight;
span.style.top = shift + "em";
span.height -= shift;
span.depth += shift;
centerSpan(span, options, style);
}
return span;
};
/**
* Builds a symbol in the given font size (note size is an integer)
*/
const mathrmSize = function(value, size, mode, options) {
return buildCommon.makeSymbol(value, "Size" + size + "-Regular",
mode, options);
};
/**
* Makes a large delimiter. This is a delimiter that comes in the Size1, Size2,
* Size3, or Size4 fonts. It is always rendered in textstyle.
*/
const makeLargeDelim = function(delim, size, center, options, mode, classes) {
const inner = mathrmSize(delim, size, mode, options);
const span = styleWrap(
makeSpan(["delimsizing", "size" + size], [inner], options),
Style.TEXT, options, classes);
if (center) {
const shift = (1 - options.style.sizeMultiplier) *
options.style.metrics.axisHeight;
span.style.top = shift + "em";
span.height -= shift;
span.depth += shift;
centerSpan(span, options, Style.TEXT);
}
return span;
};
@@ -283,7 +277,7 @@ const makeStackedDelim = function(delim, heightTotal, center, options, mode,
// centered around the axis in textstyle.
let axisHeight = options.style.metrics.axisHeight;
if (center) {
axisHeight *= options.style.sizeMultiplier;
axisHeight *= options.sizeMultiplier;
}
// Calculate the depth
const depth = realHeightTotal / 2 - axisHeight;
@@ -317,10 +311,11 @@ const makeStackedDelim = function(delim, heightTotal, center, options, mode,
inners.push(makeInner(top, font, mode));
// Finally, build the vlist
const inner = buildCommon.makeVList(inners, "bottom", depth, options);
const newOptions = options.havingBaseStyle(Style.TEXT);
const inner = buildCommon.makeVList(inners, "bottom", depth, newOptions);
return styleWrap(
makeSpan(["delimsizing", "mult"], [inner], options),
makeSpan(["delimsizing", "mult"], [inner], newOptions),
Style.TEXT, options, classes);
};
@@ -455,7 +450,8 @@ const traverseSequence = function(delim, height, sequence, options) {
// account for the style change size.
if (sequence[i].type === "small") {
heightDepth *= sequence[i].style.sizeMultiplier;
const newOptions = options.havingBaseStyle(sequence[i].style);
heightDepth *= newOptions.sizeMultiplier;
}
// Check if the delimiter at this size works for the given height.
@@ -514,7 +510,7 @@ 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.style.sizeMultiplier;
options.style.metrics.axisHeight * options.sizeMultiplier;
// Taken from TeX source, tex.web, function make_left_right
const delimiterFactor = 901;

View File

@@ -232,22 +232,6 @@
& + .mop.mtight { margin-left: @thinspace; }
}
.reset-textstyle.textstyle { font-size: 1em; }
.reset-textstyle.scriptstyle { font-size: 0.7em; }
.reset-textstyle.scriptscriptstyle { font-size: 0.5em; }
.reset-scriptstyle.textstyle { font-size: 1.42857em; }
.reset-scriptstyle.scriptstyle { font-size: 1em; }
.reset-scriptstyle.scriptscriptstyle { font-size: 0.71429em; }
.reset-scriptscriptstyle.textstyle { font-size: 2em; }
.reset-scriptscriptstyle.scriptstyle { font-size: 1.4em; }
.reset-scriptscriptstyle.scriptscriptstyle { font-size: 1em; }
.style-wrap {
position: relative;
}
.vlist {
display: inline-block;
@@ -448,15 +432,16 @@
display: inline-block;
@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;
@size2: 0.6;
@size3: 0.7;
@size4: 0.8;
@size5: 0.9;
@size6: 1.0;
@size7: 1.2;
@size8: 1.44;
@size9: 1.728;
@size10: 2.074;
@size11: 2.488;
.generate-size-change(@from, @to) {
&.reset-size@{from}.size@{to} {
@@ -466,13 +451,13 @@
}
}
.generate-to-size-change(@from, @currTo) when (@currTo =< 10) {
.generate-to-size-change(@from, @currTo) when (@currTo =< 11) {
.generate-size-change(@from, @currTo);
.generate-to-size-change(@from, (@currTo + 1));
}
.generate-from-size-change(@currFrom) when (@currFrom =< 10) {
.generate-from-size-change(@currFrom) when (@currFrom =< 11) {
.generate-to-size-change(@currFrom, 1);
.generate-from-size-change((@currFrom + 1));
@@ -502,6 +487,10 @@
width: @nulldelimiterspace;
}
.delimcenter {
position: relative;
}
.op-symbol {
position: relative;

View File

@@ -17,7 +17,7 @@ const Style = require("../src/Style");
const defaultSettings = new Settings({});
const defaultOptions = new Options({
style: Style.TEXT,
size: "size5",
size: 5,
});
const _getBuilt = function(expr, settings) {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 10 KiB