Use WeakPtrs to avoid using deallocated Widgets and ScrollableAreas
authorbfulgham@apple.com <bfulgham@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 12 Apr 2016 03:07:18 +0000 (03:07 +0000)
committerbfulgham@apple.com <bfulgham@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 12 Apr 2016 03:07:18 +0000 (03:07 +0000)
https://bugs.webkit.org/show_bug.cgi?id=156420
<rdar://problem/25637378>

Reviewed by Darin Adler.

Source/WebCore:

Avoid the risk of using deallocated Widgets and ScrollableAreas by using WeakPtrs instead of
bare pointers. This allows us to remove some explicit calls to get ScrollableArea and Widget
members in the event handling logic. Instead, null checks are sufficient to ensure we never
accidentally dereference a deleted element.

1. Modify the ScrollableArea class to support vending WeakPtrs.
2. Modify the Event Handling code to use WeakPtrs to hold ScrollableArea and RenderWidget
   objects, and to null-check these elements after event handling dispatching is finished
   to handle cases where these objects are destroyed.

Test: fast/events/wheel-event-destroys-frame.html
      fast/events/wheel-event-destroys-overflow.html

* page/EventHandler.cpp:
(WebCore::EventHandler::platformPrepareForWheelEvents): Change signature for WeakPtr.
(WebCore::EventHandler::platformCompleteWheelEvent): Ditto.
(WebCore::EventHandler::platformNotifyIfEndGesture): Ditto.
(WebCore::widgetForElement): Change to return a WeakPtr.
(WebCore::EventHandler::handleWheelEvent): Use WeakPtrs to hold elements that might be destroyed
during event handling.
* page/EventHandler.h:
* page/mac/EventHandlerEfl.cpp: Rename passWheelEventToWidget to widgetDidHandleWheelEvent.
* page/mac/EventHandlerGtk.cpp: Ditto.
* page/mac/EventHandlerIOS.mm: Ditto.
* page/mac/EventHandlerMac.mm:
(WebCore::scrollableAreaForEventTarget): Renamed from scrollViewForEventTarget. Return
a WeakPtr rather than a bare pointer.
(WebCore::scrollableAreaForContainerNode): Return WeakPtr rather than bare pointer.
(WebCore::EventHandler::completeWidgetWheelEvent): Added.
(WebCore::EventHandler::passWheelEventToWidget): Deleted.
(WebCore::EventHandler::platformPrepareForWheelEvents): Convert to WeakPtrs.
(WebCore::EventHandler::platformCompleteWheelEvent): Ditto.
(WebCore::EventHandler::platformCompletePlatformWidgetWheelEvent): Ditto.
(WebCore::EventHandler::platformNotifyIfEndGesture): Ditto.
(WebCore::EventHandler::widgetDidHandleWheelEvent): Renamed from passWheelEventToWidget.
(WebCore::EventHandler::widgetForEventTarget): Converted from static function to static
method so it can be shared with EventHandlerMac.
(WebCore::scrollViewForEventTarget): Deleted.
* page/mac/EventHandlerWin.cpp: Rename passWheelEventToWidget to widgetDidHandleWheelEvent.
* platform/ScrollableArea.cpp:
* platform/ScrollableArea.h:
(WebCore::ScrollableArea::createWeakPtr): Added.
* platform/Widget.h:
(WebCore::ScrollableArea::createWeakPtr): Added.

LayoutTests:

* fast/events/wheel-event-destroys-overflow-expected.txt: Added.
* fast/events/wheel-event-destroys-overflow.html: Added.
* platform/ios-simulator/TestExpectations: Skip wheel-event test on iOS.

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

15 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/events/wheel-event-destroys-overflow-expected.txt [new file with mode: 0644]
LayoutTests/fast/events/wheel-event-destroys-overflow.html [new file with mode: 0644]
LayoutTests/platform/ios-simulator/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/page/EventHandler.cpp
Source/WebCore/page/EventHandler.h
Source/WebCore/page/efl/EventHandlerEfl.cpp
Source/WebCore/page/gtk/EventHandlerGtk.cpp
Source/WebCore/page/ios/EventHandlerIOS.mm
Source/WebCore/page/mac/EventHandlerMac.mm
Source/WebCore/page/win/EventHandlerWin.cpp
Source/WebCore/platform/ScrollableArea.cpp
Source/WebCore/platform/ScrollableArea.h
Source/WebCore/platform/Widget.h

index df7d11e9a54ecff09fbb554e1bd62b5500c0d3cb..f36c1e0fb6c1008db904267dc15fdb6a2b7ce81e 100644 (file)
@@ -1,3 +1,15 @@
+2016-04-11  Brent Fulgham  <bfulgham@apple.com>
+
+        Use WeakPtrs to avoid using deallocated Widgets and ScrollableAreas
+        https://bugs.webkit.org/show_bug.cgi?id=156420
+        <rdar://problem/25637378>
+
+        Reviewed by Darin Adler.
+
+        * fast/events/wheel-event-destroys-overflow-expected.txt: Added.
+        * fast/events/wheel-event-destroys-overflow.html: Added.
+        * platform/ios-simulator/TestExpectations: Skip wheel-event test on iOS.
+
 2016-04-11  Dean Jackson  <dino@apple.com>
 
         putImageData needs to premultiply input
diff --git a/LayoutTests/fast/events/wheel-event-destroys-overflow-expected.txt b/LayoutTests/fast/events/wheel-event-destroys-overflow-expected.txt
new file mode 100644 (file)
index 0000000..d31f6ea
--- /dev/null
@@ -0,0 +1,3 @@
+This test should not crash.
+
+
diff --git a/LayoutTests/fast/events/wheel-event-destroys-overflow.html b/LayoutTests/fast/events/wheel-event-destroys-overflow.html
new file mode 100644 (file)
index 0000000..0ff06e6
--- /dev/null
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <script>
+        if (window.eventSender) {
+            testRunner.dumpAsText();
+            testRunner.waitUntilDone();
+        }
+
+        function onLoad()
+        {
+            var divTarget = document.getElementById('target');
+            var divTargetBounds = divTarget.getBoundingClientRect();
+
+            divTarget.addEventListener('wheel', function() {
+                // Removing the div during event firing causes crash.
+                if (divTarget.parentNode)
+                    divTarget.parentNode.removeChild(divTarget);
+                window.setTimeout(function() {
+                    if (window.testRunner)
+                        testRunner.notifyDone();
+                }, 0);
+            });
+
+            if (!window.eventSender)
+                return;
+
+            eventSender.mouseMoveTo(divTargetBounds.left + 10, divTargetBounds.top + 10);
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -1, 'began', 'none');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -1, 'changed', 'none');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(0, -1, 'changed', 'none');
+            eventSender.mouseScrollByWithWheelAndMomentumPhases(0, 0, 'ended', 'none');
+        }
+    </script>
+</head>
+<body onload="onLoad();">
+    <p>This test should not crash.<p>
+    <div id="parent" style="height: 2000px; width: 2000px;">
+        <div id="holder" class="scrollable_region"">
+            <div id="target" style='overflow-y: auto; overflow-x: hidden; max-height: 350px;'>
+                <div style='height:1000px'>Wheel Here.</div>
+            </div>
+        </div>
+    </div>
+</body>
+</html>
index f4be55da5cdeccf2420c496c48fd88efa1ad8ece..793d3bd1e570d4b83b9e9f2085ff541270aa229e 100644 (file)
@@ -58,6 +58,7 @@ fast/history/page-cache-suspended-audiocontext.html
 fast/scrolling/iframe-scrollable-after-back.html [ Skip ]
 fast/scrolling/overflow-scrollable-after-back.html [ Skip ]
 fast/events/wheel-event-destroys-frame.html [ Skip ]
+fast/events/wheel-event-destroys-overflow.html [ Skip ]
 
 # Not supported on iOS
 batterystatus
