summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwolfbeast <mcwerewolf@gmail.com>2018-09-14 20:54:19 +0200
committerwolfbeast <mcwerewolf@gmail.com>2018-09-14 20:54:19 +0200
commit351ffa462d2314c4b60369e2ba0f13b5d90f03b5 (patch)
tree3a65ef976872b6ca31f1c68998113dd25e80dc11
parent2fce053e98de11551df1afa69db7f127c44ef5f4 (diff)
downloadUXP-351ffa462d2314c4b60369e2ba0f13b5d90f03b5.tar
UXP-351ffa462d2314c4b60369e2ba0f13b5d90f03b5.tar.gz
UXP-351ffa462d2314c4b60369e2ba0f13b5d90f03b5.tar.lz
UXP-351ffa462d2314c4b60369e2ba0f13b5d90f03b5.tar.xz
UXP-351ffa462d2314c4b60369e2ba0f13b5d90f03b5.zip
Fix wrong SVG sizes with non-integer values for viewBox width/height.
Includes a standalone reftest.
-rw-r--r--dom/svg/test/reftest_viewport_noninteger.html175
-rw-r--r--layout/svg/nsSVGOuterSVGFrame.cpp9
2 files changed, 180 insertions, 4 deletions
diff --git a/dom/svg/test/reftest_viewport_noninteger.html b/dom/svg/test/reftest_viewport_noninteger.html
new file mode 100644
index 000000000..3f4852b53
--- /dev/null
+++ b/dom/svg/test/reftest_viewport_noninteger.html
@@ -0,0 +1,175 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>SVG size test</title>
+ <style>
+ body {
+ margin: 30px;
+ font-family: sans-serif;
+ }
+
+ #tests {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ grid-gap: 30px;
+ }
+
+ #tests div:hover {
+ opacity: 1 !important;
+ }
+
+ #tests p {
+ text-decoration: underline dotted black;
+ }
+
+ svg {
+ background: lightgrey;
+ }
+ </style>
+ </head>
+ <body>
+ <h1>SVG size test</h1>
+
+ <p>The grey boxes below are <code>&lt;svg&gt;</code> elements.</p>
+ <p>All SVGs in each row should have the exact same size.</p>
+ <p>Each row has its own viewBox width and height: <code>viewBox="0 0 width height"</code>.</p>
+ <p>Each column has its own width/height styling. For example, <code>style="width: 200px; height: auto;"</code>.</p>
+ <p>The first column has both an explicit widht and an explicit height, so there's not much that can go wrong there. It acts as a reference.</p>
+ <p>The first row has integer viewBox width and height. Firefox then sizes all SVGs correctly.</p>
+ <p>The remaining rows have at least one non-integer viewBox width and height. Firefox then sizes the SVGs a bit wrong.</p>
+ <p>Chrome, Safari and Edge seem to pass all tests.</p>
+
+ <p id="summary"></p>
+
+ <div id="tests"></div>
+
+ <script>
+ const testsElement = document.getElementById("tests");
+ const summaryElement = document.getElementById("summary");
+
+ // Turn for instance `2.3` into `230` (px). Round to avoid floating point
+ // issues.
+ const scale = (number) => Math.round(100 * number);
+
+ const widths = [2, 2.3, 2.5, 2.8];
+ const heights = [3, 3.3, 3.5, 3.8];
+
+ let numPassed = 0;
+ let numFailed = 0;
+
+ for (const width of widths) {
+ for (const height of heights) {
+ const variations = [
+ {width, height},
+ {width: "auto", height},
+ {width, height: "auto"},
+ {width: "auto", height: "auto"},
+ ];
+
+ for (const variation of variations) {
+ const cellElement = document.createElement("div");
+
+ const titleElement = document.createElement("h2");
+ titleElement.appendChild(makeTitle(width, height, variation));
+
+ const sizeElement = document.createElement("p");
+
+ const svgWrapperElement = document.createElement("div");
+ svgWrapperElement.style.width =
+ variation.width === "auto" && variation.height === "auto"
+ ? `${scale(width)}px`
+ : "auto";
+
+ const svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg");
+ svgElement.setAttribute("viewBox", `0 0 ${width} ${height}`);
+ svgElement.style.width =
+ typeof variation.width === "number"
+ ? `${scale(variation.width)}px`
+ : variation.width;
+ svgElement.style.height =
+ typeof variation.height === "number"
+ ? `${scale(variation.height)}px`
+ : variation.height;
+
+ svgWrapperElement.appendChild(svgElement);
+
+ cellElement.appendChild(titleElement);
+ cellElement.appendChild(sizeElement);
+ cellElement.appendChild(svgWrapperElement);
+
+ testsElement.appendChild(cellElement);
+
+ const rect = svgElement.getBoundingClientRect();
+ const actual = {
+ width: Math.round(rect.width),
+ height: Math.round(rect.height),
+ };
+ const expected = {
+ width: scale(width),
+ height: scale(height),
+ };
+ const passed =
+ actual.width === expected.width &&
+ actual.height === expected.height;
+
+ const icon = passed ? "✔" : "✘";
+ const iconText = passed ? "PASS" : "FAIL";
+ const expectedText = passed ? "" : `\nExpected size: ${expected.width}x${expected.height}`;
+ sizeElement.textContent = `${icon} ${actual.width}x${actual.height}`;
+ sizeElement.title = `${iconText}. Actual size, as measured by element.getBoundingClientRect().${expectedText}`;
+ sizeElement.style.color = passed ? "lime" : "red";
+ sizeElement.style.fontWeight = passed ? "normal" : "bold";
+
+ cellElement.style.opacity = passed ? 0.5 : 1;
+
+ if (passed) {
+ numPassed++;
+ } else {
+ numFailed++;
+ }
+ }
+ }
+ }
+
+ const numTotal = numPassed + numFailed;
+ const passed = numFailed === 0;
+ const icon = passed ? "✔" : "✘";
+ summaryElement.textContent = `${icon} ${numPassed}/${numTotal} tests passed.`;
+ summaryElement.style.color = passed ? "lime" : "red";
+ summaryElement.style.fontWeight = "bold";
+
+ function makeTitle(width, height, variation) {
+ const fragment = document.createDocumentFragment();
+
+ const first = document.createElement("abbr");
+ first.textContent = `${width}/${height}`;
+ first.title = `SVG viewBox width/height: viewBox="0 0 ${width} ${height}"`;
+
+ const separator = document.createTextNode(" | ");
+
+ const second = document.createElement("abbr");
+
+ const widthString = typeof variation.width === "number" ? "px" : variation.width;
+ const heightString = typeof variation.height === "number" ? "px" : variation.height;
+ second.textContent = `${widthString}/${heightString}`;
+
+ const widthExplanation =
+ typeof variation.width === "number"
+ ? "explicit width (px)"
+ : `${variation.width} width`
+ const heightExplanation =
+ typeof variation.height === "number"
+ ? "explicit height (px)"
+ : `${variation.height} height`
+ second.title = `${widthExplanation}, ${heightExplanation}`;
+
+ fragment.appendChild(first);
+ fragment.appendChild(separator);
+ fragment.appendChild(second);
+
+ return fragment;
+ }
+ </script>
+ </body>
+</html>
diff --git a/layout/svg/nsSVGOuterSVGFrame.cpp b/layout/svg/nsSVGOuterSVGFrame.cpp
index aeadccbc5..e1b97bb40 100644
--- a/layout/svg/nsSVGOuterSVGFrame.cpp
+++ b/layout/svg/nsSVGOuterSVGFrame.cpp
@@ -241,8 +241,9 @@ nsSVGOuterSVGFrame::GetIntrinsicRatio()
nsSVGLength2 &height = content->mLengthAttributes[SVGSVGElement::ATTR_HEIGHT];
if (!width.IsPercentage() && !height.IsPercentage()) {
- nsSize ratio(NSToCoordRoundWithClamp(width.GetAnimValue(content)),
- NSToCoordRoundWithClamp(height.GetAnimValue(content)));
+ nsSize ratio(
+ nsPresContext::CSSPixelsToAppUnits(width.GetAnimValue(content)),
+ nsPresContext::CSSPixelsToAppUnits(height.GetAnimValue(content)));
if (ratio.width < 0) {
ratio.width = 0;
}
@@ -272,8 +273,8 @@ nsSVGOuterSVGFrame::GetIntrinsicRatio()
if (viewBoxHeight < 0.0f) {
viewBoxHeight = 0.0f;
}
- return nsSize(NSToCoordRoundWithClamp(viewBoxWidth),
- NSToCoordRoundWithClamp(viewBoxHeight));
+ return nsSize(nsPresContext::CSSPixelsToAppUnits(viewBoxWidth),
+ nsPresContext::CSSPixelsToAppUnits(viewBoxHeight));
}
return nsSVGDisplayContainerFrame::GetIntrinsicRatio();