Commit 1fb7023c authored by fs@opera.com's avatar fs@opera.com

Don't render empty shapes with non-scaling-stroke

Compute and validate the shape parameters before deciding which code-path
should be used (path vs. primitive). Don't use the fallback when the
bounding box is empty.

Based on WebKit patch:
  https://bugs.webkit.org/attachment.cgi?id=232191&action=prettypatch
by:
  Nikos Andronikos <nikos.andronikos-webkit@cisra.canon.com.au>

BUG=377610

Review URL: https://codereview.chromium.org/307643003

git-svn-id: svn://svn.chromium.org/blink/trunk@175147 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 1a65bf19
...@@ -1258,6 +1258,10 @@ crbug.com/371651 svg/custom/use-disappears-after-style-update.svg [ Pass Failure ...@@ -1258,6 +1258,10 @@ crbug.com/371651 svg/custom/use-disappears-after-style-update.svg [ Pass Failure
crbug.com/371651 svg/filters/filter-refresh.svg [ Failure ] crbug.com/371651 svg/filters/filter-refresh.svg [ Failure ]
crbug.com/371651 svg/text/text-text-05-t.svg [ Failure ] crbug.com/371651 svg/text/text-text-05-t.svg [ Failure ]
crbug.com/377610 [ Linux Mac Win7 ] svg/W3C-SVG-1.1/animate-elem-32-t.svg [ NeedsRebaseline ]
crbug.com/377610 [ Linux Mac Win7 ] svg/W3C-SVG-1.1/shapes-circle-02-t.svg [ NeedsRebaseline ]
crbug.com/377610 [ Linux Mac Win7 ] svg/W3C-SVG-1.1/shapes-intro-01-t.svg [ NeedsRebaseline ]
crbug.com/371654 fast/html/imports/import-custom-element-dup-resolve.html [ Pass Failure ] crbug.com/371654 fast/html/imports/import-custom-element-dup-resolve.html [ Pass Failure ]
crbug.com/377476 fast/js/function-name.html [ NeedsManualRebaseline ] crbug.com/377476 fast/js/function-name.html [ NeedsManualRebaseline ]
......
PASS, bounding boxes sizes are (100, 100), (0, 0), (100, 100) and (0, 0)
<!DOCTYPE HTML> <!DOCTYPE html>
<html> <script src="../../resources/testharness.js"></script>
<!-- Test that svg bounding boxes are valid for a zero-width or zero-height circle --> <script src="../../resources/testharnessreport.js"></script>
<head> <title>SVG bounding boxes are valid for a zero-width or zero-height circle</title>
<script type="text/javascript"> <svg height="0">
function checkBoundingBoxHasZeroValue() { <circle cx="300" cy="300" r="50"/>
if (window.testRunner) <circle cx="300" cy="300" r="0"/>
window.testRunner.dumpAsText(); <circle vector-effect="non-scaling-stroke" cx="300" cy="300" r="50"/>
var circle1 = document.getElementById('circle1').getBBox(); <circle vector-effect="non-scaling-stroke" cx="300" cy="300" r="0"/>
var circle2 = document.getElementById('circle2').getBBox(); </svg>
var circle3 = document.getElementById('circle3').getBBox(); <script>
var circle4 = document.getElementById('circle4').getBBox(); BBox = function(x,y,w,h) {
var results = "FAIL"; this.x = x;
if (circle1.width == 100 && this.y = y;
circle1.height == 100 && this.width = w;
circle2.width == 0 && this.height = h;
circle2.height == 0 && };
circle3.width == 100 && BBox.prototype.toString = function() {
circle3.height == 100 && return this.x + "," + this.y + "," + this.width + "," + this.height;
circle4.width == 0 && };
circle4.height == 0) // The order of expected sizes should equal the document order of the rects.
results = "PASS"; var expectedBoxes = [
document.body.innerHTML = results + ", bounding boxes sizes are (" + new BBox(250, 250, 100, 100),
circle1.width + ", " + circle1.height + "), (" + new BBox(300, 300, 0, 0),
circle2.width + ", " + circle2.height + "), (" + new BBox(250, 250, 100, 100),
circle3.width + ", " + circle3.height + ") and (" + new BBox(300, 300, 0, 0),
circle4.width + ", " + circle4.height + ")"; ];
} var circles = document.getElementsByTagName('circle');
</script> for (var i = 0, length = circles.length; i < length; ++i) {
</head> var circleBBox = circles[i].getBBox();
<body onload="checkBoundingBoxHasZeroValue()"> test(function() {
<svg> assert_equals(circleBBox.x, expectedBoxes[i].x);
<circle id="circle1" cx="300" cy="300" r="50"/> assert_equals(circleBBox.y, expectedBoxes[i].y);
<circle id="circle2" cx="300" cy="300" r="0"/> assert_equals(circleBBox.width, expectedBoxes[i].width);
<circle id="circle3" vector-effect="non-scaling-stroke" cx="300" cy="300" r="50"/> assert_equals(circleBBox.height, expectedBoxes[i].height);
<circle id="circle4" vector-effect="non-scaling-stroke" cx="300" cy="300" r="0"/> }, 'Bounding box size ' + expectedBoxes[i]);
</svg> }
<body> </script>
</html>
PASS, bounding boxes sizes are (0, 100), (100, 0), (0, 100) and (100, 0)
<!DOCTYPE HTML> <!DOCTYPE html>
<html> <script src="../../resources/testharness.js"></script>
<!-- Test that svg bounding boxes are valid for a zero-width or zero-height ellipse --> <script src="../../resources/testharnessreport.js"></script>
<head> <title>SVG bounding boxes are valid for a zero-rx or zero-ry ellipse</title>
<script type="text/javascript"> <svg height="0">
function checkBoundingBoxHasZeroValue() { <ellipse cx="50" cy="100" rx="0" ry="50"/>
if (window.testRunner) <ellipse cx="50" cy="100" rx="50" ry="0"/>
window.testRunner.dumpAsText(); <ellipse vector-effect="non-scaling-stroke" cx="50" cy="100" rx="0" ry="50"/>
var ellipse1 = document.getElementById('ellipse1').getBBox(); <ellipse vector-effect="non-scaling-stroke" cx="50" cy="100" rx="50" ry="0"/>
var ellipse2 = document.getElementById('ellipse2').getBBox(); </svg>
var ellipse3 = document.getElementById('ellipse3').getBBox(); <script>
var ellipse4 = document.getElementById('ellipse4').getBBox(); BBox = function(x,y,w,h) {
var results = "FAIL"; this.x = x;
if (ellipse1.height == 100 && this.y = y;
ellipse1.width == 0 && this.width = w;
ellipse2.height == 0 && this.height = h;
ellipse2.width == 100 && };
ellipse3.height == 100 && BBox.prototype.toString = function() {
ellipse3.width == 0 && return this.x + "," + this.y + "," + this.width + "," + this.height;
ellipse4.height == 0 && };
ellipse4.width == 100) // The order of expected sizes should equal the document order of the rects.
results = "PASS"; var expectedBoxes = [
document.body.innerHTML = results + ", bounding boxes sizes are (" + new BBox(50, 50, 0, 100),
ellipse1.width + ", " + ellipse1.height + "), (" + new BBox(0, 100, 100, 0),
ellipse2.width + ", " + ellipse2.height + "), (" + new BBox(50, 50, 0, 100),
ellipse3.width + ", " + ellipse3.height + ") and (" + new BBox(0, 100, 100, 0),
ellipse4.width + ", " + ellipse4.height + ")"; ];
} var ellipses = document.getElementsByTagName('ellipse');
</script> for (var i = 0, length = ellipses.length; i < length; ++i) {
</head> var ellipseBBox = ellipses[i].getBBox();
<body onload="checkBoundingBoxHasZeroValue()"> test(function() {
<svg> assert_equals(ellipseBBox.x, expectedBoxes[i].x);
<ellipse id="ellipse1" cx="50" cy="100" rx="0" ry="50"/> assert_equals(ellipseBBox.y, expectedBoxes[i].y);
<ellipse id="ellipse2" cx="50" cy="100" rx="50" ry="0"/> assert_equals(ellipseBBox.width, expectedBoxes[i].width);
<ellipse id="ellipse3" vector-effect="non-scaling-stroke" cx="50" cy="100" rx="0" ry="50"/> assert_equals(ellipseBBox.height, expectedBoxes[i].height);
<ellipse id="ellipse4" vector-effect="non-scaling-stroke" cx="50" cy="100" rx="50" ry="0"/> }, 'Bounding box size ' + expectedBoxes[i]);
</svg> }
<body> </script>
</html>
PASS, bounding box sizes are (0, 100), (100, 0), (0, 100) and (100, 0)
<!DOCTYPE HTML> <!DOCTYPE html>
<html> <script src="../../resources/testharness.js"></script>
<!-- Test that svg bounding boxes are valid for a zero-width or zero-height rect --> <script src="../../resources/testharnessreport.js"></script>
<head> <title>SVG bounding boxes are valid for a zero-width or zero-height rect</title>
<script type="text/javascript"> <svg height="0">
function checkBoundingBoxHasZeroValue() { <rect height="100" width="0"/>
if (window.testRunner) <rect height="0" width="100"/>
window.testRunner.dumpAsText(); <rect vector-effect="non-scaling-stroke" height="100" width="0"/>
var rectBox1 = document.getElementById('rect1').getBBox(); <rect vector-effect="non-scaling-stroke" height="0" width="100"/>
var rectBox2 = document.getElementById('rect2').getBBox(); <rect rx="10" vector-effect="non-scaling-stroke" height="100" width="0"/>
var rectBox3 = document.getElementById('rect3').getBBox(); <rect rx="10" vector-effect="non-scaling-stroke" height="0" width="100"/>
var rectBox4 = document.getElementById('rect4').getBBox(); <rect ry="10" vector-effect="non-scaling-stroke" height="100" width="0"/>
var results = "FAIL"; <rect ry="10" vector-effect="non-scaling-stroke" height="0" width="100"/>
if (rectBox1.height == 100 && rectBox1.width == 0 && <rect rx="10" ry="10" vector-effect="non-scaling-stroke" height="100" width="0"/>
rectBox2.height == 0 && rectBox2.width == 100 && <rect rx="10" ry="10" vector-effect="non-scaling-stroke" height="0" width="100"/>
rectBox3.height == 100 && rectBox3.width == 0 && <rect x="100" y="200" height="100" width="0"/>
rectBox4.height == 0 && rectBox4.width == 100) <rect x="100" y="200" height="0" width="100"/>
results = "PASS"; <rect x="100" y="200" vector-effect="non-scaling-stroke" height="100" width="0"/>
document.body.innerHTML = results + ", bounding box sizes are (" + <rect x="100" y="200" vector-effect="non-scaling-stroke" height="0" width="100"/>
rectBox1.width + ", " + rectBox1.height + "), (" + <rect x="100" y="200" rx="10" vector-effect="non-scaling-stroke" height="100" width="0"/>
rectBox2.width + ", " + rectBox2.height + "), (" + <rect x="100" y="200" rx="10" vector-effect="non-scaling-stroke" height="0" width="100"/>
rectBox3.width + ", " + rectBox3.height + ") and (" + <rect x="100" y="200" ry="10" vector-effect="non-scaling-stroke" height="100" width="0"/>
rectBox4.width + ", " + rectBox4.height + ")"; <rect x="100" y="200" ry="10" vector-effect="non-scaling-stroke" height="0" width="100"/>
} <rect x="100" y="200" rx="10" ry="10" vector-effect="non-scaling-stroke" height="100" width="0"/>
</script> <rect x="100" y="200" rx="10" ry="10" vector-effect="non-scaling-stroke" height="0" width="100"/>
</head> </svg>
<body onload="checkBoundingBoxHasZeroValue()"> <script>
<svg> BBox = function(x,y,w,h) {
<rect id="rect1" height="100" width="0"/> this.x = x;
</svg> this.y = y;
<svg> this.width = w;
<rect id="rect2" height="0" width="100"/> this.height = h;
</svg> };
<svg> BBox.prototype.toString = function() {
<rect id="rect3" vector-effect="non-scaling-stroke" height="100" width="0"/> return this.x + "," + this.y + "," + this.width + "," + this.height;
</svg> };
<svg> // The order of expected sizes should equal the document order of the rects.
<rect id="rect4" vector-effect="non-scaling-stroke" height="0" width="100"/> var expectedBoxes = [
</svg> new BBox(0, 0, 0, 100),
<body> new BBox(0, 0, 100, 0),
</html> new BBox(0, 0, 0, 100),
new BBox(0, 0, 100, 0),
new BBox(0, 0, 0, 100),
new BBox(0, 0, 100, 0),
new BBox(0, 0, 0, 100),
new BBox(0, 0, 100, 0),
new BBox(0, 0, 0, 100),
new BBox(0, 0, 100, 0),
new BBox(100, 200, 0, 100),
new BBox(100, 200, 100, 0),
new BBox(100, 200, 0, 100),
new BBox(100, 200, 100, 0),
new BBox(100, 200, 0, 100),
new BBox(100, 200, 100, 0),
new BBox(100, 200, 0, 100),
new BBox(100, 200, 100, 0),
new BBox(100, 200, 0, 100),
new BBox(100, 200, 100, 0),
];
var rects = document.getElementsByTagName('rect');
for (var i = 0, length = rects.length; i < length; ++i) {
var rectBBox = rects[i].getBBox();
test(function() {
assert_equals(rectBBox.x, expectedBoxes[i].x);
assert_equals(rectBBox.y, expectedBoxes[i].y);
assert_equals(rectBBox.width, expectedBoxes[i].width);
assert_equals(rectBBox.height, expectedBoxes[i].height);
}, 'Bounding box size ' + expectedBoxes[i]);
}
</script>
<!DOCTYPE html>
<svg width="100" height="200" style="background-color: lime">
</svg>
<!DOCTYPE html>
<style>
rect, circle, ellipse {
vector-effect: non-scaling-stroke;
stroke: red;
fill: red;
}
</style>
<svg width="100" height="200" style="background-color: lime">
<!-- Neither of these should render. -->
<rect x="10" y="20" width="0" height="10"/>
<rect x="10" y="40" rx="1" width="0" height="10"/>
<rect x="10" y="60" ry="1" width="0" height="10"/>
<circle cx="10" cy="80" r="0"/>
<ellipse cx="10" cy="100" rx="0" ry="5"/>
<ellipse cx="10" cy="120" rx="5" ry="0"/>
</svg>
...@@ -53,20 +53,22 @@ void RenderSVGEllipse::updateShapeFromElement() ...@@ -53,20 +53,22 @@ void RenderSVGEllipse::updateShapeFromElement()
m_center = FloatPoint(); m_center = FloatPoint();
m_radii = FloatSize(); m_radii = FloatSize();
// Fallback to RenderSVGShape if shape has a non-scaling stroke.
if (hasNonScalingStroke()) {
RenderSVGShape::updateShapeFromElement();
m_usePathFallback = true;
return;
} else
m_usePathFallback = false;
calculateRadiiAndCenter(); calculateRadiiAndCenter();
// Spec: "A negative value is an error. A value of zero disables rendering of the element." // Spec: "A negative value is an error. A value of zero disables rendering of the element."
if (m_radii.isZero() || m_radii.width() < 0 || m_radii.height() < 0) if (m_radii.width() < 0 || m_radii.height() < 0)
return; return;
if (!m_radii.isEmpty()) {
// Fallback to RenderSVGShape if shape has a non-scaling stroke.
if (hasNonScalingStroke()) {
RenderSVGShape::updateShapeFromElement();
m_usePathFallback = true;
return;
}
m_usePathFallback = false;
}
m_fillBoundingBox = FloatRect(m_center.x() - m_radii.width(), m_center.y() - m_radii.height(), 2 * m_radii.width(), 2 * m_radii.height()); m_fillBoundingBox = FloatRect(m_center.x() - m_radii.width(), m_center.y() - m_radii.height(), 2 * m_radii.width(), 2 * m_radii.height());
m_strokeBoundingBox = m_fillBoundingBox; m_strokeBoundingBox = m_fillBoundingBox;
if (style()->svgStyle()->hasStroke()) if (style()->svgStyle()->hasStroke())
......
...@@ -54,20 +54,23 @@ void RenderSVGRect::updateShapeFromElement() ...@@ -54,20 +54,23 @@ void RenderSVGRect::updateShapeFromElement()
ASSERT(rect); ASSERT(rect);
SVGLengthContext lengthContext(rect); SVGLengthContext lengthContext(rect);
// Fallback to RenderSVGShape if rect has rounded corners or a non-scaling stroke.
if (rect->rx()->currentValue()->value(lengthContext) > 0 || rect->ry()->currentValue()->value(lengthContext) > 0 || hasNonScalingStroke()) {
RenderSVGShape::updateShapeFromElement();
m_usePathFallback = true;
return;
}
m_usePathFallback = false;
FloatSize boundingBoxSize(rect->width()->currentValue()->value(lengthContext), rect->height()->currentValue()->value(lengthContext)); FloatSize boundingBoxSize(rect->width()->currentValue()->value(lengthContext), rect->height()->currentValue()->value(lengthContext));
// Spec: "A negative value is an error. A value of zero disables rendering of the element." // Spec: "A negative value is an error."
if (boundingBoxSize.isZero() || boundingBoxSize.width() < 0 || boundingBoxSize.height() < 0) if (boundingBoxSize.width() < 0 || boundingBoxSize.height() < 0)
return; return;
// Spec: "A value of zero disables rendering of the element."
if (!boundingBoxSize.isEmpty()) {
// Fallback to RenderSVGShape if rect has rounded corners or a non-scaling stroke.
if (rect->rx()->currentValue()->value(lengthContext) > 0 || rect->ry()->currentValue()->value(lengthContext) > 0 || hasNonScalingStroke()) {
RenderSVGShape::updateShapeFromElement();
m_usePathFallback = true;
return;
}
m_usePathFallback = false;
}
m_fillBoundingBox = FloatRect(FloatPoint(rect->x()->currentValue()->value(lengthContext), rect->y()->currentValue()->value(lengthContext)), boundingBoxSize); m_fillBoundingBox = FloatRect(FloatPoint(rect->x()->currentValue()->value(lengthContext), rect->y()->currentValue()->value(lengthContext)), boundingBoxSize);
// To decide if the stroke contains a point we create two rects which represent the inner and // To decide if the stroke contains a point we create two rects which represent the inner and
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment