[chromium] Background filters for composited layers
authordanakj@chromium.org <danakj@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 13 Apr 2012 05:28:44 +0000 (05:28 +0000)
committerdanakj@chromium.org <danakj@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 13 Apr 2012 05:28:44 +0000 (05:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=80046

Reviewed by Adrienne Walker.

Source/WebCore:

Adds background filters to LayerChromium/CCLayerImpl. These filters are
applied to any pixels in the contents behind the layer and seen through
it.

This is done by adding a backgroundTexture() to the render surface, which
holds the read-back contents of the target framebuffer, background filter
applied, in the surface's own coordinate space. Then this is drawn back
into the frame buffer before the contents of the surface itself is drawn.

Tests: platform/chromium/compositing/filters/background-filter-blur-off-axis.html
       platform/chromium/compositing/filters/background-filter-blur-outsets.html
       platform/chromium/compositing/filters/background-filter-blur.html

* platform/graphics/chromium/LayerChromium.cpp:
(WebCore::LayerChromium::setBackgroundFilters):
(WebCore):
(WebCore::LayerChromium::pushPropertiesTo):
* platform/graphics/chromium/LayerChromium.h:
(LayerChromium):
(WebCore::LayerChromium::backgroundFilters):
* platform/graphics/chromium/LayerRendererChromium.cpp:
(WebCore::LayerRendererChromium::drawBackgroundFilters):
(WebCore):
(WebCore::LayerRendererChromium::drawRenderSurfaceQuad):
(WebCore::LayerRendererChromium::getFramebufferTexture):
(WebCore::LayerRendererChromium::isCurrentRenderSurface):
(WebCore::LayerRendererChromium::useRenderSurface):
(WebCore::LayerRendererChromium::useManagedTexture):
(WebCore::LayerRendererChromium::bindFramebufferToTexture):
(WebCore::LayerRendererChromium::setScissorToRect):
* platform/graphics/chromium/LayerRendererChromium.h:
(LayerRendererChromium):
* platform/graphics/chromium/RenderSurfaceChromium.h:
(WebCore::RenderSurfaceChromium::setBackgroundFilters):
(WebCore::RenderSurfaceChromium::backgroundFilters):
(RenderSurfaceChromium):
* platform/graphics/chromium/cc/CCLayerImpl.cpp:
(WebCore::CCLayerImpl::setBackgroundFilters):
(WebCore):
* platform/graphics/chromium/cc/CCLayerImpl.h:
(CCLayerImpl):
(WebCore::CCLayerImpl::backgroundFilters):
* platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:
(WebCore::subtreeShouldRenderToSeparateSurface):
(WebCore::calculateDrawTransformsAndVisibilityInternal):
* platform/graphics/chromium/cc/CCRenderSurface.cpp:
(WebCore::CCRenderSurface::drawableContentRect):
(WebCore::CCRenderSurface::prepareBackgroundTexture):
(WebCore):
(WebCore::CCRenderSurface::releaseBackgroundTexture):
(WebCore::CCRenderSurface::computeDeviceTransform):
(WebCore::CCRenderSurface::computeDeviceBoundingBox):
(WebCore::CCRenderSurface::computeReadbackDeviceBoundingBox):
(WebCore::CCRenderSurface::readbackDeviceContentRect):
(WebCore::copyTextureToFramebuffer):
(WebCore::CCRenderSurface::copyDeviceToBackgroundTexture):
(WebCore::getSkBitmapTextureId):
(WebCore::CCRenderSurface::drawContents):
(WebCore::CCRenderSurface::drawReplica):
(WebCore::CCRenderSurface::drawLayer):
(WebCore::CCRenderSurface::drawSurface):
(WebCore::CCRenderSurface::applyFilters):
* platform/graphics/chromium/cc/CCRenderSurface.h:
(CCRenderSurface):
(WebCore::CCRenderSurface::setBackgroundFilters):
(WebCore::CCRenderSurface::backgroundFilters):
(WebCore::CCRenderSurface::backgroundTexture):
* testing/Internals.cpp:
(WebCore):
(WebCore::Internals::setBackgroundBlurOnNode):
* testing/Internals.h:
(Internals):
* testing/Internals.idl:

Source/WebKit/chromium:

* tests/CCLayerImplTest.cpp:
(WebCore::TEST):

LayoutTests:

* platform/chromium/compositing/filters/background-filter-blur-expected.png: Added.
* platform/chromium/compositing/filters/background-filter-blur-expected.txt: Added.
* platform/chromium/compositing/filters/background-filter-blur-off-axis-expected.png: Added.
* platform/chromium/compositing/filters/background-filter-blur-off-axis-expected.txt: Added.
* platform/chromium/compositing/filters/background-filter-blur-off-axis.html: Added.
* platform/chromium/compositing/filters/background-filter-blur-outsets-expected.png: Added.
* platform/chromium/compositing/filters/background-filter-blur-outsets-expected.txt: Added.
* platform/chromium/compositing/filters/background-filter-blur-outsets.html: Added.
* platform/chromium/compositing/filters/background-filter-blur.html: Added.

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

26 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/chromium/compositing/filters/background-filter-blur-expected.png [new file with mode: 0644]
LayoutTests/platform/chromium/compositing/filters/background-filter-blur-expected.txt [new file with mode: 0644]
LayoutTests/platform/chromium/compositing/filters/background-filter-blur-off-axis-expected.png [new file with mode: 0644]
LayoutTests/platform/chromium/compositing/filters/background-filter-blur-off-axis-expected.txt [new file with mode: 0644]
LayoutTests/platform/chromium/compositing/filters/background-filter-blur-off-axis.html [new file with mode: 0644]
LayoutTests/platform/chromium/compositing/filters/background-filter-blur-outsets-expected.png [new file with mode: 0644]
LayoutTests/platform/chromium/compositing/filters/background-filter-blur-outsets-expected.txt [new file with mode: 0644]
LayoutTests/platform/chromium/compositing/filters/background-filter-blur-outsets.html [new file with mode: 0644]
LayoutTests/platform/chromium/compositing/filters/background-filter-blur.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/chromium/LayerChromium.cpp
Source/WebCore/platform/graphics/chromium/LayerChromium.h
Source/WebCore/platform/graphics/chromium/LayerRendererChromium.cpp
Source/WebCore/platform/graphics/chromium/LayerRendererChromium.h
Source/WebCore/platform/graphics/chromium/RenderSurfaceChromium.h
Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.cpp
Source/WebCore/platform/graphics/chromium/cc/CCLayerImpl.h
Source/WebCore/platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp
Source/WebCore/platform/graphics/chromium/cc/CCRenderSurface.cpp
Source/WebCore/platform/graphics/chromium/cc/CCRenderSurface.h
Source/WebCore/testing/Internals.cpp
Source/WebCore/testing/Internals.h
Source/WebCore/testing/Internals.idl
Source/WebKit/chromium/ChangeLog
Source/WebKit/chromium/tests/CCLayerImplTest.cpp

index 69bc003..ca3ac71 100644 (file)
@@ -1,3 +1,20 @@
+2012-04-12  Dana Jansens  <danakj@chromium.org>
+
+        [chromium] Background filters for composited layers
+        https://bugs.webkit.org/show_bug.cgi?id=80046
+
+        Reviewed by Adrienne Walker.
+
+        * platform/chromium/compositing/filters/background-filter-blur-expected.png: Added.
+        * platform/chromium/compositing/filters/background-filter-blur-expected.txt: Added.
+        * platform/chromium/compositing/filters/background-filter-blur-off-axis-expected.png: Added.
+        * platform/chromium/compositing/filters/background-filter-blur-off-axis-expected.txt: Added.
+        * platform/chromium/compositing/filters/background-filter-blur-off-axis.html: Added.
+        * platform/chromium/compositing/filters/background-filter-blur-outsets-expected.png: Added.
+        * platform/chromium/compositing/filters/background-filter-blur-outsets-expected.txt: Added.
+        * platform/chromium/compositing/filters/background-filter-blur-outsets.html: Added.
+        * platform/chromium/compositing/filters/background-filter-blur.html: Added.
+
 2012-04-12  Alexey Proskuryakov  <ap@apple.com>
 
         REGRESSION (r113900): Text tests started failing
diff --git a/LayoutTests/platform/chromium/compositing/filters/background-filter-blur-expected.png b/LayoutTests/platform/chromium/compositing/filters/background-filter-blur-expected.png
new file mode 100644 (file)
index 0000000..ee3bc36
Binary files /dev/null and b/LayoutTests/platform/chromium/compositing/filters/background-filter-blur-expected.png differ
diff --git a/LayoutTests/platform/chromium/compositing/filters/background-filter-blur-expected.txt b/LayoutTests/platform/chromium/compositing/filters/background-filter-blur-expected.txt
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/LayoutTests/platform/chromium/compositing/filters/background-filter-blur-off-axis-expected.png b/LayoutTests/platform/chromium/compositing/filters/background-filter-blur-off-axis-expected.png
new file mode 100644 (file)
index 0000000..1c28727
Binary files /dev/null and b/LayoutTests/platform/chromium/compositing/filters/background-filter-blur-off-axis-expected.png differ
diff --git a/LayoutTests/platform/chromium/compositing/filters/background-filter-blur-off-axis-expected.txt b/LayoutTests/platform/chromium/compositing/filters/background-filter-blur-off-axis-expected.txt
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/LayoutTests/platform/chromium/compositing/filters/background-filter-blur-off-axis.html b/LayoutTests/platform/chromium/compositing/filters/background-filter-blur-off-axis.html
new file mode 100644 (file)
index 0000000..5a4df44
--- /dev/null
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html><head>
+<title>Background filter blur test.</title>
+<style type="text/css">
+  .composited {
+    -webkit-transform: translateZ(0);
+  }
+  .green {
+    background-color: green;
+  }
+  body {
+    -webkit-perspective: 200px;
+  }
+  #blur {
+    -webkit-transform-style: preserve-3d;
+    -webkit-transform: rotateZ(-15deg) rotateY(90deg) rotateX(45deg) translate(70px, 60px);
+  }
+</style>
+<script type="text/javascript">
+  function setBlur() {
+    var blurNode = window.document.getElementById('blur');
+    window.internals.setBackgroundBlurOnNode(blurNode, 2);
+    layoutTestController.notifyDone();
+  }
+
+  if (window.layoutTestController) {
+    if (window.internals) {
+      layoutTestController.waitUntilDone();
+      window.setTimeout(setBlur, 0);
+    }
+    layoutTestController.dumpAsText(true);
+  }
+</script>
+</head>
+
+<body>
+<!--
+   This verifies that the perspective of the clear layer (with black border) does not influence the blending of the
+   green box behind it. Also verifies that the blur is correctly clipped inside the transformed clear layer.
+-->
+<div id="object" class="composited green" style="position:absolute; left:50px; top:50px; width:200px; height:200px;"></div>
+<div id="blur" style="position:absolute; left:30px; top:30px; width:240px; height:240px; border:1px solid black;"></div>
+</body>
+</html>
diff --git a/LayoutTests/platform/chromium/compositing/filters/background-filter-blur-outsets-expected.png b/LayoutTests/platform/chromium/compositing/filters/background-filter-blur-outsets-expected.png
new file mode 100644 (file)
index 0000000..a8ffd0c
Binary files /dev/null and b/LayoutTests/platform/chromium/compositing/filters/background-filter-blur-outsets-expected.png differ
diff --git a/LayoutTests/platform/chromium/compositing/filters/background-filter-blur-outsets-expected.txt b/LayoutTests/platform/chromium/compositing/filters/background-filter-blur-outsets-expected.txt
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/LayoutTests/platform/chromium/compositing/filters/background-filter-blur-outsets.html b/LayoutTests/platform/chromium/compositing/filters/background-filter-blur-outsets.html
new file mode 100644 (file)
index 0000000..f8793f2
--- /dev/null
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html><head>
+<title>Background filter blur outsets test.</title>
+<style type="text/css">
+  .composited {
+    -webkit-transform: translateZ(0);
+  }
+  .green-border {
+    border: 10px solid green;
+  }
+</style>
+<script type="text/javascript">
+  function setBlur() {
+    var blurNode = window.document.getElementById('blur');
+    window.internals.setBackgroundBlurOnNode(blurNode, 10);
+    layoutTestController.notifyDone();
+  }
+
+  if (window.layoutTestController) {
+    if (window.internals) {
+      window.setTimeout(setBlur, 0);
+      layoutTestController.waitUntilDone();
+    }
+    layoutTestController.dumpAsText(true);
+  }
+</script>
+</head>
+<body>
+<!--
+   The green border is outside the layer with background blur, but the background blur should use pixels from outside
+   its layer borders, up to the radius of the blur effect. So the border should be blurred underneath the top layer
+   causing the inside of the border to be blurred.
+  -->
+<div class="composited green-border" style="position:absolute; left:50px; top:50px; width:200px; height:200px;"></div>
+<div id="blur" style="position:absolute; left:59px; top:59px; width:200px; height:200px; border:1px solid black;"></div>
+</body>
+</html>
diff --git a/LayoutTests/platform/chromium/compositing/filters/background-filter-blur.html b/LayoutTests/platform/chromium/compositing/filters/background-filter-blur.html
new file mode 100644 (file)
index 0000000..2a9ec3f
--- /dev/null
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html><head>
+<title>Background filter blur test.</title>
+<style type="text/css">
+  .composited {
+    -webkit-transform: translateZ(0);
+  }
+  .green {
+    background-color: green;
+  }
+</style>
+<script type="text/javascript">
+  function setBlur() {
+    var blurNode = window.document.getElementById('blur');
+    window.internals.setBackgroundBlurOnNode(blurNode, 2);
+    layoutTestController.notifyDone();
+  }
+
+  if (window.layoutTestController) {
+    if (window.internals) {
+      window.setTimeout(setBlur, 0);
+      layoutTestController.waitUntilDone();
+    }
+    layoutTestController.dumpAsText(true);
+  }
+</script>
+</head>
+
+<body>
+<!--
+   The green box is entirely behind a layer with background blur, so it should appear blurred on its edges.
+  -->
+<div class="composited green" style="position:absolute; left:50px; top:50px; width:200px; height:200px;"></div>
+<div id="blur" style="position:absolute; left:30px; top:30px; width:240px; height:240px; border:1px solid white;"></div>
+</body>
+</html>
index 3b38a72..5700eae 100644 (file)
@@ -1,3 +1,84 @@
+2012-04-12  Dana Jansens  <danakj@chromium.org>
+
+        [chromium] Background filters for composited layers
+        https://bugs.webkit.org/show_bug.cgi?id=80046
+
+        Reviewed by Adrienne Walker.
+
+        Adds background filters to LayerChromium/CCLayerImpl. These filters are
+        applied to any pixels in the contents behind the layer and seen through
+        it.
+
+        This is done by adding a backgroundTexture() to the render surface, which
+        holds the read-back contents of the target framebuffer, background filter
+        applied, in the surface's own coordinate space. Then this is drawn back
+        into the frame buffer before the contents of the surface itself is drawn.
+
+        Tests: platform/chromium/compositing/filters/background-filter-blur-off-axis.html
+               platform/chromium/compositing/filters/background-filter-blur-outsets.html
+               platform/chromium/compositing/filters/background-filter-blur.html
+
+        * platform/graphics/chromium/LayerChromium.cpp:
+        (WebCore::LayerChromium::setBackgroundFilters):
+        (WebCore):
+        (WebCore::LayerChromium::pushPropertiesTo):
+        * platform/graphics/chromium/LayerChromium.h:
+        (LayerChromium):
+        (WebCore::LayerChromium::backgroundFilters):
+        * platform/graphics/chromium/LayerRendererChromium.cpp:
+        (WebCore::LayerRendererChromium::drawBackgroundFilters):
+        (WebCore):
+        (WebCore::LayerRendererChromium::drawRenderSurfaceQuad):
+        (WebCore::LayerRendererChromium::getFramebufferTexture):
+        (WebCore::LayerRendererChromium::isCurrentRenderSurface):
+        (WebCore::LayerRendererChromium::useRenderSurface):
+        (WebCore::LayerRendererChromium::useManagedTexture):
+        (WebCore::LayerRendererChromium::bindFramebufferToTexture):
+        (WebCore::LayerRendererChromium::setScissorToRect):
+        * platform/graphics/chromium/LayerRendererChromium.h:
+        (LayerRendererChromium):
+        * platform/graphics/chromium/RenderSurfaceChromium.h:
+        (WebCore::RenderSurfaceChromium::setBackgroundFilters):
+        (WebCore::RenderSurfaceChromium::backgroundFilters):
+        (RenderSurfaceChromium):
+        * platform/graphics/chromium/cc/CCLayerImpl.cpp:
+        (WebCore::CCLayerImpl::setBackgroundFilters):
+        (WebCore):
+        * platform/graphics/chromium/cc/CCLayerImpl.h:
+        (CCLayerImpl):
+        (WebCore::CCLayerImpl::backgroundFilters):
+        * platform/graphics/chromium/cc/CCLayerTreeHostCommon.cpp:
+        (WebCore::subtreeShouldRenderToSeparateSurface):
+        (WebCore::calculateDrawTransformsAndVisibilityInternal):
+        * platform/graphics/chromium/cc/CCRenderSurface.cpp:
+        (WebCore::CCRenderSurface::drawableContentRect):
+        (WebCore::CCRenderSurface::prepareBackgroundTexture):
+        (WebCore):
+        (WebCore::CCRenderSurface::releaseBackgroundTexture):
+        (WebCore::CCRenderSurface::computeDeviceTransform):
+        (WebCore::CCRenderSurface::computeDeviceBoundingBox):
+        (WebCore::CCRenderSurface::computeReadbackDeviceBoundingBox):
+        (WebCore::CCRenderSurface::readbackDeviceContentRect):
+        (WebCore::copyTextureToFramebuffer):
+        (WebCore::CCRenderSurface::copyDeviceToBackgroundTexture):
+        (WebCore::getSkBitmapTextureId):
+        (WebCore::CCRenderSurface::drawContents):
+        (WebCore::CCRenderSurface::drawReplica):
+        (WebCore::CCRenderSurface::drawLayer):
+        (WebCore::CCRenderSurface::drawSurface):
+        (WebCore::CCRenderSurface::applyFilters):
+        * platform/graphics/chromium/cc/CCRenderSurface.h:
+        (CCRenderSurface):
+        (WebCore::CCRenderSurface::setBackgroundFilters):
+        (WebCore::CCRenderSurface::backgroundFilters):
+        (WebCore::CCRenderSurface::backgroundTexture):
+        * testing/Internals.cpp:
+        (WebCore):
+        (WebCore::Internals::setBackgroundBlurOnNode):
+        * testing/Internals.h:
+        (Internals):
+        * testing/Internals.idl:
+
 2012-04-12  Adam Barth  <abarth@webkit.org>
 
         Remove V8DOMWindowShell::setLocation
