Title: [172649] trunk/Source
Revision
172649
Author
[email protected]
Date
2014-08-15 14:09:13 -0700 (Fri, 15 Aug 2014)

Log Message

Implement snapping behavior for iOS
https://bugs.webkit.org/show_bug.cgi?id=135769

Patch by Wenson Hsieh <[email protected]> on 2014-08-15
Reviewed by Brent Fulgham.

Source/WebCore:

Added support for snap points on iOS. This entails sending snap points from the web process to the UI process
by encoding and decoding snap points and updating ScrollingTreeOverflowScrollingNodeIOS and WKWebView to support
animation to snap points in the cases of mainframe and overflow scrolling, respectively.

There are no new tests yet -- we'll need to find a way to test this!

* WebCore.exp.in:
* page/scrolling/AsyncScrollingCoordinator.cpp:
(WebCore::setStateScrollingNodeSnapOffsetsAsFloat): Helper functions used to convert LayoutUnits to floats for snap offsets.
(WebCore::AsyncScrollingCoordinator::frameViewLayoutUpdated): Update snap offsets for mainframe scrolling, as well as the state node.
(WebCore::AsyncScrollingCoordinator::updateOverflowScrollingNode): Added snap offsets.
* page/scrolling/AxisScrollSnapOffsets.h:
(WebCore::closestSnapOffset): Computes the closest snap offset given a sorted vector of comparable types (e.g. float, LayoutUnit).
* page/scrolling/ScrollingCoordinator.h:
* page/scrolling/ScrollingStateScrollingNode.cpp:
(WebCore::ScrollingStateScrollingNode::ScrollingStateScrollingNode):
(WebCore::ScrollingStateScrollingNode::setHorizontalSnapOffsets):
(WebCore::ScrollingStateScrollingNode::setVerticalSnapOffsets):
* page/scrolling/ScrollingStateScrollingNode.h:
(WebCore::ScrollingStateScrollingNode::horizontalSnapOffsets):
(WebCore::ScrollingStateScrollingNode::verticalSnapOffsets):
* page/scrolling/ScrollingTreeScrollingNode.cpp:
(WebCore::ScrollingTreeScrollingNode::updateBeforeChildren):
* page/scrolling/ScrollingTreeScrollingNode.h:
(WebCore::ScrollingTreeScrollingNode::horizontalSnapOffsets):
(WebCore::ScrollingTreeScrollingNode::verticalSnapOffsets):
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::updateScrollInfoAfterLayout): Update snap offsets for overflow scrolling.
* rendering/RenderLayerCompositor.cpp:
(WebCore::RenderLayerCompositor::updateScrollCoordinatedLayer): Updates the state node's snap offsets for overflow scrolling.

Source/WebKit2:

Added support for snap points on iOS.

* Shared/Scrolling/RemoteScrollingCoordinatorTransaction.cpp:
(ArgumentCoder<ScrollingStateScrollingNode>::encode): Added snap offset encoding.
(ArgumentCoder<ScrollingStateScrollingNode>::decode): Added snap offset decoding.
* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView scrollViewWillEndDragging:withVelocity:targetContentOffset:]): For mainframe scrolling, retargets the scroll destination to the appropriate snap point.
* UIProcess/Scrolling/RemoteScrollingCoordinatorProxy.h: Added methods to extract relevant information for WKWebView from snap offsets in mainframe scrolling.
* UIProcess/Scrolling/ios/ScrollingTreeOverflowScrollingNodeIOS.mm:
(-[WKOverflowScrollViewDelegate scrollViewWillEndDragging:withVelocity:targetContentOffset:]): For overflow scrolling, retargets the scroll destination to the appropriate snap point.
(WebKit::ScrollingTreeOverflowScrollingNodeIOS::updateAfterChildren): Sets the deceleration factor to FAST if snap points are active.
* UIProcess/ios/RemoteScrollingCoordinatorProxyIOS.mm:
(WebKit::RemoteScrollingCoordinatorProxy::adjustTargetContentOffsetForSnapping): Used by WKWebView for mainframe scrolling to retarget the scroll destination, if necessary.
(WebKit::RemoteScrollingCoordinatorProxy::shouldSetScrollViewDecelerationRateFast): Used by WKWebView for mainframe scrolling to determine whether to set deceleration rate to the fast value.
(WebKit::RemoteScrollingCoordinatorProxy::shouldSnapForMainFrameScrolling): Helper method.
(WebKit::RemoteScrollingCoordinatorProxy::closestSnapOffsetForMainFrameScrolling): Helper method.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (172648 => 172649)


