Test if non-immediate descendants obscure background
https://bugs.webkit.org/show_bug.cgi?id=113137

Reviewed by Simon Fraser.

Source/WebCore: 

The current obscuration test only covers immediate children. We can find more cases by looking deeper into descendants.
        
The patch makes the test sufficiently smart to stop a heavy fully obscured gif animation on micrsoft.com.

* loader/cache/CachedImage.cpp:
(WebCore::CachedImage::animationAdvanced):
* rendering/RenderBox.cpp:
(WebCore::RenderBox::styleDidChange):
        
    Invalidate parents to max test depth.

(WebCore::RenderBox::backgroundPaintedExtent):
        
    Background painting is pixel snapped.

(WebCore::isCandidateForOpaquenessTest):
(WebCore::RenderBox::foregroundIsKnownToBeOpaqueInRect):
        
    Separate foreground testing and make it recursive.
    Add fast bailout for common static positioned case.
    Remove maximum child count, the fast bailouts should prevent long tests.
    Add maximum depth so we know how deep we need to invalidate in styleDidChange.

(WebCore::RenderBox::computeBackgroundIsKnownToBeObscured):
(WebCore):
* rendering/RenderBox.h:
(RenderBox):
* rendering/RenderImage.cpp:
(WebCore::RenderImage::foregroundIsKnownToBeOpaqueInRect):
(WebCore):
(WebCore::RenderImage::computeBackgroundIsKnownToBeObscured):
        
* rendering/RenderImage.h:
(RenderImage):

LayoutTests: 

* fast/backgrounds/obscured-background-child-style-change-expected.html:
* fast/backgrounds/obscured-background-child-style-change.html:
* fast/repaint/obscured-background-no-repaint-expected.txt:
* fast/repaint/obscured-background-no-repaint.html:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@146955 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/rendering/RenderImage.cpp b/Source/WebCore/rendering/RenderImage.cpp
index 7737b61..ced8a99 100644
--- a/Source/WebCore/rendering/RenderImage.cpp
+++ b/Source/WebCore/rendering/RenderImage.cpp
@@ -484,13 +484,15 @@
     return !const_cast<RenderImage*>(this)->backgroundIsKnownToBeObscured();
 }
 
-bool RenderImage::computeBackgroundIsKnownToBeObscured()
+bool RenderImage::foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, unsigned maxDepthToTest) const
 {
+    UNUSED_PARAM(maxDepthToTest);
     if (!m_imageResource->hasImage() || m_imageResource->errorOccurred())
         return false;
     if (m_imageResource->cachedImage() && !m_imageResource->cachedImage()->isLoaded())
         return false;
-
+    if (!contentBoxRect().contains(localRect))
+        return false;
     EFillBox backgroundClip = style()->backgroundClip();
     // Background paints under borders.
     if (backgroundClip == BorderFillBox && style()->hasBorder() && !borderObscuresBackground())
@@ -498,11 +500,17 @@
     // Background shows in padding area.
     if ((backgroundClip == BorderFillBox || backgroundClip == PaddingFillBox) && style()->hasPadding())
         return false;
-
     // Check for image with alpha.
     return m_imageResource->cachedImage() && m_imageResource->cachedImage()->currentFrameKnownToBeOpaque(this);
 }
 
+bool RenderImage::computeBackgroundIsKnownToBeObscured()
+{
+    if (!hasBackground())
+        return false;
+    return foregroundIsKnownToBeOpaqueInRect(backgroundPaintedExtent(), 0);
+}
+
 LayoutUnit RenderImage::minimumReplacedHeight() const
 {
     return m_imageResource->errorOccurred() ? intrinsicSize().height() : LayoutUnit();