index 10d84c5..112b03a 100644 (file)
@@ -315,6 +315,14 @@ void LayerChromium::setFilters(const FilterOperations& filters)
         CCLayerTreeHost::setNeedsFilterContext(true);
 }
 
+void LayerChromium::setBackgroundFilters(const FilterOperations& backgroundFilters)
+{
+    if (m_backgroundFilters == backgroundFilters)
+        return;
+    m_backgroundFilters = backgroundFilters;
+    setNeedsCommit();
+}
+
 void LayerChromium::setOpacity(float opacity)
 {
     if (m_opacity == opacity)
@@ -475,6 +483,7 @@ void LayerChromium::pushPropertiesTo(CCLayerImpl* layer)
         layer->setFilters(filters());
 
     layer->setFilters(filters());
+    layer->setBackgroundFilters(backgroundFilters());
     layer->setIsNonCompositedContent(m_isNonCompositedContent);
     layer->setMasksToBounds(m_masksToBounds);
     layer->setScrollable(m_scrollable);
index 26f6d03..58a8d07 100644 (file)
@@ -118,6 +118,11 @@ public:
     void setFilters(const FilterOperations&);
     const FilterOperations& filters() const { return m_filters; }
 
+    // Background filters are filters applied to what is behind this layer, when they are viewed through non-opaque
+    // regions in this layer. They are used through the WebLayer interface, and are not exposed to HTML.
+    void setBackgroundFilters(const FilterOperations&);
+    const FilterOperations& backgroundFilters() const { return m_backgroundFilters; }
+
     virtual void setOpaque(bool);
     bool opaque() const { return m_opaque; }
 
@@ -312,6 +317,7 @@ private:
     String m_debugName;
     float m_opacity;
     FilterOperations m_filters;
+    FilterOperations m_backgroundFilters;
     float m_anchorPointZ;
     bool m_isDrawable;
     bool m_masksToBounds;
index f4a500a..8d7ca26 100644 (file)
@@ -37,6 +37,7 @@
 #include "Extensions3DChromium.h"
 #include "FloatQuad.h"
 #include "GeometryBinding.h"
+#include "GrTexture.h"
 #include "GraphicsContext3D.h"
 #include "LayerChromium.h"
 #include "LayerPainterChromium.h"
@@ -207,6 +208,7 @@ LayerRendererChromium::LayerRendererChromium(LayerRendererChromiumClient* client
                                              PassRefPtr<GraphicsContext3D> context)
     : m_client(client)
     , m_currentRenderSurface(0)
+    , m_currentManagedTexture(0)
     , m_offscreenFramebufferId(0)
     , m_context(context)
     , m_defaultRenderSurface(0)
@@ -544,14 +546,73 @@ void LayerRendererChromium::drawDebugBorderQuad(const CCDebugBorderDrawQuad* qua
     GLC(context(), context()->drawElements(GraphicsContext3D::LINE_LOOP, 4, GraphicsContext3D::UNSIGNED_SHORT, 6 * sizeof(unsigned short)));
 }
 
+void LayerRendererChromium::drawBackgroundFilters(const CCRenderSurfaceDrawQuad* quad)
+{
+    // This method draws a background filter, which applies a filter to any pixels behind the quad and seen through its background.
+    // The algorithm works as follows:
+    // 1. Compute a bounding box around the pixels that will be visible through the quad.
+    // 2. Read the pixels in the bounding box into a buffer R.
+    // 3. Apply the background filter to R, so that it is applied in the pixels' coordinate space.
+    // 4. Apply the quad's inverse transform to map the pixels in R into the quad's content space. This implicitly
+    // clips R by the content bounds of the quad since the destination texture has bounds matching the quad's content.
+    // 5. Draw the background texture for the contents using the same transform as used to draw the contents itself. This is done
+    // without blending to replace the current background pixels with the new filtered background.
+    // 6. Draw the contents of the quad over drop of the new background with blending, as per usual. The filtered background
+    // pixels will show through any non-opaque pixels in this draws.
+    //
+    // Pixel copies in this algorithm occur at steps 2, 3, 4, and 5.
+
+    CCRenderSurface* drawingSurface = quad->layer()->renderSurface();
+    if (drawingSurface->backgroundFilters().isEmpty())
+        return;
+
+    // FIXME: We only allow background filters on the root render surface because other surfaces may contain
+    // translucent pixels, and the contents behind those translucent pixels wouldn't have the filter applied.
+    if (!isCurrentRenderSurface(m_defaultRenderSurface))
+        return;
+
+    const TransformationMatrix& surfaceDrawTransform = quad->isReplica() ? drawingSurface->replicaDrawTransform() : drawingSurface->drawTransform();
+
+    // FIXME: Do a single readback for both the surface and replica and cache the filtered results (once filter textures are not reused).
+    IntRect deviceRect = drawingSurface->readbackDeviceContentRect(this, surfaceDrawTransform);
+    deviceRect.intersect(m_currentRenderSurface->contentRect());
+
+    OwnPtr<ManagedTexture> deviceBackgroundTexture = ManagedTexture::create(m_renderSurfaceTextureManager.get());
+    if (!getFramebufferTexture(deviceBackgroundTexture.get(), deviceRect))
+        return;
+
+    SkBitmap filteredDeviceBackground = drawingSurface->applyFilters(this, drawingSurface->backgroundFilters(), deviceBackgroundTexture.get());
+    if (!filteredDeviceBackground.getTexture())
+        return;
+
+    GrTexture* texture = reinterpret_cast<GrTexture*>(filteredDeviceBackground.getTexture());
+    int filteredDeviceBackgroundTextureId = texture->getTextureHandle();
+
+    if (!drawingSurface->prepareBackgroundTexture(this))
+        return;
+
+    // This must be computed before switching the target render surface to the background texture.
+    TransformationMatrix contentsDeviceTransform = drawingSurface->computeDeviceTransform(this, surfaceDrawTransform);
+
+    CCRenderSurface* targetRenderSurface = m_currentRenderSurface;
+    if (useManagedTexture(drawingSurface->backgroundTexture(), drawingSurface->contentRect())) {
+        drawingSurface->copyDeviceToBackgroundTexture(this, filteredDeviceBackgroundTextureId, deviceRect, contentsDeviceTransform);
+        useRenderSurface(targetRenderSurface);
+    }
+}
+
 void LayerRendererChromium::drawRenderSurfaceQuad(const CCRenderSurfaceDrawQuad* quad)
 {
     CCLayerImpl* layer = quad->layer();
+
+    drawBackgroundFilters(quad);
+
     layer->renderSurface()->setScissorRect(this, quad->surfaceDamageRect());
     if (quad->isReplica())
         layer->renderSurface()->drawReplica(this);
     else
         layer->renderSurface()->drawContents(this);
+    layer->renderSurface()->releaseBackgroundTexture();
     layer->renderSurface()->releaseContentsTexture();
 }
 
@@ -1218,6 +1279,17 @@ void LayerRendererChromium::getFramebufferPixels(void *pixels, const IntRect& re
     }
 }
 
