Changeset 173293 in webkit


Ignore:
Timestamp:
Sep 4, 2014 5:23:05 PM (10 years ago)
Author:
Simon Fraser
Message:

Improve the logic for compositing backing store avoidance
https://bugs.webkit.org/show_bug.cgi?id=136556

Reviewed by Dean Jackson.

Source/WebCore:

Avoid backing store allocation in more cases by improving the logic that detects
whether a RenderLayer has any painted, non-layer descendent renderers.

Rename RenderLayer::hasNonEmptyChildRenderers() to hasPaintingNonLayerDescendants(),
and make it recur 3 levels deep, walking child lists of up to 20 siblings looking
for renderers that paint anything. Any renderer with box decorations paints;
replaced elements paint, and non-whitespace text nodes paint. We can avoid
making backing store when whitespace nodes are present only when user-select is none,
since we have to ensure that there's backing store to paint the selection into.

Tests: compositing/backing/inline-block-no-backing.html

compositing/backing/whitespace-nodes-no-backing.html

  • rendering/RenderLayer.cpp:

(WebCore::RenderLayer::hasNonEmptyChildRenderers): Call the recursive hasPaintingNonLayerDescendants().
(WebCore::RenderLayer::hasBoxDecorationsOrBackground):
(WebCore::RenderLayer::isVisuallyNonEmpty): Do the cheap tests first. Use isRenderReplaced()
rather than isReplaced(), since the latter includes inline-blocks.

  • rendering/RenderLayerBacking.cpp:

(WebCore::RenderLayerBacking::updateConfiguration): Don't run the isSimpleContainerCompositingLayer()
logic in the root layer, since it always wants backing store.
(WebCore::RenderLayerBacking::updateAfterDescendents): Ditto.
(WebCore::RenderLayerBacking::isSimpleContainerCompositingLayer): isReplaced() includes
inline-block, so use isRenderReplaced() instead.

LayoutTests:

Tests that dump the layer tree (showing backing store) for various combinations
of child renderers and whitespace.

  • compositing/backing/inline-block-no-backing-expected.txt: Added.
  • compositing/backing/inline-block-no-backing.html: Added.
  • compositing/backing/whitespace-nodes-no-backing-expected.txt: Added.
  • compositing/backing/whitespace-nodes-no-backing.html: Added.
