Huge filter area cause hangs and malloc failures
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 16 Jan 2012 22:37:13 +0000 (22:37 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 16 Jan 2012 22:37:13 +0000 (22:37 +0000)
https://bugs.webkit.org/show_bug.cgi?id=75711

Reviewed by Dean Jackson.

Filtering an element with a child that had a huge negative text-indent
was extremely slow, because transparencyClipBox() returned a huge rect.

Add a method, paintingExtent(), that wraps transparencyClipBox()
and intersects it with the paintDirtyRect to constrain the size
of the rect used for filters and transparency layers.

Transparency layer extent is not testable in layout tests.

* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::paintingExtent):
(WebCore::RenderLayer::beginTransparencyLayers): Floating point literals are required
to avoid ambiguous constructor call.
(WebCore::RenderLayer::paintLayer):
(WebCore::RenderLayer::paintLayerContents):
* rendering/RenderLayer.h:

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

Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderLayer.cpp
Source/WebCore/rendering/RenderLayer.h

index 74c8462..77d4f41 100644 (file)
@@ -1,5 +1,29 @@
 2012-01-16  Simon Fraser  <simon.fraser@apple.com>
 
+        Huge filter area cause hangs and malloc failures
+        https://bugs.webkit.org/show_bug.cgi?id=75711
+
+        Reviewed by Dean Jackson.
+        
+        Filtering an element with a child that had a huge negative text-indent
+        was extremely slow, because transparencyClipBox() returned a huge rect.
+        
+        Add a method, paintingExtent(), that wraps transparencyClipBox()
+        and intersects it with the paintDirtyRect to constrain the size
+        of the rect used for filters and transparency layers.
+
+        Transparency layer extent is not testable in layout tests.
+
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::paintingExtent):
+        (WebCore::RenderLayer::beginTransparencyLayers): Floating point literals are required
+        to avoid ambiguous constructor call.
+        (WebCore::RenderLayer::paintLayer):
+        (WebCore::RenderLayer::paintLayerContents):
+        * rendering/RenderLayer.h:
+
+2012-01-16  Simon Fraser  <simon.fraser@apple.com>
+
         Borders and box masks behave incorrectly with overlapping offsets
         https://bugs.webkit.org/show_bug.cgi?id=76137
 
index 6c6c78c..4a09a9f 100644 (file)
@@ -1045,23 +1045,28 @@ static LayoutRect transparencyClipBox(const RenderLayer* layer, const RenderLaye
     return clipRect;
 }
 
-void RenderLayer::beginTransparencyLayers(GraphicsContext* context, const RenderLayer* rootLayer, PaintBehavior paintBehavior)
+LayoutRect RenderLayer::paintingExtent(const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior)
+{
+    return intersection(transparencyClipBox(this, rootLayer, paintBehavior), paintDirtyRect);
+}
+
+void RenderLayer::beginTransparencyLayers(GraphicsContext* context, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior paintBehavior)
 {
     if (context->paintingDisabled() || (paintsWithTransparency(paintBehavior) && m_usedTransparency))
         return;
     
     RenderLayer* ancestor = transparentPaintingAncestor();
     if (ancestor)
-        ancestor->beginTransparencyLayers(context, rootLayer, paintBehavior);
+        ancestor->beginTransparencyLayers(context, rootLayer, paintDirtyRect, paintBehavior);
     
     if (paintsWithTransparency(paintBehavior)) {
         m_usedTransparency = true;
         context->save();
-        LayoutRect clipRect = transparencyClipBox(this, rootLayer, paintBehavior);
+        LayoutRect clipRect = paintingExtent(rootLayer, paintDirtyRect, paintBehavior);
         context->clip(clipRect);
         context->beginTransparencyLayer(renderer()->opacity());
 #ifdef REVEAL_TRANSPARENCY_LAYERS
-        context->setFillColor(Color(0, 0, 0.5f, 0.2f), ColorSpaceDeviceRGB);
+        context->setFillColor(Color(0.0f, 0.0f, 0.5f, 0.2f), ColorSpaceDeviceRGB);
         context->fillRect(clipRect);
 #endif
     }
@@ -2750,9 +2755,9 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* context,
         // layer from the parent now, assuming there is a parent
         if (paintFlags & PaintLayerHaveTransparency) {
             if (parent())
-                parent()->beginTransparencyLayers(context, rootLayer, paintBehavior);
+                parent()->beginTransparencyLayers(context, rootLayer, paintDirtyRect, paintBehavior);
             else
-                beginTransparencyLayers(context, rootLayer, paintBehavior);
+                beginTransparencyLayers(context, rootLayer, paintDirtyRect, paintBehavior);
         }
 
         // Make sure the parent's clip rects have been calculated.
@@ -2860,11 +2865,11 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co
         if (shouldPaintContent && !selectionOnly) {
             // Begin transparency layers lazily now that we know we have to paint something.
             if (haveTransparency)
-                beginTransparencyLayers(context, rootLayer, paintBehavior);
+                beginTransparencyLayers(context, rootLayer, paintDirtyRect, paintBehavior);
         
 #if ENABLE(CSS_FILTERS)
             if (filterPainter.haveFilterEffect() && !context->paintingDisabled())
-                context = filterPainter.beginFilterEffect(this, context, transparencyClipBox(this, rootLayer, paintBehavior));
+                context = filterPainter.beginFilterEffect(this, context, paintingExtent(rootLayer, paintDirtyRect, paintBehavior));
 #endif
         
             // Paint our background first, before painting any child layers.
@@ -2888,12 +2893,12 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co
         if (shouldPaintContent && !clipRectToApply.isEmpty()) {
             // Begin transparency layers lazily now that we know we have to paint something.
             if (haveTransparency)
-                beginTransparencyLayers(context, rootLayer, paintBehavior);
+                beginTransparencyLayers(context, rootLayer, paintDirtyRect, paintBehavior);
 
 #if ENABLE(CSS_FILTERS)
             // If the filter was not started yet, start it now, after the transparency layer was lazily created.
             if (filterPainter.haveFilterEffect() && !filterPainter.hasStartedFilterEffect() && !context->paintingDisabled())
-                context = filterPainter.beginFilterEffect(this, context, transparencyClipBox(this, rootLayer, paintBehavior));
+                context = filterPainter.beginFilterEffect(this, context, paintingExtent(rootLayer, paintDirtyRect, paintBehavior));
 #endif
             // Set up the clip used when painting our children.
             clipToRect(rootLayer, context, paintDirtyRect, clipRectToApply);
index 790c25c..de75f24 100644 (file)
@@ -257,7 +257,7 @@ public:
 
     bool isTransparent() const;
     RenderLayer* transparentPaintingAncestor();
-    void beginTransparencyLayers(GraphicsContext*, const RenderLayer* rootLayer, PaintBehavior);
+    void beginTransparencyLayers(GraphicsContext*, const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior);
 
     bool hasReflection() const { return renderer()->hasReflection(); }
     bool isReflection() const { return renderer()->isReplica(); }
@@ -704,6 +704,7 @@ private:
 
     void parentClipRects(const RenderLayer* rootLayer, RenderRegion*, ClipRects&, bool temporaryClipRects = false, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const;
     ClipRect backgroundClipRect(const RenderLayer* rootLayer, RenderRegion*, bool temporaryClipRects, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const;
+    LayoutRect paintingExtent(const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior);
 
     RenderLayer* enclosingTransformedAncestor() const;