+bool LayerRendererChromium::getFramebufferTexture(ManagedTexture* texture, const IntRect& deviceRect)
+{
+    if (!texture->reserve(deviceRect.size(), GraphicsContext3D::RGB))
+        return false;
+
+    texture->bindTexture(m_context.get(), m_renderSurfaceTextureAllocator.get());
+    GLC(m_context, m_context->copyTexImage2D(GraphicsContext3D::TEXTURE_2D, 0, texture->format(),
+                                             deviceRect.x(), deviceRect.y(), deviceRect.width(), deviceRect.height(), 0));
+    return true;
+}
+
 ManagedTexture* LayerRendererChromium::getOffscreenLayerTexture()
 {
     return settings().compositeOffscreen && rootLayer() ? rootLayer()->renderSurface()->contentsTexture() : 0;
@@ -1241,9 +1313,17 @@ void LayerRendererChromium::copyOffscreenTextureToDisplay()
     }
 }
 
+bool LayerRendererChromium::isCurrentRenderSurface(CCRenderSurface* renderSurface)
+{
+    // If renderSurface is 0, we can't tell if we are already using it, since m_currentRenderSurface is
+    // initialized to 0.
+    return m_currentRenderSurface == renderSurface && !m_currentManagedTexture;
+}
+
 bool LayerRendererChromium::useRenderSurface(CCRenderSurface* renderSurface)
 {
     m_currentRenderSurface = renderSurface;
+    m_currentManagedTexture = 0;
 
     if ((renderSurface == m_defaultRenderSurface && !settings().compositeOffscreen) || (!renderSurface && settings().compositeOffscreen)) {
         GLC(m_context.get(), m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, 0));
@@ -1254,12 +1334,25 @@ bool LayerRendererChromium::useRenderSurface(CCRenderSurface* renderSurface)
         return true;
     }
 