--- trunk/Source/WebCore/ChangeLog	2014-08-15 21:04:31 UTC (rev 172648)
+++ trunk/Source/WebCore/ChangeLog	2014-08-15 21:09:13 UTC (rev 172649)
@@ -1,3 +1,41 @@
+2014-08-15  Wenson Hsieh  <[email protected]>
+
+        Implement snapping behavior for iOS
+        https://bugs.webkit.org/show_bug.cgi?id=135769
+
+        Reviewed by Brent Fulgham.
+
+        Added support for snap points on iOS. This entails sending snap points from the web process to the UI process
+        by encoding and decoding snap points and updating ScrollingTreeOverflowScrollingNodeIOS and WKWebView to support
+        animation to snap points in the cases of mainframe and overflow scrolling, respectively.
+
+        There are no new tests yet -- we'll need to find a way to test this!
+
+        * WebCore.exp.in:
+        * page/scrolling/AsyncScrollingCoordinator.cpp:
+        (WebCore::setStateScrollingNodeSnapOffsetsAsFloat): Helper functions used to convert LayoutUnits to floats for snap offsets.
+        (WebCore::AsyncScrollingCoordinator::frameViewLayoutUpdated): Update snap offsets for mainframe scrolling, as well as the state node.
+        (WebCore::AsyncScrollingCoordinator::updateOverflowScrollingNode): Added snap offsets.
+        * page/scrolling/AxisScrollSnapOffsets.h:
+        (WebCore::closestSnapOffset): Computes the closest snap offset given a sorted vector of comparable types (e.g. float, LayoutUnit).
+        * page/scrolling/ScrollingCoordinator.h:
+        * page/scrolling/ScrollingStateScrollingNode.cpp:
+        (WebCore::ScrollingStateScrollingNode::ScrollingStateScrollingNode):
+        (WebCore::ScrollingStateScrollingNode::setHorizontalSnapOffsets):
+        (WebCore::ScrollingStateScrollingNode::setVerticalSnapOffsets):
+        * page/scrolling/ScrollingStateScrollingNode.h:
+        (WebCore::ScrollingStateScrollingNode::horizontalSnapOffsets):
+        (WebCore::ScrollingStateScrollingNode::verticalSnapOffsets):
+        * page/scrolling/ScrollingTreeScrollingNode.cpp:
+        (WebCore::ScrollingTreeScrollingNode::updateBeforeChildren):
+        * page/scrolling/ScrollingTreeScrollingNode.h:
+        (WebCore::ScrollingTreeScrollingNode::horizontalSnapOffsets):
+        (WebCore::ScrollingTreeScrollingNode::verticalSnapOffsets):
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::updateScrollInfoAfterLayout): Update snap offsets for overflow scrolling.
+        * rendering/RenderLayerCompositor.cpp:
+        (WebCore::RenderLayerCompositor::updateScrollCoordinatedLayer): Updates the state node's snap offsets for overflow scrolling.
+
 2014-08-15  Dirk Schulze  <[email protected]>
 
         Turn r/rx/ry to presentation attributes

Modified: trunk/Source/WebCore/WebCore.exp.in (172648 => 172649)


--- trunk/Source/WebCore/WebCore.exp.in	2014-08-15 21:04:31 UTC (rev 172648)
+++ trunk/Source/WebCore/WebCore.exp.in	2014-08-15 21:09:13 UTC (rev 172649)
@@ -3011,6 +3011,11 @@
 __ZN7WebCore16FilterOperationsaSERKS0_
 #endif
 
+#if ENABLE(CSS_SCROLL_SNAP)
+__ZN7WebCore27ScrollingStateScrollingNode22setVerticalSnapOffsetsERKN3WTF6VectorIfLm0ENS1_15CrashOnOverflowEEE
+__ZN7WebCore27ScrollingStateScrollingNode24setHorizontalSnapOffsetsERKN3WTF6VectorIfLm0ENS1_15CrashOnOverflowEEE
+#endif
+
 #if ENABLE(DASHBOARD_SUPPORT)
 __ZNK7WebCore8Document16annotatedRegionsEv
 #endif

Modified: trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp (172648 => 172649)


--- trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp	2014-08-15 21:04:31 UTC (rev 172648)
+++ trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp	2014-08-15 21:09:13 UTC (rev 172649)
@@ -59,6 +59,20 @@
     scheduleTreeStateCommit();
 }
 
+static inline void setStateScrollingNodeSnapOffsetsAsFloat(ScrollingStateScrollingNode& node, ScrollEventAxis axis, const Vector<LayoutUnit>& snapOffsets, float deviceScaleFactor)
+{
+    // FIXME: Incorporate current page scale factor in snapping to device pixel. Perhaps we should just convert to float here and let UI process do the pixel snapping?
+    Vector<float> snapOffsetsAsFloat;
+    snapOffsetsAsFloat.reserveInitialCapacity(snapOffsets.size());
+    for (size_t i = 0; i < snapOffsets.size(); ++i)
+        snapOffsetsAsFloat.append(roundToDevicePixel(snapOffsets[i], deviceScaleFactor, false));
+
+    if (axis == ScrollEventAxis::Horizontal)
+        node.setHorizontalSnapOffsets(snapOffsetsAsFloat);
+    else
+        node.setVerticalSnapOffsets(snapOffsetsAsFloat);
+}
+
 void AsyncScrollingCoordinator::frameViewLayoutUpdated(FrameView* frameView)
 {
     ASSERT(isMainThread());
@@ -97,6 +111,15 @@
     node->setTotalContentsSize(frameView->totalContentsSize());
     node->setReachableContentsSize(frameView->totalContentsSize());
 
+#if ENABLE(CSS_SCROLL_SNAP)
+    frameView->updateSnapOffsets();
+    if (const Vector<LayoutUnit>* horizontalSnapOffsets = frameView->horizontalSnapOffsets())
+        setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Horizontal, *horizontalSnapOffsets, frameView->frame().document()->deviceScaleFactor());
+
+    if (const Vector<LayoutUnit>* verticalSnapOffsets = frameView->verticalSnapOffsets())
+        setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Vertical, *verticalSnapOffsets, frameView->frame().document()->deviceScaleFactor());
+#endif
+
     ScrollableAreaParameters scrollParameters;
     scrollParameters.horizontalScrollElasticity = frameView->horizontalScrollElasticity();
     scrollParameters.verticalScrollElasticity = frameView->verticalScrollElasticity();
