Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
- KaTeX#534: Implement getTypeOfGroup for font groups.
- KaTeX#533, KaTeX#541: Improve the ways spaces are applied to lists. Since
  CSS adjacency implements mathematical spacing, it's incorrect to
  introduce "convenience spans" for spaces and display changes into
  the generated HTML -- those spans break adjacency. Apply display
  changes directly, and shift space spans into adjacent atoms.

Requires updates to two screenshotter tests, LimitControls and
SupSubLeftAlignReset. The new results for these tests are closer
to TeX output than the old results.

Also requires updates to Jasmine tests, since those assumed output
structures that have changed.
  • Loading branch information
kohler committed Nov 26, 2016
1 parent 1e9185c commit 86752d4
Show file tree
Hide file tree
Showing 14 changed files with 75 additions and 16 deletions.
11 changes: 11 additions & 0 deletions src/buildCommon.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,16 @@ var makeSpan = function(classes, children, options) {
return span;
};

/**
* Prepends the given children to the given span, updating height, depth, and
* maxFontSize.
*/
var prependChildren = function(span, children) {
span.children = children.concat(span.children);

sizeElementFromChildren(span);
};

/**
* Makes a document fragment with the given list of children.
*/
Expand Down Expand Up @@ -447,6 +457,7 @@ module.exports = {
makeFragment: makeFragment,
makeVList: makeVList,
makeOrd: makeOrd,
prependChildren: prependChildren,
sizingMultiplier: sizingMultiplier,
spacingFunctions: spacingFunctions,
};
68 changes: 56 additions & 12 deletions src/buildHTML.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,56 @@ var utils = require("./utils");

var makeSpan = buildCommon.makeSpan;

var isSpace = function(node) {
return node instanceof domTree.span && node.classes[0] === "mspace";
};

/**
* Take a list of nodes, build them in order, and return a list of the built
* nodes. This function handles the `prev` node correctly, and passes the
* previous element from the list as the prev of the next element.
* previous element from the list as the prev of the next element, ignoring
* spaces. documentFragments are flattened into their contents, so the
* returned list contains no fragments.
*/
var buildExpression = function(expression, options, prev) {
// Parse expressions into `groups`.
var groups = [];
for (var i = 0; i < expression.length; i++) {
var group = expression[i];
groups.push(buildGroup(group, options, prev));
prev = group;
var output = buildGroup(group, options, prev);
if (output instanceof domTree.documentFragment) {
Array.prototype.push.apply(groups, output.children);
} else {
groups.push(output);
}
if (!isSpace(output)) {
prev = group;
}
}
// At this point `groups` consists entirely of `symbolNode`s and `span`s.

// Explicit spaces (e.g., \;, \,) should be ignored with respect to atom
// spacing (e.g., "add thick space between mord and mrel"). Since CSS
// adjacency rules implement atom spacing, spaces should be invisible to
// CSS. So we shift them into the atoms themselves.
var lastSpace = -1;
for (i = 0; i < groups.length; i++) {
if (isSpace(groups[i])) {
if (lastSpace === -1) {
lastSpace = i;
}
} else if (lastSpace >= 0) {
var node = groups[i];
if (node instanceof domTree.symbolNode) {
node = groups[i] = makeSpan(node.classes, [node]);
}
buildCommon.prependChildren(node,
groups.splice(lastSpace, i - lastSpace));
i = lastSpace;
lastSpace = -1;
}
}

return groups;
};