-    GLC(m_context.get(), m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_offscreenFramebufferId));
-
     if (!renderSurface->prepareContentsTexture(this))
         return false;
 
-    renderSurface->contentsTexture()->framebufferTexture2D(m_context.get(), m_renderSurfaceTextureAllocator.get());
+    return bindFramebufferToTexture(renderSurface->contentsTexture(), renderSurface->contentRect());
+}
+
+bool LayerRendererChromium::useManagedTexture(ManagedTexture* texture, const IntRect& viewportRect)
+{
+    m_currentRenderSurface = 0;
+    m_currentManagedTexture = texture;
+
+    return bindFramebufferToTexture(texture, viewportRect);
+}
+
+bool LayerRendererChromium::bindFramebufferToTexture(ManagedTexture* texture, const IntRect& viewportRect)
+{
+    GLC(m_context.get(), m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_offscreenFramebufferId));
+
+    texture->framebufferTexture2D(m_context.get(), m_renderSurfaceTextureAllocator.get());
 
 #if !defined ( NDEBUG )
     if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
@@ -1268,7 +1361,7 @@ bool LayerRendererChromium::useRenderSurface(CCRenderSurface* renderSurface)
     }
 #endif
 
-    setDrawViewportRect(renderSurface->contentRect(), false);
+    setDrawViewportRect(viewportRect, false);
 
     return true;
 }
@@ -1288,7 +1381,7 @@ void LayerRendererChromium::setScissorToRect(const IntRect& scissorRect)
     // of the GL scissor is the bottom of our layer.
     // But, if rendering to offscreen texture, we reverse our sense of 'upside down'.
     int scissorY;
-    if (m_currentRenderSurface == m_defaultRenderSurface && !settings().compositeOffscreen)
+    if (isCurrentRenderSurface(m_defaultRenderSurface) && !settings().compositeOffscreen)
         scissorY = m_currentRenderSurface->contentRect().height() - (scissorRect.maxY() - m_currentRenderSurface->contentRect().y());
     else
         scissorY = scissorRect.y() - contentRect.y();
