RenderLayer scrollbars' updates should be split between layout induced and style...
authorjchaffraix@webkit.org <jchaffraix@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 5 Apr 2012 04:30:23 +0000 (04:30 +0000)
committerjchaffraix@webkit.org <jchaffraix@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 5 Apr 2012 04:30:23 +0000 (04:30 +0000)
https://bugs.webkit.org/show_bug.cgi?id=83213

Reviewed by Simon Fraser.

Refactoring only, no change in behavior.

This patches splits up the 2 reasons for modifying the scrollbars:
- style updates, handled in updateScrollbarsAfterStyleChange.
- layout time, handled in updateScrollbarsAfterLayout.

* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::contentsSize):
Removed now unneeded const-casts.

(WebCore::RenderLayer::setHasHorizontalScrollbar):
(WebCore::RenderLayer::setHasVerticalScrollbar):
Updated to use hasHorizontalScrollbar / hasVerticalScrollbar.

(WebCore::RenderLayer::scrollWidth):
(WebCore::RenderLayer::scrollHeight):
Made those functions |const|.

(WebCore::RenderLayer::computeScrollDimensions):
Removed the unneeded booleans and move the do-we-have-overflow-logic
into hasHorizontalOverflow and hasVerticalOverflow.

(WebCore::RenderLayer::hasHorizontalOverflow):
(WebCore::RenderLayer::hasVerticalOverflow):
Added those new helper functions.

(WebCore::RenderLayer::updateScrollbarsAfterLayout):
(WebCore::RenderLayer::updateScrollInfoAfterLayout):
Updated the latter to call the former.

(WebCore::RenderLayer::updateScrollbarsAfterStyleChange):
(WebCore::RenderLayer::styleChanged):
Ditto.

(WebCore::overflowCanHaveAScrollbar):
Add this helper function for updateScrollbarsAfterStyleChange.

* rendering/RenderLayer.h:
(WebCore::RenderLayer::hasHorizontalScrollbar):
(WebCore::RenderLayer::hasVerticalScrollbar):
Added those 2 new helper functions.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@113289 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderLayer.cpp
Source/WebCore/rendering/RenderLayer.h

index 9f41a8c7ce4e0878da7579b965db8a77afe867b1..2a0ee901598a07cf0dba125ecbbb34e833524c51 100644 (file)
@@ -1,3 +1,52 @@
+2012-04-04  Julien Chaffraix  <jchaffraix@webkit.org>
+
+        RenderLayer scrollbars' updates should be split between layout induced and style change induced
+        https://bugs.webkit.org/show_bug.cgi?id=83213
+
+        Reviewed by Simon Fraser.
+
+        Refactoring only, no change in behavior.
+
+        This patches splits up the 2 reasons for modifying the scrollbars:
+        - style updates, handled in updateScrollbarsAfterStyleChange.
+        - layout time, handled in updateScrollbarsAfterLayout.
+
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::contentsSize):
+        Removed now unneeded const-casts.
+
+        (WebCore::RenderLayer::setHasHorizontalScrollbar):
+        (WebCore::RenderLayer::setHasVerticalScrollbar):
+        Updated to use hasHorizontalScrollbar / hasVerticalScrollbar.
+
+        (WebCore::RenderLayer::scrollWidth):
+        (WebCore::RenderLayer::scrollHeight):
+        Made those functions |const|.
+
+        (WebCore::RenderLayer::computeScrollDimensions):
+        Removed the unneeded booleans and move the do-we-have-overflow-logic
+        into hasHorizontalOverflow and hasVerticalOverflow.
+
+        (WebCore::RenderLayer::hasHorizontalOverflow):
+        (WebCore::RenderLayer::hasVerticalOverflow):
+        Added those new helper functions.
+
+        (WebCore::RenderLayer::updateScrollbarsAfterLayout):
+        (WebCore::RenderLayer::updateScrollInfoAfterLayout):
+        Updated the latter to call the former.
+
+        (WebCore::RenderLayer::updateScrollbarsAfterStyleChange):
+        (WebCore::RenderLayer::styleChanged):
+        Ditto.
+
+        (WebCore::overflowCanHaveAScrollbar):
+        Add this helper function for updateScrollbarsAfterStyleChange.
+
+        * rendering/RenderLayer.h:
+        (WebCore::RenderLayer::hasHorizontalScrollbar):
+        (WebCore::RenderLayer::hasVerticalScrollbar):
+        Added those 2 new helper functions.
+
 2012-04-04  Andrei Burago  <aburago@chromium.org>
 
         Auto-size may not work on first load
