Changeset 63452 in webkit


Ignore:
Timestamp:
Jul 15, 2010 1:08:41 PM (14 years ago)
Author:
Simon Fraser
Message:

2010-07-15 Simon Fraser <Simon Fraser>

Reviewed by Dan Bernstein.

Avoid creating huge compositing layers for elements that project outside the viewport
https://bugs.webkit.org/show_bug.cgi?id=42338

The logic that computed the bounds of compositing layers naively used the
union of the bounds of descendant, non-composited RenderLayers, without regard
to what is actually visible. This could result in huge layers for page with
elements are large negative offsets, or with large negative text-indent (both
common).

For elements without transforms on them or in their ancestor chain, and when
no 3d transforms or hardware-accelerated animations are used, can clip compositing
layers to the size of the document, or based on CSS overflow and clip.

Tests: compositing/geometry/limit-layer-bounds-clipping-ancestor.html

compositing/geometry/limit-layer-bounds-fixed-positioned.html
compositing/geometry/limit-layer-bounds-overflow-repaint.html
compositing/geometry/limit-layer-bounds-positioned-transition.html
compositing/geometry/limit-layer-bounds-positioned.html
compositing/geometry/limit-layer-bounds-transformed-overflow.html
compositing/geometry/limit-layer-bounds-transformed.html

  • rendering/RenderLayerBacking.cpp: (WebCore::enclosingOverflowClipAncestor): Walk up the RenderLayer tree looking for an ancestor that has overflow, or to the root. Along the way, check for transformed elements. (WebCore::RenderLayerBacking::updateCompositedBounds): If we're in "consult overlap" mode, and we don't have transforms, then constrain the bounds of composited layers by the RenderView's layoutOverflowRect(), or by the enclosing layer with overflow. (WebCore::RenderLayerBacking::updateGraphicsLayerGeometry): If the offset from the renderer changes, we need to repaint the layer.