@@ -399,6 +422,10 @@
         node->setTotalContentsSize(scrollingGeometry->contentSize);
         node->setReachableContentsSize(scrollingGeometry->reachableContentSize);
         node->setScrollableAreaSize(scrollingGeometry->scrollableAreaSize);
+#if ENABLE(CSS_SCROLL_SNAP)
+        setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Horizontal, scrollingGeometry->horizontalSnapOffsets, scrolledContentsLayer->deviceScaleFactor());
+        setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Vertical, scrollingGeometry->verticalSnapOffsets, scrolledContentsLayer->deviceScaleFactor());
+#endif
     }
 }
 

Modified: trunk/Source/WebCore/page/scrolling/AxisScrollSnapOffsets.cpp (172648 => 172649)


--- trunk/Source/WebCore/page/scrolling/AxisScrollSnapOffsets.cpp	2014-08-15 21:04:31 UTC (rev 172648)
+++ trunk/Source/WebCore/page/scrolling/AxisScrollSnapOffsets.cpp	2014-08-15 21:09:13 UTC (rev 172649)
@@ -43,14 +43,22 @@
         if (RenderBox* box = child->renderBox()) {
             LayoutUnit viewWidth = box->width();
             LayoutUnit viewHeight = box->height();
-            // FIXME: Check behavior with CSS rotations.
+#if PLATFORM(IOS)
+            // FIXME: Investigate why using localToContainerPoint gives the wrong offsets for iOS mainframe. Also, these offsets won't take transforms into account (make sure to test this!)
+            float left = child->offsetLeft();
+            float top = child->offsetTop();
+#else
+            // FIXME: Check that localToContainerPoint works with CSS rotations.
             FloatPoint position = box->localToContainerPoint(FloatPoint(), parent.renderBox());
+            float left = position.x();
+            float top = position.y();
+#endif
             for (SnapCoordinate coordinate : box->style().scrollSnapCoordinates()) {
-                LayoutUnit lastPotentialSnapPositionX = LayoutUnit(position.x()) + valueForLength(coordinate.first, viewWidth);
+                LayoutUnit lastPotentialSnapPositionX = LayoutUnit(left) + valueForLength(coordinate.first, viewWidth);
                 if (shouldAddHorizontalChildOffsets && lastPotentialSnapPositionX > 0)
                     horizontalSnapOffsetSubsequence.append(lastPotentialSnapPositionX);
 
-                LayoutUnit lastPotentialSnapPositionY = LayoutUnit(position.y()) + valueForLength(coordinate.second, viewHeight);
+                LayoutUnit lastPotentialSnapPositionY = LayoutUnit(top) + valueForLength(coordinate.second, viewHeight);
                 if (shouldAddVerticalChildOffsets && lastPotentialSnapPositionY > 0)
                     verticalSnapOffsetSubsequence.append(lastPotentialSnapPositionY);
             }

Modified: trunk/Source/WebCore/page/scrolling/AxisScrollSnapOffsets.h (172648 => 172649)


--- trunk/Source/WebCore/page/scrolling/AxisScrollSnapOffsets.h	2014-08-15 21:04:31 UTC (rev 172648)
+++ trunk/Source/WebCore/page/scrolling/AxisScrollSnapOffsets.h	2014-08-15 21:09:13 UTC (rev 172649)
@@ -41,8 +41,11 @@
 
 void updateSnapOffsetsForScrollableArea(ScrollableArea&, HTMLElement& scrollingElement, const RenderBox& scrollingElementBox, const RenderStyle& scrollingElementStyle);
 
-template <typename T>
-T closestSnapOffset(const Vector<T>& snapOffsets, T scrollDestination, float velocity)
+// closestSnapOffset is a templated function that takes in a Vector representing snap offsets as LayoutTypes (e.g. LayoutUnit or float) and
+// as well as a VelocityType indicating the velocity (e.g. float, CGFloat, etc.) This function is templated because the UI process will now
+// use pixel snapped floats to represent snap offsets rather than LayoutUnits.
+template <typename LayoutType, typename VelocityType>
+LayoutType closestSnapOffset(const Vector<LayoutType>& snapOffsets, LayoutType scrollDestination, VelocityType velocity)
 {
     ASSERT(snapOffsets.size());
     if (scrollDestination <= snapOffsets.first())
@@ -65,8 +68,8 @@
             break;
         }
     }
-    T lowerSnapPosition = snapOffsets[lowerIndex];
-    T upperSnapPosition = snapOffsets[upperIndex];
+    LayoutType lowerSnapPosition = snapOffsets[lowerIndex];
+    LayoutType upperSnapPosition = snapOffsets[upperIndex];
     // Nonzero velocity indicates a flick gesture. Even if another snap point is closer, snap to the one in the direction of the flick gesture.
     if (velocity)
         return velocity < 0 ? lowerSnapPosition : upperSnapPosition;

Modified: trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.h (172648 => 172649)


--- trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.h	2014-08-15 21:04:31 UTC (rev 172648)
+++ trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.h	2014-08-15 21:09:13 UTC (rev 172649)
@@ -43,6 +43,10 @@
 #include <wtf/RetainPtr.h>
 #endif
 
+#if ENABLE(CSS_SCROLL_SNAP)
+#include "AxisScrollSnapOffsets.h"
+#endif
+
 namespace WebCore {
 
 typedef unsigned SynchronousScrollingReasons;
@@ -164,6 +168,10 @@
         FloatSize reachableContentSize; // Smaller than contentSize when overflow is hidden on one axis.
         FloatPoint scrollPosition;
         IntPoint scrollOrigin;
+#if ENABLE(CSS_SCROLL_SNAP)
+        Vector<LayoutUnit> horizontalSnapOffsets;
+        Vector<LayoutUnit> verticalSnapOffsets;
+#endif
     };
 
     virtual void updateFrameScrollingNode(ScrollingNodeID, GraphicsLayer* /*scrollLayer*/, GraphicsLayer* /*scrolledContentsLayer*/, GraphicsLayer* /*counterScrollingLayer*/, GraphicsLayer* /*insetClipLayer*/, const ScrollingGeometry* = nullptr) { }

Modified: trunk/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.cpp (172648 => 172649)


--- trunk/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.cpp	2014-08-15 21:04:31 UTC (rev 172648)
+++ trunk/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.cpp	2014-08-15 21:09:13 UTC (rev 172649)
@@ -48,6 +48,10 @@
     , m_scrollPosition(stateNode.scrollPosition())
     , m_requestedScrollPosition(stateNode.requestedScrollPosition())
     , m_scrollOrigin(stateNode.scrollOrigin())
+#if ENABLE(CSS_SCROLL_SNAP)
+    , m_horizontalSnapOffsets(stateNode.horizontalSnapOffsets())
+    , m_verticalSnapOffsets(stateNode.verticalSnapOffsets())
+#endif
     , m_scrollableAreaParameters(stateNode.scrollableAreaParameters())
     , m_requestedScrollPositionRepresentsProgrammaticScroll(stateNode.requestedScrollPositionRepresentsProgrammaticScroll())
 {
@@ -102,6 +106,26 @@
     setPropertyChanged(ScrollOrigin);
 }
 
+#if ENABLE(CSS_SCROLL_SNAP)
+void ScrollingStateScrollingNode::setHorizontalSnapOffsets(const Vector<float>& snapOffsets)
+{
+    if (m_horizontalSnapOffsets == snapOffsets)
+        return;
+
+    m_horizontalSnapOffsets = snapOffsets;
+    setPropertyChanged(HorizontalSnapOffsets);
+}
+
+void ScrollingStateScrollingNode::setVerticalSnapOffsets(const Vector<float>& snapOffsets)
+{
+    if (m_verticalSnapOffsets == snapOffsets)
+        return;
+
+    m_verticalSnapOffsets = snapOffsets;
+    setPropertyChanged(VerticalSnapOffsets);
+}
+#endif
+
 void ScrollingStateScrollingNode::setScrollableAreaParameters(const ScrollableAreaParameters& parameters)
 {
     if (m_scrollableAreaParameters == parameters)

Modified: trunk/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.h (172648 => 172649)


--- trunk/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.h	2014-08-15 21:04:31 UTC (rev 172648)
+++ trunk/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.h	2014-08-15 21:09:13 UTC (rev 172649)
@@ -48,6 +48,10 @@
         ScrollableAreaParams,
         RequestedScrollPosition,
         NumScrollingStateNodeBits,
+#if ENABLE(CSS_SCROLL_SNAP)
+        HorizontalSnapOffsets,
+        VerticalSnapOffsets,
+#endif
     };
 
     const FloatSize& scrollableAreaSize() const { return m_scrollableAreaSize; }
@@ -65,6 +69,14 @@
     const IntPoint& scrollOrigin() const { return m_scrollOrigin; }
     void setScrollOrigin(const IntPoint&);
 
+#if ENABLE(CSS_SCROLL_SNAP)
+    const Vector<float>& horizontalSnapOffsets() const { return m_horizontalSnapOffsets; }
+    void setHorizontalSnapOffsets(const Vector<float>&);
+
+    const Vector<float>& verticalSnapOffsets() const { return m_verticalSnapOffsets; }
+    void setVerticalSnapOffsets(const Vector<float>&);
+#endif
+
     const ScrollableAreaParameters& scrollableAreaParameters() const { return m_scrollableAreaParameters; }
     void setScrollableAreaParameters(const ScrollableAreaParameters& params);
 
@@ -85,6 +97,10 @@
     FloatPoint m_scrollPosition;
     FloatPoint m_requestedScrollPosition;
     IntPoint m_scrollOrigin;
+#if ENABLE(CSS_SCROLL_SNAP)
+    Vector<float> m_horizontalSnapOffsets;
+    Vector<float> m_verticalSnapOffsets;
+#endif
     ScrollableAreaParameters m_scrollableAreaParameters;
     bool m_requestedScrollPositionRepresentsProgrammaticScroll;
 };

Modified: trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp (172648 => 172649)


--- trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp	2014-08-15 21:04:31 UTC (rev 172648)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp	2014-08-15 21:09:13 UTC (rev 172649)
@@ -67,6 +67,14 @@
     if (state.hasChangedProperty(ScrollingStateScrollingNode::ScrollOrigin))
         m_scrollOrigin = state.scrollOrigin();
 
