Latched scrolling may interact badly with custom programmatic scrolling
authorbfulgham@apple.com <bfulgham@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 20 Apr 2014 02:32:48 +0000 (02:32 +0000)
committerbfulgham@apple.com <bfulgham@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 20 Apr 2014 02:32:48 +0000 (02:32 +0000)
https://bugs.webkit.org/show_bug.cgi?id=131869
<rdar://problem/16249557>

Reviewed by Darin Adler.

* dom/Element.cpp:
(WebCore::Element::setScrollLeft): Mark scrollable area as having
been scrolled programmatically.
(WebCore::Element::setScrollTop): Ditto.
* page/EventHandler.cpp:
(WebCore::EventHandler::handleWheelEvent): Check for programmatic scroll, and
clear latched state if the handler manually scrolled. Clear programmatic
scroll state at the end of event handling.
(WebCore::EventHandler::clearLatchedState): Refactored code.
* page/EventHandler.h:
* page/mac/EventHandlerMac.mm:
(WebCore::EventHandler::platformPrepareForWheelEvents): Check
if scrollable area was scrolled programmatically. If it was, do
not honor latching behavior.
* platform/ScrollableArea.cpp:
(WebCore::ScrollableArea::ScrollableArea): Initialize new member.
* platform/ScrollableArea.h:
(WebCore::ScrollableArea::isScrolledProgrammatically): Added.
(WebCore::ScrollableArea::setScrolledProgrammatically): Added.

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

Source/WebCore/ChangeLog
Source/WebCore/dom/Element.cpp
Source/WebCore/page/EventHandler.cpp
Source/WebCore/page/EventHandler.h
Source/WebCore/page/mac/EventHandlerMac.mm
Source/WebCore/platform/ScrollableArea.cpp
Source/WebCore/platform/ScrollableArea.h
WebKit.xcworkspace/xcshareddata/xcschemes/All Source (target WebProcess).xcscheme

index f48f9da..3294884 100644 (file)
@@ -1,3 +1,31 @@
+2014-04-19  Brent Fulgham  <bfulgham@apple.com>
+
+        Latched scrolling may interact badly with custom programmatic scrolling
+        https://bugs.webkit.org/show_bug.cgi?id=131869
+        <rdar://problem/16249557>
+
+        Reviewed by Darin Adler.
+
+        * dom/Element.cpp:
+        (WebCore::Element::setScrollLeft): Mark scrollable area as having
+        been scrolled programmatically.
+        (WebCore::Element::setScrollTop): Ditto.
+        * page/EventHandler.cpp:
+        (WebCore::EventHandler::handleWheelEvent): Check for programmatic scroll, and
+        clear latched state if the handler manually scrolled. Clear programmatic
+        scroll state at the end of event handling.
+        (WebCore::EventHandler::clearLatchedState): Refactored code.
+        * page/EventHandler.h:
+        * page/mac/EventHandlerMac.mm:
+        (WebCore::EventHandler::platformPrepareForWheelEvents): Check
+        if scrollable area was scrolled programmatically. If it was, do
+        not honor latching behavior.
+        * platform/ScrollableArea.cpp:
+        (WebCore::ScrollableArea::ScrollableArea): Initialize new member.
+        * platform/ScrollableArea.h:
+        (WebCore::ScrollableArea::isScrolledProgrammatically): Added.
+        (WebCore::ScrollableArea::setScrolledProgrammatically): Added.
+
 2014-04-19  Chris Fleizach  <cfleizach@apple.com>
 
         AX: grid rows are not recognized do to lack of explicit role="row", role="gridcell"
index 4f8f938..48b9277 100644 (file)
@@ -61,6 +61,7 @@
 #include "NodeRenderStyle.h"
 #include "PlatformWheelEvent.h"
 #include "PointerLockController.h"
+#include "RenderLayer.h"
 #include "RenderNamedFlowFragment.h"
 #include "RenderRegion.h"
 #include "RenderTheme.h"
@@ -798,16 +799,22 @@ void Element::setScrollLeft(int newLeft)
 {
     document().updateLayoutIgnorePendingStylesheets();
 
-    if (RenderBox* rend = renderBox())
-        rend->setScrollLeft(static_cast<int>(newLeft * rend->style().effectiveZoom()));
+    if (RenderBox* renderer = renderBox()) {
+        renderer->setScrollLeft(static_cast<int>(newLeft * renderer->style().effectiveZoom()));
+        if (auto* scrollableArea = renderer->layer())
+            scrollableArea->setScrolledProgrammatically(true);
+    }
 }
 
 void Element::setScrollTop(int newTop)
 {
     document().updateLayoutIgnorePendingStylesheets();
 
-    if (RenderBox* rend = renderBox())
-        rend->setScrollTop(static_cast<int>(newTop * rend->style().effectiveZoom()));
+    if (RenderBox* renderer = renderBox()) {
+        renderer->setScrollTop(static_cast<int>(newTop * renderer->style().effectiveZoom()));
+        if (auto* scrollableArea = renderer->layer())
+            scrollableArea->setScrolledProgrammatically(true);
+    }
 }
 
 int Element::scrollWidth()
