diff --git a/README.md b/README.md index c7de02a7..e39696a4 100644 --- a/README.md +++ b/README.md @@ -50,6 +50,7 @@ You can provide an object of options as the last argument to `katex.render` and - `errorColor`: `string`. A color string given in the format `"#XXX"` or `"#XXXXXX"`. This option determines the color which unsupported commands are rendered in. (default: `#cc0000`) - `macros`: `object`. A collection of custom macros. Each macro is a property with a name like `\name` (written `"\\name"` in JavaScript) which maps to a string that describes the expansion of the macro. - `colorIsTextColor`: `boolean`. If `true`, `\color` will work like LaTeX's `\textcolor`, and take two arguments (e.g., `\color{blue}{hello}`), which restores the old behavior of KaTeX (pre-0.8.0). If `false` (the default), `\color` will work like LaTeX's `\color`, and take one argument (e.g., `\color{blue}hello`). In both cases, `\textcolor` works as in LaTeX (e.g., `\textcolor{blue}{hello}`). +- `maxSize`: `number`. If non-zero, all user-specified sizes, e.g. in `\rule{500em}{500em}`, will be capped to `maxSize` ems. Otherwise, users can make elements and spaces arbitrarily large (the default behavior). For example: diff --git a/src/Options.js b/src/Options.js index 55cdfd23..60dffc09 100644 --- a/src/Options.js +++ b/src/Options.js @@ -51,6 +51,7 @@ class Options { this.phantom = data.phantom; this.font = data.font; this.sizeMultiplier = sizeMultipliers[this.size - 1]; + this.maxSize = data.maxSize; this._fontMetrics = null; } @@ -66,6 +67,7 @@ class Options { color: this.color, phantom: this.phantom, font: this.font, + maxSize: this.maxSize, }; for (const key in extension) { diff --git a/src/Settings.js b/src/Settings.js index 26a93ee2..efab9ce0 100644 --- a/src/Settings.js +++ b/src/Settings.js @@ -24,6 +24,7 @@ class Settings { this.errorColor = utils.deflt(options.errorColor, "#cc0000"); this.macros = options.macros || {}; this.colorIsTextColor = utils.deflt(options.colorIsTextColor, false); + this.maxSize = Math.max(0, utils.deflt(options.maxSize, Infinity)); } } diff --git a/src/buildTree.js b/src/buildTree.js index aa3e24eb..773d326e 100644 --- a/src/buildTree.js +++ b/src/buildTree.js @@ -16,6 +16,7 @@ const buildTree = function(tree, expression, settings) { // Setup the default options const options = new Options({ style: startStyle, + maxSize: settings.maxSize, }); // `buildHTML` sometimes messes with the parse tree (like turning bins -> diff --git a/src/units.js b/src/units.js index f60550e9..0efdb0b6 100644 --- a/src/units.js +++ b/src/units.js @@ -90,7 +90,7 @@ const calculateSize = function(sizeValue, options) { scale *= unitOptions.sizeMultiplier / options.sizeMultiplier; } } - return sizeValue.number * scale; + return Math.min(sizeValue.number * scale, options.maxSize); }; module.exports = { diff --git a/test/katex-spec.js b/test/katex-spec.js index 4a217db2..06e78f81 100644 --- a/test/katex-spec.js +++ b/test/katex-spec.js @@ -2308,3 +2308,25 @@ describe("Unicode", function() { expect("ΓΔΘΞΠΣΦΨΩ").toParse(); }); }); + +describe("The maxSize setting", function() { + const rule = "\\rule{999em}{999em}"; + + it("should clamp size when set", function() { + const built = getBuilt(rule, new Settings({maxSize: 5}))[0]; + expect(built.style.borderRightWidth).toEqual("5em"); + expect(built.style.borderTopWidth).toEqual("5em"); + }); + + it("should not clamp size when not set", function() { + const built = getBuilt(rule)[0]; + expect(built.style.borderRightWidth).toEqual("999em"); + expect(built.style.borderTopWidth).toEqual("999em"); + }); + + it("should make zero-width rules if a negative maxSize is passed", function() { + const built = getBuilt(rule, new Settings({maxSize: -5}))[0]; + expect(built.style.borderRightWidth).toEqual("0em"); + expect(built.style.borderTopWidth).toEqual("0em"); + }); +});