index 7cb9eb5..d501531 100644 (file)
@@ -142,6 +142,7 @@ public:
     const CCVideoLayerImpl::StreamTextureProgram* streamTextureLayerProgram();
 
     void getFramebufferPixels(void *pixels, const IntRect&);
+    bool getFramebufferTexture(ManagedTexture*, const IntRect& deviceRect);
 
     TextureManager* renderSurfaceTextureManager() const { return m_renderSurfaceTextureManager.get(); }
     TextureCopier* textureCopier() const { return m_textureCopier.get(); }
@@ -178,6 +179,7 @@ private:
     void drawQuad(const CCDrawQuad*, const FloatRect& surfaceDamageRect);
     void drawCheckerboardQuad(const CCCheckerboardDrawQuad*);
     void drawDebugBorderQuad(const CCDebugBorderDrawQuad*);
+    void drawBackgroundFilters(const CCRenderSurfaceDrawQuad*);
     void drawRenderSurfaceQuad(const CCRenderSurfaceDrawQuad*);
     void drawSolidColorQuad(const CCSolidColorDrawQuad*);
     void drawTextureQuad(const CCTextureDrawQuad*);
@@ -197,7 +199,13 @@ private:
 
     void setDrawViewportRect(const IntRect&, bool flipY);
 
+    // The current drawing target is either a RenderSurface or ManagedTexture. Use these functions to switch to a new drawing target.
     bool useRenderSurface(CCRenderSurface*);
+    bool useManagedTexture(ManagedTexture*, const IntRect& viewportRect);
+    bool isCurrentRenderSurface(CCRenderSurface*);
+
+    bool bindFramebufferToTexture(ManagedTexture*, const IntRect& viewportRect);
+
     void clearRenderSurface(CCRenderSurface*, CCRenderSurface* rootRenderSurface, const FloatRect& surfaceDamageRect);
 
     void releaseRenderSurfaceTextures();
@@ -222,6 +230,7 @@ private:
     TransformationMatrix m_windowMatrix;
 
     CCRenderSurface* m_currentRenderSurface;
+    ManagedTexture* m_currentManagedTexture;
     unsigned m_offscreenFramebufferId;
 
     // Store values that are shared between instances of each layer type
index 83a21d9..9a84ebb 100644 (file)
@@ -93,6 +93,9 @@ public:
     void setFilters(const FilterOperations& filters) { m_filters = filters; }
     const FilterOperations& filters() const { return m_filters; }
 
+    void setBackgroundFilters(const FilterOperations& filters) { m_backgroundFilters = filters; }
+    const FilterOperations& backgroundFilters() const { return m_backgroundFilters; }
+
     bool skipsDraw() const { return m_skipsDraw; }
     void setSkipsDraw(bool skipsDraw) { m_skipsDraw = skipsDraw; }
 
@@ -122,6 +125,7 @@ private:
     bool m_targetSurfaceTransformsAreAnimating;
     bool m_screenSpaceTransformsAreAnimating;
     FilterOperations m_filters;
+    FilterOperations m_backgroundFilters;
     IntRect m_clipRect;
     Vector<RefPtr<LayerChromium> > m_layerList;
 
index 850805e..78294ba 100644 (file)
@@ -364,6 +364,15 @@ void CCLayerImpl::setFilters(const FilterOperations& filters)
     noteLayerPropertyChangedForSubtree();
 }
 
