<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[181879] trunk/Source/WebCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/181879">181879</a></dd>
<dt>Author</dt> <dd>bfulgham@apple.com</dd>
<dt>Date</dt> <dd>2015-03-23 15:52:27 -0700 (Mon, 23 Mar 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Scroll latching logic can get stuck in 'scrollable=&quot;no&quot;' iframes
https://bugs.webkit.org/show_bug.cgi?id=142789
&lt;rdar://problem/20129494&gt;

Reviewed by Dean Jackson.

Clean up the EventHandler and latching code as follows:
(1) Do not handle iframe elements as part of the normal latching logic. Instead, iframes should
    be evaluated during the 'platformCompleteWheelEvent' phase of processing as top-level scrolling
    frames.
(2) Get rid of the ill-conceived notation that we should process non-mainframe and main-frame frames
    different.
(3) Modify code to reflect that the scroll latching code really deals with overflow scrolling. Consequently,
    the 'findEnclosingScrollableContainer' was renamed to 'findEnclosingOverflowScroll' and does not
    treat iframe as a suitable target.
(4) Do not create a latching state object when the container being evaluated is already scrolled to the
    extreme position in the direction of the mouse gesture. In this case, we want the enclosing frame
    to be the latching target.
(5) Do not treat the state where the mouse wheel gesture has ended manual scrolling, but has not ended
    momentum scrolling, as an appropriate time to select a latching target.

* page/EventHandler.cpp:
(WebCore::EventHandler::platformCompleteWheelEvent): Modify signature to remove unneeded argument.
(WebCore::EventHandler::handleWheelEvent): Modify call to 'platformCompleteWheelEvent' to remove unused argument.
* page/EventHandler.h:
* page/mac/EventHandlerMac.mm:
(WebCore::findEnclosingOverflowScroll): Renamed from 'findEnclosingScrollableContainer' and revised per the
notes above.
(WebCore::EventHandler::platformPrepareForWheelEvents): Remove mainFrame vs. non-mainFrame code paths and
consolidate logic.
(WebCore::EventHandler::platformCompleteWheelEvent): Remove unused argument. The wheel event target is no
longer needed here, now that iframes are not processed by this code.
(WebCore::findEnclosingScrollableContainer): Deleted.
* page/scrolling/ScrollLatchingState.cpp:
(WebCore::ScrollLatchingState::setPreviousWheelScrolledElement:) Switch to move operator for passing
a temporary RefPtr to the the function.
* page/scrolling/ScrollLatchingState.h:
* platform/PlatformWheelEvent.h:
(WebCore::PlatformWheelEvent::useLatchedEventElement): Recognize 'phase=ended, momentum=none' as a state
that should not cause latching state to be revised.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorepageEventHandlercpp">trunk/Source/WebCore/page/EventHandler.cpp</a></li>
<li><a href="#trunkSourceWebCorepageEventHandlerh">trunk/Source/WebCore/page/EventHandler.h</a></li>
<li><a href="#trunkSourceWebCorepagemacEventHandlerMacmm">trunk/Source/WebCore/page/mac/EventHandlerMac.mm</a></li>
<li><a href="#trunkSourceWebCorepagescrollingScrollLatchingStatecpp">trunk/Source/WebCore/page/scrolling/ScrollLatchingState.cpp</a></li>
<li><a href="#trunkSourceWebCorepagescrollingScrollLatchingStateh">trunk/Source/WebCore/page/scrolling/ScrollLatchingState.h</a></li>
<li><a href="#trunkSourceWebCoreplatformPlatformWheelEventh">trunk/Source/WebCore/platform/PlatformWheelEvent.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (181878 => 181879)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2015-03-23 22:50:39 UTC (rev 181878)
+++ trunk/Source/WebCore/ChangeLog        2015-03-23 22:52:27 UTC (rev 181879)
</span><span class="lines">@@ -1,3 +1,46 @@
</span><ins>+2015-03-23  Brent Fulgham  &lt;bfulgham@apple.com&gt;
+
+        Scroll latching logic can get stuck in 'scrollable=&quot;no&quot;' iframes
+        https://bugs.webkit.org/show_bug.cgi?id=142789
+        &lt;rdar://problem/20129494&gt;
+
+        Reviewed by Dean Jackson.
+
+        Clean up the EventHandler and latching code as follows:
+        (1) Do not handle iframe elements as part of the normal latching logic. Instead, iframes should
+            be evaluated during the 'platformCompleteWheelEvent' phase of processing as top-level scrolling
+            frames.
+        (2) Get rid of the ill-conceived notation that we should process non-mainframe and main-frame frames
+            different.
+        (3) Modify code to reflect that the scroll latching code really deals with overflow scrolling. Consequently,
+            the 'findEnclosingScrollableContainer' was renamed to 'findEnclosingOverflowScroll' and does not
+            treat iframe as a suitable target.
+        (4) Do not create a latching state object when the container being evaluated is already scrolled to the
+            extreme position in the direction of the mouse gesture. In this case, we want the enclosing frame
+            to be the latching target.
+        (5) Do not treat the state where the mouse wheel gesture has ended manual scrolling, but has not ended
+            momentum scrolling, as an appropriate time to select a latching target.
+
+        * page/EventHandler.cpp:
+        (WebCore::EventHandler::platformCompleteWheelEvent): Modify signature to remove unneeded argument.
+        (WebCore::EventHandler::handleWheelEvent): Modify call to 'platformCompleteWheelEvent' to remove unused argument.
+        * page/EventHandler.h:
+        * page/mac/EventHandlerMac.mm:
+        (WebCore::findEnclosingOverflowScroll): Renamed from 'findEnclosingScrollableContainer' and revised per the
+        notes above.
+        (WebCore::EventHandler::platformPrepareForWheelEvents): Remove mainFrame vs. non-mainFrame code paths and
+        consolidate logic.
+        (WebCore::EventHandler::platformCompleteWheelEvent): Remove unused argument. The wheel event target is no
+        longer needed here, now that iframes are not processed by this code.
+        (WebCore::findEnclosingScrollableContainer): Deleted.
+        * page/scrolling/ScrollLatchingState.cpp:
+        (WebCore::ScrollLatchingState::setPreviousWheelScrolledElement:) Switch to move operator for passing
+        a temporary RefPtr to the the function.
+        * page/scrolling/ScrollLatchingState.h:
+        * platform/PlatformWheelEvent.h:
+        (WebCore::PlatformWheelEvent::useLatchedEventElement): Recognize 'phase=ended, momentum=none' as a state
+        that should not cause latching state to be revised.
+
</ins><span class="cx"> 2015-03-23  Anders Carlsson  &lt;andersca@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Try to fix the iOS build.
</span></span></pre></div>
<a id="trunkSourceWebCorepageEventHandlercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/EventHandler.cpp (181878 => 181879)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/EventHandler.cpp        2015-03-23 22:50:39 UTC (rev 181878)
+++ trunk/Source/WebCore/page/EventHandler.cpp        2015-03-23 22:52:27 UTC (rev 181879)
</span><span class="lines">@@ -2612,7 +2612,7 @@
</span><span class="cx">     m_frame.mainFrame().wheelEventDeltaTracker()-&gt;recordWheelEventDelta(event);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool EventHandler::platformCompleteWheelEvent(const PlatformWheelEvent&amp; event, Element*, ContainerNode*, ScrollableArea*)
</del><ins>+bool EventHandler::platformCompleteWheelEvent(const PlatformWheelEvent&amp; event, ContainerNode*, ScrollableArea*)
</ins><span class="cx"> {
</span><span class="cx">     // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed.
</span><span class="cx">     FrameView* view = m_frame.view();
</span><span class="lines">@@ -2708,7 +2708,7 @@
</span><span class="cx">     if (scrollableArea)
</span><span class="cx">         scrollableArea-&gt;setScrolledProgrammatically(false);
</span><span class="cx"> 
</span><del>-    return platformCompleteWheelEvent(event, element.get(), scrollableContainer.get(), scrollableArea);
</del><ins>+    return platformCompleteWheelEvent(event, scrollableContainer.get(), scrollableArea);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void EventHandler::clearLatchedState()
</span></span></pre></div>
<a id="trunkSourceWebCorepageEventHandlerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/EventHandler.h (181878 => 181879)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/EventHandler.h        2015-03-23 22:50:39 UTC (rev 181878)
+++ trunk/Source/WebCore/page/EventHandler.h        2015-03-23 22:52:27 UTC (rev 181879)
</span><span class="lines">@@ -206,7 +206,7 @@
</span><span class="cx"> 
</span><span class="cx">     void platformPrepareForWheelEvents(const PlatformWheelEvent&amp;, const HitTestResult&amp;, RefPtr&lt;Element&gt;&amp; eventTarget, RefPtr&lt;ContainerNode&gt;&amp; scrollableContainer, ScrollableArea*&amp;, bool&amp; isOverWidget);
</span><span class="cx">     void platformRecordWheelEvent(const PlatformWheelEvent&amp;);
</span><del>-    bool platformCompleteWheelEvent(const PlatformWheelEvent&amp;, Element* eventTarget, ContainerNode* scrollableContainer, ScrollableArea*);
</del><ins>+    bool platformCompleteWheelEvent(const PlatformWheelEvent&amp;, ContainerNode* scrollableContainer, ScrollableArea*);
</ins><span class="cx">     bool platformCompletePlatformWidgetWheelEvent(const PlatformWheelEvent&amp;, const Widget&amp;, ContainerNode* scrollableContainer);
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(CSS_SCROLL_SNAP)
</span></span></pre></div>
<a id="trunkSourceWebCorepagemacEventHandlerMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/mac/EventHandlerMac.mm (181878 => 181879)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/mac/EventHandlerMac.mm        2015-03-23 22:50:39 UTC (rev 181878)
+++ trunk/Source/WebCore/page/mac/EventHandlerMac.mm        2015-03-23 22:52:27 UTC (rev 181879)
</span><span class="lines">@@ -37,6 +37,8 @@
</span><span class="cx"> #include &quot;Frame.h&quot;
</span><span class="cx"> #include &quot;FrameLoader.h&quot;
</span><span class="cx"> #include &quot;FrameView.h&quot;
</span><ins>+#include &quot;HTMLDocument.h&quot;
+#include &quot;HTMLIFrameElement.h&quot;
</ins><span class="cx"> #include &quot;KeyboardEvent.h&quot;
</span><span class="cx"> #include &quot;MainFrame.h&quot;
</span><span class="cx"> #include &quot;MouseEventWithHitTestResults.h&quot;
</span><span class="lines">@@ -737,11 +739,17 @@
</span><span class="cx">     return PlatformEvent::CtrlKey | PlatformEvent::AltKey;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static ContainerNode* findEnclosingScrollableContainer(ContainerNode* node)
</del><ins>+static ContainerNode* findEnclosingOverflowScroll(ContainerNode* node)
</ins><span class="cx"> {
</span><span class="cx">     // Find the first node with a valid scrollable area starting with the current
</span><span class="cx">     // node and traversing its parents (or shadow hosts).
</span><span class="cx">     for (ContainerNode* candidate = node; candidate; candidate = candidate-&gt;parentOrShadowHostNode()) {
</span><ins>+        if (is&lt;HTMLIFrameElement&gt;(candidate))
+            continue;
+
+        if (is&lt;HTMLHtmlElement&gt;(candidate) || is&lt;HTMLDocument&gt;(candidate))
+            return nullptr;
+
</ins><span class="cx">         RenderBox* box = candidate-&gt;renderBox();
</span><span class="cx">         if (box &amp;&amp; box-&gt;canBeScrolledAndHasScrollableArea())
</span><span class="cx">             return candidate;
</span><span class="lines">@@ -849,15 +857,14 @@
</span><span class="cx"> 
</span><span class="cx">     scrollableContainer = nullptr;
</span><span class="cx">     scrollableArea = nullptr;
</span><del>-    if (!view || !view-&gt;frame().isMainFrame()) {
</del><ins>+    if (!view)
</ins><span class="cx">         scrollableContainer = wheelEventTarget;
</span><del>-        scrollableArea = view;
-    } else {
</del><ins>+    else {
</ins><span class="cx">         if (eventTargetIsPlatformWidget(wheelEventTarget.get())) {
</span><span class="cx">             scrollableContainer = wheelEventTarget;
</span><span class="cx">             scrollableArea = scrollViewForEventTarget(wheelEventTarget.get());
</span><span class="cx">         } else {
</span><del>-            scrollableContainer = findEnclosingScrollableContainer(wheelEventTarget.get());
</del><ins>+            scrollableContainer = findEnclosingOverflowScroll(wheelEventTarget.get());
</ins><span class="cx">             if (scrollableContainer) {
</span><span class="cx">                 if (RenderBox* box = scrollableContainer-&gt;renderBox()) {
</span><span class="cx">                     if (is&lt;RenderListBox&gt;(*box))
</span><span class="lines">@@ -865,25 +872,30 @@
</span><span class="cx">                     else
</span><span class="cx">                         scrollableArea = box-&gt;layer();
</span><span class="cx">                 }
</span><ins>+            } else {
+                scrollableContainer = view-&gt;frame().document()-&gt;bodyOrFrameset();
+                scrollableArea = view;
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     ScrollLatchingState* latchingState = m_frame.mainFrame().latchingState();
</span><span class="cx">     if (wheelEvent.shouldConsiderLatching()) {
</span><del>-        m_frame.mainFrame().pushNewLatchingState();
-        latchingState = m_frame.mainFrame().latchingState();
-        if (scrollableArea &amp;&amp; scrollableContainer)
-            latchingState-&gt;setStartedGestureAtScrollLimit(scrolledToEdgeInDominantDirection(*scrollableContainer, *scrollableArea, wheelEvent.deltaX(), wheelEvent.deltaY()));
-        else
-            latchingState-&gt;setStartedGestureAtScrollLimit(false);
-        latchingState-&gt;setWheelEventElement(wheelEventTarget);
-        latchingState-&gt;setFrame(&amp;m_frame);
-        // FIXME: What prevents us from deleting this scrollable container while still holding a pointer to it?
-        latchingState-&gt;setScrollableContainer(scrollableContainer);
-        latchingState-&gt;setWidgetIsLatched(result.isOverWidget());
-        isOverWidget = latchingState-&gt;widgetIsLatched();
-        m_frame.mainFrame().wheelEventDeltaTracker()-&gt;beginTrackingDeltas();
</del><ins>+        if (scrollableContainer &amp;&amp; scrollableArea) {
+            bool startingAtScrollLimit = scrolledToEdgeInDominantDirection(*scrollableContainer, *scrollableArea, wheelEvent.deltaX(), wheelEvent.deltaY());
+            if (!startingAtScrollLimit) {
+                m_frame.mainFrame().pushNewLatchingState();
+                latchingState = m_frame.mainFrame().latchingState();
+                latchingState-&gt;setStartedGestureAtScrollLimit(false);
+                latchingState-&gt;setWheelEventElement(wheelEventTarget);
+                latchingState-&gt;setFrame(&amp;m_frame);
+                // FIXME: What prevents us from deleting this scrollable container while still holding a pointer to it?
+                latchingState-&gt;setScrollableContainer(scrollableContainer);
+                latchingState-&gt;setWidgetIsLatched(result.isOverWidget());
+                isOverWidget = latchingState-&gt;widgetIsLatched();
+                m_frame.mainFrame().wheelEventDeltaTracker()-&gt;beginTrackingDeltas();
+            }
+        }
</ins><span class="cx">     } else if (wheelEvent.shouldResetLatching())
</span><span class="cx">         clearLatchedState();
</span><span class="cx"> 
</span><span class="lines">@@ -923,40 +935,37 @@
</span><span class="cx">     return latchingState-&gt;frame() ? latchingState-&gt;frame()-&gt;view() : frame.view();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool EventHandler::platformCompleteWheelEvent(const PlatformWheelEvent&amp; wheelEvent, Element* wheelEventTarget, ContainerNode* scrollableContainer, ScrollableArea* scrollableArea)
</del><ins>+bool EventHandler::platformCompleteWheelEvent(const PlatformWheelEvent&amp; wheelEvent, ContainerNode* scrollableContainer, ScrollableArea* scrollableArea)
</ins><span class="cx"> {
</span><span class="cx">     // We do another check on the frame view because the event handler can run JS which results in the frame getting destroyed.
</span><span class="cx">     FrameView* view = m_frame.view();
</span><span class="cx"> 
</span><span class="cx">     ScrollLatchingState* latchingState = m_frame.mainFrame().latchingState();
</span><span class="cx">     if (wheelEvent.useLatchedEventElement() &amp;&amp; latchingState &amp;&amp; latchingState-&gt;scrollableContainer()) {
</span><del>-        view = frameViewForLatchingState(m_frame, latchingState);
-        if (!view || !view-&gt;frame().isMainFrame()) {
-            bool didHandleWheelEvent = view &amp;&amp; view-&gt;wheelEvent(wheelEvent);
-            if (scrollableContainer == latchingState-&gt;scrollableContainer()) {
-                // If we are just starting a scroll event, and have nowhere left to scroll, allow
-                // the enclosing frame to handle the scroll.
-                didHandleWheelEvent = !latchingState-&gt;startedGestureAtScrollLimit();
-                if (!didHandleWheelEvent)
-                    m_frame.mainFrame().popLatchingState();
-            }
</del><span class="cx"> 
</span><del>-            // If the platform widget is handling the event, we always want to return false
-            if (view &amp;&amp; scrollableArea == view &amp;&amp; view-&gt;platformWidget())
-                didHandleWheelEvent = false;
-            
-            m_isHandlingWheelEvent = false;
-            return didHandleWheelEvent;
</del><ins>+        m_isHandlingWheelEvent = false;
+
+        // WebKit2 code path
+        if (!frameHasPlatformWidget(m_frame) &amp;&amp; !latchingState-&gt;startedGestureAtScrollLimit() &amp;&amp; scrollableContainer == latchingState-&gt;scrollableContainer() &amp;&amp; scrollableArea &amp;&amp; view != scrollableArea) {
+            // If we did not start at the scroll limit, do not pass the event on to be handled by enclosing scrollable regions.
+            return true;
</ins><span class="cx">         }
</span><del>-        
-        if (scrollableArea &amp;&amp; !latchingState-&gt;startedGestureAtScrollLimit() &amp;&amp; scrollableContainer == latchingState-&gt;scrollableContainer()) {
-            m_isHandlingWheelEvent = false;
</del><span class="cx"> 
</span><del>-            if (eventTargetIsPlatformWidget(wheelEventTarget))
-                return !latchingState-&gt;startedGestureAtScrollLimit();
</del><ins>+        if (!latchingState-&gt;startedGestureAtScrollLimit())
+            view = frameViewForLatchingState(m_frame, latchingState);
</ins><span class="cx"> 
</span><del>-            return true;
</del><ins>+        bool didHandleWheelEvent = view &amp;&amp; view-&gt;wheelEvent(wheelEvent);
+        if (scrollableContainer == latchingState-&gt;scrollableContainer()) {
+            // If we are just starting a scroll event, and have nowhere left to scroll, allow
+            // the enclosing frame to handle the scroll.
+            didHandleWheelEvent = !latchingState-&gt;startedGestureAtScrollLimit();
</ins><span class="cx">         }
</span><ins>+
+        // If the platform widget is handling the event, we always want to return false.
+        if (view &amp;&amp; scrollableArea == view &amp;&amp; view-&gt;platformWidget())
+            didHandleWheelEvent = false;
+        
+        return didHandleWheelEvent;
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     bool didHandleEvent = view ? view-&gt;wheelEvent(wheelEvent) : false;
</span></span></pre></div>
<a id="trunkSourceWebCorepagescrollingScrollLatchingStatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/scrolling/ScrollLatchingState.cpp (181878 => 181879)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/scrolling/ScrollLatchingState.cpp        2015-03-23 22:50:39 UTC (rev 181878)
+++ trunk/Source/WebCore/page/scrolling/ScrollLatchingState.cpp        2015-03-23 22:52:27 UTC (rev 181879)
</span><span class="lines">@@ -60,7 +60,7 @@
</span><span class="cx">     m_widgetIsLatched = isOverWidget;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void ScrollLatchingState::setPreviousWheelScrolledElement(PassRefPtr&lt;Element&gt; element)
</del><ins>+void ScrollLatchingState::setPreviousWheelScrolledElement(RefPtr&lt;Element&gt;&amp;&amp; element)
</ins><span class="cx"> {
</span><span class="cx">     m_previousWheelScrolledElement = element;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCorepagescrollingScrollLatchingStateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/page/scrolling/ScrollLatchingState.h (181878 => 181879)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/page/scrolling/ScrollLatchingState.h        2015-03-23 22:50:39 UTC (rev 181878)
+++ trunk/Source/WebCore/page/scrolling/ScrollLatchingState.h        2015-03-23 22:52:27 UTC (rev 181879)
</span><span class="lines">@@ -50,7 +50,7 @@
</span><span class="cx">     void setWidgetIsLatched(bool isOverWidget);
</span><span class="cx"> 
</span><span class="cx">     Element* previousWheelScrolledElement() { return m_previousWheelScrolledElement.get(); }
</span><del>-    void setPreviousWheelScrolledElement(PassRefPtr&lt;Element&gt;);
</del><ins>+    void setPreviousWheelScrolledElement(RefPtr&lt;Element&gt;&amp;&amp;);
</ins><span class="cx">     
</span><span class="cx">     ContainerNode* scrollableContainer() { return m_scrollableContainer.get(); }
</span><span class="cx">     void setScrollableContainer(PassRefPtr&lt;ContainerNode&gt;);
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformPlatformWheelEventh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/PlatformWheelEvent.h (181878 => 181879)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/PlatformWheelEvent.h        2015-03-23 22:50:39 UTC (rev 181878)
+++ trunk/Source/WebCore/platform/PlatformWheelEvent.h        2015-03-23 22:52:27 UTC (rev 181879)
</span><span class="lines">@@ -165,7 +165,8 @@
</span><span class="cx">         bool useLatchedEventElement() const
</span><span class="cx">         {
</span><span class="cx">             return m_phase == PlatformWheelEventPhaseBegan || m_phase == PlatformWheelEventPhaseChanged
</span><del>-                || m_momentumPhase == PlatformWheelEventPhaseBegan || m_momentumPhase == PlatformWheelEventPhaseChanged;
</del><ins>+                || m_momentumPhase == PlatformWheelEventPhaseBegan || m_momentumPhase == PlatformWheelEventPhaseChanged
+                || (m_phase == PlatformWheelEventPhaseEnded &amp;&amp; m_momentumPhase == PlatformWheelEventPhaseNone);
</ins><span class="cx">         }
</span><span class="cx">         bool shouldConsiderLatching() const
</span><span class="cx">         {
</span></span></pre>
</div>
</div>

</body>
</html>