+#if ENABLE(CSS_SCROLL_SNAP)
+    if (state.hasChangedProperty(ScrollingStateScrollingNode::HorizontalSnapOffsets))
+        m_horizontalSnapOffsets = state.horizontalSnapOffsets();
+
+    if (state.hasChangedProperty(ScrollingStateScrollingNode::VerticalSnapOffsets))
+        m_verticalSnapOffsets = state.verticalSnapOffsets();
+#endif
+
     if (state.hasChangedProperty(ScrollingStateScrollingNode::ScrollableAreaParams))
         m_scrollableAreaParameters = state.scrollableAreaParameters();
 }

Modified: trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h (172648 => 172649)


--- trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h	2014-08-15 21:04:31 UTC (rev 172648)
+++ trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h	2014-08-15 21:09:13 UTC (rev 172649)
@@ -57,6 +57,11 @@
 
     virtual FloatPoint scrollPosition() const = 0;
 
+#if ENABLE(CSS_SCROLL_SNAP)
+    const Vector<float>& horizontalSnapOffsets() const { return m_horizontalSnapOffsets; }
+    const Vector<float>& verticalSnapOffsets() const { return m_verticalSnapOffsets; }
+#endif
+
 protected:
     ScrollingTreeScrollingNode(ScrollingTree&, ScrollingNodeType, ScrollingNodeID);
 
@@ -92,7 +97,10 @@
     FloatSize m_reachableContentsSize;
     FloatPoint m_lastCommittedScrollPosition;
     IntPoint m_scrollOrigin;
-    
+#if ENABLE(CSS_SCROLL_SNAP)
+    Vector<float> m_horizontalSnapOffsets;
+    Vector<float> m_verticalSnapOffsets;
+#endif
     ScrollableAreaParameters m_scrollableAreaParameters;
 };
 

Modified: trunk/Source/WebCore/platform/mac/AxisScrollSnapAnimator.mm (172648 => 172649)


--- trunk/Source/WebCore/platform/mac/AxisScrollSnapAnimator.mm	2014-08-15 21:04:31 UTC (rev 172648)
+++ trunk/Source/WebCore/platform/mac/AxisScrollSnapAnimator.mm	2014-08-15 21:09:13 UTC (rev 172649)
@@ -169,7 +169,7 @@
     LayoutUnit projectedScrollDestination = newState == ScrollSnapState::Gliding ? m_beginTrackingWheelDeltaOffset + LayoutUnit(projectedInertialScrollDistance(initialWheelDelta)) : offset;
     projectedScrollDestination = std::min(std::max(projectedScrollDestination, m_snapOffsets->first()), m_snapOffsets->last());
     m_initialOffset = offset;
-    m_targetOffset = closestSnapOffset<LayoutUnit>(*m_snapOffsets, projectedScrollDestination, initialWheelDelta);
+    m_targetOffset = closestSnapOffset<LayoutUnit, float>(*m_snapOffsets, projectedScrollDestination, initialWheelDelta);
     if (m_initialOffset == m_targetOffset)
         return;
 

Modified: trunk/Source/WebCore/rendering/RenderLayer.cpp (172648 => 172649)


--- trunk/Source/WebCore/rendering/RenderLayer.cpp	2014-08-15 21:04:31 UTC (rev 172648)
+++ trunk/Source/WebCore/rendering/RenderLayer.cpp	2014-08-15 21:09:13 UTC (rev 172649)
@@ -3309,6 +3309,12 @@
     // Composited scrolling may need to be enabled or disabled if the amount of overflow changed.
     if (compositor().updateLayerCompositingState(*this))
         compositor().setCompositingLayersNeedRebuild();
+
+#if ENABLE(CSS_SCROLL_SNAP)
+    // FIXME: Ensure that offsets are also updated in case of programmatic style changes.
+    // https://bugs.webkit.org/show_bug.cgi?id=135964
+    updateSnapOffsets();
+#endif
 }
 
 bool RenderLayer::overflowControlsIntersectRect(const IntRect& localRect) const

Modified: trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp (172648 => 172649)


--- trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp	2014-08-15 21:04:31 UTC (rev 172648)
+++ trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp	2014-08-15 21:09:13 UTC (rev 172649)
@@ -3770,6 +3770,12 @@
             scrollingGeometry.scrollableAreaSize = layer.visibleSize();
             scrollingGeometry.contentSize = layer.contentsSize();
             scrollingGeometry.reachableContentSize = layer.scrollableContentsSize();
+#if ENABLE(CSS_SCROLL_SNAP)
+            if (const Vector<LayoutUnit>* offsets = layer.horizontalSnapOffsets())
+                scrollingGeometry.horizontalSnapOffsets = *offsets;
+            if (const Vector<LayoutUnit>* offsets = layer.verticalSnapOffsets())
+                scrollingGeometry.verticalSnapOffsets = *offsets;
+#endif
             scrollingCoordinator->updateOverflowScrollingNode(nodeID, backing->scrollingLayer(), backing->scrollingContentsLayer(), &scrollingGeometry);
         }
     }

Modified: trunk/Source/WebKit2/ChangeLog (172648 => 172649)