index d20598292b80d3ce0f722f158a975cd4b3bb0e74..c5f3337dceda26dd2825192e8cc15ee2aab27a39 100644 (file)
@@ -2055,7 +2055,7 @@ IntPoint RenderLayer::convertFromContainingViewToScrollbar(const Scrollbar* scro
 
 IntSize RenderLayer::contentsSize() const
 {
-    return IntSize(const_cast<RenderLayer*>(this)->scrollWidth(), const_cast<RenderLayer*>(this)->scrollHeight());
+    return IntSize(scrollWidth(), scrollHeight());
 }
 
 int RenderLayer::visibleHeight() const
@@ -2208,7 +2208,7 @@ bool RenderLayer::allowsScrolling() const
 
 void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar)
 {
-    if (hasScrollbar == (m_hBar != 0))
+    if (hasScrollbar == hasHorizontalScrollbar())
         return;
 
     if (hasScrollbar)
@@ -2231,7 +2231,7 @@ void RenderLayer::setHasHorizontalScrollbar(bool hasScrollbar)
 
 void RenderLayer::setHasVerticalScrollbar(bool hasScrollbar)
 {
-    if (hasScrollbar == (m_vBar != 0))
+    if (hasScrollbar == hasVerticalScrollbar())
         return;
 
     if (hasScrollbar)
@@ -2347,19 +2347,19 @@ void RenderLayer::positionOverflowControls(const IntSize& offsetFromLayer)
         m_resizer->setFrameRect(resizerCornerRect(this, borderBox));
 }
 
-int RenderLayer::scrollWidth()
+int RenderLayer::scrollWidth() const
 {
     ASSERT(renderBox());
     if (m_scrollDimensionsDirty)
-        computeScrollDimensions();
+        const_cast<RenderLayer*>(this)->computeScrollDimensions();
     return snapSizeToPixel(m_scrollSize.width(), renderBox()->clientLeft());
 }
 
-int RenderLayer::scrollHeight()
+int RenderLayer::scrollHeight() const
 {
     ASSERT(renderBox());
     if (m_scrollDimensionsDirty)
-        computeScrollDimensions();
+        const_cast<RenderLayer*>(this)->computeScrollDimensions();
     return snapSizeToPixel(m_scrollSize.height(), renderBox()->clientTop());
 }
 
@@ -2395,7 +2395,7 @@ LayoutUnit RenderLayer::overflowRight() const
     return overflowRect.maxX();
 }
 
-void RenderLayer::computeScrollDimensions(bool* needHBar, bool* needVBar)
+void RenderLayer::computeScrollDimensions()
 {
     RenderBox* box = renderBox();
     ASSERT(box);
@@ -2409,58 +2409,45 @@ void RenderLayer::computeScrollDimensions(bool* needHBar, bool* needVBar)
     m_scrollSize.setHeight(overflowBottom() - overflowTop());
 
     setScrollOrigin(IntPoint(-m_scrollOverflow.width(), -m_scrollOverflow.height()));
+}
+
+bool RenderLayer::hasHorizontalOverflow() const
+{
+    ASSERT(!m_scrollDimensionsDirty);
 
-    if (needHBar)
-        *needHBar = scrollWidth() > box->pixelSnappedClientWidth();
-    if (needVBar)
-        *needVBar = scrollHeight() > box->pixelSnappedClientHeight();
+    return scrollWidth() > renderBox()->pixelSnappedClientWidth();
 }
 
-void RenderLayer::updateScrollInfoAfterLayout()
+bool RenderLayer::hasVerticalOverflow() const
 {
-    RenderBox* box = renderBox();
-    if (!box)
-        return;
+    ASSERT(!m_scrollDimensionsDirty);
 
-    m_scrollDimensionsDirty = true;
-    IntSize scrollOffsetOriginal(scrollXOffset(), scrollYOffset());
+    return scrollHeight() > renderBox()->pixelSnappedClientHeight();
+}
 
