Add vlist builder for more consistent stacking

Summary:
Add a way to automatically build vlists correctly. Previously, we built
vlists manually in ~4 different places, which made it difficult to manage
changes, and led to a large amount of duplication in the less. This also fixes
the vlist construction in safari, where the `display: inline-table` wasn't being
applied because of CSS specificity. This leads to the only significant change in
the huxley tests, with the vertical spacing.

Test Plan:
 - Make sure the tests still work
 - Make sure most of the huxley screenshots didn't change, and that the new
   changes are insignificant.
 - Make sure vlists now work in Safari
 - Make sure the change to the VerticalSpacing screenshot is caused by the
   fix-baseline span now correctly applying `display: inline-table` by creating
   the construct in master and adding `display: inline-table !important` to the
   `.fix-ie` css rule

Reviewers: alpert

Reviewed By: alpert

Differential Revision: http://phabricator.khanacademy.org/D13082
This commit is contained in:
Emily Eisenberg 2014-09-12 14:41:31 -07:00
parent 403dca64ab
commit 29b00ee6b7
9 changed files with 242 additions and 275 deletions

View File

@ -94,11 +94,139 @@ var makeFontSizer = function(options, fontSize) {
return fontSizer;
};
/*
* Makes a vertical list by stacking elements and kerns on top of each other.
* Allows for many different ways of specifying the positioning method.
*
* Arguments:
* - children: A list of child or kern nodes to be stacked on top of each other
* (i.e. the first element will be at the bottom, and the last at
* the top). Element nodes are specified as
* {type: "elem", elem: node}
* while kern nodes are specified as
* {type: "kern", size: size}
* - positionType: The method by which the vlist should be positioned. Valid
* values are:
* - "individualShift": The children list only contains elem
* nodes, and each node contains an extra
* "shift" value of how much it should be
* shifted (note that shifting is always
* moving downwards). positionData is
* ignored.
* - "top": The positionData specifies the topmost point of
* the vlist (note this is expected to be a height,
* so positive values move up)
* - "bottom": The positionData specifies the bottommost point
* of the vlist (note this is expected to be a
* depth, so positive values move down
* - "shift": The vlist will be positioned such that its
* baseline is positionData away from the baseline
* of the first child. Positive values move
* downwards.
* - "firstBaseline": The vlist will be positioned such that
* its baseline is aligned with the
* baseline of the first child.
* positionData is ignored. (this is
* equivalent to "shift" with
* positionData=0)
* - positionData: Data used in different ways depending on positionType
* - options: An Options object
*
*/
var makeVList = function(children, positionType, positionData, options) {
var depth;
if (positionType === "individualShift") {
var oldChildren = children;
children = [oldChildren[0]];
// Add in kerns to the list of children to get each element to be
// shifted to the correct specified shift
depth = -oldChildren[0].shift - oldChildren[0].elem.depth;
var currPos = depth;
for (var i = 1; i < oldChildren.length; i++) {
var diff = -oldChildren[i].shift - currPos -
oldChildren[i].elem.depth;
var size = diff -
(oldChildren[i - 1].elem.height +
oldChildren[i - 1].elem.depth);
currPos = currPos + diff;
children.push({type: "kern", size: size});
children.push(oldChildren[i]);
}
} else if (positionType === "top") {
// We always start at the bottom, so calculate the bottom by adding up
// all the sizes
var bottom = positionData;
for (var i = 0; i < children.length; i++) {
if (children[i].type === "kern") {
bottom -= children[i].size;
} else {
bottom -= children[i].elem.height + children[i].elem.depth;
}
}
depth = bottom;
} else if (positionType === "bottom") {
depth = -positionData;
} else if (positionType === "shift") {
depth = -children[0].elem.depth - positionData;
} else if (positionType === "firstBaseline") {
depth = -children[0].elem.depth;
} else {
depth = 0;
}
// Make the fontSizer
var maxFontSize = 0;
for (var i = 0; i < children.length; i++) {
if (children[i].type === "elem") {
maxFontSize = Math.max(maxFontSize, children[i].elem.maxFontSize);
}
}
var fontSizer = makeFontSizer(options, maxFontSize);
// Create a new list of actual children at the correct offsets
var realChildren = [];
var currPos = depth;
for (var i = 0; i < children.length; i++) {
if (children[i].type === "kern") {
currPos += children[i].size;
} else {
var child = children[i].elem;
var shift = -child.depth - currPos;
currPos += child.height + child.depth;
var childWrap = makeSpan([], [fontSizer, child]);
childWrap.height -= shift;
childWrap.depth += shift;
childWrap.style.top = shift + "em";
realChildren.push(childWrap);
}
}
// Add in an element at the end with no offset to fix the calculation of
// baselines in some browsers (namely IE, sometimes safari)
var baselineFix = makeSpan(
["baseline-fix"], [fontSizer, new domTree.textNode("\u00a0")]);
realChildren.push(baselineFix);
var vlist = makeSpan(["vlist"], realChildren);
// Fix the final height and depth, in case there were kerns at the ends
// since the makeSpan calculation won't take that in to account.
vlist.height = Math.max(currPos, vlist.height);
vlist.depth = Math.max(-depth, vlist.depth);
return vlist;
};
module.exports = {
makeText: makeText,
mathit: mathit,
mathrm: mathrm,
makeSpan: makeSpan,
makeFragment: makeFragment,
makeFontSizer: makeFontSizer
makeFontSizer: makeFontSizer,
makeVList: makeVList
};

