Subpixel rendering: Rounded rect gets non-renderable at certain subpixel size.
authorzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 26 Jul 2014 04:37:31 +0000 (04:37 +0000)
committerzalan@apple.com <zalan@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 26 Jul 2014 04:37:31 +0000 (04:37 +0000)
https://bugs.webkit.org/show_bug.cgi?id=135314
<rdar://problem/17812921>

Reviewed by Tim Horton.

While calculating the rounded rect for painting, the radius is adjusted to compensate
for the pixel snapped size. However while scaling the radius, certain values overflow
(float) mantissa and it produces a non-renderable rounded rect where the radius becomes bigger
than the rectangle dimensions. In such cases, we need to shrink the radius to make it
renderable again.

Source/WebCore:
Test: transitions/rounded-rect-becomes-non-renderable-while-transitioning.html

* platform/graphics/RoundedRect.cpp:
(WebCore::RoundedRect::pixelSnappedRoundedRectForPainting): shrink the radius by
one device pixel. It is as good as any other small value.

LayoutTests:
* transitions/rounded-rect-becomes-non-renderable-while-transitioning-expected.txt: Added.
* transitions/rounded-rect-becomes-non-renderable-while-transitioning.html: Added.

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

LayoutTests/ChangeLog
LayoutTests/transitions/rounded-rect-becomes-non-renderable-while-transitioning-expected.txt [new file with mode: 0644]
LayoutTests/transitions/rounded-rect-becomes-non-renderable-while-transitioning.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/RoundedRect.cpp

index a0302c1..1998cc4 100644 (file)
@@ -1,3 +1,20 @@
+2014-07-25  Zalan Bujtas  <zalan@apple.com>
+
+        Subpixel rendering: Rounded rect gets non-renderable at certain subpixel size.
+        https://bugs.webkit.org/show_bug.cgi?id=135314
+        <rdar://problem/17812921>
+
+        Reviewed by Tim Horton.
+
+        While calculating the rounded rect for painting, the radius is adjusted to compensate
+        for the pixel snapped size. However while scaling the radius, certain values overflow
+        (float) mantissa and it produces a non-renderable rounded rect where the radius becomes bigger
+        than the rectangle dimensions. In such cases, we need to shrink the radius to make it
+        renderable again.
+
+        * transitions/rounded-rect-becomes-non-renderable-while-transitioning-expected.txt: Added.
+        * transitions/rounded-rect-becomes-non-renderable-while-transitioning.html: Added.
+
 2014-07-25  Jer Noble  <jer.noble@apple.com>
 
         [MSE] Playback stalls & readyState drops to HAVE_CURRENT_DATA at end of stream with unbalanced buffered SourceBuffers
diff --git a/LayoutTests/transitions/rounded-rect-becomes-non-renderable-while-transitioning-expected.txt b/LayoutTests/transitions/rounded-rect-becomes-non-renderable-while-transitioning-expected.txt
new file mode 100644 (file)
index 0000000..68fe806
--- /dev/null
@@ -0,0 +1,3 @@
+Test passes if it does not assert in debug builds.
+
+
diff --git a/LayoutTests/transitions/rounded-rect-becomes-non-renderable-while-transitioning.html b/LayoutTests/transitions/rounded-rect-becomes-non-renderable-while-transitioning.html
new file mode 100644 (file)
index 0000000..ed4fcac
--- /dev/null
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<head>
+<title>This tests that rounded rect stays renderable during while animating size.</title>
+<style>
+  #thumb {
+    background-color: red;
+    border: solid 1px transparent;
+    border-radius: 50%;
+    width: 100px;
+    height: 100px;
+    -webkit-transition: width 500ms, height 500ms;
+}
+</style>
+<script>
+    if (window.testRunner) {
+        window.testRunner.waitUntilDone();
+        window.testRunner.dumpAsText();
+      }
+
+    function transitionFinished() {
+        if (window.testRunner)
+            window.testRunner.notifyDone();
+    }
+
+    function start() {
+      var thumb = document.getElementById("thumb");
+      thumb.addEventListener("webkitTransitionEnd", transitionFinished, true);
+      thumb.style.width = "10px";
+      thumb.style.height = "10px";
+    }
+    
+</script>
+</head>
+<body onload=start()>
+  <p>Test passes if it does not assert in debug builds.</p>
+  <div id=thumb></div>
+</body>
index 5236285..498efe7 100644 (file)
@@ -1,3 +1,23 @@
+2014-07-25  Zalan Bujtas  <zalan@apple.com>
+
+        Subpixel rendering: Rounded rect gets non-renderable at certain subpixel size.
+        https://bugs.webkit.org/show_bug.cgi?id=135314
+        <rdar://problem/17812921>
+
+        Reviewed by Tim Horton.
+
+        While calculating the rounded rect for painting, the radius is adjusted to compensate
+        for the pixel snapped size. However while scaling the radius, certain values overflow
+        (float) mantissa and it produces a non-renderable rounded rect where the radius becomes bigger
+        than the rectangle dimensions. In such cases, we need to shrink the radius to make it
+        renderable again.
+
+        Test: transitions/rounded-rect-becomes-non-renderable-while-transitioning.html
+
+        * platform/graphics/RoundedRect.cpp:
+        (WebCore::RoundedRect::pixelSnappedRoundedRectForPainting): shrink the radius by
+        one device pixel. It is as good as any other small value.
+
 2014-07-25  Jer Noble  <jer.noble@apple.com>
 
         [EME][Mac] CDM error messages not piped through to MediaKeySession correctly; clients don't receive error events
index eb88ecb..a42d422 100644 (file)
@@ -249,8 +249,13 @@ FloatRoundedRect RoundedRect::pixelSnappedRoundedRectForPainting(float deviceSca
 
     // 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.
     FloatRoundedRect::Radii adjustedRadii = radii();
-    adjustedRadii.scale(pixelSnappedRect.width() / originalRect.width(), pixelSnappedRect.height() / originalRect.height());
+    adjustedRadii.scale(pixelSnappedRect.width() / originalRect.width().toFloat(), pixelSnappedRect.height() / originalRect.height().toFloat());
     FloatRoundedRect snappedRoundedRect = FloatRoundedRect(pixelSnappedRect, adjustedRadii);
+    if (!snappedRoundedRect.isRenderable()) {
+        // Floating point mantissa overflow can produce a non-renderable rounded rect.
+        adjustedRadii.shrink(1 / deviceScaleFactor);
+        snappedRoundedRect.setRadii(adjustedRadii);
+    }
     ASSERT(snappedRoundedRect.isRenderable());
     return snappedRoundedRect;
 }