Title: [115492] branches/chromium/1084/Source
Revision
115492
Author
[email protected]
Date
2012-04-27 14:08:56 -0700 (Fri, 27 Apr 2012)

Log Message

Merge 114791 - [chromium] Clip TransparencyWin to prevent OOM from large Skia canvas
https://bugs.webkit.org/show_bug.cgi?id=84289

Reviewed by James Robinson.

Source/WebCore:

TransparencyWin will create a Skia canvas of whatever size is passed
in, even if the result will ultimately be clipped. Handle the clip
implicitly and try (in some cases) to create a smaller canvas. This
can happen due to RenderBox::paintBoxDecorations passing a paint rect
down of the entire element's size.

Modes with more complicated transforms (ScaleTransform, UnTransform)
are not handled yet.

Tests: TransparencyWin.ClippedKeepTransformNoLayer
       TransparencyWin.ClippedKeepTransformOpaqueCompositeLayer
       TransparencyWin.ClippedKeepTransformOpaqueWhiteLayer

* platform/graphics/chromium/TransparencyWin.cpp:
(WebCore::TransparencyWin::computeLayerSize):

Source/WebKit/chromium:

Add a test that would OOM if the layer wasn't clipped. Also, verify
that clipping the canvas doesn't shift pixels around incorrectly.

* tests/TransparencyWinTest.cpp:
(WebCore::testClippedLayerKeepTransform):
(WebCore):
(WebCore::TEST):


[email protected]
Review URL: https://chromiumcodereview.appspot.com/10254020

Modified Paths

Diff

Modified: branches/chromium/1084/Source/WebCore/platform/graphics/chromium/TransparencyWin.cpp (115491 => 115492)


--- branches/chromium/1084/Source/WebCore/platform/graphics/chromium/TransparencyWin.cpp	2012-04-27 21:07:11 UTC (rev 115491)
+++ branches/chromium/1084/Source/WebCore/platform/graphics/chromium/TransparencyWin.cpp	2012-04-27 21:08:56 UTC (rev 115492)
@@ -210,11 +210,19 @@
         // uses the variable: to determine how to translate things to account
         // for the offset of the layer.
         m_transformedSourceRect = m_sourceRect;
-        m_layerSize = IntSize(m_sourceRect.width(), m_sourceRect.height());
-    } else {
+    } else if (m_transformMode == KeepTransform && m_layerMode != TextComposite) {
+        // FIXME: support clipping for other modes
+        IntRect clippedSourceRect = m_sourceRect;
+        SkRect clipBounds;
+        if (m_destContext->platformContext()->canvas()->getClipBounds(&clipBounds)) {
+            FloatRect clipRect(clipBounds.left(), clipBounds.top(), clipBounds.width(), clipBounds.height());
+            clippedSourceRect.intersect(enclosingIntRect(clipRect));
+        }
+        m_transformedSourceRect = m_orgTransform.mapRect(clippedSourceRect);
+    } else
         m_transformedSourceRect = m_orgTransform.mapRect(m_sourceRect);
-        m_layerSize = IntSize(m_transformedSourceRect.width(), m_transformedSourceRect.height());
-    }
+
+    m_layerSize = IntSize(m_transformedSourceRect.width(), m_transformedSourceRect.height());
 }
 
 void TransparencyWin::setupLayer()

Modified: branches/chromium/1084/Source/WebKit/chromium/tests/TransparencyWinTest.cpp (115491 => 115492)


--- branches/chromium/1084/Source/WebKit/chromium/tests/TransparencyWinTest.cpp	2012-04-27 21:07:11 UTC (rev 115491)
+++ branches/chromium/1084/Source/WebKit/chromium/tests/TransparencyWinTest.cpp	2012-04-27 21:08:56 UTC (rev 115492)
@@ -395,6 +395,66 @@
     EXPECT_EQ(green, getPixelAt(src->context(), 15, 7));
 }
 
+static void testClippedLayerKeepTransform(TransparencyWin::LayerMode layerMode)
+{
+    // Fill with white.
+    OwnPtr<ImageBuffer> src(ImageBuffer::create(IntSize(16, 16), 1, ColorSpaceDeviceRGB));
+    Color white(0xFFFFFFFF);
+    FloatRect fullRect(0, 0, 16, 16);
+    src->context()->fillRect(fullRect, white, ColorSpaceDeviceRGB);
+
+    IntRect clipRect(IntPoint(11, 5), IntSize(1, 1));
+    src->context()->clip(clipRect);
+
+    // Scroll down by 6 (coordinate system goes up).
+    src->context()->save();
+    src->context()->translate(0, -6);
+
+    Color red(0xFFFF0000);
+    Color green(0xFF00FF00);
+    {
+        // The transparency layer after translation will be @ (0, -6) with
+        // a size that would be too large to handle unclipped.
+        TransparencyWin helper;
+        helper.init(src->context(),
+                    layerMode,
+                    TransparencyWin::KeepTransform,
+                    IntRect(0, 0, INT_MAX, INT_MAX));
+
+        // Draw a green pixel at (11, 11). This should be within the clip rect
+        // and at (11, 5) after the transform.
+        FloatRect greenRect(11, 11, 1, 1);
+        helper.context()->fillRect(greenRect, green, ColorSpaceDeviceRGB);
+
+        // Draw a red pixel at (9, 9). This should be outside the clip rect
+        // and not drawn.
+        FloatRect redRect(9, 9, 1, 1);
+        helper.context()->fillRect(redRect, red, ColorSpaceDeviceRGB);
+        helper.composite();
+    }
+
+    src->context()->restore();
+
+    // Verify green pixel got drawn in clip rect and red pixel got clipped.
+    EXPECT_EQ(green, getPixelAt(src->context(), 11, 5));
+    EXPECT_EQ(white, getPixelAt(src->context(), 9, 3));
+}
+
+TEST(TransparencyWin, ClippedKeepTransformNoLayer)
+{
+    testClippedLayerKeepTransform(TransparencyWin::NoLayer);
+}
+
+TEST(TransparencyWin, ClippedKeepTransformOpaqueCompositeLayer)
+{
+    testClippedLayerKeepTransform(TransparencyWin::OpaqueCompositeLayer);
+}
+
+TEST(TransparencyWin, ClippedKeepTransformWhiteLayer)
+{
+    testClippedLayerKeepTransform(TransparencyWin::WhiteLayer);
+}
+
 // Same as OpaqueCompositeLayer, but the canvas has a rotation applied. This
 // tests that the propert transform is applied to the copied layer.
 TEST(TransparencyWin, RotateOpaqueCompositeLayer)
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to