Title: [91628] trunk/Source/WebCore
Revision
91628
Author
simon.fra...@apple.com
Date
2011-07-22 17:39:54 -0700 (Fri, 22 Jul 2011)

Log Message

2011-07-22  Simon Fraser  <simon.fra...@apple.com>

        Avoiding painting backgrounds if they are fully obscures by an object's foreground
        https://bugs.webkit.org/show_bug.cgi?id=65030

        Reviewed by Dan Bernstein.

        Some pages use animated loading GIFs as the background of <img>,
        but WebKit keeps animating these after the <img> has loaded.

        Thwart this by avoiding the painting of such backgrounds, if we can
        determine that they are completely obscured by the border and content
        of the element.

        * platform/graphics/BitmapImage.h:
        (WebCore::BitmapImage::currentFrameHasAlpha): Utility method, since currentFrame()
        is protected.
        * rendering/RenderBox.cpp:
        (WebCore::RenderBox::paintBoxDecorations): Call paintBackground().
        (WebCore::RenderBox::paintBackground): New wrapper for the paintFillLayers() which
        paints the background layers, plus some code we call in a couple of places. This
        checks the new backgroundIsObscured() method before doing any painting.
        * rendering/RenderBox.h:
        (WebCore::RenderBox::backgroundIsObscured): New virtual method that determines
        whether any of the background is visible.
        * rendering/RenderBoxModelObject.h:
        * rendering/RenderBoxModelObject.cpp:
        (WebCore::BorderEdge::obscuresBackground): Returns true if this edge will
        entirely hide the background under it.
        (WebCore::RenderBoxModelObject::borderObscuresBackground): Determine whether
        the border hides the background.
        * rendering/RenderImage.cpp:
        (WebCore::RenderImage::backgroundIsObscured): Override the RenderBox method
        and return true if the image is a loaded, opaque bitmap image, and the background
        won't show in the border or padding areas.
        * rendering/RenderImage.h:
        * rendering/RenderTable.cpp:
        (WebCore::RenderTable::paintBoxDecorations): Use paintBackground().

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (91627 => 91628)


--- trunk/Source/WebCore/ChangeLog	2011-07-23 00:19:05 UTC (rev 91627)
+++ trunk/Source/WebCore/ChangeLog	2011-07-23 00:39:54 UTC (rev 91628)
@@ -1,3 +1,42 @@
+2011-07-22  Simon Fraser  <simon.fra...@apple.com>
+
+        Avoiding painting backgrounds if they are fully obscures by an object's foreground
+        https://bugs.webkit.org/show_bug.cgi?id=65030
+
+        Reviewed by Dan Bernstein.
+
+        Some pages use animated loading GIFs as the background of <img>,
+        but WebKit keeps animating these after the <img> has loaded.
+        
+        Thwart this by avoiding the painting of such backgrounds, if we can
+        determine that they are completely obscured by the border and content
+        of the element.
+
+        * platform/graphics/BitmapImage.h:
+        (WebCore::BitmapImage::currentFrameHasAlpha): Utility method, since currentFrame()
+        is protected.
+        * rendering/RenderBox.cpp:
+        (WebCore::RenderBox::paintBoxDecorations): Call paintBackground().
+        (WebCore::RenderBox::paintBackground): New wrapper for the paintFillLayers() which
+        paints the background layers, plus some code we call in a couple of places. This
+        checks the new backgroundIsObscured() method before doing any painting.
+        * rendering/RenderBox.h:
+        (WebCore::RenderBox::backgroundIsObscured): New virtual method that determines
+        whether any of the background is visible.
+        * rendering/RenderBoxModelObject.h:
+        * rendering/RenderBoxModelObject.cpp:
+        (WebCore::BorderEdge::obscuresBackground): Returns true if this edge will
+        entirely hide the background under it.
+        (WebCore::RenderBoxModelObject::borderObscuresBackground): Determine whether
+        the border hides the background.
+        * rendering/RenderImage.cpp:
+        (WebCore::RenderImage::backgroundIsObscured): Override the RenderBox method
+        and return true if the image is a loaded, opaque bitmap image, and the background
+        won't show in the border or padding areas.
+        * rendering/RenderImage.h:
+        * rendering/RenderTable.cpp:
+        (WebCore::RenderTable::paintBoxDecorations): Use paintBackground().
+
 2011-07-22  Kenneth Russell  <k...@google.com>
 
         HTMLImageElement::crossOrigin is hard to use because of caching

Modified: trunk/Source/WebCore/platform/graphics/BitmapImage.h (91627 => 91628)


--- trunk/Source/WebCore/platform/graphics/BitmapImage.h	2011-07-23 00:19:05 UTC (rev 91627)
+++ trunk/Source/WebCore/platform/graphics/BitmapImage.h	2011-07-23 00:39:54 UTC (rev 91628)
@@ -158,7 +158,8 @@
 #endif
 
     virtual NativeImagePtr nativeImageForCurrentFrame() { return frameAtIndex(currentFrame()); }
-    bool frameHasAlphaAtIndex(size_t); 
+    bool frameHasAlphaAtIndex(size_t);
+    bool currentFrameHasAlpha() { return frameHasAlphaAtIndex(currentFrame()); }
 
 #if !ASSERT_DISABLED
     bool notSolidColor()

Modified: trunk/Source/WebCore/rendering/RenderBox.cpp (91627 => 91628)


--- trunk/Source/WebCore/rendering/RenderBox.cpp	2011-07-23 00:19:05 UTC (rev 91627)
+++ trunk/Source/WebCore/rendering/RenderBox.cpp	2011-07-23 00:39:54 UTC (rev 91628)
@@ -862,13 +862,8 @@
     // The theme will tell us whether or not we should also paint the CSS background.
     bool themePainted = style()->hasAppearance() && !theme()->paint(this, paintInfo, paintRect);
     if (!themePainted) {
-        if (isRoot())
-            paintRootBoxFillLayers(paintInfo);
-        else if (!isBody() || document()->documentElement()->renderer()->hasBackground()) {
-            // The <body> only paints its background if the root element has defined a background
-            // independent of the body.
-            paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), paintRect, bleedAvoidance);
-        }
+        paintBackground(paintInfo, paintRect, bleedAvoidance);
+
         if (style()->hasAppearance())
             theme()->paintDecorations(this, paintInfo, paintRect);
     }
@@ -882,6 +877,18 @@
         paintInfo.context->endTransparencyLayer();
 }
 
+void RenderBox::paintBackground(const PaintInfo& paintInfo, const LayoutRect& paintRect, BackgroundBleedAvoidance bleedAvoidance)
+{
+    if (isRoot())
+        paintRootBoxFillLayers(paintInfo);
+    else if (!isBody() || document()->documentElement()->renderer()->hasBackground()) {
+        // The <body> only paints its background if the root element has defined a background
+        // independent of the body.
+        if (!backgroundIsObscured())
+            paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), paintRect, bleedAvoidance);
+    }
+}
+
 void RenderBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
 {
     if (!paintInfo.shouldPaintWithinRoot(this) || style()->visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask || paintInfo.context->paintingDisabled())

Modified: trunk/Source/WebCore/rendering/RenderBox.h (91627 => 91628)


--- trunk/Source/WebCore/rendering/RenderBox.h	2011-07-23 00:19:05 UTC (rev 91627)
+++ trunk/Source/WebCore/rendering/RenderBox.h	2011-07-23 00:39:54 UTC (rev 91628)
@@ -417,6 +417,9 @@
     virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
     virtual void updateBoxModelInfoFromStyle();
 
+    virtual bool backgroundIsObscured() const { return false; }
+    void paintBackground(const PaintInfo&, const LayoutRect&, BackgroundBleedAvoidance = BackgroundBleedNone);
+    
     void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, BackgroundBleedAvoidance, CompositeOperator, RenderObject* backgroundObject);
     void paintFillLayers(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, BackgroundBleedAvoidance = BackgroundBleedNone, CompositeOperator = CompositeSourceOver, RenderObject* backgroundObject = 0);
 

Modified: trunk/Source/WebCore/rendering/RenderBoxModelObject.cpp (91627 => 91628)


--- trunk/Source/WebCore/rendering/RenderBoxModelObject.cpp	2011-07-23 00:19:05 UTC (rev 91627)
+++ trunk/Source/WebCore/rendering/RenderBoxModelObject.cpp	2011-07-23 00:39:54 UTC (rev 91628)
@@ -1095,7 +1095,17 @@
 
         return true;
     }
+    bool obscuresBackground() const
+    {
+        if (!isPresent || isTransparent || color.hasAlpha() || style == BHIDDEN)
+            return false;
 
+        if (style == DOTTED || style == DASHED || style == DOUBLE)
+            return false;
+
+        return true;
+    }
+
     int usedWidth() const { return isPresent ? width : 0; }
     
     void getDoubleBorderStripeWidths(int& outerWidth, int& innerWidth) const
@@ -2145,6 +2155,27 @@
     return true;
 }
 
