Diff
Modified: trunk/LayoutTests/ChangeLog (200282 => 200283)
--- trunk/LayoutTests/ChangeLog 2016-04-30 03:54:41 UTC (rev 200282)
+++ trunk/LayoutTests/ChangeLog 2016-04-30 04:13:16 UTC (rev 200283)
@@ -1,3 +1,19 @@
+2016-04-29 Simon Fraser <[email protected]>
+
+ Blur filter escapes an enclosing overflow:hidden
+ https://bugs.webkit.org/show_bug.cgi?id=155029
+
+ Reviewed by Zalan Bujtas.
+
+ * css3/filters/blur-clipped-by-ancestor-expected.html: Added.
+ * css3/filters/blur-clipped-by-ancestor.html: Added.
+ * css3/filters/blur-clipped-with-overflow-expected.html: Added.
+ * css3/filters/blur-clipped-with-overflow.html: Added.
+ * css3/filters/drop-shadow-expected.html: Added.
+ * css3/filters/drop-shadow-with-overflow-hidden-expected.html: Added.
+ * css3/filters/drop-shadow-with-overflow-hidden.html: Added.
+ * css3/filters/drop-shadow.html: Added.
+
2016-04-29 Myles C. Maxfield <[email protected]>
REGRESSION(194502): overflow: scroll; direction: rtl; divs jump horizontally when scrolled vertically
Added: trunk/LayoutTests/css3/filters/blur-clipped-by-ancestor-expected.html (0 => 200283)
--- trunk/LayoutTests/css3/filters/blur-clipped-by-ancestor-expected.html (rev 0)
+++ trunk/LayoutTests/css3/filters/blur-clipped-by-ancestor-expected.html 2016-04-30 04:13:16 UTC (rev 200283)
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+ <style>
+ .wrapper {
+ height: 200px;
+ width: 200px;
+ margin: 50px;
+ border: 1px solid black;
+ }
+
+ .filtered {
+ -webkit-clip-path: inset(0px);
+ width: 100%;
+ height: 100%;
+ background-color: black;
+ filter: blur(10px);
+ }
+ </style>
+</head>
+<body>
+ <div class="wrapper">
+ <div class="filtered">
+ </div>
+ </div>
+</body>
+</html>
Added: trunk/LayoutTests/css3/filters/blur-clipped-by-ancestor.html (0 => 200283)
--- trunk/LayoutTests/css3/filters/blur-clipped-by-ancestor.html (rev 0)
+++ trunk/LayoutTests/css3/filters/blur-clipped-by-ancestor.html 2016-04-30 04:13:16 UTC (rev 200283)
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+ <style>
+ .wrapper {
+ overflow: hidden;
+ height: 200px;
+ width: 200px;
+ margin: 50px;
+ border: 1px solid black;
+ }
+
+ .filtered {
+ width: 100%;
+ height: 100%;
+ background-color: black;
+ filter: blur(10px);
+ }
+ </style>
+</head>
+<body>
+ <div class="wrapper">
+ <div class="filtered">
+ </div>
+ </div>
+</body>
+</html>
Added: trunk/LayoutTests/css3/filters/blur-clipped-with-overflow-expected.html (0 => 200283)
--- trunk/LayoutTests/css3/filters/blur-clipped-with-overflow-expected.html (rev 0)
+++ trunk/LayoutTests/css3/filters/blur-clipped-with-overflow-expected.html 2016-04-30 04:13:16 UTC (rev 200283)
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+ <style>
+ .filtered {
+ overflow: hidden;
+ margin: 40px;
+ padding: 20px;
+ height: 200px;
+ width: 200px;
+ background-color: silver;
+ border: 1px solid black;
+ filter: blur(1px);
+ box-shadow: 0 0 20px black;
+ }
+
+ .contents {
+ width: 100%;
+ height: 220px;
+ background-image: repeating-linear-gradient(blue, blue 50px, green 50px, green 100px);
+ }
+ </style>
+</head>
+<body>
+ <div class="filtered">
+ <div class="contents"></div>
+ </div>
+</body>
+</html>
Added: trunk/LayoutTests/css3/filters/blur-clipped-with-overflow.html (0 => 200283)
--- trunk/LayoutTests/css3/filters/blur-clipped-with-overflow.html (rev 0)
+++ trunk/LayoutTests/css3/filters/blur-clipped-with-overflow.html 2016-04-30 04:13:16 UTC (rev 200283)
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+ <style>
+ .filtered {
+ overflow: hidden;
+ margin: 40px;
+ padding: 20px;
+ height: 200px;
+ width: 200px;
+ background-color: silver;
+ border: 1px solid black;
+ filter: blur(1px);
+ box-shadow: 0 0 20px black;
+ }
+
+ .contents {
+ width: 100%;
+ height: 200%;
+ background-image: repeating-linear-gradient(blue, blue 50px, green 50px, green 100px);
+ }
+ </style>
+</head>
+<body>
+ <div class="filtered">
+ <div class="contents"></div>
+ </div>
+</body>
+</html>
Added: trunk/LayoutTests/css3/filters/drop-shadow-expected.html (0 => 200283)
--- trunk/LayoutTests/css3/filters/drop-shadow-expected.html (rev 0)
+++ trunk/LayoutTests/css3/filters/drop-shadow-expected.html 2016-04-30 04:13:16 UTC (rev 200283)
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <style>
+ .filtered {
+ position: absolute;
+ top: 0;
+ left: 0;
+ margin: 40px;
+ padding: 20px;
+ height: 200px;
+ width: 200px;
+ background-color: silver;
+ border: 1px solid black;
+ box-shadow: 0 0 20px transparent; /* Make layers bigger */
+ }
+
+ .shadow {
+ position: absolute;
+ top: 110px;
+ left: 110px;
+ border: 1px solid blue;
+ background-color: blue;
+ }
+ </style>
+</head>
+<body>
+ <div class="filtered shadow"></div>
+ <div class="filtered"></div>
+</body>
+</html>
Added: trunk/LayoutTests/css3/filters/drop-shadow-with-overflow-hidden-expected.html (0 => 200283)
--- trunk/LayoutTests/css3/filters/drop-shadow-with-overflow-hidden-expected.html (rev 0)
+++ trunk/LayoutTests/css3/filters/drop-shadow-with-overflow-hidden-expected.html 2016-04-30 04:13:16 UTC (rev 200283)
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+ <style>
+ .filtered {
+ overflow: hidden;
+ margin: 40px;
+ padding: 20px;
+ height: 200px;
+ width: 200px;
+ background-color: silver;
+ border: 1px solid black;
+ filter: drop-shadow(110px 110px 0 blue);
+ box-shadow: 0 0 20px black;
+ }
+ </style>
+</head>
+<body>
+ <div class="filtered"></div>
+ <!-- Fixme -->
+</body>
+</html>
Added: trunk/LayoutTests/css3/filters/drop-shadow-with-overflow-hidden.html (0 => 200283)
--- trunk/LayoutTests/css3/filters/drop-shadow-with-overflow-hidden.html (rev 0)
+++ trunk/LayoutTests/css3/filters/drop-shadow-with-overflow-hidden.html 2016-04-30 04:13:16 UTC (rev 200283)
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+ <style>
+ .filtered {
+ overflow: hidden;
+ margin: 40px;
+ padding: 20px;
+ height: 200px;
+ width: 200px;
+ background-color: silver;
+ border: 1px solid black;
+ filter: drop-shadow(110px 110px 0 blue);
+ box-shadow: 0 0 20px black;
+ }
+ </style>
+</head>
+<body>
+ <div class="filtered"></div>
+</body>
+</html>
Added: trunk/LayoutTests/css3/filters/drop-shadow.html (0 => 200283)
--- trunk/LayoutTests/css3/filters/drop-shadow.html (rev 0)
+++ trunk/LayoutTests/css3/filters/drop-shadow.html 2016-04-30 04:13:16 UTC (rev 200283)
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <style>
+ .filtered {
+ position: absolute;
+ top: 0;
+ left: 0;
+ margin: 40px;
+ padding: 20px;
+ height: 200px;
+ width: 200px;
+ background-color: silver;
+ border: 1px solid black;
+ filter: drop-shadow(110px 110px 0 blue);
+ box-shadow: 0 0 20px transparent; /* Make layers bigger */
+ }
+ </style>
+</head>
+<body>
+ <div class="filtered"></div>
+</body>
+</html>
Modified: trunk/Source/WebCore/ChangeLog (200282 => 200283)
--- trunk/Source/WebCore/ChangeLog 2016-04-30 03:54:41 UTC (rev 200282)
+++ trunk/Source/WebCore/ChangeLog 2016-04-30 04:13:16 UTC (rev 200283)
@@ -1,3 +1,38 @@
+2016-04-29 Simon Fraser <[email protected]>
+
+ Blur filter escapes an enclosing overflow:hidden
+ https://bugs.webkit.org/show_bug.cgi?id=155029
+
+ Reviewed by Zalan Bujtas.
+
+ The clipping that was applied when drawing the results of filters was wrong for two reasons.
+
+ First, it used localPaintingInfo which has already been contaminated when setting up the filters.
+ When painting the result, we need to use the original paintingInfo, to get the right paintDirtyRect.
+
+ Secondly, when setting up the clip to paint the filter result, it was relying on layerFragments[0].backgroundRect.
+ However, that was also contaminated by filter setup, since calculateRects() intersects with paintDirtyRect to
+ compute that backgroundRect, and that paintDirtyRect came from filterPainter->repaintRect().
+
+ Fix this second issue by re-running collectFragments(), which computes a fragment backgroundRect using
+ the original paintDirtyRect.
+
+ Tests: css3/filters/blur-clipped-by-ancestor.html
+ css3/filters/blur-clipped-with-overflow.html
+ css3/filters/drop-shadow-with-overflow-hidden.html
+ css3/filters/drop-shadow.html
+
+ * platform/graphics/filters/FilterEffect.cpp:
+ (WebCore::FilterEffect::clearResult): Unconditionally null these out.
+ * rendering/FilterEffectRenderer.cpp:
+ (WebCore::FilterEffectRendererHelper::beginFilterEffect): Typo fix.
+ * rendering/FilterEffectRenderer.h:
+ (WebCore::FilterEffectRendererHelper::FilterEffectRendererHelper): C++11 initialization.
+ * rendering/RenderLayer.cpp:
+ (WebCore::RenderLayer::applyFilters):
+ (WebCore::RenderLayer::paintLayerContents):
+ * rendering/RenderLayer.h: const
+
2016-04-29 Myles C. Maxfield <[email protected]>
REGRESSION(194502): overflow: scroll; direction: rtl; divs jump horizontally when scrolled vertically
Modified: trunk/Source/WebCore/platform/graphics/filters/FilterEffect.cpp (200282 => 200283)
--- trunk/Source/WebCore/platform/graphics/filters/FilterEffect.cpp 2016-04-30 03:54:41 UTC (rev 200282)
+++ trunk/Source/WebCore/platform/graphics/filters/FilterEffect.cpp 2016-04-30 04:13:16 UTC (rev 200283)
@@ -197,10 +197,9 @@
{
if (m_imageBufferResult)
m_imageBufferResult.reset();
- if (m_unmultipliedImageResult)
- m_unmultipliedImageResult = nullptr;
- if (m_premultipliedImageResult)
- m_premultipliedImageResult = nullptr;
+
+ m_unmultipliedImageResult = nullptr;
+ m_premultipliedImageResult = nullptr;
}
void FilterEffect::clearResultsRecursive()
Modified: trunk/Source/WebCore/rendering/FilterEffectRenderer.cpp (200282 => 200283)
--- trunk/Source/WebCore/rendering/FilterEffectRenderer.cpp 2016-04-30 03:54:41 UTC (rev 200282)
+++ trunk/Source/WebCore/rendering/FilterEffectRenderer.cpp 2016-04-30 04:13:16 UTC (rev 200283)
@@ -67,8 +67,6 @@
FilterEffectRenderer::FilterEffectRenderer()
: Filter(AffineTransform())
- , m_graphicsBufferAttached(false)
- , m_hasFilterThatMovesPixels(false)
{
setFilterResolution(FloatSize(1, 1));
m_sourceGraphic = SourceGraphic::create(*this);
@@ -407,7 +405,7 @@
return false;
}
- // Translate the context so that the contents of the layer is captuterd in the offscreen memory buffer.
+ // Translate the context so that the contents of the layer is captured in the offscreen memory buffer.
sourceGraphicsContext->save();
sourceGraphicsContext->translate(-m_paintOffset.x(), -m_paintOffset.y());
sourceGraphicsContext->clearRect(m_repaintRect);
Modified: trunk/Source/WebCore/rendering/FilterEffectRenderer.h (200282 => 200283)
--- trunk/Source/WebCore/rendering/FilterEffectRenderer.h 2016-04-30 03:54:41 UTC (rev 200282)
+++ trunk/Source/WebCore/rendering/FilterEffectRenderer.h 2016-04-30 04:13:16 UTC (rev 200283)
@@ -58,9 +58,7 @@
WTF_MAKE_FAST_ALLOCATED;
public:
FilterEffectRendererHelper(bool haveFilterEffect)
- : m_renderLayer(0)
- , m_haveFilterEffect(haveFilterEffect)
- , m_startedFilterEffect(false)
+ : m_haveFilterEffect(haveFilterEffect)
{
}
@@ -76,11 +74,11 @@
const LayoutRect& repaintRect() const { return m_repaintRect; }
private:
- RenderLayer* m_renderLayer; // FIXME: this is mainly used to get the FilterEffectRenderer. FilterEffectRendererHelper should be weaned off it.
+ RenderLayer* m_renderLayer { nullptr }; // FIXME: this is mainly used to get the FilterEffectRenderer. FilterEffectRendererHelper should be weaned off it.
LayoutPoint m_paintOffset;
LayoutRect m_repaintRect;
- bool m_haveFilterEffect;
- bool m_startedFilterEffect;
+ bool m_haveFilterEffect { false };
+ bool m_startedFilterEffect { false };
};
class FilterEffectRenderer final : public Filter {
@@ -145,8 +143,8 @@
IntRectExtent m_outsets;
- bool m_graphicsBufferAttached;
- bool m_hasFilterThatMovesPixels;
+ bool m_graphicsBufferAttached { false };
+ bool m_hasFilterThatMovesPixels { false };
};
} // namespace WebCore
Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (200282 => 200283)
--- trunk/Source/WebCore/rendering/RenderLayer.cpp 2016-04-30 03:54:41 UTC (rev 200282)
+++ trunk/Source/WebCore/rendering/RenderLayer.cpp 2016-04-30 04:13:16 UTC (rev 200283)
@@ -4196,11 +4196,11 @@
return nullptr;
}
-void RenderLayer::applyFilters(FilterEffectRendererHelper* filterPainter, GraphicsContext& originalContext, LayerPaintingInfo& paintingInfo, LayerFragments& layerFragments)
+void RenderLayer::applyFilters(FilterEffectRendererHelper* filterPainter, GraphicsContext& originalContext, const LayerPaintingInfo& paintingInfo, const LayerFragments& layerFragments)
{
ASSERT(filterPainter->hasStartedFilterEffect());
- // Apply the correct clipping (ie. overflow: hidden).
- // FIXME: It is incorrect to just clip to the damageRect here once multiple fragments are involved.
+
+ // FIXME: Handle more than one fragment.
ClipRect backgroundRect = layerFragments.isEmpty() ? ClipRect() : layerFragments[0].backgroundRect;
clipToRect(paintingInfo, originalContext, backgroundRect);
filterPainter->applyFilterEffect(originalContext);
@@ -4291,14 +4291,13 @@
if (shouldApplyClipPath(paintingInfo.paintBehavior, localPaintFlags))
hasClipPath = setupClipPath(context, paintingInfo, columnAwareOffsetFromRoot, rootRelativeBounds, rootRelativeBoundsComputed);
- LayerPaintingInfo localPaintingInfo(paintingInfo);
-
- bool selectionAndBackgroundsOnly = localPaintingInfo.paintBehavior & PaintBehaviorSelectionAndBackgroundsOnly;
- bool selectionOnly = localPaintingInfo.paintBehavior & PaintBehaviorSelectionOnly;
+ bool selectionAndBackgroundsOnly = paintingInfo.paintBehavior & PaintBehaviorSelectionAndBackgroundsOnly;
+ bool selectionOnly = paintingInfo.paintBehavior & PaintBehaviorSelectionOnly;
LayerFragments layerFragments;
RenderObject* subtreePaintRootForRenderer = nullptr;
- { // Scope for currentContext.
+ { // Scope for filter-related state changes.
+ LayerPaintingInfo localPaintingInfo(paintingInfo);
std::unique_ptr<FilterEffectRendererHelper> filterPainter = setupFilters(context, localPaintingInfo, paintFlags, columnAwareOffsetFromRoot, rootRelativeBounds, rootRelativeBoundsComputed);
GraphicsContext* filterContext = filterPainter ? filterPainter->filterContext() : nullptr;
@@ -4329,7 +4328,7 @@
// Collect the fragments. This will compute the clip rectangles and paint offsets for each layer fragment, as well as whether or not the content of each
// fragment should paint. If the parent's filter dictates full repaint to ensure proper filter effect,
// use the overflow clip as dirty rect, instead of no clipping. It maintains proper clipping for overflow::scroll.
- if (!paintingInfo.clipToDirtyRect && renderer().hasOverflowClip()) {
+ if (!localPaintingInfo.clipToDirtyRect && renderer().hasOverflowClip()) {
// We can turn clipping back by requesting full repaint for the overflow area.
localPaintingInfo.clipToDirtyRect = true;
paintDirtyRect = selfClipRect();
@@ -4381,7 +4380,16 @@
paintOverflowControlsForFragments(layerFragments, currentContext, localPaintingInfo);
if (filterContext) {
- applyFilters(filterPainter.get(), context, localPaintingInfo, layerFragments);
+ // When we called collectFragments() last time, paintDirtyRect was reset to represent the filter bounds.
+ // Now we need to compute the backgroundRect uncontaminated by filters, in order to clip the filtered result.
+ // Note that we also use paintingInfo here, not localPaintingInfo which filters also contaminated.
+ LayerFragments layerFragments;
+ collectFragments(layerFragments, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, ExcludeCompositedPaginatedLayers,
+ (localPaintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize,
+ (isPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip, offsetFromRoot);
+ updatePaintingInfoForFragments(layerFragments, paintingInfo, localPaintFlags, shouldPaintContent, offsetFromRoot);
+
+ applyFilters(filterPainter.get(), context, paintingInfo, layerFragments);
filterPainter = nullptr;
}
}
@@ -4389,17 +4397,17 @@
if (shouldPaintContent && !(selectionOnly || selectionAndBackgroundsOnly)) {
if (shouldPaintMask(paintingInfo.paintBehavior, localPaintFlags)) {
// Paint the mask for the fragments.
- paintMaskForFragments(layerFragments, context, localPaintingInfo, subtreePaintRootForRenderer);
+ paintMaskForFragments(layerFragments, context, paintingInfo, subtreePaintRootForRenderer);
}
if (!(paintFlags & PaintLayerPaintingCompositingMaskPhase) && (paintFlags & PaintLayerPaintingCompositingClipPathPhase)) {
// Re-use paintChildClippingMaskForFragments to paint black for the compositing clipping mask.
- paintChildClippingMaskForFragments(layerFragments, context, localPaintingInfo, subtreePaintRootForRenderer);
+ paintChildClippingMaskForFragments(layerFragments, context, paintingInfo, subtreePaintRootForRenderer);
}
if ((localPaintFlags & PaintLayerPaintingChildClippingMaskPhase)) {
// Paint the border radius mask for the fragments.
- paintChildClippingMaskForFragments(layerFragments, context, localPaintingInfo, subtreePaintRootForRenderer);
+ paintChildClippingMaskForFragments(layerFragments, context, paintingInfo, subtreePaintRootForRenderer);
}
}
Modified: trunk/Source/WebCore/rendering/RenderLayer.h (200282 => 200283)
--- trunk/Source/WebCore/rendering/RenderLayer.h 2016-04-30 03:54:41 UTC (rev 200282)
+++ trunk/Source/WebCore/rendering/RenderLayer.h 2016-04-30 04:13:16 UTC (rev 200283)
@@ -786,7 +786,7 @@
bool hasFilterThatIsPainting(GraphicsContext&, PaintLayerFlags) const;
std::unique_ptr<FilterEffectRendererHelper> setupFilters(GraphicsContext&, LayerPaintingInfo&, PaintLayerFlags, const LayoutSize& offsetFromRoot, LayoutRect& rootRelativeBounds, bool& rootRelativeBoundsComputed);
- void applyFilters(FilterEffectRendererHelper*, GraphicsContext& originalContext, LayerPaintingInfo&, LayerFragments&);
+ void applyFilters(FilterEffectRendererHelper*, GraphicsContext& originalContext, const LayerPaintingInfo&, const LayerFragments&);
void paintLayer(GraphicsContext&, const LayerPaintingInfo&, PaintLayerFlags);
void paintFixedLayersInNamedFlows(GraphicsContext&, const LayerPaintingInfo&, PaintLayerFlags);