index b2b529e..d9689b8 100644 (file)
@@ -2593,19 +2593,41 @@ bool EventHandler::handleWheelEvent(const PlatformWheelEvent& e)
             Widget* widget = toRenderWidget(target)->widget();
             if (widget && passWheelEventToWidget(e, widget)) {
                 m_isHandlingWheelEvent = false;
+                if (scrollableArea)
+                    scrollableArea->setScrolledProgrammatically(false);
                 return true;
             }
         }
 
         if (!element->dispatchWheelEvent(event)) {
             m_isHandlingWheelEvent = false;
+
+            if (scrollableArea && scrollableArea->isScrolledProgrammatically()) {
+                // Web developer is controlling scrolling. Don't attempt to latch ourselves:
+                clearLatchedState();
+                scrollableArea->setScrolledProgrammatically(false);
+            }
+
             return true;
         }
     }
 
+    if (scrollableArea)
+        scrollableArea->setScrolledProgrammatically(false);
+
     return platformCompleteWheelEvent(e, scrollableContainer, scrollableArea);
 }
 
+void EventHandler::clearLatchedState()
+{
+    m_latchedWheelEventElement = nullptr;
+#if PLATFORM(COCOA)
+    m_latchedScrollableContainer = nullptr;
+#endif
+    m_widgetIsLatched = false;
+    m_previousWheelScrolledElement = nullptr;
+}
+
 void EventHandler::defaultWheelEventHandler(Node* startNode, WheelEvent* wheelEvent)
 {
     if (!startNode || !wheelEvent)
index 7ef797b..90e3f14 100644 (file)
@@ -436,6 +436,8 @@ private:
     void autoHideCursorTimerFired(Timer<EventHandler>&);
 #endif
 
+    void clearLatchedState();
+
     Frame& m_frame;
 
     bool m_mousePressed;
index 0577bc2..c3ac0b9 100644 (file)
@@ -799,10 +799,7 @@ void EventHandler::platformPrepareForWheelEvents(const PlatformWheelEvent& wheel
         isOverWidget = m_widgetIsLatched;
         m_recentWheelEventDeltaTracker->beginTrackingDeltas();
     } else if (wheelEvent.shouldResetLatching()) {
-        m_latchedWheelEventElement = nullptr;
-        m_latchedScrollableContainer = nullptr;
-        m_widgetIsLatched = false;
-        m_previousWheelScrolledElement = nullptr;
+        clearLatchedState();
         m_recentWheelEventDeltaTracker->endTrackingDeltas();
     }
     
index 24f0d85..c7d9494 100644 (file)
@@ -59,6 +59,7 @@ ScrollableArea::ScrollableArea()
     , m_horizontalScrollElasticity(ScrollElasticityNone)
     , m_scrollbarOverlayStyle(ScrollbarOverlayStyleDefault)
     , m_scrollOriginChanged(false)
+    , m_scrolledProgrammatically(false)
 {
 }
 
index 0ee37eb..094b4d6 100644 (file)
@@ -156,6 +156,9 @@ public:
     virtual bool scrolledToLeft() const;
     virtual bool scrolledToRight() const;
 
+    bool isScrolledProgrammatically() const { return m_scrolledProgrammatically; }
+    void setScrolledProgrammatically(bool state) { m_scrolledProgrammatically = state; }
+
     enum VisibleContentRectIncludesScrollbars { ExcludeScrollbars, IncludeScrollbars };
     enum VisibleContentRectBehavior {
         ContentsVisibleRect,
@@ -292,6 +295,7 @@ private:
     unsigned m_scrollbarOverlayStyle : 2; // ScrollbarOverlayStyle
 
     unsigned m_scrollOriginChanged : 1;
+    unsigned m_scrolledProgrammatically : 1;
 };
 
 } // namespace WebCore
index 83ed414..12893d6 100644 (file)
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       launchStyle = "0"
       useCustomWorkingDirectory = "NO"
-      buildConfiguration = "Debug"
+      buildConfiguration = "Release"
       ignoresPersistentStateOnLaunch = "NO"
       debugDocumentVersioning = "YES"
       allowLocationSimulation = "YES">