+bool RenderBoxModelObject::borderObscuresBackground() const
+{
+    if (!style()->hasBorder())
+        return false;
+
+    // Bail if we have any border-image for now. We could look at the image alpha to improve this.
+    if (style()->borderImage().image())
+        return false;
+
+    BorderEdge edges[4];
+    getBorderEdgeInfo(edges);
+
+    for (int i = BSTop; i <= BSLeft; ++i) {
+        const BorderEdge& currEdge = edges[i];
+        if (!currEdge.obscuresBackground())
+            return false;
+    }
+
+    return true;
+}
+
 static inline IntRect areaCastingShadowInHole(const IntRect& holeRect, int shadowBlur, int shadowSpread, const IntSize& shadowOffset)
 {
     IntRect bounds(holeRect);

Modified: trunk/Source/WebCore/rendering/RenderBoxModelObject.h (91627 => 91628)


--- trunk/Source/WebCore/rendering/RenderBoxModelObject.h	2011-07-23 00:19:05 UTC (rev 91627)
+++ trunk/Source/WebCore/rendering/RenderBoxModelObject.h	2011-07-23 00:39:54 UTC (rev 91628)
@@ -183,6 +183,7 @@
     void calculateBackgroundImageGeometry(const FillLayer*, const IntRect& paintRect, BackgroundImageGeometry&);
     void getBorderEdgeInfo(class BorderEdge[], bool includeLogicalLeftEdge = true, bool includeLogicalRightEdge = true) const;
     bool borderObscuresBackgroundEdge(const FloatSize& contextScale) const;
+    bool borderObscuresBackground() const;
 
     bool shouldPaintAtLowQuality(GraphicsContext*, Image*, const void*, const IntSize&);
 

Modified: trunk/Source/WebCore/rendering/RenderImage.cpp (91627 => 91628)


--- trunk/Source/WebCore/rendering/RenderImage.cpp	2011-07-23 00:19:05 UTC (rev 91627)
+++ trunk/Source/WebCore/rendering/RenderImage.cpp	2011-07-23 00:39:54 UTC (rev 91628)
@@ -27,6 +27,7 @@
 #include "config.h"
 #include "RenderImage.h"
 
+#include "BitmapImage.h"
 #include "FontCache.h"
 #include "Frame.h"
 #include "FrameSelection.h"
@@ -387,6 +388,36 @@
     context->drawImage(m_imageResource->image(rect.width(), rect.height()).get(), style()->colorSpace(), rect, compositeOperator, useLowQualityScaling);
 }
 
+bool RenderImage::backgroundIsObscured() const
+{
+    if (!m_imageResource->hasImage() || m_imageResource->errorOccurred())
+        return false;
+
+    if (m_imageResource->cachedImage() && !m_imageResource->cachedImage()->isLoaded())
+        return false;
+
+    EFillBox backgroundClip = style()->backgroundClip();
+
+    // Background paints under borders.
+    if (backgroundClip == BorderFillBox && style()->hasBorder() && !borderObscuresBackground())
+        return false;
+
+    // Background shows in padding area.
+    if ((backgroundClip == BorderFillBox || backgroundClip == PaddingFillBox) && style()->hasPadding())
+        return false;
+
+    // Check for bitmap image with alpha.
+    Image* image = m_imageResource->image().get();
+    if (!image || !image->isBitmapImage())
+        return false;
+        
+    BitmapImage* bitmapImage = static_cast<BitmapImage*>(image);
+    if (bitmapImage->currentFrameHasAlpha())
+        return false;
+
+    return true;
+}
+
 int RenderImage::minimumReplacedHeight() const
 {
     return m_imageResource->errorOccurred() ? intrinsicSize().height() : 0;

Modified: trunk/Source/WebCore/rendering/RenderImage.h (91627 => 91628)


--- trunk/Source/WebCore/rendering/RenderImage.h	2011-07-23 00:19:05 UTC (rev 91627)
+++ trunk/Source/WebCore/rendering/RenderImage.h	2011-07-23 00:39:54 UTC (rev 91628)
@@ -78,6 +78,8 @@
 
     virtual void paintReplaced(PaintInfo&, const IntPoint&);
 
+    virtual bool backgroundIsObscured() const;
+
     virtual int minimumReplacedHeight() const;
 
     virtual void notifyFinished(CachedResource*);

Modified: trunk/Source/WebCore/rendering/RenderTable.cpp (91627 => 91628)


--- trunk/Source/WebCore/rendering/RenderTable.cpp	2011-07-23 00:19:05 UTC (rev 91627)
+++ trunk/Source/WebCore/rendering/RenderTable.cpp	2011-07-23 00:39:54 UTC (rev 91628)
@@ -558,14 +558,7 @@
     subtractCaptionRect(rect);
 
     paintBoxShadow(paintInfo.context, rect, style(), Normal);
-    
-    if (isRoot())
-        paintRootBoxFillLayers(paintInfo);
-    else if (!isBody() || document()->documentElement()->renderer()->hasBackground())
-        // The <body> only paints its background if the root element has defined a background
-        // independent of the body.
-        paintFillLayers(paintInfo, style()->visitedDependentColor(CSSPropertyBackgroundColor), style()->backgroundLayers(), rect);
-
+    paintBackground(paintInfo, rect);
     paintBoxShadow(paintInfo.context, rect, style(), Inset);
 
     if (style()->hasBorder() && !collapseBorders())
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to