Fix exponential behavior in accent production (#834)

src/functions.js was returning two properties referring to the base; since buildHTML runs `JSON.parse(JSON.stringify(tree))` to get an immutable copy, that meant we'd traverse and serialize and parse an exponentially-sized tree.

Test Plan: `\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{\breve{A}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}` renders instantly; previously, it reliably timed out with even half that depth.
This commit is contained in:
Sophie Alpert
2017-08-30 04:11:33 -07:00
committed by Kevin Barabash
parent d36ca4a2fa
commit b27d7011d1
3 changed files with 12 additions and 7 deletions

View File

@@ -1576,7 +1576,7 @@ groupTypes.horizBrace = function(group, options) {
groupTypes.accentUnder = function(group, options) {
// Treat under accents much like underlines.
const innerGroup = buildGroup(group.value.body, options);
const innerGroup = buildGroup(group.value.base, options);
const accentBody = stretchy.svgSpan(group, options);
const kern = (/tilde/.test(group.value.label) ? 0.12 : 0);

View File

@@ -656,7 +656,6 @@ defineFunction([
label: context.funcName,
isStretchy: isStretchy,
isShifty: isShifty,
value: ordargument(base),
base: base,
};
});
@@ -677,7 +676,6 @@ defineFunction([
label: context.funcName,
isStretchy: false,
isShifty: true,
value: ordargument(base),
base: base,
};
});
@@ -704,12 +702,11 @@ defineFunction([
], {
numArgs: 1,
}, function(context, args) {
const body = args[0];
const base = args[0];
return {
type: "accentUnder",
label: context.funcName,
value: ordargument(body),
body: body,
base: base,
};
});

View File

@@ -442,6 +442,14 @@ c-1 5-5 9-11 9h-2L532 67 19 159h-2c-5 0-9-4-11-9l-5-22c-1-6 2-12 8-13z'/>`,
<line x1='0' y1='100%' x2='100%' y2='0' stroke-width='0.046em'/>`,
};
const groupLength = function(arg) {
if (arg.type === "ordgroup") {
return arg.value.length;
} else {
return 1;
}
};
const svgSpan = function(group, options) {
// Create a span with inline SVG for the element.
const label = group.value.label.substr(1);
@@ -453,7 +461,7 @@ const svgSpan = function(group, options) {
if (utils.contains(["widehat", "widetilde", "undertilde"], label)) {
// There are four SVG images available for each function.
// Choose a taller image when there are more characters.
const numChars = group.value.value.length;
const numChars = groupLength(group.value.base);
if (numChars > 5) {
height = 0.312;
imageName = (label === "widehat" ? "widehat" : "tilde") + "4";