Changeset 146955 in webkit


Ignore:
Timestamp:
Mar 26, 2013, 6:00:57 PM (12 years ago)
Author:
Antti Koivisto
Message:

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:
Location:
trunk
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r146949 r146955  
     12013-03-26  Antti Koivisto  <antti@apple.com>
     2
     3        Test if non-immediate descendants obscure background
     4        https://bugs.webkit.org/show_bug.cgi?id=113137
     5
     6        Reviewed by Simon Fraser.
     7
     8        * fast/backgrounds/obscured-background-child-style-change-expected.html:
     9        * fast/backgrounds/obscured-background-child-style-change.html:
     10        * fast/repaint/obscured-background-no-repaint-expected.txt:
     11        * fast/repaint/obscured-background-no-repaint.html:
     12
    1132013-03-26  Chris Fleizach  <cfleizach@apple.com>
    214
  • trunk/LayoutTests/fast/backgrounds/obscured-background-child-style-change-expected.html

    r146279 r146955  
    88    .child {
    99        position: relative;
    10         background-color: rgba(0,255,0,0.2);
     10        background-color: rgba(0,255,0,0.8);
    1111        width: 100px;
    1212        height: 100px;
     
    1717    </div>
    1818</div>
     19<div class=parent>
     20    <div>
     21        <div class=child>
     22        </div>
     23    </div>
     24</div>
     25<script>
     26document.body.offsetTop;
     27if (window.testRunner)
     28    testRunner.display();
     29var children = document.getElementsByClassName("child");
     30children[0].style.backgroundColor = "rgba(0,255,0,0.5)";
     31children[1].style.backgroundColor = "rgba(0,255,0,0.5)";
     32</script>
  • trunk/LayoutTests/fast/backgrounds/obscured-background-child-style-change.html

    r146279 r146955  
    77}
    88.child {
    9     position: relative;
    109    background-color: red;
    1110    width: 100px;
     
    1413</style>
    1514<div class=parent>
    16 <div class=child>
     15    <div class=child>
     16    </div>
    1717</div>
     18<div class=parent>
     19    <div>
     20        <div class=child>
     21        </div>
     22    </div>
    1823</div>
    1924<script>
    2025document.body.offsetTop;
    21 document.getElementsByClassName("child")[0].style.backgroundColor = "rgba(0,255,0,0.2)";
     26if (window.testRunner)
     27    testRunner.display();
     28var children = document.getElementsByClassName("child");
     29children[0].style.backgroundColor = "rgba(0,255,0,0.5)";
     30children[1].style.backgroundColor = "rgba(0,255,0,0.5)";
    2231</script>
  • trunk/LayoutTests/fast/repaint/obscured-background-no-repaint-expected.txt

    r145680 r146955  
    99TEST COMPLETE
    1010
     11 
     12
  • trunk/LayoutTests/fast/repaint/obscured-background-no-repaint.html

    r146279 r146955  
    3333    }
    3434    #test3 img {
     35        background-image: url(resources/animated.gif)
     36    }
     37    #test4 .parent {
     38        position: relative;
     39        height: 100px;
     40        width: 100px;
     41        background-color: red;
     42        background-repeat: no-repeat;
     43        background-position: center;
    3544        background-image: url(resources/animated.gif)
    3645    }
     
    8291    <img src="resources/apple.jpg">
    8392</div>
     93<div id="test4">
     94    <div class="parent">
     95        <a>
     96            <div></div>
     97            <div>
     98                <img src="resources/apple.jpg">
     99            </div>
     100        </a>
     101    </div>
     102</div>
    84103</body>
    85104<script src="../js/resources/js-test-post.js"></script>
  • trunk/Source/WebCore/ChangeLog

    r146954 r146955  
     12013-03-26  Antti Koivisto  <antti@apple.com>
     2
     3        Test if non-immediate descendants obscure background
     4        https://bugs.webkit.org/show_bug.cgi?id=113137
     5
     6        Reviewed by Simon Fraser.
     7
     8        The current obscuration test only covers immediate children. We can find more cases by looking deeper into descendants.
     9       
     10        The patch makes the test sufficiently smart to stop a heavy fully obscured gif animation on micrsoft.com.
     11
     12        * loader/cache/CachedImage.cpp:
     13        (WebCore::CachedImage::animationAdvanced):
     14        * rendering/RenderBox.cpp:
     15        (WebCore::RenderBox::styleDidChange):
     16       
     17            Invalidate parents to max test depth.
     18
     19        (WebCore::RenderBox::backgroundPaintedExtent):
     20       
     21            Background painting is pixel snapped.
     22
     23        (WebCore::isCandidateForOpaquenessTest):
     24        (WebCore::RenderBox::foregroundIsKnownToBeOpaqueInRect):
     25       
     26            Separate foreground testing and make it recursive.
     27            Add fast bailout for common static positioned case.
     28            Remove maximum child count, the fast bailouts should prevent long tests.
     29            Add maximum depth so we know how deep we need to invalidate in styleDidChange.
     30
     31        (WebCore::RenderBox::computeBackgroundIsKnownToBeObscured):
     32        (WebCore):
     33        * rendering/RenderBox.h:
     34        (RenderBox):
     35        * rendering/RenderImage.cpp:
     36        (WebCore::RenderImage::foregroundIsKnownToBeOpaqueInRect):
     37        (WebCore):
     38        (WebCore::RenderImage::computeBackgroundIsKnownToBeObscured):
     39       
     40        * rendering/RenderImage.h:
     41        (RenderImage):
     42
    1432013-03-26  Benjamin Poulain  <bpoulain@apple.com>
    244
  • trunk/Source/WebCore/rendering/RenderBox.cpp

    r146531 r146955  
    9090// autoscroll is started.
    9191static const int autoscrollBeltSize = 20;
     92static const unsigned backgroundObscurationTestMaxDepth = 4;
    9293
    9394bool RenderBox::s_hadOverflowClip = false;
     
    284285
    285286    // Our opaqueness might have changed without triggering layout.
    286     if (parent() && (diff == StyleDifferenceRepaint || diff == StyleDifferenceRepaintLayer))
    287         parent()->invalidateBackgroundObscurationStatus();
     287    if (diff == StyleDifferenceRepaint || diff == StyleDifferenceRepaintLayer) {
     288        RenderObject* parentToInvalidate = parent();
     289        for (unsigned i = 0; i < backgroundObscurationTestMaxDepth && parentToInvalidate; ++i) {
     290            parentToInvalidate->invalidateBackgroundObscurationStatus();
     291            parentToInvalidate = parentToInvalidate->parent();
     292        }
     293    }
    288294
    289295    bool isBodyRenderer = isBody();
     
    11511157{
    11521158    ASSERT(hasBackground());
    1153     LayoutRect backgroundRect = borderBoxRect();
     1159    LayoutRect backgroundRect = pixelSnappedIntRect(borderBoxRect());
    11541160
    11551161    Color backgroundColor = style()->visitedDependentColor(CSSPropertyBackgroundColor);
     
    11971203}
    11981204
     1205static bool isCandidateForOpaquenessTest(RenderBox* childBox)
     1206{
     1207    RenderStyle* childStyle = childBox->style();
     1208    if (childStyle->position() != StaticPosition && childBox->containingBlock() != childBox->parent())
     1209        return false;
     1210    if (childStyle->visibility() != VISIBLE || childStyle->shapeOutside())
     1211        return false;
     1212    if (!childBox->width() || !childBox->height())
     1213        return false;
     1214    if (RenderLayer* childLayer = childBox->layer()) {
     1215#if USE(ACCELERATED_COMPOSITING)
     1216        if (childLayer->isComposited())
     1217            return false;
     1218#endif
     1219        // FIXME: Deal with z-index.
     1220        if (!childStyle->hasAutoZIndex())
     1221            return false;
     1222        if (childLayer->hasTransform() || childLayer->isTransparent() || childLayer->hasFilter())
     1223            return false;
     1224    }
     1225    return true;
     1226}
     1227
     1228bool RenderBox::foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, unsigned maxDepthToTest) const
     1229{
     1230    if (!maxDepthToTest)
     1231        return false;
     1232    for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
     1233        if (!child->isBox())
     1234            continue;
     1235        RenderBox* childBox = toRenderBox(child);
     1236        if (!isCandidateForOpaquenessTest(childBox))
     1237            continue;
     1238        LayoutPoint childLocation = childBox->location();
     1239        if (childBox->isRelPositioned())
     1240            childLocation.move(childBox->relativePositionOffset());
     1241        LayoutRect childLocalRect = localRect;
     1242        childLocalRect.moveBy(-childLocation);
     1243        if (childLocalRect.y() < 0 || childLocalRect.x() < 0) {
     1244            // If there is unobscured area above/left of a static positioned box then the rect is probably not covered.
     1245            if (childBox->style()->position() == StaticPosition)
     1246                return false;
     1247            continue;
     1248        }
     1249        if (childLocalRect.maxY() > childBox->height() || childLocalRect.maxX() > childBox->width())
     1250            continue;
     1251        if (childBox->backgroundIsKnownToBeOpaqueInRect(childLocalRect))
     1252            return true;
     1253        if (childBox->foregroundIsKnownToBeOpaqueInRect(childLocalRect, maxDepthToTest - 1))
     1254            return true;
     1255    }
     1256    return false;
     1257}
     1258
    11991259bool RenderBox::computeBackgroundIsKnownToBeObscured()
    12001260{
     
    12081268
    12091269    LayoutRect backgroundRect = backgroundPaintedExtent();
    1210     // If we don't find a covering child fast there probably isn't one.
    1211     static const unsigned maximumChildrenCountToTest = 4;
    1212     unsigned count = 0;
    1213     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
    1214         if (++count > maximumChildrenCountToTest)
    1215             break;
    1216         if (!child->isBox())
    1217             continue;
    1218         RenderBox* childBox = toRenderBox(child);
    1219         RenderStyle* childStyle = child->style();
    1220         if (childStyle->visibility() != VISIBLE || childStyle->shapeOutside())
    1221             continue;
    1222         if (childStyle->position() != StaticPosition && childBox->containingBlock() != this)
    1223             continue;
    1224         LayoutPoint childLocation = childBox->location();
    1225         if (childBox->isRelPositioned())
    1226             childLocation.move(childBox->relativePositionOffset());
    1227         LayoutRect childLocalBackgroundRect = backgroundRect;
    1228         childLocalBackgroundRect.moveBy(-childLocation);
    1229         if (RenderLayer* childLayer = childBox->layer()) {
    1230 #if USE(ACCELERATED_COMPOSITING)
    1231             if (childLayer->isComposited())
    1232                 continue;
    1233 #endif
    1234             if (childLayer->zIndex() < 0)
    1235                 continue;
    1236             if (childLayer->hasTransform() || childLayer->isTransparent())
    1237                 continue;
    1238         }
    1239         if (childBox->backgroundIsKnownToBeOpaqueInRect(childLocalBackgroundRect))
    1240             return true;
    1241     }
    1242     return false;
     1270    return foregroundIsKnownToBeOpaqueInRect(backgroundRect, backgroundObscurationTestMaxDepth);
    12431271}
    12441272
  • trunk/Source/WebCore/rendering/RenderBox.h

    r146531 r146955  
    595595
    596596    LayoutRect backgroundPaintedExtent() const;
     597    virtual bool foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, unsigned maxDepthToTest) const;
    597598    virtual bool computeBackgroundIsKnownToBeObscured() OVERRIDE;
     599
    598600    void paintBackground(const PaintInfo&, const LayoutRect&, BackgroundBleedAvoidance = BackgroundBleedNone);
    599601   
  • trunk/Source/WebCore/rendering/RenderImage.cpp

    r146279 r146955  
    485485}
    486486
    487 bool RenderImage::computeBackgroundIsKnownToBeObscured()
    488 {
     487bool RenderImage::foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, unsigned maxDepthToTest) const
     488{
     489    UNUSED_PARAM(maxDepthToTest);
    489490    if (!m_imageResource->hasImage() || m_imageResource->errorOccurred())
    490491        return false;
    491492    if (m_imageResource->cachedImage() && !m_imageResource->cachedImage()->isLoaded())
    492493        return false;
    493 
     494    if (!contentBoxRect().contains(localRect))
     495        return false;
    494496    EFillBox backgroundClip = style()->backgroundClip();
    495497    // Background paints under borders.
     
    499501    if ((backgroundClip == BorderFillBox || backgroundClip == PaddingFillBox) && style()->hasPadding())
    500502        return false;
    501 
    502503    // Check for image with alpha.
    503504    return m_imageResource->cachedImage() && m_imageResource->cachedImage()->currentFrameKnownToBeOpaque(this);
     505}
     506
     507bool RenderImage::computeBackgroundIsKnownToBeObscured()
     508{
     509    if (!hasBackground())
     510        return false;
     511    return foregroundIsKnownToBeOpaqueInRect(backgroundPaintedExtent(), 0);
    504512}
    505513
  • trunk/Source/WebCore/rendering/RenderImage.h

    r146835 r146955  
    8989    virtual void paintReplaced(PaintInfo&, const LayoutPoint&);
    9090
     91    virtual bool foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, unsigned maxDepthToTest) const OVERRIDE;
    9192    virtual bool computeBackgroundIsKnownToBeObscured() OVERRIDE;
    9293
Note: See TracChangeset for help on using the changeset viewer.