Changeset 135746 in webkit


Ignore:
Timestamp:
Nov 26, 2012 11:37:45 AM (11 years ago)
Author:
Simon Fraser
Message:

Optimize layer updates after scrolling
https://bugs.webkit.org/show_bug.cgi?id=102635

Reviewed by Sam Weinig.

updateLayerPositionsAfterScroll() previously unconditionally cleared clip
rects, and recomputed repaint rects too often. Recomputing both of these
can be very expensive, as they involve tree walks up to the root.

We can optimize layer updates after document scrolling by only clearing clip
rects, and recomputing repaint rects, if we encounter a fixed- or sticky-position
element. For overflow scroll, we have to clear clip rects and recompute repaint rects.

  • page/FrameView.cpp:

(WebCore::FrameView::repaintFixedElementsAfterScrolling): Call updateLayerPositionsAfterDocumentScroll().

  • rendering/RenderLayer.cpp:

(WebCore::RenderLayer::updateLayerPositions): Call clearClipRects() because
updateLayerPosition() no longer does.
(WebCore::RenderLayer::updateLayerPositionsAfterDocumentScroll): Version of updateLayerPositionsAfterScroll()
that is for document scrolls. It has no need to push layers to the geometry map.
(WebCore::RenderLayer::updateLayerPositionsAfterOverflowScroll): Pushes layers to the geometry map,
and calls updateLayerPositionsAfterScroll() with the IsOverflowScroll flag.
(WebCore::RenderLayer::updateLayerPositionsAfterScroll): Set the HasChangedAncestor flag
if our location changed, and use that as a hint to clear cached rects. Be more conservative
than before about when to clear cached clip rects.
(WebCore::RenderLayer::updateLayerPosition): Move responsibility for calling
clearClipRects() ouf of this function and into callers.
(The one caller outside RenderLayer will be removed via bug 102624).
Return a bool indicating whether our position changed.
(WebCore::RenderLayer::scrollTo): Call updateLayerPositionsAfterOverflowScroll().
(WebCore::RenderLayer::updateClipRects): Added some #ifdeffed out code that is useful
to verify that cached clips are correct; it's too slow to leave enabled in debug builds.

  • rendering/RenderLayer.h:

(WebCore::RenderLayer::setLocation): Change to take a LayoutPoint, rather than separate
x and y.