index 4d5a50a33fcd63efa91f8f7d11edab8a101b69ea..4f8e41846c7b417059a7f16ee78db1901f5a376d 100644 (file)
@@ -1,3 +1,56 @@
+2016-04-11  Brent Fulgham  <bfulgham@apple.com>
+
+        Use WeakPtrs to avoid using deallocated Widgets and ScrollableAreas
+        https://bugs.webkit.org/show_bug.cgi?id=156420
+        <rdar://problem/25637378>
+
+        Reviewed by Darin Adler.
+
+        Avoid the risk of using deallocated Widgets and ScrollableAreas by using WeakPtrs instead of
+        bare pointers. This allows us to remove some explicit calls to get ScrollableArea and Widget
+        members in the event handling logic. Instead, null checks are sufficient to ensure we never
+        accidentally dereference a deleted element.
+
+        1. Modify the ScrollableArea class to support vending WeakPtrs.
+        2. Modify the Event Handling code to use WeakPtrs to hold ScrollableArea and RenderWidget
+           objects, and to null-check these elements after event handling dispatching is finished
+           to handle cases where these objects are destroyed.
+
+        Test: fast/events/wheel-event-destroys-frame.html
+              fast/events/wheel-event-destroys-overflow.html
+
+        * page/EventHandler.cpp:
+        (WebCore::EventHandler::platformPrepareForWheelEvents): Change signature for WeakPtr.
+        (WebCore::EventHandler::platformCompleteWheelEvent): Ditto.
+        (WebCore::EventHandler::platformNotifyIfEndGesture): Ditto.
+        (WebCore::widgetForElement): Change to return a WeakPtr.
+        (WebCore::EventHandler::handleWheelEvent): Use WeakPtrs to hold elements that might be destroyed
+        during event handling.
+        * page/EventHandler.h:
+        * page/mac/EventHandlerEfl.cpp: Rename passWheelEventToWidget to widgetDidHandleWheelEvent.
+        * page/mac/EventHandlerGtk.cpp: Ditto.
+        * page/mac/EventHandlerIOS.mm: Ditto.
+        * page/mac/EventHandlerMac.mm:
+        (WebCore::scrollableAreaForEventTarget): Renamed from scrollViewForEventTarget. Return
+        a WeakPtr rather than a bare pointer.
+        (WebCore::scrollableAreaForContainerNode): Return WeakPtr rather than bare pointer.
+        (WebCore::EventHandler::completeWidgetWheelEvent): Added.
+        (WebCore::EventHandler::passWheelEventToWidget): Deleted.
+        (WebCore::EventHandler::platformPrepareForWheelEvents): Convert to WeakPtrs.
+        (WebCore::EventHandler::platformCompleteWheelEvent): Ditto.
+        (WebCore::EventHandler::platformCompletePlatformWidgetWheelEvent): Ditto.
+        (WebCore::EventHandler::platformNotifyIfEndGesture): Ditto.
+        (WebCore::EventHandler::widgetDidHandleWheelEvent): Renamed from passWheelEventToWidget.
+        (WebCore::EventHandler::widgetForEventTarget): Converted from static function to static
+        method so it can be shared with EventHandlerMac.
+        (WebCore::scrollViewForEventTarget): Deleted.
+        * page/mac/EventHandlerWin.cpp: Rename passWheelEventToWidget to widgetDidHandleWheelEvent.
+        * platform/ScrollableArea.cpp:
+        * platform/ScrollableArea.h:
+        (WebCore::ScrollableArea::createWeakPtr): Added.
+        * platform/Widget.h:
+        (WebCore::ScrollableArea::createWeakPtr): Added.
+
 2016-04-11  Dean Jackson  <dino@apple.com>
 
         putImageData needs to premultiply input
index bc1b40e61c206240dac4f53d4570176b5ded3181..18c475f1ee817e4e5f1702db3b4fa3993e0344bf 100644 (file)
@@ -2559,7 +2559,7 @@ bool EventHandler::shouldTurnVerticalTicksIntoHorizontal(const HitTestResult&, c
 
 #if !PLATFORM(MAC)
 
-void EventHandler::platformPrepareForWheelEvents(const PlatformWheelEvent&, const HitTestResult&, RefPtr<Element>&, RefPtr<ContainerNode>&, ScrollableArea*&, bool&)
+void EventHandler::platformPrepareForWheelEvents(const PlatformWheelEvent&, const HitTestResult&, RefPtr<Element>&, RefPtr<ContainerNode>&, WeakPtr<ScrollableArea>&, bool&)
 {
 }
 
@@ -2568,7 +2568,7 @@ void EventHandler::platformRecordWheelEvent(const PlatformWheelEvent& event)
     m_frame.mainFrame().wheelEventDeltaFilter()->updateFromDelta(FloatSize(event.deltaX(), event.deltaY()));
 }
 