--- trunk/Source/WebKit2/ChangeLog	2014-08-15 21:04:31 UTC (rev 172648)
+++ trunk/Source/WebKit2/ChangeLog	2014-08-15 21:09:13 UTC (rev 172649)
@@ -1,3 +1,27 @@
+2014-08-15  Wenson Hsieh  <[email protected]>
+
+        Implement snapping behavior for iOS
+        https://bugs.webkit.org/show_bug.cgi?id=135769
+
+        Reviewed by Brent Fulgham.
+
+        Added support for snap points on iOS.
+
+        * Shared/Scrolling/RemoteScrollingCoordinatorTransaction.cpp:
+        (ArgumentCoder<ScrollingStateScrollingNode>::encode): Added snap offset encoding.
+        (ArgumentCoder<ScrollingStateScrollingNode>::decode): Added snap offset decoding.
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView scrollViewWillEndDragging:withVelocity:targetContentOffset:]): For mainframe scrolling, retargets the scroll destination to the appropriate snap point.
+        * UIProcess/Scrolling/RemoteScrollingCoordinatorProxy.h: Added methods to extract relevant information for WKWebView from snap offsets in mainframe scrolling.
+        * UIProcess/Scrolling/ios/ScrollingTreeOverflowScrollingNodeIOS.mm:
+        (-[WKOverflowScrollViewDelegate scrollViewWillEndDragging:withVelocity:targetContentOffset:]): For overflow scrolling, retargets the scroll destination to the appropriate snap point.
+        (WebKit::ScrollingTreeOverflowScrollingNodeIOS::updateAfterChildren): Sets the deceleration factor to FAST if snap points are active.
+        * UIProcess/ios/RemoteScrollingCoordinatorProxyIOS.mm:
+        (WebKit::RemoteScrollingCoordinatorProxy::adjustTargetContentOffsetForSnapping): Used by WKWebView for mainframe scrolling to retarget the scroll destination, if necessary.
+        (WebKit::RemoteScrollingCoordinatorProxy::shouldSetScrollViewDecelerationRateFast): Used by WKWebView for mainframe scrolling to determine whether to set deceleration rate to the fast value.
+        (WebKit::RemoteScrollingCoordinatorProxy::shouldSnapForMainFrameScrolling): Helper method.
+        (WebKit::RemoteScrollingCoordinatorProxy::closestSnapOffsetForMainFrameScrolling): Helper method.
+
 2014-08-15  Gavin Barraclough  <[email protected]>
 
         Fix plugin visibility check.

Modified: trunk/Source/WebKit2/Shared/Scrolling/RemoteScrollingCoordinatorTransaction.cpp (172648 => 172649)


--- trunk/Source/WebKit2/Shared/Scrolling/RemoteScrollingCoordinatorTransaction.cpp	2014-08-15 21:04:31 UTC (rev 172648)
+++ trunk/Source/WebKit2/Shared/Scrolling/RemoteScrollingCoordinatorTransaction.cpp	2014-08-15 21:09:13 UTC (rev 172649)
@@ -128,6 +128,10 @@
     SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::ReachableContentsSize, reachableContentsSize)
     SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::ScrollPosition, scrollPosition)
     SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::ScrollOrigin, scrollOrigin)
+#if ENABLE(CSS_SCROLL_SNAP)
+    SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::HorizontalSnapOffsets, horizontalSnapOffsets)
+    SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::VerticalSnapOffsets, verticalSnapOffsets)
+#endif
     SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::ScrollableAreaParams, scrollableAreaParameters)
     SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::RequestedScrollPosition, requestedScrollPosition)
     SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::RequestedScrollPosition, requestedScrollPositionRepresentsProgrammaticScroll)
@@ -193,6 +197,10 @@
     SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::ReachableContentsSize, FloatSize, setReachableContentsSize);
     SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::ScrollPosition, FloatPoint, setScrollPosition);
     SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::ScrollOrigin, IntPoint, setScrollOrigin);
+#if ENABLE(CSS_SCROLL_SNAP)
+    SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::HorizontalSnapOffsets, Vector<float>, setHorizontalSnapOffsets);
+    SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::VerticalSnapOffsets, Vector<float>, setVerticalSnapOffsets);
+#endif
     SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::ScrollableAreaParams, ScrollableAreaParameters, setScrollableAreaParameters);
     
     if (node.hasChangedProperty(ScrollingStateScrollingNode::RequestedScrollPosition)) {

Modified: trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm (172648 => 172649)


--- trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm	2014-08-15 21:04:31 UTC (rev 172648)
+++ trunk/Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm	2014-08-15 21:09:13 UTC (rev 172649)
@@ -83,6 +83,7 @@
 #import "PrintInfo.h"
 #import "ProcessThrottler.h"
 #import "RemoteLayerTreeDrawingAreaProxy.h"
+#import "RemoteScrollingCoordinatorProxy.h"
 #import "WKPDFView.h"
 #import "WKScrollView.h"
 #import "WKWebViewContentProviderRegistry.h"
@@ -1282,6 +1283,11 @@
     if (scrollView.panGestureRecognizer.state == UIGestureRecognizerStateBegan)
         [_contentView scrollViewWillStartPanOrPinchGesture];
     [_contentView willStartZoomOrScroll];
+#if ENABLE(CSS_SCROLL_SNAP) && ENABLE(ASYNC_SCROLLING)
+    // FIXME: We will want to detect whether snapping will occur before beginning to drag. See WebPageProxy::didCommitLayerTree.
+    WebKit::RemoteScrollingCoordinatorProxy* coordinator = _page->scrollingCoordinatorProxy();
+    scrollView.decelerationRate = (coordinator && coordinator->shouldSetScrollViewDecelerationRateFast()) ? UIScrollViewDecelerationRateFast : UIScrollViewDecelerationRateNormal;
+#endif
 }
 
 - (void)_didFinishScrolling