+void CCLayerImpl::setBackgroundFilters(const FilterOperations& backgroundFilters)
+{
+    if (m_backgroundFilters == backgroundFilters)
+        return;
+
+    m_backgroundFilters = backgroundFilters;
+    m_layerPropertyChanged = true;
+}
+
 void CCLayerImpl::setMasksToBounds(bool masksToBounds)
 {
     if (m_masksToBounds == masksToBounds)
index 055944f..3f08d68 100644 (file)
@@ -110,6 +110,9 @@ public:
     void setFilters(const FilterOperations&);
     const FilterOperations& filters() const { return m_filters; }
 
+    void setBackgroundFilters(const FilterOperations&);
+    const FilterOperations& backgroundFilters() const { return m_backgroundFilters; }
+
     void setMasksToBounds(bool);
     bool masksToBounds() const { return m_masksToBounds; }
 
@@ -335,6 +338,7 @@ private:
     String m_debugName;
 
     FilterOperations m_filters;
+    FilterOperations m_backgroundFilters;
 
     TransformationMatrix m_drawTransform;
     TransformationMatrix m_screenSpaceTransform;
index a99f15a..60020b5 100644 (file)
@@ -220,7 +220,7 @@ static bool subtreeShouldRenderToSeparateSurface(LayerType* layer, bool axisAlig
         return true;
 
     // If the layer uses a CSS filter.
-    if (!layer->filters().isEmpty())
+    if (!layer->filters().isEmpty() || !layer->backgroundFilters().isEmpty())
         return true;
 
     // If the layer flattens its subtree (i.e. the layer doesn't preserve-3d), but it is
@@ -451,6 +451,8 @@ static bool calculateDrawTransformsAndVisibilityInternal(LayerType* layer, Layer
             nearestAncestorThatMovesPixels = renderSurface;
         renderSurface->setNearestAncestorThatMovesPixels(nearestAncestorThatMovesPixels);
 
+        renderSurface->setBackgroundFilters(layer->backgroundFilters());
+
         renderSurfaceLayerList.append(layer);
     } else {
         layer->setDrawTransform(combinedTransform);
index c4793a5..c8b91cf 100644 (file)
@@ -71,7 +71,7 @@ FloatRect CCRenderSurface::drawableContentRect() const
     FloatRect localContentRect(-0.5 * m_contentRect.width(), -0.5 * m_contentRect.height(),
                                m_contentRect.width(), m_contentRect.height());
     FloatRect drawableContentRect = m_drawTransform.mapRect(localContentRect);
-    if (m_owningLayer->replicaLayer())
+    if (hasReplica())
         drawableContentRect.unite(m_replicaDrawTransform.mapRect(localContentRect));
 
     return drawableContentRect;
@@ -104,6 +104,110 @@ void CCRenderSurface::releaseContentsTexture()
     m_contentsTexture->unreserve();
 }
 
+bool CCRenderSurface::prepareBackgroundTexture(LayerRendererChromium* layerRenderer)
+{
+    IntSize requiredSize(m_contentRect.size());
+    TextureManager* textureManager = layerRenderer->renderSurfaceTextureManager();
+
+    if (!m_backgroundTexture)
+        m_backgroundTexture = ManagedTexture::create(textureManager);
+
+    if (m_backgroundTexture->isReserved())
+        return true;
+
+    if (!m_backgroundTexture->reserve(requiredSize, GraphicsContext3D::RGBA))
+        return false;
+
+    return true;
+}
+
+void CCRenderSurface::releaseBackgroundTexture()
+{
+    if (!m_backgroundTexture)
+        return;
+    m_backgroundTexture->unreserve();
+}
+
+TransformationMatrix CCRenderSurface::computeDeviceTransform(LayerRendererChromium* layerRenderer, const TransformationMatrix& drawTransform) const
+{
+    TransformationMatrix renderTransform = drawTransform;
+    // Apply a scaling factor to size the quad from 1x1 to its intended size.
+    renderTransform.scale3d(m_contentRect.width(), m_contentRect.height(), 1);
+    TransformationMatrix deviceTransform = TransformationMatrix(layerRenderer->windowMatrix() * layerRenderer->projectionMatrix() * renderTransform).to2dTransform();
+    return deviceTransform;
+}
+
+IntRect CCRenderSurface::computeDeviceBoundingBox(LayerRendererChromium* layerRenderer, const TransformationMatrix& drawTransform) const
+{
+    TransformationMatrix contentsDeviceTransform = computeDeviceTransform(layerRenderer, drawTransform);
+
+    // Can only draw surface if device matrix is invertible.
+    if (!contentsDeviceTransform.isInvertible())
+        return IntRect();
+
+    FloatQuad deviceQuad = contentsDeviceTransform.mapQuad(layerRenderer->sharedGeometryQuad());
+    return enclosingIntRect(deviceQuad.boundingBox());
+}
+
+IntRect CCRenderSurface::computeReadbackDeviceBoundingBox(LayerRendererChromium* layerRenderer, const TransformationMatrix& drawTransform) const
+{
+    IntRect deviceRect = computeDeviceBoundingBox(layerRenderer, drawTransform);
+
+    if (m_backgroundFilters.isEmpty())
+        return deviceRect;
+
+    int top, right, bottom, left;
+    m_backgroundFilters.getOutsets(top, right, bottom, left);
+    deviceRect.move(-left, -top);
+    deviceRect.expand(left + right, top + bottom);
+
+    return deviceRect;
+}
+
+IntRect CCRenderSurface::readbackDeviceContentRect(LayerRendererChromium* layerRenderer, const TransformationMatrix& drawTransform) const
+{
+    return computeReadbackDeviceBoundingBox(layerRenderer, drawTransform);
+}
+
+static void copyTextureToFramebuffer(LayerRendererChromium* layerRenderer, int textureId, const IntSize& bounds, const TransformationMatrix& drawMatrix)
+{
+    const CCRenderSurface::Program* program = layerRenderer->renderSurfaceProgram();
+
+    GLC(layerRenderer->context(), layerRenderer->context()->activeTexture(GraphicsContext3D::TEXTURE0));
+    GLC(layerRenderer->context(), layerRenderer->context()->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId));
+    GLC(layerRenderer->context(), layerRenderer->context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR));
+    GLC(layerRenderer->context(), layerRenderer->context()->texParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR));
+
+    GLC(layerRenderer->context(), layerRenderer->context()->useProgram(program->program()));
+    GLC(layerRenderer->context(), layerRenderer->context()->uniform1i(program->fragmentShader().samplerLocation(), 0));
+    layerRenderer->drawTexturedQuad(drawMatrix, bounds.width(), bounds.height(), 1, layerRenderer->sharedGeometryQuad(),
+                                    program->vertexShader().matrixLocation(),
+                                    program->fragmentShader().alphaLocation(),
+                                    -1);
+}
+
+void CCRenderSurface::copyDeviceToBackgroundTexture(LayerRendererChromium* layerRenderer, int deviceBackgroundTextureId, const IntRect& deviceTextureRect, const TransformationMatrix& deviceTransform) const
+{
+    ASSERT(!m_backgroundFilters.isEmpty());
+
+    TransformationMatrix deviceToSurfaceTransform;
+    deviceToSurfaceTransform.translate(m_contentRect.width() / 2.0, m_contentRect.height() / 2.0);
+    deviceToSurfaceTransform.scale3d(m_contentRect.width(), m_contentRect.height(), 1);
+    deviceToSurfaceTransform *= deviceTransform.inverse();
+    deviceToSurfaceTransform.translate(deviceTextureRect.width() / 2.0, deviceTextureRect.height() / 2.0);
+    deviceToSurfaceTransform.translate(deviceTextureRect.x(), deviceTextureRect.y());
+
+    copyTextureToFramebuffer(layerRenderer, deviceBackgroundTextureId, deviceTextureRect.size(), deviceToSurfaceTransform);
+}
+
+inline static int getSkBitmapTextureId(const SkBitmap& bitmap, int fallback)
+{
+    if (!bitmap.getTexture())
+        return fallback;
+    GrTexture* texture = reinterpret_cast<GrTexture*>(bitmap.getTexture());
+    return texture->getTextureHandle();
+}
+
 void CCRenderSurface::setScissorRect(LayerRendererChromium* layerRenderer, const FloatRect& surfaceDamageRect) const
 {
     if (m_owningLayer->parent() && m_owningLayer->parent()->usesLayerClipping() && layerRenderer->capabilities().usingPartialSwap) {
@@ -124,8 +228,11 @@ void CCRenderSurface::drawContents(LayerRendererChromium* layerRenderer)
         return;
 
     // FIXME: Cache this value so that we don't have to do it for both the surface and its replica.
-    SkBitmap filterBitmap = applyFilters(layerRenderer);
-    drawLayer(layerRenderer, m_maskLayer, m_drawTransform, filterBitmap);
+    // Apply filters to the contents texture.
+    SkBitmap filterBitmap = applyFilters(layerRenderer, m_filters, m_contentsTexture.get());
+
+    int contentsTextureId = getSkBitmapTextureId(filterBitmap, m_contentsTexture->textureId());
+    drawLayer(layerRenderer, m_maskLayer, m_drawTransform, contentsTextureId);
 }
 
 void CCRenderSurface::drawReplica(LayerRendererChromium* layerRenderer)
@@ -134,7 +241,9 @@ void CCRenderSurface::drawReplica(LayerRendererChromium* layerRenderer)
     if (!hasReplica() || m_skipsDraw || !m_contentsTexture)
         return;
 
-    SkBitmap filterBitmap = applyFilters(layerRenderer);
+    // Apply filters to the contents texture.
+    SkBitmap filterBitmap = applyFilters(layerRenderer, m_filters, m_contentsTexture.get());
+
     // FIXME: By using the same RenderSurface for both the content and its reflection,
     // it's currently not possible to apply a separate mask to the reflection layer
     // or correctly handle opacity in reflections (opacity must be applied after drawing
@@ -145,21 +254,22 @@ void CCRenderSurface::drawReplica(LayerRendererChromium* layerRenderer)
     if (!m_maskLayer && m_owningLayer->replicaLayer())
         replicaMaskLayer = m_owningLayer->replicaLayer()->maskLayer();
 
-    drawLayer(layerRenderer, replicaMaskLayer, m_replicaDrawTransform, filterBitmap);
+    int contentsTextureId = getSkBitmapTextureId(filterBitmap, m_contentsTexture->textureId());
+    drawLayer(layerRenderer, replicaMaskLayer, m_replicaDrawTransform, contentsTextureId);
 }
 