Location:
trunk
Files:
16 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r63450 r63452  
     12010-07-15  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Reviewed by Dan Bernstein.
     4
     5        Avoid creating huge compositing layers for elements that project outside the viewport
     6        https://bugs.webkit.org/show_bug.cgi?id=42338
     7       
     8        Tests for constraining the size of compositing layers to the layout bounds, or the enclosing
     9        overflow ancestor.
     10
     11        * compositing/geometry/limit-layer-bounds-clipping-ancestor-expected.txt: Added.
     12        * compositing/geometry/limit-layer-bounds-clipping-ancestor.html: Added.
     13        * compositing/geometry/limit-layer-bounds-fixed-positioned-expected.txt: Added.
     14        * compositing/geometry/limit-layer-bounds-fixed-positioned.html: Added.
     15        * compositing/geometry/limit-layer-bounds-overflow-repaint.html: Added.
     16        * compositing/geometry/limit-layer-bounds-positioned-expected.txt: Added.
     17        * compositing/geometry/limit-layer-bounds-positioned-transition-expected.txt: Added.
     18        * compositing/geometry/limit-layer-bounds-positioned-transition.html: Added.
     19        * compositing/geometry/limit-layer-bounds-positioned.html: Added.
     20        * compositing/geometry/limit-layer-bounds-transformed-expected.txt: Added.
     21        * compositing/geometry/limit-layer-bounds-transformed-overflow-expected.txt: Added.
     22        * compositing/geometry/limit-layer-bounds-transformed-overflow.html: Added.
     23        * compositing/geometry/limit-layer-bounds-transformed.html: Added.
     24        * platform/mac/compositing/geometry/limit-layer-bounds-overflow-repaint-expected.checksum: Added.
     25        * platform/mac/compositing/geometry/limit-layer-bounds-overflow-repaint-expected.png: Added.
     26        * platform/mac/compositing/geometry/limit-layer-bounds-overflow-repaint-expected.txt: Added.
     27
    1282010-07-15  Alex Nicolaou  <anicolao@chromium.org>
    229
  • trunk/WebCore/ChangeLog

    r63450 r63452  
     12010-07-15  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Reviewed by Dan Bernstein.
     4
     5        Avoid creating huge compositing layers for elements that project outside the viewport
     6        https://bugs.webkit.org/show_bug.cgi?id=42338
     7
     8        The logic that computed the bounds of compositing layers naively used the
     9        union of the bounds of descendant, non-composited RenderLayers, without regard
     10        to what is actually visible. This could result in huge layers for page with
     11        elements are large negative offsets, or with large negative text-indent (both
     12        common).
     13       
     14        For elements without transforms on them or in their ancestor chain, and when
     15        no 3d transforms or hardware-accelerated animations are used, can clip compositing
     16        layers to the size of the document, or based on CSS overflow and clip.
     17
     18        Tests: compositing/geometry/limit-layer-bounds-clipping-ancestor.html
     19               compositing/geometry/limit-layer-bounds-fixed-positioned.html
     20               compositing/geometry/limit-layer-bounds-overflow-repaint.html
     21               compositing/geometry/limit-layer-bounds-positioned-transition.html
     22               compositing/geometry/limit-layer-bounds-positioned.html
     23               compositing/geometry/limit-layer-bounds-transformed-overflow.html
     24               compositing/geometry/limit-layer-bounds-transformed.html
     25
     26        * rendering/RenderLayerBacking.cpp:
     27        (WebCore::enclosingOverflowClipAncestor):  Walk up the RenderLayer tree
     28        looking for an ancestor that has overflow, or to the root. Along the way, check for
     29        transformed elements.
     30        (WebCore::RenderLayerBacking::updateCompositedBounds):  If we're in "consult
     31        overlap" mode, and we don't have transforms, then constrain the bounds
     32        of composited layers by the RenderView's layoutOverflowRect(), or by the
     33        enclosing layer with overflow.
     34        (WebCore::RenderLayerBacking::updateGraphicsLayerGeometry): If the offset from the renderer changes,
     35        we need to repaint the layer.
     36
    1372010-07-15  Alex Nicolaou  <anicolao@chromium.org>
    238
  • trunk/WebCore/rendering/RenderLayerBacking.cpp

    r63368 r63452  
    6565static bool hasBoxDecorationsOrBackground(const RenderObject*);
    6666static bool hasBoxDecorationsOrBackgroundImage(const RenderStyle*);
     67static IntRect clipBox(RenderBox* renderer);
    6768
    6869static inline bool is3DCanvas(RenderObject* renderer)
     
    140141}
    141142
     143static RenderLayer* enclosingOverflowClipAncestor(RenderLayer* layer, bool& crossesTransform)
     144{
     145    crossesTransform = false;
     146
     147    for (RenderLayer* curr = layer->parent(); curr; curr = curr->parent()) {
     148        if (curr->renderer()->hasOverflowClip())
     149            return curr;
     150
     151        if (curr->hasTransform())
     152            crossesTransform = true;
     153    }
     154   
     155    return 0;
     156}
     157
    142158void RenderLayerBacking::updateCompositedBounds()
    143159{
    144160    IntRect layerBounds = compositor()->calculateCompositedBounds(m_owningLayer, m_owningLayer);
    145161
     162    // Clip to the size of the document or enclosing overflow-scroll layer.
     163    if (compositor()->compositingConsultsOverlap() && !m_owningLayer->hasTransform()) {
     164        bool crossesTransform;
     165        RenderLayer* overflowAncestor = enclosingOverflowClipAncestor(m_owningLayer, crossesTransform);
     166        // If an ancestor is transformed, we can't currently compute the correct rect to intersect with.
     167        // We'd need RenderObject::convertContainerToLocalQuad(), which doesn't yet exist.
     168        if (!crossesTransform) {
     169            IntRect clippingBounds;
     170            RenderLayer* boundsRelativeLayer;
     171
     172            if (overflowAncestor) {
     173                RenderBox* overflowBox = toRenderBox(overflowAncestor->renderer());
     174                // If scrollbars are visible, then constrain the layer to the scrollable area, so we can avoid redraws
     175                // on scrolling. Otherwise just clip to the visible area (it can still be scrolled via JS, but we'll come
     176                // back through this code when the scroll offset changes).
     177                if (overflowBox->scrollsOverflow())
     178                    clippingBounds = IntRect(-overflowAncestor->scrollXOffset(), -overflowAncestor->scrollYOffset(), overflowBox->scrollWidth(), overflowBox->scrollHeight());
     179                else
     180                    clippingBounds = clipBox(overflowBox);
     181
     182                boundsRelativeLayer = overflowAncestor;
     183            } else {
     184                RenderView* view = m_owningLayer->renderer()->view();
     185                clippingBounds = view->layoutOverflowRect();
     186                boundsRelativeLayer = view->layer();
     187            }
     188           
     189            int deltaX = 0;
     190            int deltaY = 0;
     191            m_owningLayer->convertToLayerCoords(boundsRelativeLayer, deltaX, deltaY);
     192            clippingBounds.move(-deltaX, -deltaY);
     193            layerBounds.intersect(clippingBounds);
     194        }
     195    }
     196   
    146197    // If the element has a transform-origin that has fixed lengths, and the renderer has zero size,
    147198    // then we need to ensure that the compositing layer has non-zero size so that we can apply
     
    309360
    310361    m_graphicsLayer->setPosition(FloatPoint() + (relativeCompositingBounds.location() - graphicsLayerParentLocation));
     362   
     363    IntSize oldOffsetFromRenderer = m_graphicsLayer->offsetFromRenderer();
    311364    m_graphicsLayer->setOffsetFromRenderer(localCompositingBounds.location() - IntPoint());
     365    // If the compositing layer offset changes, we need to repaint.
     366    if (oldOffsetFromRenderer != m_graphicsLayer->offsetFromRenderer())
     367        m_graphicsLayer->setNeedsDisplay();
    312368   
    313369    FloatSize oldSize = m_graphicsLayer->size();
Note: See TracChangeset for help on using the changeset viewer.