Changeset 135777 in webkit


Ignore:
Timestamp:
Nov 26, 2012, 3:12:49 PM (13 years ago)
Author:
Simon Fraser
Message:

<rdar://problem/12751360>
Merge r135746

2012-11-26 Simon Fraser <Simon Fraser>

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:
branches/safari-536.28-branch/Source/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • branches/safari-536.28-branch/Source/WebCore/ChangeLog

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

    r135776 r135777  
    17621762        if (RenderView* root = rootRenderer(this)) {
    17631763            root->updateWidgetPositions();
    1764             root->layer()->updateLayerPositionsAfterScroll();
     1764            root->layer()->updateLayerPositionsAfterDocumentScroll();
    17651765        }
    17661766    }
  • branches/safari-536.28-branch/Source/WebCore/rendering/RenderLayer.cpp

    r135776 r135777  
    330330    if (geometryMap)
    331331        geometryMap->pushMappingsToAncestor(this, parent());
     332
     333    // Clear our cached clip rect information.
     334    clearClipRects();
    332335   
    333336    if (hasOverflowControls()) {
     
    452455}
    453456
    454 void RenderLayer::updateLayerPositionsAfterScroll()
     457void RenderLayer::updateLayerPositionsAfterDocumentScroll()
     458{
     459    ASSERT(this == renderer()->view()->layer());
     460
     461    RenderGeometryMap geometryMap;
     462    updateLayerPositionsAfterScroll(&geometryMap);
     463}
     464
     465void RenderLayer::updateLayerPositionsAfterOverflowScroll()
    455466{
    456467    RenderGeometryMap geometryMap;
     
    458469    if (this != view->layer())
    459470        geometryMap.pushMappingsToAncestor(parent(), 0);
    460     updateLayerPositionsAfterScroll(&geometryMap);
     471
     472    // FIXME: why is it OK to not check the ancestors of this layer in order to
     473    // initialize the HasSeenViewportConstrainedAncestor and HasSeenAncestorWithOverflowClip flags?
     474    updateLayerPositionsAfterScroll(&geometryMap, IsOverflowScroll);
    461475}
    462476
     
    473487        return;
    474488
    475     updateLayerPosition();
     489    bool positionChanged = updateLayerPosition();
     490    if (positionChanged)
     491        flags |= HasChangedAncestor;
    476492
    477493    if (geometryMap)
    478494        geometryMap->pushMappingsToAncestor(this, parent());
    479495
    480     if ((flags & HasSeenViewportConstrainedAncestor) || renderer()->style()->position() == FixedPosition) {
    481         // FIXME: Is it worth passing the offsetFromRoot around like in updateLayerPositions?
     496    if (flags & HasChangedAncestor || flags & HasSeenViewportConstrainedAncestor || flags & IsOverflowScroll)
     497        clearClipRects();
     498
     499    if (renderer()->style()->position() == FixedPosition)
     500        flags |= HasSeenViewportConstrainedAncestor;
     501
     502    if (renderer()->hasOverflowClip())
     503        flags |= HasSeenAncestorWithOverflowClip;
     504
     505    if (flags & HasSeenViewportConstrainedAncestor
     506        || (flags & IsOverflowScroll && flags & HasSeenAncestorWithOverflowClip && !m_canSkipRepaintRectsUpdateOnScroll)) {
    482507        // FIXME: We could track the repaint container as we walk down the tree.
    483508        computeRepaintRects(renderer()->containerForRepaint(), geometryMap);
    484         flags |= HasSeenViewportConstrainedAncestor;
    485     } else if ((flags & HasSeenAncestorWithOverflowClip) && !m_canSkipRepaintRectsUpdateOnScroll) {
    486         // If we have seen an overflow clip, we should update our repaint rects as clippedOverflowRectForRepaint
    487         // intersects it with our ancestor overflow clip that may have moved.
    488         computeRepaintRects(renderer()->containerForRepaint(), geometryMap);
    489     }
    490 
    491     if (renderer()->hasOverflowClip())
    492         flags |= HasSeenAncestorWithOverflowClip;
    493 
     509    } else {
     510        // Check that our cached rects are correct.
     511        ASSERT(m_repaintRect == renderer()->clippedOverflowRectForRepaint(renderer()->containerForRepaint()));
     512        ASSERT(m_outlineBox == renderer()->outlineBoundsForRepaint(renderer()->containerForRepaint(), geometryMap));
     513    }
     514   
    494515    for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
    495516        child->updateLayerPositionsAfterScroll(geometryMap, flags);
     
    753774}
    754775
    755 void RenderLayer::updateLayerPosition()
     776bool RenderLayer::updateLayerPosition()
    756777{
    757778    LayoutPoint localPoint;
     
    769790    }
    770791
    771     // Clear our cached clip rect information.
    772     clearClipRects();
    773  
    774792    if (!renderer()->isPositioned() && renderer()->parent()) {
    775793        // We must adjust our position by walking up the render tree looking for the
     
    814832        localPoint -= scrollOffset;
    815833    }
    816        
     834
     835    bool positionOrOffsetChanged = false;
    817836    if (renderer()->isRelPositioned()) {
    818         m_relativeOffset = renderer()->relativePositionOffset();
     837        LayoutSize newOffset = renderer()->relativePositionOffset();
     838        positionOrOffsetChanged = newOffset != m_relativeOffset;
     839        m_relativeOffset = newOffset;
    819840        localPoint.move(m_relativeOffset);
    820841    } else {
     
    824845    // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers.
    825846    localPoint -= inlineBoundingBoxOffset;
    826     setLocation(localPoint.x(), localPoint.y());
     847   
     848    positionOrOffsetChanged |= location() != localPoint;
     849    setLocation(localPoint);
     850    return positionOrOffsetChanged;
    827851}
    828852
     
    15661590    m_scrollOffset = newScrollOffset;
    15671591
     1592    RenderView* view = renderer()->view();
     1593   
     1594    // We should have a RenderView if we're trying to scroll.
     1595    ASSERT(view);
     1596
    15681597    // Update the positions of our child layers (if needed as only fixed layers should be impacted by a scroll).
    15691598    // We don't update compositing layers, because we need to do a deep update from the compositing ancestor.
    1570     updateLayerPositionsAfterScroll();
    1571 
    1572     RenderView* view = renderer()->view();
    1573    
    1574     // We should have a RenderView if we're trying to scroll.
    1575     ASSERT(view);
    1576     if (view) {
     1599    bool inLayout = view ? view->frameView()->isInLayout() : false;
     1600    if (!inLayout) {
     1601        // If we're in the middle of layout, we'll just update layers once layout has finished.
     1602        updateLayerPositionsAfterOverflowScroll();
     1603        if (view) {
     1604            // Update regions, scrolling may change the clip of a particular region.
    15771605#if ENABLE(DASHBOARD_SUPPORT)
    1578         // Update dashboard regions, scrolling may change the clip of a
    1579         // particular region.
    1580         view->frameView()->updateDashboardRegions();
    1581 #endif
    1582 
    1583         view->updateWidgetPositions();
    1584     }
    1585 
    1586     updateCompositingLayersAfterScroll();
     1606            view->frameView()->updateDashboardRegions();
     1607#endif
     1608            view->updateWidgetPositions();
     1609        }
     1610        updateCompositingLayersAfterScroll();
     1611    }
    15871612
    15881613    RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint();
     
    38303855        ASSERT(rootLayer == m_clipRectsCache->m_clipRectsRoot[clipRectsType]);
    38313856        ASSERT(m_clipRectsCache->m_scrollbarRelevancy[clipRectsType] == relevancy);
     3857       
     3858#ifdef CHECK_CACHED_CLIP_RECTS
     3859        // This code is useful to check cached clip rects, but is too expensive to leave enabled in debug builds by default.
     3860        ClipRectsContext tempContext(clipRectsContext);
     3861        tempContext.clipRectsType = TemporaryClipRects;
     3862        ClipRects clipRects;
     3863        calculateClipRects(tempContext, clipRects);
     3864        ASSERT(clipRects == *m_clipRectsCache->m_clipRects[clipRectsType].get());
     3865#endif
    38323866        return; // We have the correct cached value.
    38333867    }
  • branches/safari-536.28-branch/Source/WebCore/rendering/RenderLayer.h

    r135776 r135777  
    301301   
    302302    const LayoutPoint& location() const { return m_topLeft; }
    303     void setLocation(LayoutUnit x, LayoutUnit y) { m_topLeft = LayoutPoint(x, y); }
     303    void setLocation(const LayoutPoint& p) { m_topLeft = p; }
    304304
    305305    const IntSize& size() const { return m_layerSize; }
     
    383383    bool canRender3DTransforms() const;
    384384
    385     void updateLayerPosition();
     385    // Returns true if the position changed.
     386    bool updateLayerPosition();
    386387
    387388    enum UpdateLayerPositionsFlag {
     
    395396
    396397    void updateLayerPositionsAfterLayout(const RenderLayer* rootLayer, UpdateLayerPositionsFlags);
    397     void updateLayerPositionsAfterScroll();
    398 
     398
     399    void updateLayerPositionsAfterOverflowScroll();
     400    void updateLayerPositionsAfterDocumentScroll();
     401   
    399402    void updateTransform();
    400403
     
    662665    enum UpdateLayerPositionsAfterScrollFlag {
    663666        NoFlag = 0,
    664         HasSeenViewportConstrainedAncestor = 1 << 0,
    665         HasSeenAncestorWithOverflowClip = 1 << 1
     667        IsOverflowScroll = 1 << 0,
     668        HasSeenViewportConstrainedAncestor = 1 << 1,
     669        HasSeenAncestorWithOverflowClip = 1 << 2,
     670        HasChangedAncestor = 1 << 3
    666671    };
    667672    typedef unsigned UpdateLayerPositionsAfterScrollFlags;
Note: See TracChangeset for help on using the changeset viewer.