-void CCRenderSurface::drawLayer(LayerRendererChromium* layerRenderer, CCLayerImpl* maskLayer, const TransformationMatrix& drawTransform, const SkBitmap& filterBitmap)
+void CCRenderSurface::drawLayer(LayerRendererChromium* layerRenderer, CCLayerImpl* maskLayer, const TransformationMatrix& drawTransform, int contentsTextureId)
 {
-    TransformationMatrix renderMatrix = drawTransform;
-    // Apply a scaling factor to size the quad from 1x1 to its intended size.
-    renderMatrix.scale3d(m_contentRect.width(), m_contentRect.height(), 1);
-
-    TransformationMatrix deviceMatrix = TransformationMatrix(layerRenderer->windowMatrix() * layerRenderer->projectionMatrix() * renderMatrix).to2dTransform();
+    TransformationMatrix deviceMatrix = computeDeviceTransform(layerRenderer, drawTransform);
 
     // Can only draw surface if device matrix is invertible.
     if (!deviceMatrix.isInvertible())
         return;
 
+    // Draw the background texture if there is one.
+    if (m_backgroundTexture && m_backgroundTexture->isReserved())
+        copyTextureToFramebuffer(layerRenderer, m_backgroundTexture->textureId(), m_contentRect.size(), drawTransform);
+
     FloatQuad quad = deviceMatrix.mapQuad(layerRenderer->sharedGeometryQuad());
     CCLayerQuad deviceRect = CCLayerQuad(FloatQuad(quad.boundingBox()));
     CCLayerQuad layerQuad = CCLayerQuad(quad);
@@ -177,27 +287,29 @@ void CCRenderSurface::drawLayer(LayerRendererChromium* layerRenderer, CCLayerImp
         if (!maskLayer->bounds().isEmpty())
             useMask = true;
 
+    // FIXME: pass in backgroundTextureId and blend the background in with this draw instead of having a separate drawBackground() pass.
+
     if (useMask) {
         if (useAA) {
             const MaskProgramAA* program = layerRenderer->renderSurfaceMaskProgramAA();
-            drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, deviceRect, layerQuad, program, program->fragmentShader().maskSamplerLocation(), program->vertexShader().pointLocation(), program->fragmentShader().edgeLocation(), filterBitmap);
+            drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, deviceRect, layerQuad, contentsTextureId, program, program->fragmentShader().maskSamplerLocation(), program->vertexShader().pointLocation(), program->fragmentShader().edgeLocation());
         } else {
             const MaskProgram* program = layerRenderer->renderSurfaceMaskProgram();
-            drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, deviceRect, layerQuad, program, program->fragmentShader().maskSamplerLocation(), -1, -1, filterBitmap);
+            drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, deviceRect, layerQuad, contentsTextureId, program, program->fragmentShader().maskSamplerLocation(), -1, -1);
         }
     } else {
         if (useAA) {
             const ProgramAA* program = layerRenderer->renderSurfaceProgramAA();
-            drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, deviceRect, layerQuad, program, -1, program->vertexShader().pointLocation(), program->fragmentShader().edgeLocation(), filterBitmap);
+            drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, deviceRect, layerQuad, contentsTextureId, program, -1, program->vertexShader().pointLocation(), program->fragmentShader().edgeLocation());
         } else {
             const Program* program = layerRenderer->renderSurfaceProgram();
-            drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, deviceRect, layerQuad, program, -1, -1, -1, filterBitmap);
+            drawSurface(layerRenderer, maskLayer, drawTransform, deviceMatrix, deviceRect, layerQuad, contentsTextureId, program, -1, -1, -1);
         }
     }
 }
 
 template <class T>