-bool EventHandler::platformCompleteWheelEvent(const PlatformWheelEvent& event, ContainerNode*, ScrollableArea*)
+bool EventHandler::platformCompleteWheelEvent(const PlatformWheelEvent& event, ContainerNode*, const WeakPtr<ScrollableArea>&)
 {
     // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed.
     FrameView* view = m_frame.view();
@@ -2583,7 +2583,7 @@ bool EventHandler::platformCompletePlatformWidgetWheelEvent(const PlatformWheelE
     return true;
 }
 
-void EventHandler::platformNotifyIfEndGesture(const PlatformWheelEvent&, ScrollableArea*)
+void EventHandler::platformNotifyIfEndGesture(const PlatformWheelEvent&, const WeakPtr<ScrollableArea>&)
 {
 }
 
@@ -2598,18 +2598,46 @@ void EventHandler::clearOrScheduleClearingLatchedStateIfNeeded(const PlatformWhe
 }
 #endif
 
-static Widget* widgetForElement(const Element& element)
+Widget* EventHandler::widgetForEventTarget(Element* eventTarget)
 {
-    RenderElement* target = element.renderer();
-    if (!target)
+    if (!eventTarget)
         return nullptr;
 
+    auto* target = eventTarget->renderer();
     if (!is<RenderWidget>(target))
         return nullptr;
 
     return downcast<RenderWidget>(*target).widget();
 }
 
+static WeakPtr<Widget> widgetForElement(const Element& element)
+{
+    auto target = element.renderer();
+    if (!is<RenderWidget>(target) || !downcast<RenderWidget>(*target).widget())
+        return { };
+
+    return downcast<RenderWidget>(*target).widget()->createWeakPtr();
+}
+
+bool EventHandler::completeWidgetWheelEvent(const PlatformWheelEvent& event, const WeakPtr<Widget>& widget, const WeakPtr<ScrollableArea>& scrollableArea, ContainerNode* scrollableContainer)
+{
+    m_isHandlingWheelEvent = false;
+    
+    // We do another check on the widget because the event handler can run JS which results in the frame getting destroyed.
+    if (!widget)
+        return false;
+    
+    if (scrollableArea)
+        scrollableArea->setScrolledProgrammatically(false);
+
+    platformNotifyIfEndGesture(event, scrollableArea);
+
+    if (!widget->platformWidget())
+        return true;
+
+    return platformCompletePlatformWidgetWheelEvent(event, *widget.get(), scrollableContainer);
+}
+
 bool EventHandler::handleWheelEvent(const PlatformWheelEvent& event)
 {
     RenderView* renderView = m_frame.contentRenderer();
@@ -2631,7 +2659,7 @@ bool EventHandler::handleWheelEvent(const PlatformWheelEvent& event)
 
     RefPtr<Element> element = result.innerElement();
     RefPtr<ContainerNode> scrollableContainer;
-    ScrollableArea* scrollableArea = nullptr;
+    WeakPtr<ScrollableArea> scrollableArea;
     bool isOverWidget = result.isOverWidget();
     platformPrepareForWheelEvents(event, result, element, scrollableContainer, scrollableArea, isOverWidget);
 
@@ -2650,21 +2678,9 @@ bool EventHandler::handleWheelEvent(const PlatformWheelEvent& event)
 
     if (element) {
         if (isOverWidget) {
-            Widget* widget = widgetForElement(*element);
-            if (widget && passWheelEventToWidget(event, *widget)) {
-                m_isHandlingWheelEvent = false;
-
-                // We do another check on the widget because the event handler can run JS which results in the frame getting destroyed.
-                Widget* widget = widgetForElement(*element);
-                if (!widget)
-                    return false;
-
-                if (scrollableArea)
-                    scrollableArea->setScrolledProgrammatically(false);
-                platformNotifyIfEndGesture(adjustedEvent, scrollableArea);
-                if (!widget->platformWidget())
-                    return true;
-                return platformCompletePlatformWidgetWheelEvent(event, *widget, scrollableContainer.get());
+            if (WeakPtr<Widget> widget = widgetForElement(*element)) {
+                if (widgetDidHandleWheelEvent(event, *widget.get()))
+                    return completeWidgetWheelEvent(adjustedEvent, widget, scrollableArea, scrollableContainer.get());
             }
         }
 
index ac58e9ddf34b31a2a9d511bccc25c1248ccfa91e..e917a12f90fe78c2f4ffd46b50a7f3ee7ec2b052 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -204,11 +204,11 @@ public:
     void defaultWheelEventHandler(Node*, WheelEvent*);
     bool handlePasteGlobalSelection(const PlatformMouseEvent&);
 
-    void platformPrepareForWheelEvents(const PlatformWheelEvent&, const HitTestResult&, RefPtr<Element>& eventTarget, RefPtr<ContainerNode>& scrollableContainer, ScrollableArea*&, bool& isOverWidget);
+    void platformPrepareForWheelEvents(const PlatformWheelEvent&, const HitTestResult&, RefPtr<Element>& eventTarget, RefPtr<ContainerNode>& scrollableContainer, WeakPtr<ScrollableArea>&, bool& isOverWidget);
     void platformRecordWheelEvent(const PlatformWheelEvent&);
-    bool platformCompleteWheelEvent(const PlatformWheelEvent&, ContainerNode* scrollableContainer, ScrollableArea*);
+    bool platformCompleteWheelEvent(const PlatformWheelEvent&, ContainerNode* scrollableContainer, const WeakPtr<ScrollableArea>&);
     bool platformCompletePlatformWidgetWheelEvent(const PlatformWheelEvent&, const Widget&, ContainerNode* scrollableContainer);
-    void platformNotifyIfEndGesture(const PlatformWheelEvent&, ScrollableArea*);
+    void platformNotifyIfEndGesture(const PlatformWheelEvent&, const WeakPtr<ScrollableArea>&);
 
 #if ENABLE(IOS_TOUCH_EVENTS) || ENABLE(IOS_GESTURE_EVENTS)
     typedef Vector<RefPtr<Touch>> TouchArray;
@@ -318,6 +318,8 @@ public:
     WEBCORE_EXPORT void setImmediateActionStage(ImmediateActionStage stage);
     ImmediateActionStage immediateActionStage() const { return m_immediateActionStage; }
 
+    static Widget* widgetForEventTarget(Element* eventTarget);
+
 private:
 #if ENABLE(DRAG_SUPPORT)
     static DragState& dragState();
@@ -415,7 +417,8 @@ private:
     bool passWidgetMouseDownEventToWidget(RenderWidget*);
 
     bool passMouseDownEventToWidget(Widget*);
-    bool passWheelEventToWidget(const PlatformWheelEvent&, Widget&);
+    bool widgetDidHandleWheelEvent(const PlatformWheelEvent&, Widget&);
+    bool completeWidgetWheelEvent(const PlatformWheelEvent&, const WeakPtr<Widget>&, const WeakPtr<ScrollableArea>&, ContainerNode*);
 
     void defaultSpaceEventHandler(KeyboardEvent*);
     void defaultBackspaceEventHandler(KeyboardEvent*);
index cbd251d9d9da4ddb921eaa0580792a004f2c8e85..6b7c6d9b418cd93a3a4d66ca04b2e2a05857659a 100644 (file)
@@ -87,7 +87,7 @@ bool EventHandler::eventActivatedView(const PlatformMouseEvent&) const
     return false;
 }
 
-bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent& event, Widget& widget)
+bool EventHandler::widgetDidHandleWheelEvent(const PlatformWheelEvent& event, Widget& widget)
 {
     if (!is<FrameView>(widget))
         return false;
index 3a007710d3120fedf9b210574d8ba44a997e4979..0b07bd0a14199bf70315084a337563b074faaedc 100644 (file)
@@ -87,7 +87,7 @@ bool EventHandler::eventActivatedView(const PlatformMouseEvent&) const
     return false;
 }
 
-bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent& event, Widget& widget)
+bool EventHandler::widgetDidHandleWheelEvent(const PlatformWheelEvent& event, Widget& widget)
 {
     if (!is<FrameView>(widget))
         return false;
index e88c5791f7ed01be42e09102c03e9f30e215983a..990610529bd98b9a151e9caf1ce65f0b90cd1985 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2006-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -406,7 +406,7 @@ bool EventHandler::passSubframeEventToSubframe(MouseEventWithHitTestResults& eve
     return false;
 }
 
-bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent&, Widget& widget)
+bool EventHandler::widgetDidHandleWheelEvent(const PlatformWheelEvent&, Widget& widget)
 {
     BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
index b20c8d76f525e5ad53a62a9ae73e8989d9cf1573..a29fd57648dead8d98cc945e256cf99769cc8d0d 100644 (file)
@@ -463,7 +463,7 @@ static void selfRetainingNSScrollViewScrollWheel(NSScrollView *self, SEL selecto
         [self release];
 }
 
-bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent& wheelEvent, Widget& widget)
+bool EventHandler::widgetDidHandleWheelEvent(const PlatformWheelEvent& wheelEvent, Widget& widget)
 {
     BEGIN_BLOCK_OBJC_EXCEPTIONS;
 
@@ -855,33 +855,18 @@ static bool scrolledToEdgeInDominantDirection(const ContainerNode& container, co
     return area.scrolledToTop();
 }
 
-static Widget* widgetForEventTarget(Element* eventTarget)
+static WeakPtr<ScrollableArea> scrollableAreaForEventTarget(Element* eventTarget)
 {
-    if (!eventTarget)
-        return nullptr;
-    
-    auto* target = eventTarget->renderer();
-    if (!is<RenderWidget>(target))
-        return nullptr;
-    
-    return downcast<RenderWidget>(*target).widget();
-}
+    auto* widget = EventHandler::widgetForEventTarget(eventTarget);
+    if (!widget || !widget->isScrollView())
+        return { };
 
-static ScrollView* scrollViewForEventTarget(Element* eventTarget)
-{
-    Widget* widget = widgetForEventTarget(eventTarget);
-    if (!widget)
-        return nullptr;
-    
-    if (!widget->isScrollView())
-        return nullptr;
-    
-    return reinterpret_cast<ScrollView*>(widget);
+    return static_cast<ScrollableArea*>(static_cast<ScrollView*>(widget))->createWeakPtr();
 }
     
 static bool eventTargetIsPlatformWidget(Element* eventTarget)
 {
-    Widget* widget = widgetForEventTarget(eventTarget);
+    Widget* widget = EventHandler::widgetForEventTarget(eventTarget);
     if (!widget)
         return false;
     
@@ -917,14 +902,17 @@ static bool latchingIsLockedToAncestorOfThisFrame(const Frame& frame)
     return false;
 }
 
-static ScrollableArea* scrollableAreaForContainerNode(ContainerNode& container)
+static WeakPtr<ScrollableArea> scrollableAreaForContainerNode(ContainerNode& container)
 {
-    ScrollableArea* scrollableArea = nullptr;
+    auto box = container.renderBox();
+    if (!box)
+        return { };
 
-    if (RenderBox* box = container.renderBox())
-        scrollableArea = scrollableAreaForBox(*box);
-
-    return scrollableArea;
+    auto scrollableAreaPtr = scrollableAreaForBox(*box);
+    if (!scrollableAreaPtr)
+        return { };
+    
+    return scrollableAreaPtr->createWeakPtr();
 }
 
 static bool latchedToFrameOrBody(ContainerNode& container)
@@ -957,27 +945,25 @@ void EventHandler::clearOrScheduleClearingLatchedStateIfNeeded(const PlatformWhe
     }
 }
 
-void EventHandler::platformPrepareForWheelEvents(const PlatformWheelEvent& wheelEvent, const HitTestResult& result, RefPtr<Element>& wheelEventTarget, RefPtr<ContainerNode>& scrollableContainer, ScrollableArea*& scrollableArea, bool& isOverWidget)
+void EventHandler::platformPrepareForWheelEvents(const PlatformWheelEvent& wheelEvent, const HitTestResult& result, RefPtr<Element>& wheelEventTarget, RefPtr<ContainerNode>& scrollableContainer, WeakPtr<ScrollableArea>& scrollableArea, bool& isOverWidget)
 {
     clearOrScheduleClearingLatchedStateIfNeeded(wheelEvent);
 
     FrameView* view = m_frame.view();
 
-    scrollableContainer = nullptr;
-    scrollableArea = nullptr;
     if (!view)
         scrollableContainer = wheelEventTarget;
     else {
         if (eventTargetIsPlatformWidget(wheelEventTarget.get())) {
             scrollableContainer = wheelEventTarget;
-            scrollableArea = scrollViewForEventTarget(wheelEventTarget.get());
+            scrollableArea = scrollableAreaForEventTarget(wheelEventTarget.get());
         } else {
             scrollableContainer = findEnclosingScrollableContainer(wheelEventTarget.get(), wheelEvent.deltaX(), wheelEvent.deltaY());
             if (scrollableContainer && !is<HTMLIFrameElement>(wheelEventTarget.get()))
                 scrollableArea = scrollableAreaForContainerNode(*scrollableContainer);
             else {
                 scrollableContainer = view->frame().document()->bodyOrFrameset();
-                scrollableArea = view;
+                scrollableArea = static_cast<ScrollableArea*>(view)->createWeakPtr();
             }
         }
     }
@@ -989,7 +975,7 @@ void EventHandler::platformPrepareForWheelEvents(const PlatformWheelEvent& wheel
     ScrollLatchingState* latchingState = m_frame.mainFrame().latchingState();
     if (wheelEvent.shouldConsiderLatching()) {
         if (scrollableContainer && scrollableArea) {
-            bool startingAtScrollLimit = scrolledToEdgeInDominantDirection(*scrollableContainer, *scrollableArea, wheelEvent.deltaX(), wheelEvent.deltaY());
+            bool startingAtScrollLimit = scrolledToEdgeInDominantDirection(*scrollableContainer, *scrollableArea.get(), wheelEvent.deltaX(), wheelEvent.deltaY());
             if (!startingAtScrollLimit) {
                 m_frame.mainFrame().pushNewLatchingState();
                 latchingState = m_frame.mainFrame().latchingState();
@@ -1047,7 +1033,7 @@ static FrameView* frameViewForLatchingState(Frame& frame, ScrollLatchingState* l
     return latchingState->frame() ? latchingState->frame()->view() : frame.view();
 }
 
-bool EventHandler::platformCompleteWheelEvent(const PlatformWheelEvent& wheelEvent, ContainerNode* scrollableContainer, ScrollableArea* scrollableArea)
+bool EventHandler::platformCompleteWheelEvent(const PlatformWheelEvent& wheelEvent, ContainerNode* scrollableContainer, const WeakPtr<ScrollableArea>& scrollableArea)
 {
     FrameView* view = m_frame.view();
     // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed.
@@ -1060,7 +1046,7 @@ bool EventHandler::platformCompleteWheelEvent(const PlatformWheelEvent& wheelEve
         m_isHandlingWheelEvent = false;
 
         // WebKit2 code path
-        if (!frameHasPlatformWidget(m_frame) && !latchingState->startedGestureAtScrollLimit() && scrollableContainer == latchingState->scrollableContainer() && scrollableArea && view != scrollableArea) {
+        if (!frameHasPlatformWidget(m_frame) && !latchingState->startedGestureAtScrollLimit() && scrollableContainer == latchingState->scrollableContainer() && scrollableArea && view != scrollableArea.get()) {
             // If we did not start at the scroll limit, do not pass the event on to be handled by enclosing scrollable regions.
             return true;
         }
@@ -1078,7 +1064,7 @@ bool EventHandler::platformCompleteWheelEvent(const PlatformWheelEvent& wheelEve
         }
 
         // If the platform widget is handling the event, we always want to return false.
-        if (scrollableArea == view && view->platformWidget())
+        if (scrollableArea.get() == view && view->platformWidget())
             didHandleWheelEvent = false;
         
         return didHandleWheelEvent;
@@ -1105,7 +1091,7 @@ bool EventHandler::platformCompletePlatformWidgetWheelEvent(const PlatformWheelE
     return false;
 }
 
-void EventHandler::platformNotifyIfEndGesture(const PlatformWheelEvent& wheelEvent, ScrollableArea* scrollableArea)
+void EventHandler::platformNotifyIfEndGesture(const PlatformWheelEvent& wheelEvent, const WeakPtr<ScrollableArea>& scrollableArea)
 {
     if (!scrollableArea)
         return;
index 128f4f81f30caa259fef908e8b8cd170b9088fba..106f077ff5e1e8dc564a719de4e9a1f4d8c27b88 100644 (file)
@@ -73,7 +73,7 @@ bool EventHandler::passMouseReleaseEventToSubframe(MouseEventWithHitTestResults&
     return true;
 }
 
-bool EventHandler::passWheelEventToWidget(const PlatformWheelEvent& wheelEvent, Widget& widget)
+bool EventHandler::widgetDidHandleWheelEvent(const PlatformWheelEvent& wheelEvent, Widget& widget)
 {
     if (!is<FrameView>(widget))
         return false;
index 75b976a3d53e193606177112e41c997c3cadaa94..d3a35e211c92afebf8444aed042143388e64436e 100644 (file)
@@ -48,10 +48,10 @@ namespace WebCore {
 struct SameSizeAsScrollableArea {
     virtual ~SameSizeAsScrollableArea();
 #if ENABLE(CSS_SCROLL_SNAP)
-    void* pointers[3];
+    void* pointers[4];
     unsigned currentIndices[2];
 #else
-    void* pointer;
+    void* pointer[2];
 #endif
     IntPoint origin;
     unsigned bitfields : 16;
index e231f6b3fc8702f5131173dcd2b515e1d4d4f908..3fdaab4cd3cad6c782a8ae6dc47a0b96609bf6c1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008, 2011, 2014-2015 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008-2016 Apple Inc. All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -28,6 +28,7 @@
 
 #include "Scrollbar.h"
 #include <wtf/Vector.h>
+#include <wtf/WeakPtr.h>
 
 namespace WebCore {
 
@@ -63,6 +64,8 @@ public:
 
     WEBCORE_EXPORT bool handleWheelEvent(const PlatformWheelEvent&);
 
+    WeakPtr<ScrollableArea> createWeakPtr() { return m_weakPtrFactory.createWeakPtr(); }
+
 #if ENABLE(CSS_SCROLL_SNAP)
     const Vector<LayoutUnit>* horizontalSnapOffsets() const { return m_horizontalSnapOffsets.get(); };
     const Vector<LayoutUnit>* verticalSnapOffsets() const { return m_verticalSnapOffsets.get(); };
@@ -349,6 +352,8 @@ private:
 
     mutable std::unique_ptr<ScrollAnimator> m_scrollAnimator;
 
+    WeakPtrFactory<ScrollableArea> m_weakPtrFactory { this };
+
 #if ENABLE(CSS_SCROLL_SNAP)
     std::unique_ptr<Vector<LayoutUnit>> m_horizontalSnapOffsets;
     std::unique_ptr<Vector<LayoutUnit>> m_verticalSnapOffsets;
index 29191a4eafdee75d59366e6a5ca9c1a6a912b708..28c001967ff395368e83e347201d87202c19018e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004, 2005, 2006 Apple Inc.  All rights reserved.
+ * Copyright (C) 2004-2016 Apple Inc.  All rights reserved.
  * Copyright (C) 2008 Collabora Ltd.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -38,6 +38,7 @@
 #include <wtf/Forward.h>
 #include <wtf/RefCounted.h>
 #include <wtf/TypeCasts.h>
+#include <wtf/WeakPtr.h>
 
 #if PLATFORM(COCOA)
 #include <wtf/RetainPtr.h>
@@ -191,6 +192,8 @@ public:
     WEBCORE_EXPORT virtual IntPoint convertToContainingView(const IntPoint&) const;
     WEBCORE_EXPORT virtual IntPoint convertFromContainingView(const IntPoint&) const;
 
+    WeakPtr<Widget> createWeakPtr() { return m_weakPtrFactory.createWeakPtr(); }
+
 private:
     void init(PlatformWidget); // Must be called by all Widget constructors to initialize cross-platform data.
 
@@ -212,6 +215,7 @@ private:
 #else
     RetainPtr<NSView> m_widget;
 #endif
+    WeakPtrFactory<Widget> m_weakPtrFactory { this };
     bool m_selfVisible;
     bool m_parentVisible;