-    bool horizontalOverflow, verticalOverflow;
-    computeScrollDimensions(&horizontalOverflow, &verticalOverflow);
+void RenderLayer::updateScrollbarsAfterLayout()
+{
+    RenderBox* box = renderBox();
+    ASSERT(box);
 
-    if (box->style()->overflowX() != OMARQUEE) {
-        // Layout may cause us to be in an invalid scroll position.  In this case we need
-        // to pull our scroll offsets back to the max (or push them up to the min).
-        int newX = max(0, min<int>(scrollXOffset(), scrollWidth() - box->clientWidth()));
-        int newY = max(0, min<int>(scrollYOffset(), scrollHeight() - box->clientHeight()));
-        if (newX != scrollXOffset() || newY != scrollYOffset())
-            scrollToOffset(newX, newY);
-    }
+    bool hasHorizontalOverflow = this->hasHorizontalOverflow();
+    bool hasVerticalOverflow = this->hasVerticalOverflow();
 
-    bool haveHorizontalBar = m_hBar;
-    bool haveVerticalBar = m_vBar;
-    
     // overflow:scroll should just enable/disable.
     if (m_hBar && renderer()->style()->overflowX() == OSCROLL)
-        m_hBar->setEnabled(horizontalOverflow);
+        m_hBar->setEnabled(hasHorizontalOverflow);
     if (m_vBar && renderer()->style()->overflowY() == OSCROLL)
-        m_vBar->setEnabled(verticalOverflow);
+        m_vBar->setEnabled(hasVerticalOverflow);
 
-    // A dynamic change from a scrolling overflow to overflow:hidden means we need to get rid of any
-    // scrollbars that may be present.
-    if (renderer()->style()->overflowX() == OHIDDEN && haveHorizontalBar)
-        setHasHorizontalScrollbar(false);
-    if (renderer()->style()->overflowY() == OHIDDEN && haveVerticalBar)
-        setHasVerticalScrollbar(false);
-    
     // overflow:auto may need to lay out again if scrollbars got added/removed.
-    bool scrollbarsChanged = (box->hasAutoHorizontalScrollbar() && haveHorizontalBar != horizontalOverflow) || 
-                             (box->hasAutoVerticalScrollbar() && haveVerticalBar != verticalOverflow);    
-    if (scrollbarsChanged) {
+    bool autoHorizontalScrollBarChanged = box->hasAutoHorizontalScrollbar() && (hasHorizontalScrollbar() != hasHorizontalOverflow);
+    bool autoVerticalScrollBarChanged = box->hasAutoVerticalScrollbar() && (hasVerticalScrollbar() != hasVerticalOverflow);
+
+    if (autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged) {
         if (box->hasAutoHorizontalScrollbar())
-            setHasHorizontalScrollbar(horizontalOverflow);
+            setHasHorizontalScrollbar(hasHorizontalOverflow);
         if (box->hasAutoVerticalScrollbar())
-            setHasVerticalScrollbar(verticalOverflow);
+            setHasVerticalScrollbar(hasVerticalOverflow);
 
 #if ENABLE(DASHBOARD_SUPPORT)
         // Force an update since we know the scrollbars have changed things.
@@ -2477,8 +2464,7 @@ void RenderLayer::updateScrollInfoAfterLayout()
                 renderer()->setNeedsLayout(true, MarkOnlyThis);
                 if (renderer()->isRenderBlock()) {
                     RenderBlock* block = toRenderBlock(renderer());
-                    block->scrollbarsChanged(box->hasAutoHorizontalScrollbar() && haveHorizontalBar != horizontalOverflow,
-                                             box->hasAutoVerticalScrollbar() && haveVerticalBar != verticalOverflow);
+                    block->scrollbarsChanged(autoHorizontalScrollBarChanged, autoVerticalScrollBarChanged);
                     block->layoutBlock(true); // FIXME: Need to handle positioned floats triggering extra relayouts.
                 } else
                     renderer()->layout();
@@ -2486,12 +2472,6 @@ void RenderLayer::updateScrollInfoAfterLayout()
             }
         }
     }
-    
-    // If overflow:scroll is turned into overflow:auto a bar might still be disabled (Bug 11985).
-    if (m_hBar && box->hasAutoHorizontalScrollbar())
-        m_hBar->setEnabled(true);
-    if (m_vBar && box->hasAutoVerticalScrollbar())
-        m_vBar->setEnabled(true);
 
     // Set up the range (and page step/line step).
     if (m_hBar) {
@@ -2506,6 +2486,29 @@ void RenderLayer::updateScrollInfoAfterLayout()
         m_vBar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
         m_vBar->setProportion(clientHeight, m_scrollSize.height());
     }