-void CCRenderSurface::drawSurface(LayerRendererChromium* layerRenderer, CCLayerImpl* maskLayer, const TransformationMatrix& drawTransform, const TransformationMatrix& deviceTransform, const CCLayerQuad& deviceRect, const CCLayerQuad& layerQuad, const T* program, int shaderMaskSamplerLocation, int shaderQuadLocation, int shaderEdgeLocation, const SkBitmap& filterBitmap)
+void CCRenderSurface::drawSurface(LayerRendererChromium* layerRenderer, CCLayerImpl* maskLayer, const TransformationMatrix& drawTransform, const TransformationMatrix& deviceTransform, const CCLayerQuad& deviceRect, const CCLayerQuad& layerQuad, int contentsTextureId, const T* program, int shaderMaskSamplerLocation, int shaderQuadLocation, int shaderEdgeLocation)
 {
     GraphicsContext3D* context3D = layerRenderer->context();
 
@@ -206,11 +318,7 @@ void CCRenderSurface::drawSurface(LayerRendererChromium* layerRenderer, CCLayerI
 
     GLC(context3D, context3D->activeTexture(GraphicsContext3D::TEXTURE0));
     GLC(context3D, context3D->uniform1i(program->fragmentShader().samplerLocation(), 0));
-    if (filterBitmap.getTexture()) {
-        GrTexture* texture = reinterpret_cast<GrTexture*>(filterBitmap.getTexture());
-        context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, texture->getTextureHandle());
-    } else
-        m_contentsTexture->bindTexture(context3D, layerRenderer->renderSurfaceTextureAllocator());
+    context3D->bindTexture(GraphicsContext3D::TEXTURE_2D, contentsTextureId);
 
     if (shaderMaskSamplerLocation != -1) {
         GLC(context3D, context3D->activeTexture(GraphicsContext3D::TEXTURE1));
@@ -233,9 +341,9 @@ void CCRenderSurface::drawSurface(LayerRendererChromium* layerRenderer, CCLayerI
                                     program->vertexShader().matrixLocation(), program->fragmentShader().alphaLocation(), shaderQuadLocation);
 }
 
-SkBitmap CCRenderSurface::applyFilters(LayerRendererChromium* layerRenderer)
+SkBitmap CCRenderSurface::applyFilters(LayerRendererChromium* layerRenderer, const FilterOperations& filters, ManagedTexture* sourceTexture)
 {
-    if (!m_contentsTexture || !m_filters.size())
+    if (filters.isEmpty())
         return SkBitmap();
 
     RefPtr<GraphicsContext3D> filterContext = CCProxy::hasImplThread() ? SharedGraphicsContext3D::getForImplThread() : SharedGraphicsContext3D::get();
@@ -244,7 +352,7 @@ SkBitmap CCRenderSurface::applyFilters(LayerRendererChromium* layerRenderer)
 
     layerRenderer->context()->flush();
 
-    return CCRenderSurfaceFilters::apply(m_filters, m_contentsTexture->textureId(), m_contentRect.size(), filterContext.get());
+    return CCRenderSurfaceFilters::apply(filters, sourceTexture->textureId(), sourceTexture->size(), filterContext.get());
 }
 
 String CCRenderSurface::name() const
index 42cda32..f4132e2 100644 (file)
@@ -57,11 +57,18 @@ public:
     bool prepareContentsTexture(LayerRendererChromium*);
     void releaseContentsTexture();
 
+    bool prepareBackgroundTexture(LayerRendererChromium*);
+    void releaseBackgroundTexture();
+
     void setScissorRect(LayerRendererChromium*, const FloatRect& surfaceDamageRect) const;
 
     void drawContents(LayerRendererChromium*);
     void drawReplica(LayerRendererChromium*);
 
+    // Takes a texture with pixels in device space, and a transform from content space to the device. Copies the device-space texture back into
+    // content space for the surface, storing the result in the backgroundTexture(). The surface's backgroundTexture() must be the active drawing target.
+    void copyDeviceToBackgroundTexture(LayerRendererChromium*, int deviceBackgroundTextureId, const IntRect& deviceTextureRect, const TransformationMatrix& deviceTransform) const;
+
     String name() const;
     void dumpSurface(TextStream&, int indent) const;
 
@@ -69,13 +76,21 @@ public:
 
     // Returns the rect that encloses the RenderSurface including any reflection.
     FloatRect drawableContentRect() const;
+    // Returns the rect that encloses the pixels that may affect the pixel values in this surface through background filters.
+    IntRect readbackDeviceContentRect(LayerRendererChromium*, const TransformationMatrix& drawTransform) const;
+
+    // Gives the transform from the surface content space, with origin in the top left, to the current target device space, with origin in the top left.
+    TransformationMatrix computeDeviceTransform(LayerRendererChromium*, const TransformationMatrix& drawTransform) const;
 
     float drawOpacity() const { return m_drawOpacity; }
     void setDrawOpacity(float opacity) { m_drawOpacity = opacity; }
 
     void setFilters(const FilterOperations& filters) { m_filters = filters; }
     const FilterOperations& filters() const { return m_filters; }
-    SkBitmap applyFilters(LayerRendererChromium*);
+    SkBitmap applyFilters(LayerRendererChromium*, const FilterOperations&, ManagedTexture* sourceTexture);
+
+    void setBackgroundFilters(const FilterOperations& filters) { m_backgroundFilters = filters; }
+    const FilterOperations& backgroundFilters() const { return m_backgroundFilters; }
 
     void setNearestAncestorThatMovesPixels(CCRenderSurface* surface) { m_nearestAncestorThatMovesPixels = surface; }
     const CCRenderSurface* nearestAncestorThatMovesPixels() const { return m_nearestAncestorThatMovesPixels; }
@@ -127,6 +142,7 @@ public:
     typedef ProgramBinding<VertexShaderQuad, FragmentShaderRGBATexAlphaMaskAA> MaskProgramAA;
 
     ManagedTexture* contentsTexture() const { return m_contentsTexture.get(); }
+    ManagedTexture* backgroundTexture() const { return m_backgroundTexture.get(); }
 
     int owningLayerId() const;
 
@@ -142,9 +158,12 @@ public:
     PassOwnPtr<CCSharedQuadState> createReplicaSharedQuadState() const;
 
 private:
-    void drawLayer(LayerRendererChromium*, CCLayerImpl*, const TransformationMatrix&, const SkBitmap& filterBitmap);
+    IntRect computeDeviceBoundingBox(LayerRendererChromium*, const TransformationMatrix& drawTransform) const;
+    IntRect computeReadbackDeviceBoundingBox(LayerRendererChromium*, const TransformationMatrix& drawTransform) const;
+
+    void drawLayer(LayerRendererChromium*, CCLayerImpl*, const TransformationMatrix&, int contentsTextureId);
     template <class T>
-    void drawSurface(LayerRendererChromium*, CCLayerImpl*, const TransformationMatrix& drawTransform, const TransformationMatrix& deviceTransform, const CCLayerQuad& deviceRect, const CCLayerQuad&, const T* program, int shaderMaskSamplerLocation, int shaderQuadLocation, int shaderEdgeLocation, const SkBitmap& filterBitmap);
+    void drawSurface(LayerRendererChromium*, CCLayerImpl*, const TransformationMatrix& drawTransform, const TransformationMatrix& deviceTransform, const CCLayerQuad& deviceRect, const CCLayerQuad&, int contentsTextureId, const T* program, int shaderMaskSamplerLocation, int shaderQuadLocation, int shaderEdgeLocation);
 
     CCLayerImpl* m_owningLayer;
     CCLayerImpl* m_maskLayer;
@@ -154,6 +173,8 @@ private:
     bool m_surfacePropertyChanged;
 
     OwnPtr<ManagedTexture> m_contentsTexture;
+    OwnPtr<ManagedTexture> m_backgroundTexture;
+
     float m_drawOpacity;
     bool m_drawOpacityIsAnimating;
     TransformationMatrix m_drawTransform;
@@ -165,6 +186,7 @@ private:
     bool m_targetSurfaceTransformsAreAnimating;
     bool m_screenSpaceTransformsAreAnimating;
     FilterOperations m_filters;
+    FilterOperations m_backgroundFilters;
     IntRect m_clipRect;
     Vector<CCLayerImpl*> m_layerList;
 
index 25a464a..12cd0f6 100644 (file)
 #include "WebKitPoint.h"
 #endif
 
+#if PLATFORM(CHROMIUM)
+#include "FilterOperations.h"
+#include "GraphicsLayer.h"
+#include "LayerChromium.h"
+#include "RenderLayerBacking.h"
+#endif
+
 namespace WebCore {
 
 static bool markerTypesFrom(const String& markerType, DocumentMarker::MarkerTypes& result)
@@ -423,6 +430,48 @@ PassRefPtr<ClientRectList> Internals::inspectorHighlightRects(Document* document
 #endif
 }
 
+#if PLATFORM(CHROMIUM)
+void Internals::setBackgroundBlurOnNode(Node* node, int blurLength, ExceptionCode& ec)
+{
+    if (!node) {
+        ec = INVALID_ACCESS_ERR;
+        return;
+    }
+
+    RenderObject* renderObject = node->renderer();
+    if (!renderObject) {
+        ec = INVALID_NODE_TYPE_ERR;
+        return;
+    }
+
+    RenderLayer* renderLayer = renderObject->enclosingLayer();
+    if (!renderLayer || !renderLayer->isComposited()) {
+        ec = INVALID_STATE_ERR;
+        return;
+    }
+
+    GraphicsLayer* graphicsLayer = renderLayer->backing()->graphicsLayer();
+    if (!graphicsLayer) {
+        ec = INVALID_NODE_TYPE_ERR;
+        return;
+    }
+
+    PlatformLayer* platformLayer = graphicsLayer->platformLayer();
+    if (!platformLayer) {
+        ec = INVALID_NODE_TYPE_ERR;
+        return;
+    }
+
+    FilterOperations filters;
+    filters.operations().append(BlurFilterOperation::create(Length(blurLength, Fixed), FilterOperation::BLUR));
+    platformLayer->setBackgroundFilters(filters);
+}
+#else
+void Internals::setBackgroundBlurOnNode(Node*, int, ExceptionCode&)
+{
+}
+#endif
+
 unsigned Internals::markerCountForNode(Node* node, const String& markerType, ExceptionCode& ec)
 {
     if (!node) {
index 51a5a85..7364281 100644 (file)
@@ -100,6 +100,8 @@ public:
 
     PassRefPtr<ClientRectList> inspectorHighlightRects(Document*, ExceptionCode&);
 
+    void setBackgroundBlurOnNode(Node*, int blurLength, ExceptionCode&);
+
     unsigned markerCountForNode(Node*, const String&, ExceptionCode&);
     PassRefPtr<Range> markerRangeForNode(Node*, const String& markerType, unsigned index, ExceptionCode&);
     String markerDescriptionForNode(Node*, const String& markerType, unsigned index, ExceptionCode&);
index 50632a6..5e37dd7 100644 (file)
@@ -72,6 +72,8 @@ module window {
 
         ClientRectList inspectorHighlightRects(in Document document) raises (DOMException);
 
+        void setBackgroundBlurOnNode(in Node node, in long blurLength) raises(DOMException);
+
         unsigned long markerCountForNode(in Node node, in DOMString markerType) raises(DOMException);
         Range markerRangeForNode(in Node node, in DOMString markerType, in unsigned long index) raises(DOMException);
         DOMString markerDescriptionForNode(in Node node, in DOMString markerType, in unsigned long index) raises(DOMException);
index ef30f6f..6eaeae1 100644 (file)
@@ -1,3 +1,13 @@
+2012-04-12  Dana Jansens  <danakj@chromium.org>
+
+        [chromium] Background filters for composited layers
+        https://bugs.webkit.org/show_bug.cgi?id=80046
+
+        Reviewed by Adrienne Walker.
+
+        * tests/CCLayerImplTest.cpp:
+        (WebCore::TEST):
+
 2012-04-12  Sheriff Bot  <webkit.review.bot@gmail.com>
 
         Unreviewed, rolling out r114075.
index 39f554b..36c1082 100644 (file)
@@ -112,6 +112,7 @@ TEST(CCLayerImplTest, verifyLayerChangesAreTrackedProperly)
     EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->setDebugBorderWidth(arbitraryNumber));
     EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->setDrawsContent(true));
     EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->setBackgroundColor(Color::gray));
+    EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(root->setBackgroundFilters(arbitraryFilters));
 
     // Special case: check that sublayer transform changes all layer's descendants, but not the layer itself.
     root->resetAllChangeTrackingForSubtree();