Location:
trunk/Source/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r135742 r135746  
     12012-11-26  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Optimize layer updates after scrolling
     4        https://bugs.webkit.org/show_bug.cgi?id=102635
     5
     6        Reviewed by Sam Weinig.
     7
     8        updateLayerPositionsAfterScroll() previously unconditionally cleared clip
     9        rects, and recomputed repaint rects too often. Recomputing both of these
     10        can be very expensive, as they involve tree walks up to the root.
     11       
     12        We can optimize layer updates after document scrolling by only clearing clip
     13        rects, and recomputing repaint rects, if we encounter a fixed- or sticky-position
     14        element. For overflow scroll, we have to clear clip rects and recompute repaint rects.
     15
     16        * page/FrameView.cpp:
     17        (WebCore::FrameView::repaintFixedElementsAfterScrolling): Call updateLayerPositionsAfterDocumentScroll().
     18        * rendering/RenderLayer.cpp:
     19        (WebCore::RenderLayer::updateLayerPositions): Call clearClipRects() because
     20        updateLayerPosition() no longer does.
     21        (WebCore::RenderLayer::updateLayerPositionsAfterDocumentScroll): Version of updateLayerPositionsAfterScroll()
     22        that is for document scrolls. It has no need to push layers to the geometry map.
     23        (WebCore::RenderLayer::updateLayerPositionsAfterOverflowScroll): Pushes layers to the geometry map,
     24        and calls updateLayerPositionsAfterScroll() with the IsOverflowScroll flag.
     25        (WebCore::RenderLayer::updateLayerPositionsAfterScroll): Set the HasChangedAncestor flag
     26        if our location changed, and use that as a hint to clear cached rects. Be more conservative
     27        than before about when to clear cached clip rects.
     28        (WebCore::RenderLayer::updateLayerPosition):  Move responsibility for calling
     29        clearClipRects() ouf of this function and into callers.
     30        (The one caller outside RenderLayer will be removed via bug 102624).
     31        Return a bool indicating whether our position changed.
     32        (WebCore::RenderLayer::scrollTo): Call updateLayerPositionsAfterOverflowScroll().
     33        (WebCore::RenderLayer::updateClipRects): Added some #ifdeffed out code that is useful
     34        to verify that cached clips are correct; it's too slow to leave enabled in debug builds.
     35        * rendering/RenderLayer.h:
     36        (WebCore::RenderLayer::setLocation): Change to take a LayoutPoint, rather than separate
     37        x and y.
     38
    1392012-11-26  Rafael Brandao  <rafael.lobo@openbossa.org>
    240
  • trunk/Source/WebCore/page/FrameView.cpp

    r135025 r135746  
    18231823        if (RenderView* root = rootRenderer(this)) {
    18241824            root->updateWidgetPositions();
    1825             root->layer()->updateLayerPositionsAfterScroll();
     1825            root->layer()->updateLayerPositionsAfterDocumentScroll();
    18261826        }
    18271827    }
  • trunk/Source/WebCore/rendering/RenderLayer.cpp

    r135605 r135746  
    344344    if (geometryMap)
    345345        geometryMap->pushMappingsToAncestor(this, parent());
     346
     347    // Clear our cached clip rect information.
     348    clearClipRects();
    346349   
    347350    if (hasOverflowControls()) {
     
    495498}
    496499
    497 void RenderLayer::updateLayerPositionsAfterScroll()
     500void RenderLayer::updateLayerPositionsAfterDocumentScroll()
     501{
     502    ASSERT(this == renderer()->view()->layer());
     503
     504    RenderGeometryMap geometryMap(UseTransforms);
     505    updateLayerPositionsAfterScroll(&geometryMap);
     506}
     507
     508void RenderLayer::updateLayerPositionsAfterOverflowScroll()
    498509{
    499510    RenderGeometryMap geometryMap(UseTransforms);
     
    501512    if (this != view->layer())
    502513        geometryMap.pushMappingsToAncestor(parent(), 0);
    503     updateLayerPositionsAfterScroll(&geometryMap);
     514
     515    // FIXME: why is it OK to not check the ancestors of this layer in order to
     516    // initialize the HasSeenViewportConstrainedAncestor and HasSeenAncestorWithOverflowClip flags?
     517    updateLayerPositionsAfterScroll(&geometryMap, IsOverflowScroll);
    504518}
    505519
     
    516530        return;
    517531
    518     updateLayerPosition();
     532    bool positionChanged = updateLayerPosition();
     533    if (positionChanged)
     534        flags |= HasChangedAncestor;
    519535
    520536    if (geometryMap)
    521537        geometryMap->pushMappingsToAncestor(this, parent());
    522538
    523     if ((flags & HasSeenViewportConstrainedAncestor) || renderer()->style()->hasViewportConstrainedPosition()) {
    524         // FIXME: Is it worth passing the offsetFromRoot around like in updateLayerPositions?
     539    if (flags & HasChangedAncestor || flags & HasSeenViewportConstrainedAncestor || flags & IsOverflowScroll)
     540        clearClipRects();
     541
     542    if (renderer()->style()->hasViewportConstrainedPosition())
     543        flags |= HasSeenViewportConstrainedAncestor;
     544
     545    if (renderer()->hasOverflowClip())
     546        flags |= HasSeenAncestorWithOverflowClip;
     547
     548    if (flags & HasSeenViewportConstrainedAncestor
     549        || (flags & IsOverflowScroll && flags & HasSeenAncestorWithOverflowClip && !m_canSkipRepaintRectsUpdateOnScroll)) {
    525550        // FIXME: We could track the repaint container as we walk down the tree.
    526551        computeRepaintRects(renderer()->containerForRepaint(), geometryMap);
    527         flags |= HasSeenViewportConstrainedAncestor;
    528     } else if ((flags & HasSeenAncestorWithOverflowClip) && !m_canSkipRepaintRectsUpdateOnScroll) {
    529         // If we have seen an overflow clip, we should update our repaint rects as clippedOverflowRectForRepaint
    530         // intersects it with our ancestor overflow clip that may have moved.
    531         computeRepaintRects(renderer()->containerForRepaint(), geometryMap);
    532     }
    533 
    534     if (renderer()->hasOverflowClip())
    535         flags |= HasSeenAncestorWithOverflowClip;
    536 
     552    } else {
     553        // Check that our cached rects are correct.
     554        ASSERT(m_repaintRect == renderer()->clippedOverflowRectForRepaint(renderer()->containerForRepaint()));
     555        ASSERT(m_outlineBox == renderer()->outlineBoundsForRepaint(renderer()->containerForRepaint(), geometryMap));
     556    }
     557   
    537558    for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
    538559        child->updateLayerPositionsAfterScroll(geometryMap, flags);
     
    835856}
    836857
    837 void RenderLayer::updateLayerPosition()
     858bool RenderLayer::updateLayerPosition()
    838859{
    839860    LayoutPoint localPoint;
     
    851872    }
    852873
    853     // Clear our cached clip rect information.
    854     clearClipRects();
    855  
    856874    if (!renderer()->isOutOfFlowPositioned() && renderer()->parent()) {
    857875        // We must adjust our position by walking up the render tree looking for the
     
    901919    }
    902920   
     921    bool positionOrOffsetChanged = false;
    903922    if (renderer()->isInFlowPositioned()) {
    904         m_offsetForInFlowPosition = toRenderBoxModelObject(renderer())->offsetForInFlowPosition();
     923        LayoutSize newOffset = toRenderBoxModelObject(renderer())->offsetForInFlowPosition();
     924        positionOrOffsetChanged = newOffset != m_offsetForInFlowPosition;
     925        m_offsetForInFlowPosition = newOffset;
    905926        localPoint.move(m_offsetForInFlowPosition);
    906927    } else {
     
    910931    // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers.
    911932    localPoint -= inlineBoundingBoxOffset;
    912     setLocation(localPoint.x(), localPoint.y());
     933   
     934    positionOrOffsetChanged |= location() != localPoint;
     935    setLocation(localPoint);
     936    return positionOrOffsetChanged;
    913937}
    914938
     
    17371761    if (!inLayout) {
    17381762        // If we're in the middle of layout, we'll just update layers once layout has finished.
    1739         updateLayerPositionsAfterScroll();
     1763        updateLayerPositionsAfterOverflowScroll();
    17401764        if (view) {
    17411765            // Update regions, scrolling may change the clip of a particular region.
     
    41294153        ASSERT(m_clipRectsCache->m_respectingOverflowClip[clipRectsType] == (clipRectsContext.respectOverflowClip == RespectOverflowClip));
    41304154        ASSERT(m_clipRectsCache->m_scrollbarRelevancy[clipRectsType] == clipRectsContext.overlayScrollbarSizeRelevancy);
     4155       
     4156#ifdef CHECK_CACHED_CLIP_RECTS
     4157        // This code is useful to check cached clip rects, but is too expensive to leave enabled in debug builds by default.
     4158        ClipRectsContext tempContext(clipRectsContext);
     4159        tempContext.clipRectsType = TemporaryClipRects;
     4160        ClipRects clipRects;
     4161        calculateClipRects(tempContext, clipRects);
     4162        ASSERT(clipRects == *m_clipRectsCache->m_clipRects[clipRectsType].get());
     4163#endif
    41314164        return; // We have the correct cached value.
    41324165    }
  • trunk/Source/WebCore/rendering/RenderLayer.h

    r135605 r135746  
    310310   
    311311    const LayoutPoint& location() const { return m_topLeft; }
    312     void setLocation(LayoutUnit x, LayoutUnit y) { m_topLeft = LayoutPoint(x, y); }
     312    void setLocation(const LayoutPoint& p) { m_topLeft = p; }
    313313
    314314    const IntSize& size() const { return m_layerSize; }
     
    391391    bool canRender3DTransforms() const;
    392392
    393     void updateLayerPosition();
     393    // Returns true if the position changed.
     394    bool updateLayerPosition();
    394395
    395396    enum UpdateLayerPositionsFlag {
     
    403404
    404405    void updateLayerPositionsAfterLayout(const RenderLayer* rootLayer, UpdateLayerPositionsFlags);
    405     void updateLayerPositionsAfterScroll();
     406
     407    void updateLayerPositionsAfterOverflowScroll();
     408    void updateLayerPositionsAfterDocumentScroll();
    406409   
    407410    bool isPaginated() const { return m_isPaginated; }
     
    741744    enum UpdateLayerPositionsAfterScrollFlag {
    742745        NoFlag = 0,
    743         HasSeenViewportConstrainedAncestor = 1 << 0,
    744         HasSeenAncestorWithOverflowClip = 1 << 1
     746        IsOverflowScroll = 1 << 0,
     747        HasSeenViewportConstrainedAncestor = 1 << 1,
     748        HasSeenAncestorWithOverflowClip = 1 << 2,
     749        HasChangedAncestor = 1 << 3
    745750    };
    746751    typedef unsigned UpdateLayerPositionsAfterScrollFlags;
Note: See TracChangeset for help on using the changeset viewer.