View File

@ -147,12 +147,13 @@ var groupTypes = {
[options.style.reset(), options.style.sub().cls()], [sub]);
}
var u, v;
if (isCharacterBox(group.value.base)) {
var u = 0;
var v = 0;
u = 0;
v = 0;
} else {
var u = base.height - fontMetrics.metrics.supDrop;
var v = base.depth + fontMetrics.metrics.subDrop;
u = base.height - fontMetrics.metrics.supDrop;
v = base.depth + fontMetrics.metrics.subDrop;
}
var p;
@ -172,43 +173,24 @@ var groupTypes = {
var supsub;
if (!group.value.sup) {
var fontSizer = buildCommon.makeFontSizer(options, submid.maxFontSize);
var subwrap = makeSpan(["msub"], [fontSizer, submid]);
v = Math.max(v, fontMetrics.metrics.sub1,
sub.height - 0.8 * fontMetrics.metrics.xHeight);
subwrap.style.top = v + "em";
subwrap.style.marginRight = scriptspace;
supsub = buildCommon.makeVList([
{type: "elem", elem: submid}
], "shift", v, options);
subwrap.depth = subwrap.depth + v;
subwrap.height = 0;
var fixIE = makeSpan(["fix-ie"], [fontSizer, new domTree.textNode("\u00a0")]);
supsub = makeSpan(["msupsub"], [subwrap, fixIE]);
supsub.children[0].style.marginRight = scriptspace;
} else if (!group.value.sub) {
var fontSizer = buildCommon.makeFontSizer(options, supmid.maxFontSize);
var supwrap = makeSpan(["msup"], [fontSizer, supmid]);
u = Math.max(u, p,
sup.depth + 0.25 * fontMetrics.metrics.xHeight);
supwrap.style.top = -u + "em";
supwrap.style.marginRight = scriptspace;
supsub = buildCommon.makeVList([
{type: "elem", elem: supmid}
], "shift", -u, options);
supwrap.height = supwrap.height + u;
supwrap.depth = 0;
var fixIE = makeSpan(["fix-ie"], [fontSizer, new domTree.textNode("\u00a0")]);
supsub = makeSpan(["msupsub"], [supwrap, fixIE]);
supsub.children[0].style.marginRight = scriptspace;
} else {
var fontSizer = buildCommon.makeFontSizer(options,
Math.max(submid.maxFontSize, supmid.maxFontSize));
var subwrap = makeSpan(["msub"], [fontSizer, submid]);
var supwrap = makeSpan(["msup"], [fontSizer, supmid]);
u = Math.max(u, p,
sup.depth + 0.25 * fontMetrics.metrics.xHeight);
v = Math.max(v, fontMetrics.metrics.sub2);
@ -224,21 +206,13 @@ var groupTypes = {
}
}
supwrap.style.top = -u + "em";
subwrap.style.top = v + "em";
supsub = buildCommon.makeVList([
{type: "elem", elem: submid, shift: v},
{type: "elem", elem: supmid, shift: -u}
], "individualShift", null, options);
supwrap.style.marginRight = scriptspace;
subwrap.style.marginRight = scriptspace;
supwrap.height = supwrap.height + u;
supwrap.depth = 0;
subwrap.height = 0;
subwrap.depth = subwrap.depth + v;
var fixIE = makeSpan(["fix-ie"], [fontSizer, new domTree.textNode("\u00a0")]);
supsub = makeSpan(["msupsub"], [supwrap, subwrap, fixIE]);
supsub.children[0].style.marginRight = scriptspace;
supsub.children[1].style.marginRight = scriptspace;
}
return makeSpan([getTypeOfGroup(group.value.base)],
@ -273,22 +247,16 @@ var groupTypes = {
var dstyle = fstyle.fracDen();
var numer = buildGroup(group.value.numer, options.withStyle(nstyle));
var numernumer = makeSpan([fstyle.reset(), nstyle.cls()], [numer]);
var numerreset = makeSpan([fstyle.reset(), nstyle.cls()], [numer]);
var denom = buildGroup(group.value.denom, options.withStyle(dstyle));
var denomdenom = makeSpan([fstyle.reset(), dstyle.cls()], [denom])
var fontSizer = buildCommon.makeFontSizer(options,
Math.max(numer.maxFontSize, denom.maxFontSize));
var line = makeSpan([options.style.reset(), Style.TEXT.cls(), "line"]);
var numerrow = makeSpan(["mfracnum"], [fontSizer, numernumer]);
var mid = makeSpan(["mfracmid"], [fontSizer, line]);
var denomrow = makeSpan(["mfracden"], [fontSizer, denomdenom]);
var denomreset = makeSpan([fstyle.reset(), dstyle.cls()], [denom])
var theta = fontMetrics.metrics.defaultRuleThickness / options.style.sizeMultiplier;
var mid = makeSpan([options.style.reset(), Style.TEXT.cls(), "frac-line"]);
mid.height = theta;
var u, v, phi;
if (fstyle.size === Style.DISPLAY.size) {
u = fontMetrics.metrics.num1;
@ -310,30 +278,20 @@ var groupTypes = {
v += phi - ((a - 0.5 * theta) - (denom.height - v));
}
numerrow.style.top = -u + "em";
mid.style.top = -(a - 0.5 * theta) + "em";
denomrow.style.top = v + "em";
var midShift = -(a - 0.5 * theta);
numerrow.height = numerrow.height + u;
numerrow.depth = 0;
denomrow.height = 0;
denomrow.depth = denomrow.depth + v;
var fixIE = makeSpan(["fix-ie"], [
fontSizer, new domTree.textNode("\u00a0")]);
var frac = makeSpan([], [numerrow, mid, denomrow, fixIE]);
var frac = buildCommon.makeVList([
{type: "elem", elem: denomreset, shift: v},
{type: "elem", elem: mid, shift: midShift},
{type: "elem", elem: numerreset, shift: -u}
], "individualShift", null, options);
frac.height *= fstyle.sizeMultiplier / options.style.sizeMultiplier;
frac.depth *= fstyle.sizeMultiplier / options.style.sizeMultiplier;
var wrap = makeSpan(
[options.style.reset(), fstyle.cls()], [frac]);
return makeSpan(["minner"], [
makeSpan(["mfrac"], [wrap])
], options.getColor());
return makeSpan(
["minner", "mfrac", options.style.reset(), fstyle.cls()],
[frac], options.getColor());
},
color: function(group, options, prev) {
@ -434,26 +392,18 @@ var groupTypes = {
},
sqrt: function(group, options, prev) {
var innerGroup = buildGroup(group.value.body,
var inner = buildGroup(group.value.body,
options.withStyle(options.style.cramp()));
var fontSizer = buildCommon.makeFontSizer(
options, Math.max(innerGroup.maxFontSize, 1.0));
// The theta variable in the TeXbook
var lineWidth = fontMetrics.metrics.defaultRuleThickness;
var lineInner =
makeSpan([options.style.reset(), Style.TEXT.cls(), "line"]);
lineInner.maxFontSize = 1.0;
var line = makeSpan(["sqrt-line"], [fontSizer, lineInner]);
var inner = makeSpan(["sqrt-inner"], [fontSizer, innerGroup]);
var fixIE = makeSpan(
["fix-ie"], [fontSizer, new domTree.textNode("\u00a0")]);
var theta = fontMetrics.metrics.defaultRuleThickness /
options.style.sizeMultiplier;
var line = makeSpan(
[options.style.reset(), Style.TEXT.cls(), "sqrt-line"], [],
options.getColor());
line.height = theta;
line.maxFontSize = 1.0;
var phi = theta;
if (options.style.id < Style.TEXT.id) {
phi = fontMetrics.metrics.xHeight;
@ -467,18 +417,19 @@ var groupTypes = {
var delim = makeSpan(["sqrt-sign"], [
delimiter.customSizedDelim("\\surd", minDelimiterHeight,
false, options, group.mode)]);
false, options, group.mode)],
options.getColor());
var delimDepth = delim.height + delim.depth;
var delimDepth = (delim.height + delim.depth) - theta;
if (delimDepth > inner.height + inner.depth + psi) {
psi = (psi + delimDepth - inner.height - inner.depth) / 2;
}
delim.style.top = (-inner.height - psi + delim.height - theta) + "em";
line.style.top = (-inner.height - psi) + "em";
line.height = inner.height + psi + 2 * theta;
delimShift = -(inner.height + psi + theta) + delim.height;
delim.style.top = delimShift + "em";
delim.height -= delimShift;
delim.depth += delimShift;
// We add a special case here, because even when `inner` is empty, we
// still get a line. So, we use a simple heuristic to decide if we
@ -489,7 +440,12 @@ var groupTypes = {
if (inner.height === 0 && inner.depth === 0) {
body = makeSpan();
} else {
body = makeSpan(["sqrt-body"], [line, inner, fixIE]);
body = buildCommon.makeVList([
{type: "elem", elem: inner},
{type: "kern", size: psi},
{type: "elem", elem: line},
{type: "kern", size: theta}
], "firstBaseline", null, options);
}
return makeSpan(["sqrt", "mord"], [delim, body]);
@ -499,26 +455,22 @@ var groupTypes = {
var innerGroup = buildGroup(group.value.body,
options.withStyle(options.style.cramp()));
var fontSizer = buildCommon.makeFontSizer(options, innerGroup.maxFontSize);
// The theta variable in the TeXbook
var lineWidth = fontMetrics.metrics.defaultRuleThickness /
var theta = fontMetrics.metrics.defaultRuleThickness /
options.style.sizeMultiplier;
var line = makeSpan(
["overline-line"], [fontSizer, makeSpan([options.style.reset(), Style.TEXT.cls(), "line"])]);
var inner = makeSpan(["overline-inner"], [fontSizer, innerGroup]);
var fixIE = makeSpan(
["fix-ie"], [fontSizer, new domTree.textNode("\u00a0")]);
[options.style.reset(), Style.TEXT.cls(), "overline-line"]);
line.height = theta;
line.maxFontSize = 1.0;
line.style.top = (-inner.height - 3 * lineWidth) + "em";
// The line is supposed to have 1 extra line width above it in height
// (TeXbook pg. 443, nr. 9)
line.height = inner.height + 5 * lineWidth;
var vlist = buildCommon.makeVList([
{type: "elem", elem: innerGroup},
{type: "kern", size: 3 * theta},
{type: "elem", elem: line},
{type: "kern", size: theta}
], "firstBaseline", null, options);
return makeSpan(["overline", "mord"], [
line, inner, fixIE
], options.getColor());
return makeSpan(["overline", "mord"], [vlist], options.getColor());
},
sizing: function(group, options, prev) {

View File

@ -77,23 +77,19 @@ var makeLargeDelim = function(delim, size, center, options, mode) {
};
// Make an inner span with the given offset and in the given font
var makeInner = function(symbol, offset, font, mode) {
var makeInner = function(symbol, font, mode) {
var sizeClass;
if (font === "Size1-Regular") {
sizeClass = "size1";
sizeClass = "delim-size1";
} else if (font === "Size4-Regular") {
sizeClass = "size4";
sizeClass = "delim-size4";
}
var inner = makeSpan(
["delimsizinginner", sizeClass],
[makeSpan([], [buildCommon.makeText(symbol, font, mode)])]);
inner.style.top = offset + "em";
inner.height -= offset;
inner.depth += offset;
return inner;
return {type: "elem", elem: inner};
};
var makeStackedDelim = function(delim, heightTotal, center, options, mode) {
@ -102,7 +98,6 @@ var makeStackedDelim = function(delim, heightTotal, center, options, mode) {
top = repeat = bottom = delim;
middle = null;
var font = "Size1-Regular";
var overlap = false;
// We set the parts and font based on the symbol. Note that we use
// '\u23d0' instead of '|' and '\u2016' instead of '\\|' for the
@ -123,62 +118,44 @@ var makeStackedDelim = function(delim, heightTotal, center, options, mode) {
top = "\\Uparrow";
repeat = "\u2016";
bottom = "\\Downarrow";
// For some reason, the sizes of this one delimiter don't work out
// right, so we shrink it a bit to make it now add an extraneous
// repeating part
if (height + depth <= 1.21) {
height -= 0.01;
depth -= 0.01;
}
} else if (delim === "|" || delim === "\\vert") {
overlap = true;
} else if (delim === "\\|" || delim === "\\Vert") {
overlap = true;
} else if (delim === "[" || delim === "\\lbrack") {
top = "\u23a1";
repeat = "\u23a2";
bottom = "\u23a3";
font = "Size4-Regular";
overlap = true;
} else if (delim === "]" || delim === "\\rbrack") {
top = "\u23a4";
repeat = "\u23a5";
bottom = "\u23a6";
font = "Size4-Regular";
overlap = true;
} else if (delim === "\\lfloor") {
repeat = top = "\u23a2";
bottom = "\u23a3";
font = "Size4-Regular";
overlap = true;
} else if (delim === "\\lceil") {
top = "\u23a1";
repeat = bottom = "\u23a2";
font = "Size4-Regular";
overlap = true;
} else if (delim === "\\rfloor") {
repeat = top = "\u23a5";
bottom = "\u23a6";
font = "Size4-Regular";
overlap = true;
} else if (delim === "\\rceil") {
top = "\u23a4";
repeat = bottom = "\u23a5";
font = "Size4-Regular";
overlap = true;
} else if (delim === "(") {
top = "\u239b";
repeat = "\u239c";
bottom = "\u239d";
font = "Size4-Regular";
overlap = true;
} else if (delim === ")") {
top = "\u239e";
repeat = "\u239f";
bottom = "\u23a0";
font = "Size4-Regular";
overlap = true;
} else if (delim === "\\{" || delim === "\\lbrace") {
top = "\u23a7";
middle = "\u23a8";
@ -196,7 +173,6 @@ var makeStackedDelim = function(delim, heightTotal, center, options, mode) {
bottom = "\u23b7";
repeat = "\ue000";
font = "Size4-Regular";
overlap = true;
}
// Get the metrics of the three sections
@ -234,32 +210,16 @@ var makeStackedDelim = function(delim, heightTotal, center, options, mode) {
// Keep a list of the inner spans
var inners = [];
// Add the top symbol
inners.push(
makeInner(top, topMetrics.height - height, font, mode));
// Add the bottom symbol
inners.push(makeInner(bottom, font, mode));
if (middle === null) {
var repeatHeight = realHeightTotal - topHeightTotal - bottomHeightTotal;
var symbolCount = Math.ceil(repeatHeight / repeatHeightTotal);
var overlapAmount;
if (overlap) {
// 2 * overlapAmount + repeatHeight =
// (symbolCount - 1) * (repeatHeightTotal - overlapAmount) +
// repeatHeightTotal
overlapAmount = (symbolCount * repeatHeightTotal -
repeatHeight) / (symbolCount + 1);
} else {
overlapAmount = 0;
}
// Add repeat symbols until there's only space for the bottom symbol
var currHeight = height - topHeightTotal + overlapAmount;
for (var i = 0; i < symbolCount; i++) {
inners.push(
makeInner(repeat,
repeatMetrics.height - currHeight, font, mode));
currHeight -= repeatHeightTotal - overlapAmount;
inners.push(makeInner(repeat, font, mode));
}
} else {
// When there is a middle bit, we need the middle part and two repeated
@ -277,40 +237,25 @@ var makeStackedDelim = function(delim, heightTotal, center, options, mode) {
Math.ceil(bottomRepeatHeight / repeatHeightTotal);
// Add the top repeated part
var currHeight = height - topHeightTotal;
for (var i = 0; i < topSymbolCount; i++) {
inners.push(
makeInner(repeat,
repeatMetrics.height - currHeight, font, mode));
currHeight -= repeatHeightTotal;
inners.push(makeInner(repeat, font, mode));
}
// Add the middle piece
var midPoint = realHeightTotal / 2 - depth;
inners.push(
makeInner(middle,
middleMetrics.height - midPoint - middleHeightTotal / 2,
font, mode));
inners.push(makeInner(middle, font, mode));
// Add the bottom repeated part
currHeight = midPoint - middleHeightTotal / 2;
for (var i = 0; i < bottomSymbolCount; i++) {
inners.push(
makeInner(repeat,
repeatMetrics.height - currHeight, font, mode));
currHeight -= repeatHeightTotal;
inners.push(makeInner(repeat, font, mode));
}
}
// Add the bottom symbol
inners.push(
makeInner(bottom, depth - bottomMetrics.depth, font, mode));
inners.push(makeInner(top, font, mode));
var fixIE = makeSpan(["fix-ie"], [new domTree.textNode("\u00a0")]);
inners.push(fixIE);
var inner = buildCommon.makeVList(inners, "bottom", depth, options);
return styleWrap(
makeSpan(["delimsizing", "mult"], inners, options.getColor()),
makeSpan(["delimsizing", "mult"], [inner], options.getColor()),
Style.TEXT, options);
};

View File

@ -34,11 +34,6 @@ big parens
font-family: KaTeX_AMS;
}
.fix-ie {
display: inline-table;
table-layout: fixed;
}
// This value is also used in fontMetrics.js, if you change it make sure the
// values match.
@ptperem: 10.0;
@ -171,52 +166,35 @@ big parens
position: relative;
}
.baseline-align-hack-outer() {
.vlist {
display: inline-block;
}
.baseline-align-hack-middle() {
display: block;
height: 0;
}
> span {
display: block;
height: 0;
position: relative;
.baseline-align-hack-inner() {
display: inline-block;
> span {
display: inline-block;
}
}
.baseline-fix {
display: inline-table;
table-layout: fixed;
}
}
.msupsub {
.baseline-align-hack-outer;
text-align: left;
.msup,
.msub,
.fix-ie {
.baseline-align-hack-middle;
position: relative;
> span {
.baseline-align-hack-inner;
}
}
}
.mfrac {
.baseline-align-hack-outer;
.mfracnum,
.mfracmid,
.mfracden,
.fix-ie {
.baseline-align-hack-middle;
position: relative;
> span > span {
text-align: center;
> span {
.baseline-align-hack-inner;
}
}
.mfracmid > .line {
.frac-line {
width: 100%;
&:before {
@ -316,21 +294,8 @@ big parens
}
.overline {
.baseline-align-hack-outer;
> .overline-line,
> .overline-inner,
> .fix-ie {
.baseline-align-hack-middle;
position: relative;
text-align: center;
> span {
.baseline-align-hack-inner;
}
}
> .overline-line > .line {
.overline-line {
width: 100%;
&:before {
@ -355,37 +320,22 @@ big parens
position: relative;
}
> .sqrt-body {
.baseline-align-hack-outer;
.sqrt-line {
width: 100%;
> .sqrt-line,
> .sqrt-inner,
> .fix-ie {
.baseline-align-hack-middle;
position: relative;
> span {
.baseline-align-hack-inner;
}
&:before {
border-bottom-style: solid;
border-bottom-width: 1px;
content: "";
display: block;
}
> .sqrt-line > .line {
width: 100%;
&:before {
border-bottom-style: solid;
border-bottom-width: 1px;
content: "";
display: block;
}
&:after {
border-bottom-style: solid;
border-bottom-width: 0.04em;
content: "";
display: block;
margin-top: -1px;
}
&:after {
border-bottom-style: solid;
border-bottom-width: 0.04em;
content: "";
display: block;
margin-top: -1px;
}
}
}
@ -434,19 +384,11 @@ big parens
&.size4 { font-family: KaTeX_Size4; }
&.mult {
.baseline-align-hack-outer;
> .fix-ie,
> .delimsizinginner {
.baseline-align-hack-middle;
position: relative;
&.size1 > span {
font-family: Katex_Size1;
}
&.size4 > span {
font-family: Katex_Size4;
}
.delim-size1 > span {
font-family: Katex_Size1;
}
.delim-size4 > span {
font-family: Katex_Size4;
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB