diff --git a/src/buildHTML.js b/src/buildHTML.js index e9556ec8..0ec022db 100644 --- a/src/buildHTML.js +++ b/src/buildHTML.js @@ -1115,6 +1115,10 @@ groupTypes.sqrt = function(group, options) { // First, we do the same steps as in overline to build the inner group // and line let inner = buildGroup(group.value.body, options.havingCrampedStyle()); + if (inner.height === 0) { + // Render a small surd. + inner.height = options.fontMetrics().xHeight; + } // Some groups can return document fragments. Handle those by wrapping // them in a span. @@ -1159,26 +1163,16 @@ groupTypes.sqrt = function(group, options) { // Shift the sqrt image const imgShift = img.height - inner.height - lineClearance - ruleWidth; - // 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 - // should omit the body entirely. (note this doesn't work for something - // like `\sqrt{\rlap{x}}`, but if someone is doing that they deserve for - // it not to work. - let body; - if (inner.height === 0 && inner.depth === 0) { - body = makeSpan(); - } else { - inner.style.paddingLeft = img.surdWidth + "em"; + inner.style.paddingLeft = img.advanceWidth + "em"; - // Overlay the image and the argument. - body = buildCommon.makeVList([ - {type: "elem", elem: inner}, - {type: "kern", size: -(inner.height + imgShift)}, - {type: "elem", elem: img}, - {type: "kern", size: ruleWidth}, - ], "firstBaseline", null, options); - body.children[0].children[0].classes.push("svg-align"); - } + // Overlay the image and the argument. + const body = buildCommon.makeVList([ + {type: "elem", elem: inner}, + {type: "kern", size: -(inner.height + imgShift)}, + {type: "elem", elem: img}, + {type: "kern", size: ruleWidth}, + ], "firstBaseline", null, options); + body.children[0].children[0].classes.push("svg-align"); if (!group.value.index) { return makeSpan(["mord", "sqrt"], [body], options); diff --git a/src/delimiter.js b/src/delimiter.js index 2c4d226a..98ee924f 100644 --- a/src/delimiter.js +++ b/src/delimiter.js @@ -329,14 +329,13 @@ const sqrtSvg = function(sqrtName, height, viewBoxHeight, options) { } const pathNode = new domTree.pathNode(sqrtName, alternate); - let attributes = [["width", "100%"], ["height", height + "em"]]; + // Note: 1000:1 ratio of viewBox to document em width. + const attributes = [["width", "400em"], ["height", height + "em"]]; attributes.push(["viewBox", "0 0 400000 " + viewBoxHeight]); attributes.push(["preserveAspectRatio", "xMinYMin slice"]); - const innerSVG = new domTree.svgNode([pathNode], attributes); + const svg = new domTree.svgNode([pathNode], attributes); - attributes = [["width", "100%"], ["height", height + "em"]]; - const svg = new domTree.svgNode([innerSVG], attributes); - return buildCommon.makeSpan([], [svg], options); + return buildCommon.makeSpan(["hide-tail"], [svg], options); }; const sqrtSpan = function(height, delim, options) { @@ -353,22 +352,25 @@ const sqrtSpan = function(height, delim, options) { sizeMultiplier = newOptions.sizeMultiplier / options.sizeMultiplier; spanHeight = 1 * sizeMultiplier; span = sqrtSvg("sqrtMain", spanHeight, viewBoxHeight, options); - span.surdWidth = 0.833 * sizeMultiplier; // from the font. + span.style.minWidth = "0.853em"; + span.advanceWidth = 0.833 * sizeMultiplier; // from the font. } else if (delim.type === "large") { // These SVGs come from fonts: KaTeX_Size1, _Size2, etc. viewBoxHeight = 1000 * sizeToMaxHeight[delim.size]; spanHeight = sizeToMaxHeight[delim.size] / sizeMultiplier; span = sqrtSvg("sqrtSize" + delim.size, spanHeight, viewBoxHeight, options); - span.surdWidth = 1.0 / sizeMultiplier; // from the font + span.style.minWidth = "1.02em"; + span.advanceWidth = 1.0 / sizeMultiplier; // 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 / sizeMultiplier; - viewBoxHeight = Math.floor(1000 * spanHeight); + viewBoxHeight = Math.floor(1000 * height); span = sqrtSvg("sqrtTall", spanHeight, viewBoxHeight, options); - span.surdWidth = 1.056 / sizeMultiplier; + span.style.minWidth = "0.742em"; + span.advanceWidth = 1.056 / sizeMultiplier; } span.height = spanHeight; diff --git a/src/stretchy.js b/src/stretchy.js index 7a3e3c21..0a71b10b 100644 --- a/src/stretchy.js +++ b/src/stretchy.js @@ -158,6 +158,7 @@ const svgSpan = function(group, options) { let path; let pathName; let svgNode; + const classNames = []; if (utils.contains(["widehat", "widetilde", "undertilde"], label)) { // There are four SVG images available for each function. @@ -208,7 +209,7 @@ const svgSpan = function(group, options) { attributes = []; if (numSvgChildren === 1) { - width = "100%"; + width = "400em"; align = alignOne; } else if (numSvgChildren === 2) { // small overlap to prevent a 1 pixel gap. @@ -231,13 +232,22 @@ const svgSpan = function(group, options) { attributes.push(["viewBox", `0 0 ${viewBoxWidth} ${vbHeight}`]); attributes.push(["preserveAspectRatio", align + " slice"]); - innerSVGs.push(new domTree.svgNode([path], attributes)); + if (numSvgChildren > 1) { + innerSVGs.push(new domTree.svgNode([path], attributes)); + } else { + // The single svgChild is a child of a hide-tail span, not the + // child of another svg. + svgNode = new domTree.svgNode([path], attributes); + classNames.push("hide-tail"); + } + } + if (numSvgChildren > 1) { + attributes = [["width", "100%"], ["height", height + "em"]]; + svgNode = new domTree.svgNode(innerSVGs, attributes); } - attributes = [["width", "100%"], ["height", height + "em"]]; - svgNode = new domTree.svgNode(innerSVGs, attributes); } - const span = buildCommon.makeSpan([], [svgNode], options); + const span = buildCommon.makeSpan(classNames, [svgNode], options); // Note that we are returning span.depth = 0. // Any adjustments relative to the baseline must be done in buildHTML. span.height = height; diff --git a/static/katex.less b/static/katex.less index f7fad196..9d9425d7 100644 --- a/static/katex.less +++ b/static/katex.less @@ -575,6 +575,13 @@ } } + // Hide the long tail of a stretchy SVG. + .hide-tail { + width: 100%; // necessary only to get IE to work properly + position: relative; // ditto + overflow: hidden; // This line applies to all browsers. + } + // Lengthen the extensible arrows via padding. .x-arrow-pad { padding: 0 0.5em; diff --git a/test/screenshotter/images/DisplayStyle-chrome.png b/test/screenshotter/images/DisplayStyle-chrome.png index be2e8524..65619e34 100644 Binary files a/test/screenshotter/images/DisplayStyle-chrome.png and b/test/screenshotter/images/DisplayStyle-chrome.png differ diff --git a/test/screenshotter/images/ExtensibleArrows-chrome.png b/test/screenshotter/images/ExtensibleArrows-chrome.png index bce71b0c..2f516662 100644 Binary files a/test/screenshotter/images/ExtensibleArrows-chrome.png and b/test/screenshotter/images/ExtensibleArrows-chrome.png differ diff --git a/test/screenshotter/images/ExtensibleArrows-firefox.png b/test/screenshotter/images/ExtensibleArrows-firefox.png index 524d679b..ab8cac64 100644 Binary files a/test/screenshotter/images/ExtensibleArrows-firefox.png and b/test/screenshotter/images/ExtensibleArrows-firefox.png differ diff --git a/test/screenshotter/images/LowerAccent-chrome.png b/test/screenshotter/images/LowerAccent-chrome.png index d46e9c04..249f97c3 100644 Binary files a/test/screenshotter/images/LowerAccent-chrome.png and b/test/screenshotter/images/LowerAccent-chrome.png differ diff --git a/test/screenshotter/images/LowerAccent-firefox.png b/test/screenshotter/images/LowerAccent-firefox.png index 4b1127e4..f3319345 100644 Binary files a/test/screenshotter/images/LowerAccent-firefox.png and b/test/screenshotter/images/LowerAccent-firefox.png differ diff --git a/test/screenshotter/images/OverUnderset-chrome.png b/test/screenshotter/images/OverUnderset-chrome.png index 762da945..a51f8a6b 100644 Binary files a/test/screenshotter/images/OverUnderset-chrome.png and b/test/screenshotter/images/OverUnderset-chrome.png differ diff --git a/test/screenshotter/images/Raisebox-chrome.png b/test/screenshotter/images/Raisebox-chrome.png index 004e41c7..fc8da117 100644 Binary files a/test/screenshotter/images/Raisebox-chrome.png and b/test/screenshotter/images/Raisebox-chrome.png differ diff --git a/test/screenshotter/images/Raisebox-firefox.png b/test/screenshotter/images/Raisebox-firefox.png index a2623731..f5ca0a6d 100644 Binary files a/test/screenshotter/images/Raisebox-firefox.png and b/test/screenshotter/images/Raisebox-firefox.png differ diff --git a/test/screenshotter/images/Smash-chrome.png b/test/screenshotter/images/Smash-chrome.png index 2be9b9b8..4fa5c919 100644 Binary files a/test/screenshotter/images/Smash-chrome.png and b/test/screenshotter/images/Smash-chrome.png differ diff --git a/test/screenshotter/images/Sqrt-chrome.png b/test/screenshotter/images/Sqrt-chrome.png index 1e99e73a..401d4def 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 9c5a5158..d395f85d 100644 Binary files a/test/screenshotter/images/Sqrt-firefox.png and b/test/screenshotter/images/Sqrt-firefox.png differ diff --git a/test/screenshotter/images/SqrtRoot-chrome.png b/test/screenshotter/images/SqrtRoot-chrome.png index 35ec9171..70fa0da7 100644 Binary files a/test/screenshotter/images/SqrtRoot-chrome.png and b/test/screenshotter/images/SqrtRoot-chrome.png differ diff --git a/test/screenshotter/images/SqrtRoot-firefox.png b/test/screenshotter/images/SqrtRoot-firefox.png index 61f2336e..fc0bef09 100644 Binary files a/test/screenshotter/images/SqrtRoot-firefox.png and b/test/screenshotter/images/SqrtRoot-firefox.png differ diff --git a/test/screenshotter/images/StretchyAccent-chrome.png b/test/screenshotter/images/StretchyAccent-chrome.png index da2cc8cf..82640f42 100644 Binary files a/test/screenshotter/images/StretchyAccent-chrome.png and b/test/screenshotter/images/StretchyAccent-chrome.png differ diff --git a/test/screenshotter/images/StretchyAccent-firefox.png b/test/screenshotter/images/StretchyAccent-firefox.png index 503bd6ee..ccb75dde 100644 Binary files a/test/screenshotter/images/StretchyAccent-firefox.png and b/test/screenshotter/images/StretchyAccent-firefox.png differ diff --git a/test/screenshotter/images/StretchyAccentColor-chrome.png b/test/screenshotter/images/StretchyAccentColor-chrome.png index 4623ff7f..a6bfcb9c 100644 Binary files a/test/screenshotter/images/StretchyAccentColor-chrome.png and b/test/screenshotter/images/StretchyAccentColor-chrome.png differ diff --git a/test/screenshotter/images/StretchyAccentColor-firefox.png b/test/screenshotter/images/StretchyAccentColor-firefox.png index bb70bede..209802ab 100644 Binary files a/test/screenshotter/images/StretchyAccentColor-firefox.png and b/test/screenshotter/images/StretchyAccentColor-firefox.png differ diff --git a/test/screenshotter/images/UnsupportedCmds-chrome.png b/test/screenshotter/images/UnsupportedCmds-chrome.png index 3594301d..824bdedf 100644 Binary files a/test/screenshotter/images/UnsupportedCmds-chrome.png and b/test/screenshotter/images/UnsupportedCmds-chrome.png differ diff --git a/test/screenshotter/images/UnsupportedCmds-firefox.png b/test/screenshotter/images/UnsupportedCmds-firefox.png index a28a4e3d..f33aa70c 100644 Binary files a/test/screenshotter/images/UnsupportedCmds-firefox.png and b/test/screenshotter/images/UnsupportedCmds-firefox.png differ