Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Use SVGs for some stacked delims #3686

Merged
merged 7 commits into from Aug 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
93 changes: 68 additions & 25 deletions src/delimiter.js
Expand Up @@ -25,7 +25,7 @@ import ParseError from "./ParseError";
import Style from "./Style";

import {PathNode, SvgNode, SymbolNode} from "./domTree";
import {sqrtPath, innerPath} from "./svgGeometry";
import {sqrtPath, innerPath, tallDelim} from "./svgGeometry";
import buildCommon from "./buildCommon";
import {getCharacterMetrics} from "./fontMetrics";
import symbols from "./symbols";
Expand Down Expand Up @@ -229,6 +229,8 @@ const makeStackedDelim = function(
let middle;
let repeat;
let bottom;
let svgLabel = "";
let viewBoxWidth = 0;
top = repeat = bottom = delim;
middle = null;
// Also keep track of what font the delimiters are in
Expand All @@ -255,44 +257,64 @@ const makeStackedDelim = function(
bottom = "\\Downarrow";
} else if (utils.contains(verts, delim)) {
repeat = "\u2223";
svgLabel = "vert";
viewBoxWidth = 333;
} else if (utils.contains(doubleVerts, delim)) {
repeat = "\u2225";
svgLabel = "doublevert";
viewBoxWidth = 556;
} else if (delim === "[" || delim === "\\lbrack") {
top = "\u23a1";
repeat = "\u23a2";
bottom = "\u23a3";
font = "Size4-Regular";
svgLabel = "lbrack";
viewBoxWidth = 667;
} else if (delim === "]" || delim === "\\rbrack") {
top = "\u23a4";
repeat = "\u23a5";
bottom = "\u23a6";
font = "Size4-Regular";
svgLabel = "rbrack";
viewBoxWidth = 667;
} else if (delim === "\\lfloor" || delim === "\u230a") {
repeat = top = "\u23a2";
bottom = "\u23a3";
font = "Size4-Regular";
svgLabel = "lfloor";
viewBoxWidth = 667;
} else if (delim === "\\lceil" || delim === "\u2308") {
top = "\u23a1";
repeat = bottom = "\u23a2";
font = "Size4-Regular";
svgLabel = "lceil";
viewBoxWidth = 667;
} else if (delim === "\\rfloor" || delim === "\u230b") {
repeat = top = "\u23a5";
bottom = "\u23a6";
font = "Size4-Regular";
svgLabel = "rfloor";
viewBoxWidth = 667;
} else if (delim === "\\rceil" || delim === "\u2309") {
top = "\u23a4";
repeat = bottom = "\u23a5";
font = "Size4-Regular";
svgLabel = "rceil";
viewBoxWidth = 667;
} else if (delim === "(" || delim === "\\lparen") {
top = "\u239b";
repeat = "\u239c";
bottom = "\u239d";
font = "Size4-Regular";
svgLabel = "lparen";
viewBoxWidth = 875;
} else if (delim === ")" || delim === "\\rparen") {
top = "\u239e";
repeat = "\u239f";
bottom = "\u23a0";
font = "Size4-Regular";
svgLabel = "rparen";
viewBoxWidth = 875;
} else if (delim === "\\{" || delim === "\\lbrace") {
top = "\u23a7";
middle = "\u23a8";
Expand Down Expand Up @@ -365,38 +387,59 @@ const makeStackedDelim = function(
// Calculate the depth
const depth = realHeightTotal / 2 - axisHeight;


// Now, we start building the pieces that will go into the vlist
// Keep a list of the pieces of the stacked delimiter
const stack = [];

// Add the bottom symbol
stack.push(makeGlyphSpan(bottom, font, mode));
stack.push(lap); // overlap

if (middle === null) {
// The middle section will be an SVG. Make it an extra 0.016em tall.
// We'll overlap by 0.008em at top and bottom.
const innerHeight = realHeightTotal - topHeightTotal - bottomHeightTotal
+ 2 * lapInEms;
stack.push(makeInner(repeat, innerHeight, options));
if (svgLabel.length > 0) {
// Instead of stacking glyphs, create a single SVG.
// This evades browser problems with imprecise positioning of spans.
const midHeight = realHeightTotal - topHeightTotal - bottomHeightTotal;
const viewBoxHeight = Math.round(realHeightTotal * 1000);
const pathStr = tallDelim(svgLabel, Math.round(midHeight * 1000));
const path = new PathNode(svgLabel, pathStr);
const width = (viewBoxWidth / 1000).toFixed(3) + "em";
const height = (viewBoxHeight / 1000).toFixed(3) + "em";
const svg = new SvgNode([path], {
"width": width,
"height": height,
"viewBox": `0 0 ${viewBoxWidth} ${viewBoxHeight}`,
});
const wrapper = buildCommon.makeSvgSpan([], [svg], options);
wrapper.height = viewBoxHeight / 1000;
wrapper.style.width = width;
wrapper.style.height = height;
stack.push({type: "elem", elem: wrapper});
} else {
// When there is a middle bit, we need the middle part and two repeated
// sections
const innerHeight = (realHeightTotal - topHeightTotal - bottomHeightTotal -
middleHeightTotal) / 2 + 2 * lapInEms;
stack.push(makeInner(repeat, innerHeight, options));
// Now insert the middle of the brace.
stack.push(lap);
stack.push(makeGlyphSpan(middle, font, mode));
// Stack glyphs
// Start by adding the bottom symbol
stack.push(makeGlyphSpan(bottom, font, mode));
stack.push(lap); // overlap

if (middle === null) {
// The middle section will be an SVG. Make it an extra 0.016em tall.
// We'll overlap by 0.008em at top and bottom.
const innerHeight = realHeightTotal - topHeightTotal - bottomHeightTotal
+ 2 * lapInEms;
stack.push(makeInner(repeat, innerHeight, options));
} else {
// When there is a middle bit, we need the middle part and two repeated
// sections
const innerHeight = (realHeightTotal - topHeightTotal -
bottomHeightTotal - middleHeightTotal) / 2 + 2 * lapInEms;
stack.push(makeInner(repeat, innerHeight, options));
// Now insert the middle of the brace.
stack.push(lap);
stack.push(makeGlyphSpan(middle, font, mode));
stack.push(lap);
stack.push(makeInner(repeat, innerHeight, options));
}

// Add the top symbol
stack.push(lap);
stack.push(makeInner(repeat, innerHeight, options));
stack.push(makeGlyphSpan(top, font, mode));
}

// Add the top symbol
stack.push(lap);
stack.push(makeGlyphSpan(top, font, mode));

// Finally, build the vlist
const newOptions = options.havingBaseStyle(Style.TEXT);
const inner = buildCommon.makeVList({
Expand Down
56 changes: 56 additions & 0 deletions src/svgGeometry.js
Expand Up @@ -487,3 +487,59 @@ 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 const tallDelim = function(label: string, midHeight: number): string {
switch (label) {
case "lbrack":
return `M403 1759 V84 H666 V0 H319 V1759 v${midHeight} v1759 h347 v-84
H403z M403 1759 V0 H319 V1759 v${midHeight} v1759 h84z`;
case "rbrack":
return `M347 1759 V0 H0 V84 H263 V1759 v${midHeight} v1759 H0 v84 H347z
M347 1759 V0 H263 V1759 v${midHeight} v1759 h84z`;
case "vert":
return `M145 15 v585 v${midHeight} v585 c2.667,10,9.667,15,21,15
c10,0,16.667,-5,20,-15 v-585 v${-midHeight} v-585 c-2.667,-10,-9.667,-15,-21,-15
c-10,0,-16.667,5,-20,15z M188 15 H145 v585 v${midHeight} v585 h43z`;
case "doublevert":
return `M145 15 v585 v${midHeight} v585 c2.667,10,9.667,15,21,15
c10,0,16.667,-5,20,-15 v-585 v${-midHeight} v-585 c-2.667,-10,-9.667,-15,-21,-15
c-10,0,-16.667,5,-20,15z M188 15 H145 v585 v${midHeight} v585 h43z
M367 15 v585 v${midHeight} v585 c2.667,10,9.667,15,21,15
c10,0,16.667,-5,20,-15 v-585 v${-midHeight} v-585 c-2.667,-10,-9.667,-15,-21,-15
c-10,0,-16.667,5,-20,15z M410 15 H367 v585 v${midHeight} v585 h43z`;
case "lfloor":
return `M319 602 V0 H403 V602 v${midHeight} v1715 h263 v84 H319z
MM319 602 V0 H403 V602 v${midHeight} v1715 H319z`;
case "rfloor":
return `M319 602 V0 H403 V602 v${midHeight} v1799 H0 v-84 H319z
MM319 602 V0 H403 V602 v${midHeight} v1715 H319z`;
case "lceil":
return `M403 1759 V84 H666 V0 H319 V1759 v${midHeight} v602 h84z
M403 1759 V0 H319 V1759 v${midHeight} v602 h84z`;
case "rceil":
return `M347 1759 V0 H0 V84 H263 V1759 v${midHeight} v602 h84z
M347 1759 V0 h-84 V1759 v${midHeight} v602 h84z`;
case "lparen":
return `M863,9c0,-2,-2,-5,-6,-9c0,0,-17,0,-17,0c-12.7,0,-19.3,0.3,-20,1
c-5.3,5.3,-10.3,11,-15,17c-242.7,294.7,-395.3,682,-458,1162c-21.3,163.3,-33.3,349,
-36,557 l0,${midHeight + 84}c0.2,6,0,26,0,60c2,159.3,10,310.7,24,454c53.3,528,210,
949.7,470,1265c4.7,6,9.7,11.7,15,17c0.7,0.7,7,1,19,1c0,0,18,0,18,0c4,-4,6,-7,6,-9
c0,-2.7,-3.3,-8.7,-10,-18c-135.3,-192.7,-235.5,-414.3,-300.5,-665c-65,-250.7,-102.5,
-544.7,-112.5,-882c-2,-104,-3,-167,-3,-189
l0,-${midHeight + 92}c0,-162.7,5.7,-314,17,-454c20.7,-272,63.7,-513,129,-723c65.3,
-210,155.3,-396.3,270,-559c6.7,-9.3,10,-15.3,10,-18z`;
case "rparen":
return `M76,0c-16.7,0,-25,3,-25,9c0,2,2,6.3,6,13c21.3,28.7,42.3,60.3,
63,95c96.7,156.7,172.8,332.5,228.5,527.5c55.7,195,92.8,416.5,111.5,664.5
c11.3,139.3,17,290.7,17,454c0,28,1.7,43,3.3,45l0,${midHeight + 9}
c-3,4,-3.3,16.7,-3.3,38c0,162,-5.7,313.7,-17,455c-18.7,248,-55.8,469.3,-111.5,664
c-55.7,194.7,-131.8,370.3,-228.5,527c-20.7,34.7,-41.7,66.3,-63,95c-2,3.3,-4,7,-6,11
c0,7.3,5.7,11,17,11c0,0,11,0,11,0c9.3,0,14.3,-0.3,15,-1c5.3,-5.3,10.3,-11,15,-17
c242.7,-294.7,395.3,-681.7,458,-1161c21.3,-164.7,33.3,-350.7,36,-558
l0,-${midHeight + 144}c-2,-159.3,-10,-310.7,-24,-454c-53.3,-528,-210,-949.7,
-470,-1265c-4.7,-6,-9.7,-11.7,-15,-17c-0.7,-0.7,-6.7,-1,-18,-1z`;
default:
// We should not ever get here.
throw new Error("Unknown stretchy delimiter.");
}
};
Binary file modified test/screenshotter/images/Arrays-chrome.png
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/Arrays-firefox.png
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/Arrays-safari.png
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/CD-chrome.png
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/CD-firefox.png
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/CD-safari.png
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/DeepFontSizing-chrome.png
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/DeepFontSizing-firefox.png
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/DeepFontSizing-safari.png
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/DelimiterSizing-chrome.png
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/DelimiterSizing-firefox.png
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/DelimiterSizing-safari.png
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/ExtensibleArrows-chrome.png
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/ExtensibleArrows-firefox.png
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/ExtensibleArrows-safari.png
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/LowerAccent-chrome.png
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/LowerAccent-firefox.png
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/LowerAccent-safari.png
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/StretchyAccent-chrome.png
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/StretchyAccent-firefox.png
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/StretchyAccent-safari.png
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/SupSubHorizSpacing-chrome.png
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/SupSubHorizSpacing-firefox.png
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/SupSubHorizSpacing-safari.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.