@@ -1299,6 +1305,13 @@
     // zooming. We'll animate to the right place once the zoom finishes.
     if ([scrollView isZooming])
         *targetContentOffset = [scrollView contentOffset];
+#if ENABLE(CSS_SCROLL_SNAP) && ENABLE(ASYNC_SCROLLING)
+    if (WebKit::RemoteScrollingCoordinatorProxy* coordinator = _page->scrollingCoordinatorProxy()) {
+        // FIXME: Here, I'm finding the maximum horizontal/vertical scroll offsets. There's probably a better way to do this.
+        CGSize maxScrollOffsets = CGSizeMake(scrollView.contentSize.width - scrollView.bounds.size.width, scrollView.contentSize.height - scrollView.bounds.size.height);
+        coordinator->adjustTargetContentOffsetForSnapping(maxScrollOffsets, velocity, targetContentOffset);
+    }
+#endif
 }
 
 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate

Modified: trunk/Source/WebKit2/UIProcess/Scrolling/RemoteScrollingCoordinatorProxy.h (172648 => 172649)


--- trunk/Source/WebKit2/UIProcess/Scrolling/RemoteScrollingCoordinatorProxy.h	2014-08-15 21:04:31 UTC (rev 172648)
+++ trunk/Source/WebKit2/UIProcess/Scrolling/RemoteScrollingCoordinatorProxy.h	2014-08-15 21:09:13 UTC (rev 172649)
@@ -84,10 +84,18 @@
     void scrollingTreeNodeWillStartPanGesture();
     void scrollingTreeNodeWillStartScroll();
     void scrollingTreeNodeDidEndScroll();
+#if ENABLE(CSS_SCROLL_SNAP)
+    void adjustTargetContentOffsetForSnapping(CGSize maxScrollDimensions, CGPoint velocity, CGPoint* targetContentOffset) const;
+    bool shouldSetScrollViewDecelerationRateFast() const;
 #endif
+#endif
 
 private:
     void connectStateNodeLayers(WebCore::ScrollingStateTree&, const RemoteLayerTreeHost&);
+#if ENABLE(CSS_SCROLL_SNAP)
+    bool shouldSnapForMainFrameScrolling(WebCore::ScrollEventAxis) const;
+    float closestSnapOffsetForMainFrameScrolling(WebCore::ScrollEventAxis, float scrollDestination, float velocity) const;
+#endif
 
     WebPageProxy& m_webPageProxy;
     RefPtr<RemoteScrollingTree> m_scrollingTree;

Modified: trunk/Source/WebKit2/UIProcess/Scrolling/ios/ScrollingTreeOverflowScrollingNodeIOS.mm (172648 => 172649)


--- trunk/Source/WebKit2/UIProcess/Scrolling/ios/ScrollingTreeOverflowScrollingNodeIOS.mm	2014-08-15 21:04:31 UTC (rev 172648)
+++ trunk/Source/WebKit2/UIProcess/Scrolling/ios/ScrollingTreeOverflowScrollingNodeIOS.mm	2014-08-15 21:09:13 UTC (rev 172649)
@@ -37,6 +37,10 @@
 #import <UIKit/UIScrollView.h>
 #import <wtf/TemporaryChange.h>
 
+#if ENABLE(CSS_SCROLL_SNAP)
+#import <WebCore/AxisScrollSnapOffsets.h>
+#endif
+
 using namespace WebCore;
 
 @interface WKOverflowScrollViewDelegate : NSObject <UIScrollViewDelegate> {
@@ -73,6 +77,16 @@
     _scrollingTreeNode->overflowScrollWillStart();
 }
 
+#if ENABLE(CSS_SCROLL_SNAP)
+- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
+{
+    if (!_scrollingTreeNode->horizontalSnapOffsets().isEmpty())
+        targetContentOffset->x = closestSnapOffset<float, CGFloat>(_scrollingTreeNode->horizontalSnapOffsets(), targetContentOffset->x, velocity.x);
+    if (!_scrollingTreeNode->verticalSnapOffsets().isEmpty())
+        targetContentOffset->y = closestSnapOffset<float, CGFloat>(_scrollingTreeNode->verticalSnapOffsets(), targetContentOffset->y, velocity.y);
+}
+#endif
+
 - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)willDecelerate
 {
     if (_inUserInteraction && !willDecelerate) {
@@ -188,7 +202,12 @@
 
             scrollView.contentInset = insets;
         }
-            
+
+#if ENABLE(CSS_SCROLL_SNAP)
+        // FIXME: If only one axis snaps in 2D scrolling, the other axis will decelerate fast as well. Is this what we want?
+        if (scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::HorizontalSnapOffsets) || scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::VerticalSnapOffsets))
+            scrollView.decelerationRate = horizontalSnapOffsets().size() || verticalSnapOffsets().size() ? UIScrollViewDecelerationRateFast : UIScrollViewDecelerationRateNormal;
+#endif
         END_BLOCK_OBJC_EXCEPTIONS
     }
 }

