Subpixel rendering: border-radius painting falls back to rectangle when the snapped...
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 5 Jun 2014 18:18:40 +0000 (18:18 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 5 Jun 2014 18:18:40 +0000 (18:18 +0000)
https://bugs.webkit.org/show_bug.cgi?id=133491

Reviewed by Simon Fraser.

Pixel snapping can change the rectangle's size when it is on a certain subpixel position. (usually it does not)
This patch ensures that the snapped rect is still renderable by adjusting the radii as well.

Source/WebCore:
Test: fast/borders/hidpi-border-radius-with-subpixel-margin-not-renderable.html

* platform/graphics/RoundedRect.cpp:
(WebCore::RoundedRect::Radii::scale):
(WebCore::RoundedRect::pixelSnappedRoundedRectForPainting):
* platform/graphics/RoundedRect.h:

LayoutTests:
* fast/borders/hidpi-border-radius-with-subpixel-margin-not-renderable-expected.html: Added.
* fast/borders/hidpi-border-radius-with-subpixel-margin-not-renderable.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@169620 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/fast/borders/hidpi-border-radius-with-subpixel-margin-not-renderable-expected.html [new file with mode: 0644]
LayoutTests/fast/borders/hidpi-border-radius-with-subpixel-margin-not-renderable.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/RoundedRect.cpp
Source/WebCore/platform/graphics/RoundedRect.h

index 9acd3c5..b95bc8c 100644 (file)
@@ -1,3 +1,16 @@
+2014-06-05  Zalan Bujtas  <zalan@apple.com>
+
+        Subpixel rendering: border-radius painting falls back to rectangle when the snapped rounded rect becomes non-renderable.
+        https://bugs.webkit.org/show_bug.cgi?id=133491
+
+        Reviewed by Simon Fraser.
+
+        Pixel snapping can change the rectangle's size when it is on a certain subpixel position. (usually it does not)
+        This patch ensures that the snapped rect is still renderable by adjusting the radii as well.
+
+        * fast/borders/hidpi-border-radius-with-subpixel-margin-not-renderable-expected.html: Added.
+        * fast/borders/hidpi-border-radius-with-subpixel-margin-not-renderable.html: Added.
+
 2014-06-05  Frédéric Wang  <fred.wang@free.fr>
 
         Apply Character-level mirroring to stretchy operators in RTL mode.
diff --git a/LayoutTests/fast/borders/hidpi-border-radius-with-subpixel-margin-not-renderable-expected.html b/LayoutTests/fast/borders/hidpi-border-radius-with-subpixel-margin-not-renderable-expected.html
new file mode 100644 (file)
index 0000000..e6d706e
--- /dev/null
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>This tests that rounded rect on subpixel position stays renderable.</title>
+<style>
+  div {
+    width: 20px;
+    height: 20px;
+    background-color: red;
+
+    margin-top: -0.5px;
+    border-bottom-left-radius: 20px;
+  }
+</style>
+</head>
+<body>
+  <div></div>
+</body>
+</html>
diff --git a/LayoutTests/fast/borders/hidpi-border-radius-with-subpixel-margin-not-renderable.html b/LayoutTests/fast/borders/hidpi-border-radius-with-subpixel-margin-not-renderable.html
new file mode 100644 (file)
index 0000000..472e7f9
--- /dev/null
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>This tests that rounded rect on subpixel position stays renderable.</title>
+<style>
+  div {
+    width: 20px;
+    height: 20px;
+    background-color: red;
+
+    margin-top: -0.53px;
+    border-bottom-left-radius: 20px;
+  }
+</style>
+</head>
+<body>
+  <div></div>
+</body>
+</html>
index 0004d8b..eab8202 100644 (file)
@@ -1,3 +1,20 @@
+2014-06-05  Zalan Bujtas  <zalan@apple.com>
+
+        Subpixel rendering: border-radius painting falls back to rectangle when the snapped rounded rect becomes non-renderable.
+        https://bugs.webkit.org/show_bug.cgi?id=133491
+
+        Reviewed by Simon Fraser.
+
+        Pixel snapping can change the rectangle's size when it is on a certain subpixel position. (usually it does not)
+        This patch ensures that the snapped rect is still renderable by adjusting the radii as well.
+
+        Test: fast/borders/hidpi-border-radius-with-subpixel-margin-not-renderable.html
+
+        * platform/graphics/RoundedRect.cpp:
+        (WebCore::RoundedRect::Radii::scale):
+        (WebCore::RoundedRect::pixelSnappedRoundedRectForPainting):
+        * platform/graphics/RoundedRect.h:
+
 2014-06-05  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r169587.
index 08683e6..0954108 100644 (file)
@@ -43,23 +43,27 @@ bool RoundedRect::Radii::isZero() const
 
 void RoundedRect::Radii::scale(float factor)
 {
-    if (factor == 1)
+    scale(factor, factor);
+}
+
+void RoundedRect::Radii::scale(float horizontalFactor, float verticalFactor)
+{
+    if (horizontalFactor == 1 && verticalFactor == 1)
         return;
 
     // If either radius on a corner becomes zero, reset both radii on that corner.
-    m_topLeft.scale(factor);
+    m_topLeft.scale(horizontalFactor, verticalFactor);
     if (!m_topLeft.width() || !m_topLeft.height())
         m_topLeft = LayoutSize();
-    m_topRight.scale(factor);
+    m_topRight.scale(horizontalFactor, verticalFactor);
     if (!m_topRight.width() || !m_topRight.height())
         m_topRight = LayoutSize();
-    m_bottomLeft.scale(factor);
+    m_bottomLeft.scale(horizontalFactor, verticalFactor);
     if (!m_bottomLeft.width() || !m_bottomLeft.height())
         m_bottomLeft = LayoutSize();
-    m_bottomRight.scale(factor);
+    m_bottomRight.scale(horizontalFactor, verticalFactor);
     if (!m_bottomRight.width() || !m_bottomRight.height())
         m_bottomRight = LayoutSize();
-
 }
 
 void RoundedRect::Radii::expand(const LayoutUnit& topWidth, const LayoutUnit& bottomWidth, const LayoutUnit& leftWidth, const LayoutUnit& rightWidth)
@@ -240,10 +244,11 @@ bool RoundedRect::intersectsQuad(const FloatQuad& quad) const
 FloatRoundedRect RoundedRect::pixelSnappedRoundedRectForPainting(float deviceScaleFactor) const
 {
     LayoutRect originalRect = rect();
-    FloatRect paintingRect = pixelSnappedForPainting(rect(), deviceScaleFactor);
-    FloatRoundedRect::Radii paintingRadii = radii();
-    paintingRadii.shrink(paintingRect.y() - originalRect.y(), originalRect.maxY() - paintingRect.maxY(), paintingRect.x() - originalRect.x(), originalRect.maxX() - paintingRect.maxX());
-    return FloatRoundedRect(paintingRect, paintingRadii);
+    FloatRect pixelSnappedRect = pixelSnappedForPainting(originalRect, deviceScaleFactor);
+    Radii adjustedRadii = radii();
+    // Snapping usually does not alter size, but when it does, we need to make sure that the final rect is still renderable by distributing the size delta proportionally.
+    adjustedRadii.scale(pixelSnappedRect.width() / originalRect.width(), pixelSnappedRect.height() / originalRect.height());
+    return FloatRoundedRect(pixelSnappedRect, adjustedRadii);
 }
 
 } // namespace WebCore
index ac14802..5a849fe 100644 (file)
@@ -64,6 +64,7 @@ public:
         void excludeLogicalEdges(bool isHorizontal, bool excludeLogicalLeftEdge, bool excludeLogicalRightEdge);
 
         void scale(float factor);
+        void scale(float horizontalFactor, float verticalFactor);
         void expand(const LayoutUnit& topWidth, const LayoutUnit& bottomWidth, const LayoutUnit& leftWidth, const LayoutUnit& rightWidth);
         void expand(const LayoutUnit& size) { expand(size, size, size, size); }
         void shrink(const LayoutUnit& topWidth, const LayoutUnit& bottomWidth, const LayoutUnit& leftWidth, const LayoutUnit& rightWidth) { expand(-topWidth, -bottomWidth, -leftWidth, -rightWidth); }