Changeset 200283 in webkit


Ignore:
Timestamp:
Apr 29, 2016, 9:13:16 PM (10 years ago)
Author:
Simon Fraser
Message:

Blur filter escapes an enclosing overflow:hidden
https://bugs.webkit.org/show_bug.cgi?id=155029

Reviewed by Zalan Bujtas.

Source/WebCore:

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

LayoutTests:

  • 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.
Location:
trunk
Files:
8 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r200282 r200283  
     12016-04-29  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Blur filter escapes an enclosing overflow:hidden
     4        https://bugs.webkit.org/show_bug.cgi?id=155029
     5
     6        Reviewed by Zalan Bujtas.
     7
     8        * css3/filters/blur-clipped-by-ancestor-expected.html: Added.
     9        * css3/filters/blur-clipped-by-ancestor.html: Added.
     10        * css3/filters/blur-clipped-with-overflow-expected.html: Added.
     11        * css3/filters/blur-clipped-with-overflow.html: Added.
     12        * css3/filters/drop-shadow-expected.html: Added.
     13        * css3/filters/drop-shadow-with-overflow-hidden-expected.html: Added.
     14        * css3/filters/drop-shadow-with-overflow-hidden.html: Added.
     15        * css3/filters/drop-shadow.html: Added.
     16
    1172016-04-29  Myles C. Maxfield  <mmaxfield@apple.com>
    218
  • trunk/Source/WebCore/ChangeLog

    r200282 r200283  
     12016-04-29  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Blur filter escapes an enclosing overflow:hidden
     4        https://bugs.webkit.org/show_bug.cgi?id=155029
     5
     6        Reviewed by Zalan Bujtas.
     7
     8        The clipping that was applied when drawing the results of filters was wrong for two reasons.
     9
     10        First, it used localPaintingInfo which has already been contaminated when setting up the filters.
     11        When painting the result, we need to use the original paintingInfo, to get the right paintDirtyRect.
     12
     13        Secondly, when setting up the clip to paint the filter result, it was relying on layerFragments[0].backgroundRect.
     14        However, that was also contaminated by filter setup, since calculateRects() intersects with paintDirtyRect to
     15        compute that backgroundRect, and that paintDirtyRect came from filterPainter->repaintRect().
     16       
     17        Fix this second issue by re-running collectFragments(), which computes a fragment backgroundRect using
     18        the original paintDirtyRect.
     19
     20        Tests: css3/filters/blur-clipped-by-ancestor.html
     21               css3/filters/blur-clipped-with-overflow.html
     22               css3/filters/drop-shadow-with-overflow-hidden.html
     23               css3/filters/drop-shadow.html
     24
     25        * platform/graphics/filters/FilterEffect.cpp:
     26        (WebCore::FilterEffect::clearResult): Unconditionally null these out.
     27        * rendering/FilterEffectRenderer.cpp:
     28        (WebCore::FilterEffectRendererHelper::beginFilterEffect): Typo fix.
     29        * rendering/FilterEffectRenderer.h:
     30        (WebCore::FilterEffectRendererHelper::FilterEffectRendererHelper): C++11 initialization.
     31        * rendering/RenderLayer.cpp:
     32        (WebCore::RenderLayer::applyFilters):
     33        (WebCore::RenderLayer::paintLayerContents):
     34        * rendering/RenderLayer.h: const
     35
    1362016-04-29  Myles C. Maxfield  <mmaxfield@apple.com>
    237
  • trunk/Source/WebCore/platform/graphics/filters/FilterEffect.cpp

    r192138 r200283  
    198198    if (m_imageBufferResult)
    199199        m_imageBufferResult.reset();
    200     if (m_unmultipliedImageResult)
    201         m_unmultipliedImageResult = nullptr;
    202     if (m_premultipliedImageResult)
    203         m_premultipliedImageResult = nullptr;
     200
     201    m_unmultipliedImageResult = nullptr;
     202    m_premultipliedImageResult = nullptr;
    204203}
    205204
  • trunk/Source/WebCore/rendering/FilterEffectRenderer.cpp

    r200279 r200283  
    6868FilterEffectRenderer::FilterEffectRenderer()
    6969    : Filter(AffineTransform())
    70     , m_graphicsBufferAttached(false)
    71     , m_hasFilterThatMovesPixels(false)
    7270{
    7371    setFilterResolution(FloatSize(1, 1));
     
    408406    }
    409407   
    410     // Translate the context so that the contents of the layer is captuterd in the offscreen memory buffer.
     408    // Translate the context so that the contents of the layer is captured in the offscreen memory buffer.
    411409    sourceGraphicsContext->save();
    412410    sourceGraphicsContext->translate(-m_paintOffset.x(), -m_paintOffset.y());
  • trunk/Source/WebCore/rendering/FilterEffectRenderer.h

    r197563 r200283  
    5959public:
    6060    FilterEffectRendererHelper(bool haveFilterEffect)
    61         : m_renderLayer(0)
    62         , m_haveFilterEffect(haveFilterEffect)
    63         , m_startedFilterEffect(false)
     61        : m_haveFilterEffect(haveFilterEffect)
    6462    {
    6563    }
     
    7775
    7876private:
    79     RenderLayer* m_renderLayer; // FIXME: this is mainly used to get the FilterEffectRenderer. FilterEffectRendererHelper should be weaned off it.
     77    RenderLayer* m_renderLayer { nullptr }; // FIXME: this is mainly used to get the FilterEffectRenderer. FilterEffectRendererHelper should be weaned off it.
    8078    LayoutPoint m_paintOffset;
    8179    LayoutRect m_repaintRect;
    82     bool m_haveFilterEffect;
    83     bool m_startedFilterEffect;
     80    bool m_haveFilterEffect { false };
     81    bool m_startedFilterEffect { false };
    8482};
    8583
     
    146144    IntRectExtent m_outsets;
    147145
    148     bool m_graphicsBufferAttached;
    149     bool m_hasFilterThatMovesPixels;
     146    bool m_graphicsBufferAttached { false };
     147    bool m_hasFilterThatMovesPixels { false };
    150148};
    151149
  • trunk/Source/WebCore/rendering/RenderLayer.cpp

    r200279 r200283  
    41974197}
    41984198
    4199 void RenderLayer::applyFilters(FilterEffectRendererHelper* filterPainter, GraphicsContext& originalContext, LayerPaintingInfo& paintingInfo, LayerFragments& layerFragments)
     4199void RenderLayer::applyFilters(FilterEffectRendererHelper* filterPainter, GraphicsContext& originalContext, const LayerPaintingInfo& paintingInfo, const LayerFragments& layerFragments)
    42004200{
    42014201    ASSERT(filterPainter->hasStartedFilterEffect());
    4202     // Apply the correct clipping (ie. overflow: hidden).
    4203     // FIXME: It is incorrect to just clip to the damageRect here once multiple fragments are involved.
     4202
     4203    // FIXME: Handle more than one fragment.
    42044204    ClipRect backgroundRect = layerFragments.isEmpty() ? ClipRect() : layerFragments[0].backgroundRect;
    42054205    clipToRect(paintingInfo, originalContext, backgroundRect);
     
    42924292        hasClipPath = setupClipPath(context, paintingInfo, columnAwareOffsetFromRoot, rootRelativeBounds, rootRelativeBoundsComputed);
    42934293
    4294     LayerPaintingInfo localPaintingInfo(paintingInfo);
    4295 
    4296     bool selectionAndBackgroundsOnly = localPaintingInfo.paintBehavior & PaintBehaviorSelectionAndBackgroundsOnly;
    4297     bool selectionOnly = localPaintingInfo.paintBehavior & PaintBehaviorSelectionOnly;
     4294    bool selectionAndBackgroundsOnly = paintingInfo.paintBehavior & PaintBehaviorSelectionAndBackgroundsOnly;
     4295    bool selectionOnly = paintingInfo.paintBehavior & PaintBehaviorSelectionOnly;
    42984296    LayerFragments layerFragments;
    42994297    RenderObject* subtreePaintRootForRenderer = nullptr;
    43004298
    4301     { // Scope for currentContext.
     4299    { // Scope for filter-related state changes.
     4300        LayerPaintingInfo localPaintingInfo(paintingInfo);
    43024301        std::unique_ptr<FilterEffectRendererHelper> filterPainter = setupFilters(context, localPaintingInfo, paintFlags, columnAwareOffsetFromRoot, rootRelativeBounds, rootRelativeBoundsComputed);
    43034302
     
    43304329            // fragment should paint. If the parent's filter dictates full repaint to ensure proper filter effect,
    43314330            // use the overflow clip as dirty rect, instead of no clipping. It maintains proper clipping for overflow::scroll.
    4332             if (!paintingInfo.clipToDirtyRect && renderer().hasOverflowClip()) {
     4331            if (!localPaintingInfo.clipToDirtyRect && renderer().hasOverflowClip()) {
    43334332                // We can turn clipping back by requesting full repaint for the overflow area.
    43344333                localPaintingInfo.clipToDirtyRect = true;
     
    43824381
    43834382        if (filterContext) {
    4384             applyFilters(filterPainter.get(), context, localPaintingInfo, layerFragments);
     4383            // When we called collectFragments() last time, paintDirtyRect was reset to represent the filter bounds.
     4384            // Now we need to compute the backgroundRect uncontaminated by filters, in order to clip the filtered result.
     4385            // Note that we also use paintingInfo here, not localPaintingInfo which filters also contaminated.
     4386            LayerFragments layerFragments;
     4387            collectFragments(layerFragments, paintingInfo.rootLayer, paintingInfo.paintDirtyRect, ExcludeCompositedPaginatedLayers,
     4388                (localPaintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, IgnoreOverlayScrollbarSize,
     4389                (isPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip, offsetFromRoot);
     4390            updatePaintingInfoForFragments(layerFragments, paintingInfo, localPaintFlags, shouldPaintContent, offsetFromRoot);
     4391
     4392            applyFilters(filterPainter.get(), context, paintingInfo, layerFragments);
    43854393            filterPainter = nullptr;
    43864394        }
     
    43904398        if (shouldPaintMask(paintingInfo.paintBehavior, localPaintFlags)) {
    43914399            // Paint the mask for the fragments.
    4392             paintMaskForFragments(layerFragments, context, localPaintingInfo, subtreePaintRootForRenderer);
     4400            paintMaskForFragments(layerFragments, context, paintingInfo, subtreePaintRootForRenderer);
    43934401        }
    43944402
    43954403        if (!(paintFlags & PaintLayerPaintingCompositingMaskPhase) && (paintFlags & PaintLayerPaintingCompositingClipPathPhase)) {
    43964404            // Re-use paintChildClippingMaskForFragments to paint black for the compositing clipping mask.
    4397             paintChildClippingMaskForFragments(layerFragments, context, localPaintingInfo, subtreePaintRootForRenderer);
     4405            paintChildClippingMaskForFragments(layerFragments, context, paintingInfo, subtreePaintRootForRenderer);
    43984406        }
    43994407       
    44004408        if ((localPaintFlags & PaintLayerPaintingChildClippingMaskPhase)) {
    44014409            // Paint the border radius mask for the fragments.
    4402             paintChildClippingMaskForFragments(layerFragments, context, localPaintingInfo, subtreePaintRootForRenderer);
     4410            paintChildClippingMaskForFragments(layerFragments, context, paintingInfo, subtreePaintRootForRenderer);
    44034411        }
    44044412    }
  • trunk/Source/WebCore/rendering/RenderLayer.h

    r200279 r200283  
    787787    bool hasFilterThatIsPainting(GraphicsContext&, PaintLayerFlags) const;
    788788    std::unique_ptr<FilterEffectRendererHelper> setupFilters(GraphicsContext&, LayerPaintingInfo&, PaintLayerFlags, const LayoutSize& offsetFromRoot, LayoutRect& rootRelativeBounds, bool& rootRelativeBoundsComputed);
    789     void applyFilters(FilterEffectRendererHelper*, GraphicsContext& originalContext, LayerPaintingInfo&, LayerFragments&);
     789    void applyFilters(FilterEffectRendererHelper*, GraphicsContext& originalContext, const LayerPaintingInfo&, const LayerFragments&);
    790790
    791791    void paintLayer(GraphicsContext&, const LayerPaintingInfo&, PaintLayerFlags);
Note: See TracChangeset for help on using the changeset viewer.