diff --git a/docs/options.md b/docs/options.md
index d10458d6..70e9dec6 100644
--- a/docs/options.md
+++ b/docs/options.md
@@ -14,6 +14,7 @@ You can provide an object of options as the last argument to [`katex.render` and
- `throwOnError`: `boolean`. If `true` (the default), KaTeX will throw a `ParseError` when it encounters an unsupported command or invalid LaTeX. If `false`, KaTeX will render unsupported commands as text, and render invalid LaTeX as its source code with hover text giving the error, in the color given by `errorColor`.
- `errorColor`: `string`. A color string given in the format `"#XXX"` or `"#XXXXXX"`. This option determines the color that unsupported commands and invalid LaTeX are rendered in when `throwOnError` is set to `false`. (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, or a function that accepts an instance of `MacroExpander` as first argument and returns the expansion as a string. `MacroExpander` is an internal API and subject to non-backwards compatible changes. See [`src/macros.js`](https://github.com/KaTeX/KaTeX/blob/master/src/macros.js) for its usage. Single-character keys can also be included in which case the character will be redefined as the given macro (similar to TeX active characters). *This object will be modified* if the LaTeX code defines its own macros via `\gdef`, which enables consecutive calls to KaTeX to share state.
+- `minRuleThickness`: `number`. Specifies a minimum thickness, in ems, for fraction lines, `\sqrt` top lines, `{array}` vertical lines, `\hline`, `\hdashline`, `\underline`, `\overline`, and the borders of `\fbox`, `\boxed`, and `\fcolorbox`. The usual value for these items is `0.04`, so for `minRuleThickness` to be effective it should probably take a value slightly above `0.04`, say `0.05` or `0.06`. Negative values will be ignored.
- `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`. All user-specified sizes, e.g. in `\rule{500em}{500em}`, will be capped to `maxSize` ems. If set to `Infinity` (the default), users can make elements and spaces arbitrarily large.
- `maxExpand`: `number`. Limit the number of macro expansions to the specified number, to prevent e.g. infinite macro loops. If set to `Infinity`, the macro expander will try to fully expand as in LaTeX. (default: 1000)
diff --git a/src/Options.js b/src/Options.js
index ab92de27..8f20ae02 100644
--- a/src/Options.js
+++ b/src/Options.js
@@ -52,6 +52,7 @@ export type OptionsData = {
fontShape?: FontShape;
sizeMultiplier?: number;
maxSize: number;
+ minRuleThickness: number;
};
/**
@@ -76,6 +77,7 @@ class Options {
fontShape: FontShape;
sizeMultiplier: number;
maxSize: number;
+ minRuleThickness: number;
_fontMetrics: FontMetrics | void;
/**
@@ -95,6 +97,7 @@ class Options {
this.fontShape = data.fontShape || '';
this.sizeMultiplier = sizeMultipliers[this.size - 1];
this.maxSize = data.maxSize;
+ this.minRuleThickness = data.minRuleThickness;
this._fontMetrics = undefined;
}
@@ -114,6 +117,7 @@ class Options {
fontWeight: this.fontWeight,
fontShape: this.fontShape,
maxSize: this.maxSize,
+ minRuleThickness: this.minRuleThickness,
};
for (const key in extension) {
diff --git a/src/Settings.js b/src/Settings.js
index 14d5520d..59be4f22 100644
--- a/src/Settings.js
+++ b/src/Settings.js
@@ -24,6 +24,7 @@ export type SettingsOptions = {
throwOnError?: boolean;
errorColor?: string;
macros?: MacroMap;
+ minRuleThickness?: number;
colorIsTextColor?: boolean;
strict?: boolean | "ignore" | "warn" | "error" | StrictFunction;
maxSize?: number;
@@ -49,6 +50,7 @@ class Settings {
throwOnError: boolean;
errorColor: string;
macros: MacroMap;
+ minRuleThickness: number;
colorIsTextColor: boolean;
strict: boolean | "ignore" | "warn" | "error" | StrictFunction;
maxSize: number;
@@ -65,6 +67,10 @@ class Settings {
this.throwOnError = utils.deflt(options.throwOnError, true);
this.errorColor = utils.deflt(options.errorColor, "#cc0000");
this.macros = options.macros || {};
+ this.minRuleThickness = Math.max(
+ 0,
+ utils.deflt(options.minRuleThickness, 0)
+ );
this.colorIsTextColor = utils.deflt(options.colorIsTextColor, false);
this.strict = utils.deflt(options.strict, "warn");
this.maxSize = Math.max(0, utils.deflt(options.maxSize, Infinity));
diff --git a/src/buildCommon.js b/src/buildCommon.js
index 06d734d1..bab32096 100644
--- a/src/buildCommon.js
+++ b/src/buildCommon.js
@@ -423,7 +423,10 @@ const makeLineSpan = function(
thickness?: number,
) {
const line = makeSpan([className], [], options);
- line.height = thickness || options.fontMetrics().defaultRuleThickness;
+ line.height = Math.max(
+ thickness || options.fontMetrics().defaultRuleThickness,
+ options.minRuleThickness,
+ );
line.style.borderBottomWidth = line.height + "em";
line.maxFontSize = 1.0;
return line;
diff --git a/src/buildTree.js b/src/buildTree.js
index 32ff073f..61d301ac 100644
--- a/src/buildTree.js
+++ b/src/buildTree.js
@@ -13,6 +13,7 @@ const optionsFromSettings = function(settings: Settings) {
return new Options({
style: (settings.displayMode ? Style.DISPLAY : Style.TEXT),
maxSize: settings.maxSize,
+ minRuleThickness: settings.minRuleThickness,
});
};
diff --git a/src/delimiter.js b/src/delimiter.js
index a150406b..ad688fce 100644
--- a/src/delimiter.js
+++ b/src/delimiter.js
@@ -25,6 +25,7 @@ import ParseError from "./ParseError";
import Style from "./Style";
import {PathNode, SvgNode, SymbolNode} from "./domTree";
+import {sqrtPath} from "./svgGeometry";
import buildCommon from "./buildCommon";
import {getCharacterMetrics} from "./fontMetrics";
import symbols from "./symbols";
@@ -377,21 +378,11 @@ const sqrtSvg = function(
sqrtName: string,
height: number,
viewBoxHeight: number,
+ extraViniculum: number,
options: Options,
): SvgSpan {
- let alternate;
- if (sqrtName === "sqrtTall") {
- // sqrtTall is from glyph U23B7 in the font KaTeX_Size4-Regular
- // One path edge has a variable length. It runs from the viniculumn
- // to a point near (14 units) the bottom of the surd. The viniculum
- // is 40 units thick. So the length of the line in question is:
- const vertSegment = viewBoxHeight - 54 - vbPad;
- alternate = `M702 ${vbPad}H400000v40H742v${vertSegment}l-4 4-4 4c-.667.7
--2 1.5-4 2.5s-4.167 1.833-6.5 2.5-5.5 1-9.5 1h-12l-28-84c-16.667-52-96.667
--294.333-240-727l-212 -643 -85 170c-4-3.333-8.333-7.667-13 -13l-13-13l77-155
- 77-156c66 199.333 139 419.667 219 661 l218 661zM702 ${vbPad}H400000v40H742z`;
- }
- const pathNode = new PathNode(sqrtName, alternate);
+ const path = sqrtPath(sqrtName, extraViniculum, viewBoxHeight);
+ const pathNode = new PathNode(sqrtName, path);
const svg = new SvgNode([pathNode], {
// Note: 1000:1 ratio of viewBox to document em width.
@@ -425,6 +416,11 @@ const makeSqrtImage = function(
let sizeMultiplier = newOptions.sizeMultiplier; // default
+ // The standard sqrt SVGs each have a 0.04em thick viniculum.
+ // If Settings.minRuleThickness is larger than that, we add extraViniculum.
+ const extraViniculum = Math.max(0,
+ options.minRuleThickness - options.fontMetrics().sqrtRuleThickness);
+
// Create a span containing an SVG image of a sqrt symbol.
let span;
let spanHeight = 0;
@@ -440,34 +436,39 @@ const makeSqrtImage = function(
if (delim.type === "small") {
// Get an SVG that is derived from glyph U+221A in font KaTeX-Main.
- viewBoxHeight = 1000 + vbPad; // 1000 unit glyph height.
+ // 1000 unit normal glyph height.
+ viewBoxHeight = 1000 + 1000 * extraViniculum + vbPad;
if (height < 1.0) {
sizeMultiplier = 1.0; // mimic a \textfont radical
} else if (height < 1.4) {
sizeMultiplier = 0.7; // mimic a \scriptfont radical
}
- spanHeight = (1.0 + emPad) / sizeMultiplier;
- texHeight = 1.00 / sizeMultiplier;
- span = sqrtSvg("sqrtMain", spanHeight, viewBoxHeight, options);
+ spanHeight = (1.0 + extraViniculum + emPad) / sizeMultiplier;
+ texHeight = (1.00 + extraViniculum) / sizeMultiplier;
+ span = sqrtSvg("sqrtMain", spanHeight, viewBoxHeight, extraViniculum,
+ options);
span.style.minWidth = "0.853em";
advanceWidth = 0.833 / sizeMultiplier; // from the font.
} else if (delim.type === "large") {
// These SVGs come from fonts: KaTeX_Size1, _Size2, etc.
viewBoxHeight = (1000 + vbPad) * sizeToMaxHeight[delim.size];
- texHeight = sizeToMaxHeight[delim.size] / sizeMultiplier;
- spanHeight = (sizeToMaxHeight[delim.size] + emPad) / sizeMultiplier;
- span = sqrtSvg("sqrtSize" + delim.size, spanHeight, viewBoxHeight, options);
+ texHeight = (sizeToMaxHeight[delim.size] + extraViniculum) / sizeMultiplier;
+ spanHeight = (sizeToMaxHeight[delim.size] + extraViniculum + emPad)
+ / sizeMultiplier;
+ span = sqrtSvg("sqrtSize" + delim.size, spanHeight, viewBoxHeight,
+ extraViniculum, options);
span.style.minWidth = "1.02em";
advanceWidth = 1.0 / sizeMultiplier; // 1.0 from the font.
} else {
// Tall sqrt. In TeX, this would be stacked using multiple glyphs.
// We'll use a single SVG to accomplish the same thing.
- spanHeight = height + emPad;
- texHeight = height;
- viewBoxHeight = Math.floor(1000 * height) + vbPad;
- span = sqrtSvg("sqrtTall", spanHeight, viewBoxHeight, options);
+ spanHeight = height + extraViniculum + emPad;
+ texHeight = height + extraViniculum;
+ viewBoxHeight = Math.floor(1000 * height + extraViniculum) + vbPad;
+ span = sqrtSvg("sqrtTall", spanHeight, viewBoxHeight, extraViniculum,
+ options);
span.style.minWidth = "0.742em";
advanceWidth = 1.056;
}
@@ -482,7 +483,8 @@ const makeSqrtImage = function(
// This actually should depend on the chosen font -- e.g. \boldmath
// should use the thicker surd symbols from e.g. KaTeX_Main-Bold, and
// have thicker rules.
- ruleWidth: options.fontMetrics().sqrtRuleThickness * sizeMultiplier,
+ ruleWidth: (options.fontMetrics().sqrtRuleThickness + extraViniculum)
+ * sizeMultiplier,
};
};
diff --git a/src/domTree.js b/src/domTree.js
index 38ffd912..580cf1a7 100644
--- a/src/domTree.js
+++ b/src/domTree.js
@@ -13,7 +13,7 @@
*/
import {scriptFromCodepoint} from "./unicodeScripts";
import utils from "./utils";
-import svgGeometry from "./svgGeometry";
+import {path} from "./svgGeometry";
import type Options from "./Options";
import {DocumentFragment} from "./tree";
@@ -136,12 +136,16 @@ export type CssStyle = $Shape<{
backgroundColor: string,
borderBottomWidth: string,
borderColor: string,
+ borderRightStyle: string,
borderRightWidth: string,
borderTopWidth: string,
+ borderStyle: string;
+ borderWidth: string,
bottom: string,
color: string,
height: string,
left: string,
+ margin: string,
marginLeft: string,
marginRight: string,
marginTop: string,
@@ -529,7 +533,7 @@ export class PathNode implements VirtualNode {
constructor(pathName: string, alternate?: string) {
this.pathName = pathName;
- this.alternate = alternate; // Used only for tall \sqrt
+ this.alternate = alternate; // Used only for \sqrt
}
toNode(): Node {
@@ -539,7 +543,7 @@ export class PathNode implements VirtualNode {
if (this.alternate) {
node.setAttribute("d", this.alternate);
} else {
- node.setAttribute("d", svgGeometry.path[this.pathName]);
+ node.setAttribute("d", path[this.pathName]);
}
return node;
@@ -549,7 +553,7 @@ export class PathNode implements VirtualNode {
if (this.alternate) {
return ``;
} else {
- return ``;
+ return ``;
}
}
}
diff --git a/src/environments/array.js b/src/environments/array.js
index f36f1a3f..134f2d0c 100644
--- a/src/environments/array.js
+++ b/src/environments/array.js
@@ -174,6 +174,12 @@ const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
let body = new Array(nr);
const hlines = [];
+ const ruleThickness = Math.max(
+ // From LaTeX \showthe\arrayrulewidth. Equals 0.04 em.
+ (options.fontMetrics().arrayRuleWidth),
+ options.minRuleThickness, // User override.
+ );
+
// Horizontal spacing
const pt = 1 / options.fontMetrics().ptPerEm;
let arraycolsep = 5 * pt; // default value, i.e. \arraycolsep in article.cls
@@ -284,20 +290,15 @@ const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
cols.push(colSep);
}
- if (colDescr.separator === "|") {
+ if (colDescr.separator === "|" || colDescr.separator === ":") {
+ const lineType = (colDescr.separator === "|") ? "solid" : "dashed";
const separator = buildCommon.makeSpan(
["vertical-separator"], [], options
);
separator.style.height = totalHeight + "em";
- separator.style.verticalAlign =
- -(totalHeight - offset) + "em";
-
- cols.push(separator);
- } else if (colDescr.separator === ":") {
- const separator = buildCommon.makeSpan(
- ["vertical-separator", "vs-dashed"], [], options
- );
- separator.style.height = totalHeight + "em";
+ separator.style.borderRightWidth = `${ruleThickness}em`;
+ separator.style.borderRightStyle = lineType;
+ separator.style.margin = `0 -${ruleThickness / 2}em`;
separator.style.verticalAlign =
-(totalHeight - offset) + "em";
@@ -361,8 +362,9 @@ const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
// Add \hline(s), if any.
if (hlines.length > 0) {
- const line = buildCommon.makeLineSpan("hline", options, 0.05);
- const dashes = buildCommon.makeLineSpan("hdashline", options, 0.05);
+ const line = buildCommon.makeLineSpan("hline", options, ruleThickness);
+ const dashes = buildCommon.makeLineSpan("hdashline", options,
+ ruleThickness);
const vListElems = [{type: "elem", elem: body, shift: 0}];
while (hlines.length > 0) {
const hline = hlines.pop();
diff --git a/src/fontMetrics.js b/src/fontMetrics.js
index 868a5263..ead7559a 100644
--- a/src/fontMetrics.js
+++ b/src/fontMetrics.js
@@ -82,6 +82,14 @@ const sigmasAndXis = {
// The space between adjacent `|` columns in an array definition. From
// `\showthe\doublerulesep` in LaTeX. Equals 2.0 / ptPerEm.
doubleRuleSep: [0.2, 0.2, 0.2],
+
+ // The width of separator lines in {array} environments. From
+ // `\showthe\arrayrulewidth` in LaTeX. Equals 0.4 / ptPerEm.
+ arrayRuleWidth: [0.04, 0.04, 0.04],
+
+ // Two values from LaTeX source2e:
+ fboxsep: [0.3, 0.3, 0.3], // 3 pt / ptPerEm
+ fboxrule: [0.04, 0.04, 0.04], // 0.4 pt / ptPerEm
};
// This map contains a mapping from font name and character code to character
diff --git a/src/functions/enclose.js b/src/functions/enclose.js
index 9a5285a5..364e05a6 100644
--- a/src/functions/enclose.js
+++ b/src/functions/enclose.js
@@ -46,15 +46,24 @@ const htmlBuilder = (group, options) => {
// Add vertical padding
let vertPad = 0;
- // ref: LaTeX source2e: \fboxsep = 3pt; \fboxrule = .4pt
+ let ruleThickness = 0;
// ref: cancel package: \advance\totalheight2\p@ % "+2"
if (/box/.test(label)) {
- vertPad = label === "colorbox" ? 0.3 : 0.34;
+ ruleThickness = Math.max(
+ options.fontMetrics().fboxrule, // default
+ options.minRuleThickness, // User override.
+ );
+ vertPad = options.fontMetrics().fboxsep +
+ (label === "colorbox" ? 0 : ruleThickness);
} else {
vertPad = isSingleChar ? 0.2 : 0;
}
img = stretchy.encloseSpan(inner, label, vertPad, options);
+ if (/fbox|boxed|fcolorbox/.test(label)) {
+ img.style.borderStyle = "solid";
+ img.style.borderWidth = `${ruleThickness}em`;
+ }
imgShift = inner.depth + vertPad;
if (group.backgroundColor) {
@@ -111,6 +120,7 @@ const htmlBuilder = (group, options) => {
};
const mathmlBuilder = (group, options) => {
+ let fboxsep = 0;
const node = new mathMLTree.MathNode(
(group.label.indexOf("colorbox") > -1) ? "mpadded" : "menclose",
[mml.buildGroup(group.body, options)]
@@ -132,12 +142,17 @@ const mathmlBuilder = (group, options) => {
case "\\colorbox":
// doesn't have a good notation option. So use
// instead. Set some attributes that come included with .
- node.setAttribute("width", "+6pt");
- node.setAttribute("height", "+6pt");
- node.setAttribute("lspace", "3pt"); // LaTeX source2e: \fboxsep = 3pt
- node.setAttribute("voffset", "3pt");
+ fboxsep = options.fontMetrics().fboxsep *
+ options.fontMetrics().ptPerEm;
+ node.setAttribute("width", `+${2 * fboxsep}pt`);
+ node.setAttribute("height", `+${2 * fboxsep}pt`);
+ node.setAttribute("lspace", `${fboxsep}pt`); //
+ node.setAttribute("voffset", `${fboxsep}pt`);
if (group.label === "\\fcolorbox") {
- const thk = options.fontMetrics().defaultRuleThickness;
+ const thk = Math.max(
+ options.fontMetrics().fboxrule, // default
+ options.minRuleThickness, // user override
+ );
node.setAttribute("style", "border: " + thk + "em solid " +
String(group.borderColor));
}
diff --git a/src/functions/overline.js b/src/functions/overline.js
index 6a76eac0..4c11c14e 100644
--- a/src/functions/overline.js
+++ b/src/functions/overline.js
@@ -31,13 +31,14 @@ defineFunction({
const line = buildCommon.makeLineSpan("overline-line", options);
// Generate the vlist, with the appropriate kerns
+ const defaultRuleThickness = options.fontMetrics().defaultRuleThickness;
const vlist = buildCommon.makeVList({
positionType: "firstBaseline",
children: [
{type: "elem", elem: innerGroup},
- {type: "kern", size: 3 * line.height},
+ {type: "kern", size: 3 * defaultRuleThickness},
{type: "elem", elem: line},
- {type: "kern", size: line.height},
+ {type: "kern", size: defaultRuleThickness},
],
}, options);
diff --git a/src/functions/underline.js b/src/functions/underline.js
index e0bba1c3..36c1927f 100644
--- a/src/functions/underline.js
+++ b/src/functions/underline.js
@@ -29,13 +29,14 @@ defineFunction({
const line = buildCommon.makeLineSpan("underline-line", options);
// Generate the vlist, with the appropriate kerns
+ const defaultRuleThickness = options.fontMetrics().defaultRuleThickness;
const vlist = buildCommon.makeVList({
positionType: "top",
positionData: innerGroup.height,
children: [
- {type: "kern", size: line.height},
+ {type: "kern", size: defaultRuleThickness},
{type: "elem", elem: line},
- {type: "kern", size: 3 * line.height},
+ {type: "kern", size: 3 * defaultRuleThickness},
{type: "elem", elem: innerGroup},
],
}, options);
diff --git a/src/katex.less b/src/katex.less
index bcfee716..c95430f7 100644
--- a/src/katex.less
+++ b/src/katex.less
@@ -409,15 +409,10 @@
.mtable {
.vertical-separator {
display: inline-block;
- margin: 0 -0.025em;
- border-right: 0.05em solid;
+ // margin and border-right are set in Javascript
min-width: 1px; // Prevent Chrome from omitting a line.
}
- .vs-dashed {
- border-right: 0.05em dashed;
- }
-
.arraycolsep {
display: inline-block;
}
diff --git a/src/svgGeometry.js b/src/svgGeometry.js
index f0e5f0a5..25c999ec 100644
--- a/src/svgGeometry.js
+++ b/src/svgGeometry.js
@@ -1,61 +1,152 @@
// @flow
/**
- * This file provides support to domTree.js
+ * This file provides support to domTree.js and delimiter.js.
* It's a storehouse of path geometry for SVG images.
*/
// In all paths below, the viewBox-to-em scale is 1000:1.
-const hLinePad = 80; // padding above a sqrt viniculum.
+const hLinePad = 80; // padding above a sqrt viniculum. Prevents image cropping.
-const path: {[string]: string} = {
+// The viniculum of a \sqrt can be made thicker by a KaTeX rendering option.
+// Think of variable extraViniculum as two detours in the SVG path.
+// The detour begins at the lower left of the area labeled extraViniculum below.
+// The detour proceeds one extraViniculum distance up and slightly to the right,
+// displacing the radiused corner between surd and viniculum. The radius is
+// traversed as usual, then the detour resumes. It goes right, to the end of
+// the very long viniculumn, then down one extraViniculum distance,
+// after which it resumes regular path geometry for the radical.
+/* viniculum
+ /
+ /▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒←extraViniculum
+ / █████████████████████←0.04em (40 unit) std viniculum thickness
+ / /
+ / /
+ / /\
+ / / surd
+*/
+
+const sqrtMain = function(extraViniculum: number, hLinePad: number): string {
// sqrtMain path geometry is from glyph U221A in the font KaTeX Main
- // All surds have 80 units padding above the viniculumn.
- sqrtMain: `M95,${622 + hLinePad}c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,
--10,-9.5,-14c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54c44.2,-33.3,65.8,
--50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10s173,378,173,378c0.7,0,
-35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429c69,-144,104.5,-217.7,106.5,
--221c5.3,-9.3,12,-14,20,-14H400000v40H845.2724s-225.272,467,-225.272,467
-s-235,486,-235,486c-2.7,4.7,-9,7,-19,7c-6,0,-10,-1,-12,-3s-194,-422,-194,-422
-s-65,47,-65,47z M834 ${hLinePad}H400000v40H845z`,
+ return `M95,${622 + extraViniculum + hLinePad}
+c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14
+c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54
+c44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10
+s173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429
+c69,-144,104.5,-217.7,106.5,-221
+l${extraViniculum / 2.075} -${extraViniculum}
+c5.3,-9.3,12,-14,20,-14
+H400000v${40 + extraViniculum}H845.2724
+s-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7
+c-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47z
+Ml${834 + extraViniculum} ${hLinePad}h400000v${40 + extraViniculum}h-400000z`;
+};
+const sqrtSize1 = function(extraViniculum: number, hLinePad: number): string {
// size1 is from glyph U221A in the font KaTeX_Size1-Regular
- sqrtSize1: `M263,${601 + hLinePad}c0.7,0,18,39.7,52,119c34,79.3,68.167,
-158.7,102.5,238c34.3,79.3,51.8,119.3,52.5,120c340,-704.7,510.7,-1060.3,512,-1067
-c4.7,-7.3,11,-11,19,-11H40000v40H1012.3s-271.3,567,-271.3,567c-38.7,80.7,-84,
-175,-136,283c-52,108,-89.167,185.3,-111.5,232c-22.3,46.7,-33.8,70.3,-34.5,71
-c-4.7,4.7,-12.3,7,-23,7s-12,-1,-12,-1s-109,-253,-109,-253c-72.7,-168,-109.3,
--252,-110,-252c-10.7,8,-22,16.7,-34,26c-22,17.3,-33.3,26,-34,26s-26,-26,-26,-26
-s76,-59,76,-59s76,-60,76,-60z M1001 ${hLinePad}H40000v40H1012z`,
+ return `M263,${601 + extraViniculum + hLinePad}c0.7,0,18,39.7,52,119
+c34,79.3,68.167,158.7,102.5,238c34.3,79.3,51.8,119.3,52.5,120
+c340,-704.7,510.7,-1060.3,512,-1067
+l${extraViniculum / 2.084} -${extraViniculum}
+c4.7,-7.3,11,-11,19,-11
+H40000v${40 + extraViniculum}H1012.3
+s-271.3,567,-271.3,567c-38.7,80.7,-84,175,-136,283c-52,108,-89.167,185.3,-111.5,232
+c-22.3,46.7,-33.8,70.3,-34.5,71c-4.7,4.7,-12.3,7,-23,7s-12,-1,-12,-1
+s-109,-253,-109,-253c-72.7,-168,-109.3,-252,-110,-252c-10.7,8,-22,16.7,-34,26
+c-22,17.3,-33.3,26,-34,26s-26,-26,-26,-26s76,-59,76,-59s76,-60,76,-60z
+M${1001 + extraViniculum} ${hLinePad}h400000v${40 + extraViniculum}h-400000z`;
+};
+const sqrtSize2 = function(extraViniculum: number, hLinePad: number): string {
// size2 is from glyph U221A in the font KaTeX_Size2-Regular
- // The 80 units padding is most obvious here. Note start node at M1001 80.
- sqrtSize2: `M1001,${hLinePad}H400000v40H1013.1s-83.4,268,-264.1,840c-180.7,
-572,-277,876.3,-289,913c-4.7,4.7,-12.7,7,-24,7s-12,0,-12,0c-1.3,-3.3,-3.7,-11.7,
--7,-25c-35.3,-125.3,-106.7,-373.3,-214,-744c-10,12,-21,25,-33,39s-32,39,-32,39
-c-6,-5.3,-15,-14,-27,-26s25,-30,25,-30c26.7,-32.7,52,-63,76,-91s52,-60,52,-60
-s208,722,208,722c56,-175.3,126.3,-397.3,211,-666c84.7,-268.7,153.8,-488.2,207.5,
--658.5c53.7,-170.3,84.5,-266.8,92.5,-289.5c4,-6.7,10,-10,18,-10z
-M1001 ${hLinePad}H400000v40H1013z`,
+ return `M983 ${10 + extraViniculum + hLinePad}
+l${extraViniculum / 3.13} -${extraViniculum}
+c4,-6.7,10,-10,18,-10 H400000v${40 + extraViniculum}
+H1013.1s-83.4,268,-264.1,840c-180.7,572,-277,876.3,-289,913c-4.7,4.7,-12.7,7,-24,7
+s-12,0,-12,0c-1.3,-3.3,-3.7,-11.7,-7,-25c-35.3,-125.3,-106.7,-373.3,-214,-744
+c-10,12,-21,25,-33,39s-32,39,-32,39c-6,-5.3,-15,-14,-27,-26s25,-30,25,-30
+c26.7,-32.7,52,-63,76,-91s52,-60,52,-60s208,722,208,722
+c56,-175.3,126.3,-397.3,211,-666c84.7,-268.7,153.8,-488.2,207.5,-658.5
+c53.7,-170.3,84.5,-266.8,92.5,-289.5z
+M${1001 + extraViniculum} ${hLinePad}h400000v${40 + extraViniculum}h-400000z`;
+};
+const sqrtSize3 = function(extraViniculum: number, hLinePad: number): string {
// size3 is from glyph U221A in the font KaTeX_Size3-Regular
- sqrtSize3: `M424,${2398 + hLinePad}c-1.3,-0.7,-38.5,-172,-111.5,-514c-73,
--342,-109.8,-513.3,-110.5,-514c0,-2,-10.7,14.3,-32,49c-4.7,7.3,-9.8,15.7,-15.5,
-25c-5.7,9.3,-9.8,16,-12.5,20s-5,7,-5,7c-4,-3.3,-8.3,-7.7,-13,-13s-13,-13,-13,
--13s76,-122,76,-122s77,-121,77,-121s209,968,209,968c0,-2,84.7,-361.7,254,-1079
-c169.3,-717.3,254.7,-1077.7,256,-1081c4,-6.7,10,-10,18,-10H400000v40H1014.6
-s-87.3,378.7,-272.6,1166c-185.3,787.3,-279.3,1182.3,-282,1185c-2,6,-10,9,-24,9
-c-8,0,-12,-0.7,-12,-2z M1001 ${hLinePad}H400000v40H1014z`,
+ return `M424,${2398 + extraViniculum + hLinePad}
+c-1.3,-0.7,-38.5,-172,-111.5,-514c-73,-342,-109.8,-513.3,-110.5,-514
+c0,-2,-10.7,14.3,-32,49c-4.7,7.3,-9.8,15.7,-15.5,25c-5.7,9.3,-9.8,16,-12.5,20
+s-5,7,-5,7c-4,-3.3,-8.3,-7.7,-13,-13s-13,-13,-13,-13s76,-122,76,-122s77,-121,77,-121
+s209,968,209,968c0,-2,84.7,-361.7,254,-1079c169.3,-717.3,254.7,-1077.7,256,-1081
+l${extraViniculum / 4.223} -${extraViniculum}c4,-6.7,10,-10,18,-10 H400000
+v${40 + extraViniculum}H1014.6
+s-87.3,378.7,-272.6,1166c-185.3,787.3,-279.3,1182.3,-282,1185
+c-2,6,-10,9,-24,9
+c-8,0,-12,-0.7,-12,-2z M${1001 + extraViniculum} ${hLinePad}
+h400000v${40 + extraViniculum}h-400000z`;
+};
+const sqrtSize4 = function(extraViniculum: number, hLinePad: number): string {
// size4 is from glyph U221A in the font KaTeX_Size4-Regular
- sqrtSize4: `M473,${2713 + hLinePad}c339.3,-1799.3,509.3,-2700,510,-2702
-c3.3,-7.3,9.3,-11,18,-11H400000v40H1017.7s-90.5,478,-276.2,1466c-185.7,988,
--279.5,1483,-281.5,1485c-2,6,-10,9,-24,9c-8,0,-12,-0.7,-12,-2c0,-1.3,-5.3,-32,
--16,-92c-50.7,-293.3,-119.7,-693.3,-207,-1200c0,-1.3,-5.3,8.7,-16,30c-10.7,
-21.3,-21.3,42.7,-32,64s-16,33,-16,33s-26,-26,-26,-26s76,-153,76,-153s77,-151,
-77,-151c0.7,0.7,35.7,202,105,604c67.3,400.7,102,602.7,104,606z
-M1001 ${hLinePad}H400000v40H1017z`,
+ return `M473,${2713 + extraViniculum + hLinePad}
+c339.3,-1799.3,509.3,-2700,510,-2702 l${extraViniculum / 5.298} -${extraViniculum}
+c3.3,-7.3,9.3,-11,18,-11 H400000v${40 + extraViniculum}H1017.7
+s-90.5,478,-276.2,1466c-185.7,988,-279.5,1483,-281.5,1485c-2,6,-10,9,-24,9
+c-8,0,-12,-0.7,-12,-2c0,-1.3,-5.3,-32,-16,-92c-50.7,-293.3,-119.7,-693.3,-207,-1200
+c0,-1.3,-5.3,8.7,-16,30c-10.7,21.3,-21.3,42.7,-32,64s-16,33,-16,33s-26,-26,-26,-26
+s76,-153,76,-153s77,-151,77,-151c0.7,0.7,35.7,202,105,604c67.3,400.7,102,602.7,104,
+606zM${1001 + extraViniculum} ${hLinePad}h400000v${40 + extraViniculum}H1017.7z`;
+};
+const sqrtTall = function(
+ extraViniculum: number,
+ hLinePad: number,
+ viewBoxHeight: number
+): string {
+ // sqrtTall is from glyph U23B7 in the font KaTeX_Size4-Regular
+ // One path edge has a variable length. It runs vertically from the viniculumn
+ // to a point near (14 units) the bottom of the surd. The viniculum
+ // is normally 40 units thick. So the length of the line in question is:
+ const vertSegment = viewBoxHeight - 54 - hLinePad - extraViniculum;
+
+ return `M702 ${extraViniculum + hLinePad}H400000${40 + extraViniculum}
+H742v${vertSegment}l-4 4-4 4c-.667.7 -2 1.5-4 2.5s-4.167 1.833-6.5 2.5-5.5 1-9.5 1
+h-12l-28-84c-16.667-52-96.667 -294.333-240-727l-212 -643 -85 170
+c-4-3.333-8.333-7.667-13 -13l-13-13l77-155 77-156c66 199.333 139 419.667
+219 661 l218 661zM702 ${hLinePad}H400000v${40 + extraViniculum}H742z`;
+};
+
+export const sqrtPath = function(
+ size: string,
+ extraViniculum: number,
+ viewBoxHeight: number
+): string {
+ extraViniculum = 1000 * extraViniculum; // Convert from document ems to viewBox.
+ let path = "";
+
+ switch (size) {
+ case "sqrtMain":
+ path = sqrtMain(extraViniculum, hLinePad);
+ break;
+ case "sqrtSize1":
+ path = sqrtSize1(extraViniculum, hLinePad);
+ break;
+ case "sqrtSize2":
+ path = sqrtSize2(extraViniculum, hLinePad);
+ break;
+ case "sqrtSize3":
+ path = sqrtSize3(extraViniculum, hLinePad);
+ break;
+ case "sqrtSize4":
+ path = sqrtSize4(extraViniculum, hLinePad);
+ break;
+ case "sqrtTall":
+ path = sqrtTall(extraViniculum, hLinePad, viewBoxHeight);
+ }
+ return path;
+};
+
+export const path: {[string]: string} = {
// The doubleleftarrow geometry is from glyph U+21D0 in the font KaTeX Main
doubleleftarrow: `M262 157
l10-10c34-36 62.7-77 86-123 3.3-8 5-13.3 5-16 0-5.3-6.7-8-20-8-7.3
@@ -363,6 +454,3 @@ c4.7,-4.7,7,-9.3,7,-14c0,-9.3,-3.7,-15.3,-11,-18c-92.7,-56.7,-159,-133.7,-199,
c-2,2.7,-1,9.7,3,21c15.3,42,36.7,81.8,64,119.5c27.3,37.7,58,69.2,92,94.5z
M500 241 v40 H399408 v-40z M500 435 v40 H400000 v-40z`,
};
-
-
-export default {path};
diff --git a/test/screenshotter/images/Arrays-chrome.png b/test/screenshotter/images/Arrays-chrome.png
index ca55d366..98d8909d 100644
Binary files a/test/screenshotter/images/Arrays-chrome.png and b/test/screenshotter/images/Arrays-chrome.png differ
diff --git a/test/screenshotter/images/Arrays-firefox.png b/test/screenshotter/images/Arrays-firefox.png
index 1bd1d8e0..203ea348 100644
Binary files a/test/screenshotter/images/Arrays-firefox.png and b/test/screenshotter/images/Arrays-firefox.png differ
diff --git a/test/screenshotter/images/Sqrt-chrome.png b/test/screenshotter/images/Sqrt-chrome.png
index ec5b4f13..2e3c23ed 100644
Binary files a/test/screenshotter/images/Sqrt-chrome.png and b/test/screenshotter/images/Sqrt-chrome.png differ
diff --git a/test/screenshotter/images/Sqrt-firefox.png b/test/screenshotter/images/Sqrt-firefox.png
index c5de0b3d..81ed3627 100644
Binary files a/test/screenshotter/images/Sqrt-firefox.png and b/test/screenshotter/images/Sqrt-firefox.png differ
diff --git a/test/screenshotter/ss_data.yaml b/test/screenshotter/ss_data.yaml
index 61556742..2bd841b3 100644
--- a/test/screenshotter/ss_data.yaml
+++ b/test/screenshotter/ss_data.yaml
@@ -323,7 +323,9 @@ Spacing: |
\end{matrix}
Sqrt: |
\sqrt{\sqrt{\sqrt{x}}}_{\sqrt{\sqrt{x}}}^{\sqrt{\sqrt{\sqrt{x}}}
- ^{\sqrt{\sqrt{\sqrt{x}}}}}
+ ^{\sqrt{\sqrt{\sqrt{x}}}}} \\
+ \sqrt{\frac{\frac{A}{B}}{\frac{A}{B}}} \;
+ \sqrt{\frac{\frac{\frac{A}{B}}{\frac{A}{B}}}{\frac{\frac{A}{B}}{\frac{A}{B}}}}
SqrtRoot: |
\begin{array}{l}
1+\sqrt[3]{2}+\sqrt[1923^234]{2^{2^{2^{2^{2^{2^{2^{2^{2^{2^{2^2}}}}}}}}}}} \\