Changeset 109851 in webkit


Ignore:
Timestamp:
Mar 5, 2012 9:13:00 PM (12 years ago)
Author:
enne@google.com
Message:

Compositing overlap testing can throw layers into compositing when they should not be.
https://bugs.webkit.org/show_bug.cgi?id=50192

Reviewed by Simon Fraser.

Source/WebCore:

The previous overlap map behavior was that a non-composited query
layer would become composited due to overlap if and only if the query
layer's absolute bounds overlapped the absolute bounds of some other
layer which:

  • draws before the query layer
  • is or has a compositing ancestor

This behavior, while correct, was too permissive in throwing layers
into compositing, causing many layers to get their own backing when
they could have just gone into their compositing ancestor's backing.

The correct logic is that non-composited query layer needs to be
composited due to overlap if and only if the query layer's absolute
bounds overlap the absolute bounds of some other layer which:

  • draws before the query layer
  • has a different compositing ancestor than the query layer
  • is or has a compositing ancestor that is a descendent of the query layer's compositing ancestor

This patch changes the semantics of the overlap map to enable this
behavior.

Rather than having one global overlap map, there is now a stack of
overlap maps. New (empty) overlap maps are pushed onto the stack
whenever a layer becomes a compositing ancestor and popped after all
of the compositing requirements for that layer's children have been
computed.

The compositing ancestor and all of its non-composited children of a
compositing ancestor do not get considered for overlap until their
composited ancestor has been popped off the stack. If a compositing
ancestor has a compositing subtree, then any descendents of that
compositing ancestor that draw after that subtree will consider
everything in the compositing subtree for overlap.

Test: compositing/layer-creation/stacking-context-overlap.html

  • platform/graphics/Region.cpp:

(WebCore::Region::intersects):
(WebCore):

  • platform/graphics/Region.h:

(Region):

  • rendering/RenderLayerCompositor.cpp:

(RenderLayerCompositor::OverlapMap):
(WebCore::RenderLayerCompositor::OverlapMap::OverlapMap):
(WebCore::RenderLayerCompositor::OverlapMap::add):
(WebCore::RenderLayerCompositor::OverlapMap::contains):
(WebCore::RenderLayerCompositor::OverlapMap::overlapsLayers):
(WebCore::RenderLayerCompositor::OverlapMap::isEmpty):
(WebCore::RenderLayerCompositor::OverlapMap::popCompositingContainer):
(WebCore::RenderLayerCompositor::OverlapMap::pushCompositingContainer):
(WebCore::RenderLayerCompositor::addToOverlapMapRecursive):
(WebCore::RenderLayerCompositor::computeCompositingRequirements):

  • rendering/RenderLayerCompositor.h:

(RenderLayerCompositor):

LayoutTests:

  • compositing/layer-creation/stacking-context-overlap-expected.txt: Added.
  • compositing/layer-creation/stacking-context-overlap.html: Added.
  • compositing/layer-creation/stacking-context-overlap-nested-expected.txt: Added.
  • compositing/layer-creation/stacking-context-overlap-nested.html: Added.
  • platform/chromium/test_expectations.txt:
Location:
trunk
Files:
4 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r109846 r109851  
     12012-03-05  Adrienne Walker  <enne@google.com>
     2
     3        Compositing overlap testing can throw layers into compositing when they should not be.
     4        https://bugs.webkit.org/show_bug.cgi?id=50192
     5
     6        Reviewed by Simon Fraser.
     7
     8        * compositing/layer-creation/stacking-context-overlap-expected.txt: Added.
     9        * compositing/layer-creation/stacking-context-overlap.html: Added.
     10        * compositing/layer-creation/stacking-context-overlap-nested-expected.txt: Added.
     11        * compositing/layer-creation/stacking-context-overlap-nested.html: Added.
     12        * platform/chromium/test_expectations.txt:
     13
    1142012-03-05  Yoshifumi Inoue  <yosin@chromium.org>
    215
  • trunk/LayoutTests/platform/chromium/test_expectations.txt

    r109828 r109851  
    34103410BUGWK75161 GPU : media/video-poster-blocked-by-willsendrequest.html = PASS TEXT
    34113411BUGWK75161 CPU : media/video-poster-blocked-by-willsendrequest.html = TEXT
    3412 
    3413 BUGWK75237 SNOWLEOPARD CPU : compositing/reflections/reflection-on-composited.html = PASS IMAGE
    34143412
    34153413BUGWK75367 : svg/css/composite-shadow-example.html = PASS TEXT
     
    43134311// New test; landed at r109779 but results look wrong on most Chrome platforms.
    43144312BUGSENORBLANCO : http/tests/incremental/partial-jpeg.html = FAIL
     4313
     4314// Needs rebaselining. Layers are merged, and rotated text drawn better.
     4315BUGWK50192 : compositing/geometry/limit-layer-bounds-fixed-positioned.html = TEXT
     4316BUGWK50192 : compositing/geometry/limit-layer-bounds-overflow-root.html = TEXT
     4317BUGWK50192 : compositing/geometry/limit-layer-bounds-positioned-transition.html = TEXT
     4318BUGWK50192 : compositing/geometry/limit-layer-bounds-positioned.html = TEXT
     4319BUGWK50192 WIN LINUX : compositing/geometry/limit-layer-bounds-transformed-overflow.html = TEXT
     4320BUGWK50192 MAC LEOPARD : compositing/geometry/limit-layer-bounds-transformed-overflow.html = TEXT
     4321BUGWK50192 : compositing/geometry/limit-layer-bounds-transformed.html = TEXT
     4322BUGWK50192 : compositing/geometry/fixed-position-transform-composited-page-scale-down.html = IMAGE
     4323BUGWK50192 LINUX MAC : compositing/geometry/fixed-position-transform-composited-page-scale.html = IMAGE
     4324BUGWK50192 : compositing/reflections/reflection-on-composited.html = IMAGE
     4325BUGWK50192 : compositing/shadows/shadow-drawing.html = IMAGE
     4326BUGWK50192 : fast/repaint/block-selection-gap-in-composited-layer.html = IMAGE
  • trunk/Source/WebCore/ChangeLog

    r109847 r109851  
     12012-03-05  Adrienne Walker  <enne@google.com>
     2
     3        Compositing overlap testing can throw layers into compositing when they should not be.
     4        https://bugs.webkit.org/show_bug.cgi?id=50192
     5
     6        Reviewed by Simon Fraser.
     7
     8        The previous overlap map behavior was that a non-composited query
     9        layer would become composited due to overlap if and only if the query
     10        layer's absolute bounds overlapped the absolute bounds of some other
     11        layer which:
     12            - draws before the query layer
     13            - is or has a compositing ancestor
     14
     15        This behavior, while correct, was too permissive in throwing layers
     16        into compositing, causing many layers to get their own backing when
     17        they could have just gone into their compositing ancestor's backing.
     18
     19        The correct logic is that non-composited query layer needs to be
     20        composited due to overlap if and only if the query layer's absolute
     21        bounds overlap the absolute bounds of some other layer which:
     22            - draws before the query layer
     23            - has a different compositing ancestor than the query layer
     24            - is or has a compositing ancestor that is a descendent of the
     25              query layer's compositing ancestor
     26
     27        This patch changes the semantics of the overlap map to enable this
     28        behavior.
     29
     30        Rather than having one global overlap map, there is now a stack of
     31        overlap maps. New (empty) overlap maps are pushed onto the stack
     32        whenever a layer becomes a compositing ancestor and popped after all
     33        of the compositing requirements for that layer's children have been
     34        computed.
     35
     36        The compositing ancestor and all of its non-composited children of a
     37        compositing ancestor do not get considered for overlap until their
     38        composited ancestor has been popped off the stack. If a compositing
     39        ancestor has a compositing subtree, then any descendents of that
     40        compositing ancestor that draw after that subtree will consider
     41        everything in the compositing subtree for overlap.
     42
     43        Test: compositing/layer-creation/stacking-context-overlap.html
     44
     45        * platform/graphics/Region.cpp:
     46        (WebCore::Region::intersects):
     47        (WebCore):
     48        * platform/graphics/Region.h:
     49        (Region):
     50        * rendering/RenderLayerCompositor.cpp:
     51        (RenderLayerCompositor::OverlapMap):
     52        (WebCore::RenderLayerCompositor::OverlapMap::OverlapMap):
     53        (WebCore::RenderLayerCompositor::OverlapMap::add):
     54        (WebCore::RenderLayerCompositor::OverlapMap::contains):
     55        (WebCore::RenderLayerCompositor::OverlapMap::overlapsLayers):
     56        (WebCore::RenderLayerCompositor::OverlapMap::isEmpty):
     57        (WebCore::RenderLayerCompositor::OverlapMap::popCompositingContainer):
     58        (WebCore::RenderLayerCompositor::OverlapMap::pushCompositingContainer):
     59        (WebCore::RenderLayerCompositor::addToOverlapMapRecursive):
     60        (WebCore::RenderLayerCompositor::computeCompositingRequirements):
     61        * rendering/RenderLayerCompositor.h:
     62        (RenderLayerCompositor):
     63
    1642012-03-05  Anders Carlsson  <andersca@apple.com>
    265
  • trunk/Source/WebCore/platform/graphics/Region.cpp

    r109273 r109851  
    7878}
    7979
     80bool Region::intersects(const Region& region) const
     81{
     82    if (!m_bounds.intersects(region.m_bounds))
     83        return false;
     84
     85    // FIXME: this could be optimized.
     86    Region tempRegion(*this);
     87    tempRegion.intersect(region);
     88    return !tempRegion.isEmpty();
     89}
     90
    8091unsigned Region::totalArea() const
    8192{
  • trunk/Source/WebCore/platform/graphics/Region.h

    r109273 r109851  
    5252
    5353    bool contains(const IntPoint&) const;
     54
     55    // Returns true if the query region intersects any part of this region.
     56    bool intersects(const Region&) const;
    5457
    5558    unsigned totalArea() const;
  • trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp

    r109788 r109851  
    7676using namespace HTMLNames;
    7777
     78class RenderLayerCompositor::OverlapMap {
     79    WTF_MAKE_NONCOPYABLE(OverlapMap);
     80public:
     81    OverlapMap()
     82    {
     83        // Begin assuming the root layer will be composited so that there is
     84        // something on the stack. The root layer should also never get an
     85        // popCompositingContainer call.
     86        pushCompositingContainer();
     87    }
     88
     89    void add(const RenderLayer* layer, const IntRect& bounds)
     90    {
     91        // Layers do not contribute to overlap immediately--instead, they will
     92        // contribute to overlap as soon as their composited ancestor has been
     93        // recursively processed and popped off the stack.
     94        ASSERT(m_overlapStack.size() >= 2);
     95        m_overlapStack[m_overlapStack.size() - 2].unite(bounds);
     96        m_layers.add(layer);
     97    }
     98
     99    bool contains(const RenderLayer* layer)
     100    {
     101        return m_layers.contains(layer);
     102    }
     103
     104    bool overlapsLayers(const IntRect& bounds) const
     105    {
     106        return m_overlapStack.last().intersects(bounds);
     107    }
     108
     109    bool isEmpty()
     110    {
     111        return m_layers.isEmpty();
     112    }
     113
     114    void pushCompositingContainer()
     115    {
     116        m_overlapStack.append(Region());
     117    }
     118
     119    void popCompositingContainer()
     120    {
     121        m_overlapStack[m_overlapStack.size() - 2].unite(m_overlapStack.last());
     122        m_overlapStack.removeLast();
     123    }
     124
     125private:
     126    Vector<Region> m_overlapStack;
     127    HashSet<const RenderLayer*> m_layers;
     128};
     129
    78130struct CompositingState {
    79131    CompositingState(RenderLayer* compAncestor)
     
    638690}
    639691
    640 bool RenderLayerCompositor::overlapsCompositedLayers(OverlapMap& overlapMap, const IntRect& layerBounds)
    641 {
    642     RenderLayerCompositor::OverlapMap::const_iterator end = overlapMap.end();
    643     for (RenderLayerCompositor::OverlapMap::const_iterator it = overlapMap.begin(); it != end; ++it) {
    644         const IntRect& bounds = it->second;
    645         if (layerBounds.intersects(bounds))
    646             return true;
    647     }
    648    
    649     return false;
    650 }
    651 
    652692//  Recurse through the layers in z-index and overflow order (which is equivalent to painting order)
    653693//  For the z-order children of a compositing layer:
     
    679719            absBounds.setSize(IntSize(1, 1));
    680720        haveComputedBounds = true;
    681         mustOverlapCompositedLayers = overlapsCompositedLayers(*overlapMap, absBounds);
     721        mustOverlapCompositedLayers = overlapMap->overlapsLayers(absBounds);
    682722    }
    683723   
     
    689729    CompositingState childState(compositingState.m_compositingAncestor);
    690730#ifndef NDEBUG
    691     ++childState.m_depth;
     731    childState.m_depth = compositingState.m_depth + 1;
    692732#endif
    693733
     
    698738        // This layer now acts as the ancestor for kids.
    699739        childState.m_compositingAncestor = layer;
    700     }
    701 
    702     if (overlapMap && childState.m_compositingAncestor && !childState.m_compositingAncestor->isRootLayer()) {
    703         addToOverlapMap(*overlapMap, layer, absBounds, haveComputedBounds);
     740
     741        if (overlapMap)
     742            overlapMap->pushCompositingContainer();
    704743    }
    705744
     
    727766                    childState.m_compositingAncestor = layer;
    728767                    if (overlapMap)
    729                         addToOverlapMap(*overlapMap, layer, absBounds, haveComputedBounds);
     768                        overlapMap->pushCompositingContainer();
    730769                    willBeComposited = true;
    731770                }
     
    761800    ASSERT(willBeComposited == needsToBeComposited(layer));
    762801
     802    // All layers (even ones that aren't being composited) need to get added to
     803    // the overlap map. Layers that do not composite will draw into their
     804    // compositing ancestor's backing, and so are still considered for overlap.
     805    if (overlapMap && childState.m_compositingAncestor && !childState.m_compositingAncestor->isRootLayer())
     806        addToOverlapMap(*overlapMap, layer, absBounds, haveComputedBounds);
     807
    763808    // If we have a software transform, and we have layers under us, we need to also
    764809    // be composited. Also, if we have opacity < 1, then we need to be a layer so that
     
    766811    if (!willBeComposited && canBeComposited(layer) && childState.m_subtreeIsCompositing && requiresCompositingWhenDescendantsAreCompositing(layer->renderer())) {
    767812        layer->setMustOverlapCompositedLayers(true);
    768         if (overlapMap)
     813        childState.m_compositingAncestor = layer;
     814        if (overlapMap) {
     815            overlapMap->pushCompositingContainer();
    769816            addToOverlapMapRecursive(*overlapMap, layer);
     817        }
    770818        willBeComposited = true;
    771819    }
     
    785833    // so test that again.
    786834    if (!willBeComposited && canBeComposited(layer) && clipsCompositingDescendants(layer)) {
    787         if (overlapMap)
     835        childState.m_compositingAncestor = layer;
     836        if (overlapMap) {
     837            overlapMap->pushCompositingContainer();
    788838            addToOverlapMapRecursive(*overlapMap, layer);
     839        }
    789840        willBeComposited = true;
    790841    }
     842
     843    if (overlapMap && childState.m_compositingAncestor == layer && !layer->isRootLayer())
     844        overlapMap->popCompositingContainer();
    791845
    792846    // If we're back at the root, and no other layers need to be composited, and the root layer itself doesn't need
  • trunk/Source/WebCore/rendering/RenderLayerCompositor.h

    r108140 r109851  
    211211
    212212private:
     213    class OverlapMap;
     214
    213215    // GraphicsLayerClient Implementation
    214216    virtual void notifyAnimationStarted(const GraphicsLayer*, double) { }
     
    234236    void recursiveRepaintLayerRect(RenderLayer*, const IntRect&);
    235237
    236     typedef HashMap<RenderLayer*, IntRect> OverlapMap;
    237238    void addToOverlapMap(OverlapMap&, RenderLayer*, IntRect& layerBounds, bool& boundsComputed);
    238239    void addToOverlapMapRecursive(OverlapMap&, RenderLayer*);
    239     static bool overlapsCompositedLayers(OverlapMap&, const IntRect& layerBounds);
    240240
    241241    void updateCompositingLayersTimerFired(Timer<RenderLayerCompositor>*);
Note: See TracChangeset for help on using the changeset viewer.