Location:
trunk
Files:
4 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r173291 r173293  
     12014-09-04  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Improve the logic for compositing backing store avoidance
     4        https://bugs.webkit.org/show_bug.cgi?id=136556
     5
     6        Reviewed by Dean Jackson.
     7       
     8        Tests that dump the layer tree (showing backing store) for various combinations
     9        of child renderers and whitespace.
     10
     11        * compositing/backing/inline-block-no-backing-expected.txt: Added.
     12        * compositing/backing/inline-block-no-backing.html: Added.
     13        * compositing/backing/whitespace-nodes-no-backing-expected.txt: Added.
     14        * compositing/backing/whitespace-nodes-no-backing.html: Added.
     15
    1162014-09-04  Beth Dakin  <bdakin@apple.com>
    217
  • trunk/Source/WebCore/ChangeLog

    r173292 r173293  
     12014-09-04  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Improve the logic for compositing backing store avoidance
     4        https://bugs.webkit.org/show_bug.cgi?id=136556
     5
     6        Reviewed by Dean Jackson.
     7       
     8        Avoid backing store allocation in more cases by improving the logic that detects
     9        whether a RenderLayer has any painted, non-layer descendent renderers.
     10       
     11        Rename RenderLayer::hasNonEmptyChildRenderers() to hasPaintingNonLayerDescendants(),
     12        and make it recur 3 levels deep, walking child lists of up to 20 siblings looking
     13        for renderers that paint anything. Any renderer with box decorations paints;
     14        replaced elements paint, and non-whitespace text nodes paint. We can avoid
     15        making backing store when whitespace nodes are present only when user-select is none,
     16        since we have to ensure that there's backing store to paint the selection into.
     17
     18        Tests: compositing/backing/inline-block-no-backing.html
     19               compositing/backing/whitespace-nodes-no-backing.html
     20
     21        * rendering/RenderLayer.cpp:
     22        (WebCore::RenderLayer::hasNonEmptyChildRenderers): Call the recursive hasPaintingNonLayerDescendants().
     23        (WebCore::RenderLayer::hasBoxDecorationsOrBackground):
     24        (WebCore::RenderLayer::isVisuallyNonEmpty): Do the cheap tests first. Use isRenderReplaced()
     25        rather than isReplaced(), since the latter includes inline-blocks.
     26        * rendering/RenderLayerBacking.cpp:
     27        (WebCore::RenderLayerBacking::updateConfiguration): Don't run the isSimpleContainerCompositingLayer()
     28        logic in the root layer, since it always wants backing store.
     29        (WebCore::RenderLayerBacking::updateAfterDescendents): Ditto.
     30        (WebCore::RenderLayerBacking::isSimpleContainerCompositingLayer): isReplaced() includes
     31        inline-block, so use isRenderReplaced() instead.
     32
    1332014-09-04  Daniel Bates  <dabates@apple.com>
    234
  • trunk/Source/WebCore/rendering/RenderLayer.cpp

    r173275 r173293  
    9999#include "RenderTableCell.h"
    100100#include "RenderTableRow.h"
     101#include "RenderText.h"
    101102#include "RenderTheme.h"
    102103#include "RenderTreeAsText.h"
     
    62466247}
    62476248
     6249// FIXME: use RenderObject::hasBoxDecorations(). And why hasBorderRadius() and filter?
     6250static bool hasBoxDecorations(const RenderStyle& style)
     6251{
     6252    return style.hasBorder() || style.hasBorderRadius() || style.hasOutline() || style.hasAppearance() || style.boxShadow() || style.hasFilter();
     6253}
     6254
     6255static bool hasBoxDecorationsOrBackground(const RenderElement& renderer)
     6256{
     6257    return hasBoxDecorations(renderer.style()) || renderer.hasBackground();
     6258}
     6259
     6260// Constrain the depth and breadth of the search for performance.
     6261static const int maxDescendentDepth = 3;
     6262static const int maxSiblingCount = 20;
     6263
     6264static bool hasPaintingNonLayerDescendants(const RenderElement& renderer, int depth)
     6265{
     6266    if (depth > maxDescendentDepth)
     6267        return true;
     6268   
     6269    int siblingCount = 0;
     6270    for (const auto& child : childrenOfType<RenderObject>(renderer)) {
     6271        if (++siblingCount > maxSiblingCount)
     6272            return true;
     6273       
     6274        if (child.isText()) {
     6275            bool isSelectable = renderer.style().userSelect() != SELECT_NONE;
     6276            if (isSelectable || !toRenderText(child).isAllCollapsibleWhitespace())
     6277                return true;
     6278        }
     6279       
     6280        if (!child.isRenderElement())
     6281            continue;
     6282       
     6283        const RenderElement& renderElementChild = toRenderElement(child);
     6284
     6285        if (renderElementChild.isRenderLayerModelObject() && toRenderLayerModelObject(renderElementChild).hasSelfPaintingLayer())
     6286            continue;
     6287
     6288        if (hasBoxDecorationsOrBackground(renderElementChild))
     6289            return true;
     6290       
     6291        if (renderElementChild.isRenderReplaced())
     6292            return true;
     6293
     6294        if (hasPaintingNonLayerDescendants(renderElementChild, depth + 1))
     6295            return true;
     6296    }
     6297
     6298    return false;
     6299}
     6300
    62486301bool RenderLayer::hasNonEmptyChildRenderers() const
    62496302{
    6250     // Some HTML can cause whitespace text nodes to have renderers, like:
    6251     // <div>
    6252     // <img src=...>
    6253     // </div>
    6254     // so test for 0x0 RenderTexts here
    6255     for (RenderObject* child = renderer().firstChild(); child; child = child->nextSibling()) {
    6256         if (!child->hasLayer()) {
    6257             if (child->isRenderInline() || !child->isBox())
    6258                 return true;
    6259        
    6260             if (toRenderBox(child)->width() > 0 || toRenderBox(child)->height() > 0)
    6261                 return true;
    6262         }
    6263     }
    6264     return false;
    6265 }
    6266 
    6267 static bool hasBoxDecorations(const RenderStyle& style)
    6268 {
    6269     return style.hasBorder() || style.hasBorderRadius() || style.hasOutline() || style.hasAppearance() || style.boxShadow() || style.hasFilter();
     6303    return hasPaintingNonLayerDescendants(renderer(), 0);
    62706304}
    62716305
    62726306bool RenderLayer::hasBoxDecorationsOrBackground() const
    62736307{
    6274     return hasBoxDecorations(renderer().style()) || renderer().hasBackground();
     6308    return WebCore::hasBoxDecorationsOrBackground(renderer());
    62756309}
    62766310
     
    62906324        return false;
    62916325
     6326    if (renderer().isRenderReplaced() || hasOverflowControls())
     6327        return true;
     6328
     6329    if (hasBoxDecorationsOrBackground())
     6330        return true;
     6331   
    62926332    if (hasNonEmptyChildRenderers())
    6293         return true;
    6294 
    6295     if (renderer().isReplaced())
    6296         return true;
    6297 
    6298     if (hasVisibleBoxDecorations())
    62996333        return true;
    63006334
  • trunk/Source/WebCore/rendering/RenderLayerBacking.cpp

    r173268 r173293  
    563563        m_graphicsLayer->setReplicatedByLayer(0);
    564564
    565     bool isSimpleContainer = isSimpleContainerCompositingLayer();
    566     bool didUpdateContentsRect = false;
    567     updateDirectlyCompositedContents(isSimpleContainer, didUpdateContentsRect);
    568 
    569     updateRootLayerConfiguration();
     565    if (!m_owningLayer.isRootLayer()) {
     566        bool isSimpleContainer = isSimpleContainerCompositingLayer();
     567        bool didUpdateContentsRect = false;
     568        updateDirectlyCompositedContents(isSimpleContainer, didUpdateContentsRect);
     569    } else
     570        updateRootLayerConfiguration();
    570571   
    571572    if (isDirectlyCompositedImage())
     
    956957void RenderLayerBacking::updateAfterDescendents()
    957958{
    958     bool didUpdateContentsRect = false;
    959     bool isSimpleContainer = isSimpleContainerCompositingLayer();
    960     updateDirectlyCompositedContents(isSimpleContainer, didUpdateContentsRect);
    961     if (!didUpdateContentsRect && m_graphicsLayer->usesContentsLayer())
    962         resetContentsRect();
     959    bool isSimpleContainer = false;
     960    if (!m_owningLayer.isRootLayer()) {
     961        bool didUpdateContentsRect = false;
     962        // FIXME: this duplicates work we did in updateConfiguration().
     963        isSimpleContainer = isSimpleContainerCompositingLayer();
     964        updateDirectlyCompositedContents(isSimpleContainer, didUpdateContentsRect);
     965        if (!didUpdateContentsRect && m_graphicsLayer->usesContentsLayer())
     966            resetContentsRect();
     967    }
    963968
    964969    updateDrawsContent(isSimpleContainer);
     
    16931698bool RenderLayerBacking::isSimpleContainerCompositingLayer() const
    16941699{
    1695     if (renderer().isReplaced() && (!isCompositedPlugin(&renderer()) || isRestartedPlugin(&renderer())))
     1700    if (renderer().isRenderReplaced() && (!isCompositedPlugin(&renderer()) || isRestartedPlugin(&renderer())))
    16961701        return false;
    16971702
Note: See TracChangeset for help on using the changeset viewer.