+}
+
+void RenderLayer::updateScrollInfoAfterLayout()
+{
+    RenderBox* box = renderBox();
+    if (!box)
+        return;
+
+    m_scrollDimensionsDirty = true;
+    IntSize scrollOffsetOriginal(scrollXOffset(), scrollYOffset());
+
+    computeScrollDimensions();
+
+    if (box->style()->overflowX() != OMARQUEE) {
+        // Layout may cause us to be at an invalid scroll position. In this case we need
+        // to pull our scroll offsets back to the max (or push them up to the min).
+        int newX = max(0, min<int>(scrollXOffset(), scrollWidth() - box->clientWidth()));
+        int newY = max(0, min<int>(scrollYOffset(), scrollHeight() - box->clientHeight()));
+        if (newX != scrollXOffset() || newY != scrollYOffset())
+            scrollToOffset(newX, newY);
+    }
+
+    updateScrollbarsAfterLayout();
 
     if (scrollOffsetOriginal != scrollOffset())
         scrollToOffsetWithoutAnimation(IntPoint(scrollXOffset(), scrollYOffset()));
@@ -4603,6 +4606,37 @@ bool RenderLayer::isSelfPaintingLayer() const
         || renderer()->isRenderIFrame();
 }
 
+static bool overflowCanHaveAScrollbar(EOverflow overflow)
+{
+    return overflow == OAUTO || overflow == OSCROLL || overflow == OOVERLAY;
+}
+
+void RenderLayer::updateScrollbarsAfterStyleChange(const RenderStyle* oldStyle)
+{
+    // Overflow are a box concept.
+    if (!renderBox())
+        return;
+
+    EOverflow overflowX = renderBox()->style()->overflowX();
+    EOverflow overflowY = renderBox()->style()->overflowY();
+    if (hasHorizontalScrollbar() && !overflowCanHaveAScrollbar(overflowX))
+        setHasHorizontalScrollbar(false);
+    if (hasVerticalScrollbar() && !overflowCanHaveAScrollbar(overflowY))
+        setHasVerticalScrollbar(false);
+
+    // With overflow: scroll, scrollbars are always visible but may be disabled.
+    // When switching to another value, we need to re-enable them (see bug 11985).
+    if (hasHorizontalScrollbar() && oldStyle->overflowX() == OSCROLL && overflowX != OSCROLL) {
+        ASSERT(overflowCanHaveAScrollbar(overflowX));
+        m_hBar->setEnabled(true);
+    }
+
+    if (hasVerticalScrollbar() && oldStyle->overflowY() == OSCROLL && overflowY != OSCROLL) {
+        ASSERT(overflowCanHaveAScrollbar(overflowY));
+        m_vBar->setEnabled(true);
+    }
+}
+
 void RenderLayer::styleChanged(StyleDifference, const RenderStyle* oldStyle)
 {
     bool isNormalFlowOnly = shouldBeNormalFlowOnly();
@@ -4624,6 +4658,8 @@ void RenderLayer::styleChanged(StyleDifference, const RenderStyle* oldStyle)
         m_marquee = 0;
     }
     
+    updateScrollbarsAfterStyleChange(oldStyle);
+
     if (!hasReflection() && m_reflection)
         removeReflection();
     else if (hasReflection()) {
index 21c3ad6ba85c79acea41ddb28c77b7748edd2b24..05bda83eeb385914924136f9b229b699501495fe 100644 (file)
@@ -280,8 +280,8 @@ public:
 
     LayoutRect rect() const { return LayoutRect(location(), size()); }
 
-    int scrollWidth();
-    int scrollHeight();
+    int scrollWidth() const;
+    int scrollHeight() const;
 
     void panScrollFromPoint(const LayoutPoint&);
 
@@ -314,6 +314,9 @@ public:
     PassRefPtr<Scrollbar> createScrollbar(ScrollbarOrientation);
     void destroyScrollbar(ScrollbarOrientation);
 
+    bool hasHorizontalScrollbar() const { return horizontalScrollbar(); }
+    bool hasVerticalScrollbar() const { return verticalScrollbar(); }
+
     // ScrollableArea overrides
     virtual Scrollbar* horizontalScrollbar() const { return m_hBar.get(); }
     virtual Scrollbar* verticalScrollbar() const { return m_vBar.get(); }
@@ -585,6 +588,9 @@ private:
 
     bool shouldRepaintAfterLayout() const;
 
+    void updateScrollbarsAfterStyleChange(const RenderStyle* oldStyle);
+    void updateScrollbarsAfterLayout();
+
     friend IntSize RenderBox::scrolledContentOffset() const;
     IntSize scrolledContentOffset() const { return scrollOffset() + m_scrollOverflow; }
 
@@ -649,7 +655,9 @@ private:
     
     bool hitTestContents(const HitTestRequest&, HitTestResult&, const LayoutRect& layerBounds, const LayoutPoint& hitTestPoint, HitTestFilter) const;
     
-    void computeScrollDimensions(bool* needHBar = 0, bool* needVBar = 0);
+    void computeScrollDimensions();
+    bool hasHorizontalOverflow() const;
+    bool hasVerticalOverflow() const;
 
     bool shouldBeNormalFlowOnly() const;