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: http://svn.webkit.org/repository/webkit/trunk@114081
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+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
--- /dev/null
+<!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>
--- /dev/null
+<!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>
--- /dev/null
+<!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>
+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
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)
layer->setFilters(filters());
layer->setFilters(filters());
+ layer->setBackgroundFilters(backgroundFilters());
layer->setIsNonCompositedContent(m_isNonCompositedContent);
layer->setMasksToBounds(m_masksToBounds);
layer->setScrollable(m_scrollable);
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; }
String m_debugName;
float m_opacity;
FilterOperations m_filters;
+ FilterOperations m_backgroundFilters;
float m_anchorPointZ;
bool m_isDrawable;
bool m_masksToBounds;
#include "Extensions3DChromium.h"
#include "FloatQuad.h"
#include "GeometryBinding.h"
+#include "GrTexture.h"
#include "GraphicsContext3D.h"
#include "LayerChromium.h"
#include "LayerPainterChromium.h"
PassRefPtr<GraphicsContext3D> context)
: m_client(client)
, m_currentRenderSurface(0)
+ , m_currentManagedTexture(0)
, m_offscreenFramebufferId(0)
, m_context(context)
, m_defaultRenderSurface(0)
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();
}
}
}
+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;
}
}
+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));
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) {
}
#endif
- setDrawViewportRect(renderSurface->contentRect(), false);
+ setDrawViewportRect(viewportRect, false);
return true;
}
// 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();
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(); }
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*);
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();
TransformationMatrix m_windowMatrix;
CCRenderSurface* m_currentRenderSurface;
+ ManagedTexture* m_currentManagedTexture;
unsigned m_offscreenFramebufferId;
// Store values that are shared between instances of each layer type
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; }
bool m_targetSurfaceTransformsAreAnimating;
bool m_screenSpaceTransformsAreAnimating;
FilterOperations m_filters;
+ FilterOperations m_backgroundFilters;
IntRect m_clipRect;
Vector<RefPtr<LayerChromium> > m_layerList;
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)
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; }
String m_debugName;
FilterOperations m_filters;
+ FilterOperations m_backgroundFilters;
TransformationMatrix m_drawTransform;
TransformationMatrix m_screenSpaceTransform;
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
nearestAncestorThatMovesPixels = renderSurface;
renderSurface->setNearestAncestorThatMovesPixels(nearestAncestorThatMovesPixels);
+ renderSurface->setBackgroundFilters(layer->backgroundFilters());
+
renderSurfaceLayerList.append(layer);
} else {
layer->setDrawTransform(combinedTransform);
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;
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) {
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)
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
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);
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();
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));
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();
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
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;
// 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; }
typedef ProgramBinding<VertexShaderQuad, FragmentShaderRGBATexAlphaMaskAA> MaskProgramAA;
ManagedTexture* contentsTexture() const { return m_contentsTexture.get(); }
+ ManagedTexture* backgroundTexture() const { return m_backgroundTexture.get(); }
int owningLayerId() const;
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;
bool m_surfacePropertyChanged;
OwnPtr<ManagedTexture> m_contentsTexture;
+ OwnPtr<ManagedTexture> m_backgroundTexture;
+
float m_drawOpacity;
bool m_drawOpacityIsAnimating;
TransformationMatrix m_drawTransform;
bool m_targetSurfaceTransformsAreAnimating;
bool m_screenSpaceTransformsAreAnimating;
FilterOperations m_filters;
+ FilterOperations m_backgroundFilters;
IntRect m_clipRect;
Vector<CCLayerImpl*> m_layerList;
#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)
#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) {
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&);
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);
+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.
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();