Expand Down Expand Up @@ -80,12 +118,13 @@ var getTypeOfGroup = function(group) {
return getTypeOfGroup(group.value.base);
} else if (group.type === "llap" || group.type === "rlap") {
return getTypeOfGroup(group.value);
} else if (group.type === "color") {
return getTypeOfGroup(group.value.value);
} else if (group.type === "sizing") {
return getTypeOfGroup(group.value.value);
} else if (group.type === "styling") {
return getTypeOfGroup(group.value.value);
} else if (group.type === "color" || group.type === "sizing"
|| group.type === "styling") {
// Return type of rightmost element of group.
var atoms = group.value.value;
return getTypeOfGroup(atoms[atoms.length - 1]);
} else if (group.type === "font") {
return getTypeOfGroup(group.value.body);
} else if (group.type === "delimsizing") {
return groupToType[group.value.delimType];
} else {
Expand Down Expand Up @@ -697,14 +736,14 @@ groupTypes.spacing = function(group, options, prev) {
// things has an entry in the symbols table, so these will be turned
// into appropriate outputs.
return makeSpan(
["mord", "mspace"],
["mspace"],
[buildCommon.mathsym(group.value, group.mode)]
);
} else {
// Other kinds of spaces are of arbitrary width. We use CSS to
// generate these.
return makeSpan(
["mord", "mspace",
["mspace",
buildCommon.spacingFunctions[group.value].className]);
}
};
Expand Down Expand Up @@ -1109,7 +1148,12 @@ groupTypes.styling = function(group, options, prev) {
var inner = buildExpression(
group.value.value, newOptions, prev);

return makeSpan([options.style.reset(), newStyle.cls()], inner, newOptions);
// Add size-resetting classes to the inner list.
for (var i = 0; i < inner.length; i++) {
inner[i].classes.push(options.style.reset(), newStyle.cls());
}

return new buildCommon.makeFragment(inner);
};

groupTypes.font = function(group, options, prev) {
Expand Down
9 changes: 5 additions & 4 deletions test/katex-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1581,7 +1581,8 @@ describe("A bin builder", function() {

it("should correctly interact with color objects", function() {
expect(getBuilt("\\blue{x}+y")[1].classes).toContain("mbin");
expect(getBuilt("\\blue{x+}+y")[1].classes).toContain("mord");
expect(getBuilt("\\blue{x+}+y")[1].classes).toContain("mbin");
expect(getBuilt("\\blue{x+}+y")[2].classes).toContain("mord");
});
});

Expand Down Expand Up @@ -1695,17 +1696,17 @@ describe("A phantom builder", function() {
});

it("should make the children transparent", function() {
var children = getBuilt("\\phantom{x+1}")[0].children;
var children = getBuilt("\\phantom{x+1}");
expect(children[0].style.color).toBe("transparent");
expect(children[1].style.color).toBe("transparent");
expect(children[2].style.color).toBe("transparent");
});

it("should make all descendants transparent", function() {
var children = getBuilt("\\phantom{x+\\blue{1}}")[0].children;
var children = getBuilt("\\phantom{x+\\blue{1}}");
expect(children[0].style.color).toBe("transparent");
expect(children[1].style.color).toBe("transparent");
expect(children[2].children[0].style.color).toBe("transparent");
expect(children[2].style.color).toBe("transparent");
});
});

Expand Down
Binary file added test/screenshotter/images/BoldSpacing-chrome.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/screenshotter/images/BoldSpacing-firefox.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/screenshotter/images/ColorSpacing-chrome.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/screenshotter/images/LimitControls-chrome.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/screenshotter/images/LimitControls-firefox.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/screenshotter/images/SupSubLeftAlignReset-chrome.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/screenshotter/images/SupSubLeftAlignReset-firefox.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions test/screenshotter/ss_data.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ ArrayType: 1\begin{array}{c}2\\3\end{array}4
Baseline: a+b-c\cdot d/e
BasicTest: a
BinomTest: \dbinom{a}{b}\tbinom{a}{b}^{\binom{a}{b}+17}
BoldSpacing: \mathbf{A}^2+\mathbf{B}_3*\mathscr{C}'
Cases: |
f(a,b)=\begin{cases}
a+1&\text{if }b\text{ is odd} \\
Expand All @@ -36,6 +37,7 @@ Cases: |
Colors:
tex: \blue{a}\color{#0f0}{b}\color{red}{c}
nolatex: different syntax and different scope
ColorSpacing: \color{black}{\displaystyle \int x} + 1
DashesAndQuotes: \text{``a'' b---c -- d----`e'-{-}-f}--``x''
DeepFontSizing:
tex: |
Expand Down Expand Up @@ -82,6 +84,7 @@ MathRm: \mathrm{Ax2k\breve{a}\omega\Omega\imath+\KaTeX}
MathSf: \mathsf{Ax2k\breve{a}\omega\Omega\imath+\KaTeX}
MathScr: \mathscr{Ax2k\breve{a}\omega\Omega\imath+\KaTeX}
MathTt: \mathtt{Ax2k\breve{a}\omega\Omega\imath+\KaTeX}
NegativeSpaceBetweenRel: A =\!= B
NestedFractions: |
\dfrac{\frac{a}{b}}{\frac{c}{d}}\dfrac{\dfrac{a}{b}}
{\dfrac{c}{d}}\frac{\frac{a}{b}}{\frac{c}{d}}
Expand Down

0 comments on commit 86752d4

Please sign in to comment.