Modified: trunk/Source/WebKit2/UIProcess/ios/RemoteScrollingCoordinatorProxyIOS.mm (172648 => 172649)


--- trunk/Source/WebKit2/UIProcess/ios/RemoteScrollingCoordinatorProxyIOS.mm	2014-08-15 21:04:31 UTC (rev 172648)
+++ trunk/Source/WebKit2/UIProcess/ios/RemoteScrollingCoordinatorProxyIOS.mm	2014-08-15 21:09:13 UTC (rev 172649)
@@ -23,20 +23,26 @@
  * THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "config.h"
-#include "RemoteScrollingCoordinatorProxy.h"
+#import "config.h"
+#import "RemoteScrollingCoordinatorProxy.h"
 
 #if PLATFORM(IOS)
 #if ENABLE(ASYNC_SCROLLING)
 
-#include "LayerRepresentation.h"
-#include "RemoteLayerTreeHost.h"
-#include "WebPageProxy.h"
-#include <WebCore/ScrollingStateFrameScrollingNode.h>
-#include <WebCore/ScrollingStateOverflowScrollingNode.h>
-#include <WebCore/ScrollingStateTree.h>
-#include <UIKit/UIView.h>
+#import "LayerRepresentation.h"
+#import "RemoteLayerTreeHost.h"
+#import "WebPageProxy.h"
+#import <UIKit/UIView.h>
+#import <WebCore/ScrollingStateFrameScrollingNode.h>
+#import <WebCore/ScrollingStateOverflowScrollingNode.h>
+#import <WebCore/ScrollingStateTree.h>
 
+#if ENABLE(CSS_SCROLL_SNAP)
+#import <WebCore/AxisScrollSnapOffsets.h>
+#import <WebCore/ScrollTypes.h>
+#import <WebCore/ScrollingTreeFrameScrollingNode.h>
+#endif
+
 using namespace WebCore;
 
 namespace WebKit {
@@ -106,6 +112,47 @@
     m_webPageProxy.overflowScrollDidEndScroll();
 }
 
+#if ENABLE(CSS_SCROLL_SNAP)
+void RemoteScrollingCoordinatorProxy::adjustTargetContentOffsetForSnapping(CGSize maxScrollOffsets, CGPoint velocity, CGPoint* targetContentOffset) const
+{
+    // The bounds checking with maxScrollOffsets is to ensure that we won't interfere with rubber-banding when scrolling to the edge of the page.
+    if (shouldSnapForMainFrameScrolling(WebCore::ScrollEventAxis::Horizontal) && targetContentOffset->x > 0 && targetContentOffset->x < maxScrollOffsets.width) {
+        float potentialSnapPosition = closestSnapOffsetForMainFrameScrolling(WebCore::ScrollEventAxis::Horizontal, targetContentOffset->x, velocity.x);
+        targetContentOffset->x = std::min<float>(maxScrollOffsets.width, potentialSnapPosition);
+    }
+    // FIXME: We need to account for how the top navigation bar changes in size.
+    if (shouldSnapForMainFrameScrolling(WebCore::ScrollEventAxis::Vertical) && targetContentOffset->y > 0 && targetContentOffset->y < maxScrollOffsets.height) {
+        float potentialSnapPosition = closestSnapOffsetForMainFrameScrolling(WebCore::ScrollEventAxis::Vertical, targetContentOffset->y, velocity.y);
+        targetContentOffset->y = std::min<float>(maxScrollOffsets.height, potentialSnapPosition);
+    }
+}
+
+bool RemoteScrollingCoordinatorProxy::shouldSetScrollViewDecelerationRateFast() const
+{
+    return shouldSnapForMainFrameScrolling(ScrollEventAxis::Horizontal) || shouldSnapForMainFrameScrolling(ScrollEventAxis::Vertical);
+}
+
+bool RemoteScrollingCoordinatorProxy::shouldSnapForMainFrameScrolling(ScrollEventAxis axis) const
+{
+    ScrollingTreeNode* root = m_scrollingTree->rootNode();
+    if (root && root->isFrameScrollingNode()) {
+        ScrollingTreeFrameScrollingNode* rootFrame = static_cast<ScrollingTreeFrameScrollingNode*>(root);
+        const Vector<float>& snapOffsets = axis == ScrollEventAxis::Horizontal ? rootFrame->horizontalSnapOffsets() : rootFrame->verticalSnapOffsets();
+        return snapOffsets.size() > 0;
+    }
+    return false;
+}
+
+float RemoteScrollingCoordinatorProxy::closestSnapOffsetForMainFrameScrolling(ScrollEventAxis axis, float scrollDestination, float velocity) const
+{
+    ScrollingTreeNode* root = m_scrollingTree->rootNode();
+    ASSERT(root && root->isFrameScrollingNode());
+    ScrollingTreeFrameScrollingNode* rootFrame = static_cast<ScrollingTreeFrameScrollingNode*>(root);
+    const Vector<float>& snapOffsets = axis == ScrollEventAxis::Horizontal ? rootFrame->horizontalSnapOffsets() : rootFrame->verticalSnapOffsets();
+    return closestSnapOffset<float, float>(snapOffsets, scrollDestination, velocity);
+}
+#endif
+
 } // namespace WebKit
 
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to