[WK2] Provide a mechanism to grab the back-forward list for gesture navigation purpos...
authortimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 18 Jul 2014 13:41:06 +0000 (13:41 +0000)
committertimothy_horton@apple.com <timothy_horton@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 18 Jul 2014 13:41:06 +0000 (13:41 +0000)
https://bugs.webkit.org/show_bug.cgi?id=134999
<rdar://problem/17238025>

Reviewed by Sam Weinig.

In some cases, clients may need to throw a WKWebView with no back-forward list over
another WKWebView, and want to participate in gesture swipe as if they were actually
the page being overlaid.

* UIProcess/API/Cocoa/WKWebView.mm:
(-[WKWebView setAllowsBackForwardNavigationGestures:]):
* UIProcess/API/Cocoa/WKWebViewConfiguration.mm:
(-[WKWebViewConfiguration copyWithZone:]):
(-[WKWebViewConfiguration _alternateWebViewForNavigationGestures]):
(-[WKWebViewConfiguration _setAlternateWebViewForNavigationGestures:]):
* UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h:
Keep an "alternate" WKWebView "for navigation gestures", which ViewGestureController
will use as the real source of back-forward items, and the destination of the swipe navigation.
All swipe delegate callbacks will also fire from the alternate view, because it owns the items
and will be doing the navigation.

* UIProcess/ios/ViewGestureControllerIOS.mm:
(WebKit::ViewGestureController::setAlternateBackForwardListSourceView):
(WebKit::ViewGestureController::beginSwipeGesture):
Send navigationGestureDidBegin via the alternate view's WebPageProxy if it exists.
Record a new snapshot on the current page, but copy it to the alternate view if necessary,
so that when swiping forward from the alternate view, it will have the "right" snapshot.
Get the target back forward item from the alternate view.
Send navigationGestureWillEnd via the alternate view's WebPageProxy if it exists.

(WebKit::ViewGestureController::canSwipeInDirection):
Determine if we can swipe in a direction by looking at the alternate view's back-forward list if necessary.

(WebKit::ViewGestureController::endSwipeGesture):
Send navigationGestureDidEnd via the alternate view's WebPageProxy if it exists.
Perform the navigation on the alternate view if necessary.

(WebKit::ViewGestureController::removeSwipeSnapshot):
Send navigationGestureSnapshotWasRemoved via the alternate view's WebPageProxy if it exists.

* UIProcess/mac/ViewGestureController.h:

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

Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/Cocoa/WKWebView.mm
Source/WebKit2/UIProcess/API/Cocoa/WKWebViewConfiguration.mm
Source/WebKit2/UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h
Source/WebKit2/UIProcess/ios/ViewGestureControllerIOS.mm
Source/WebKit2/UIProcess/mac/ViewGestureController.h

index ad06629..0325e4e 100644 (file)
@@ -1,3 +1,48 @@
+2014-07-18  Tim Horton  <timothy_horton@apple.com>
+
+        [WK2] Provide a mechanism to grab the back-forward list for gesture navigation purposes from another WKWebView
+        https://bugs.webkit.org/show_bug.cgi?id=134999
+        <rdar://problem/17238025>
+
+        Reviewed by Sam Weinig.
+
+        In some cases, clients may need to throw a WKWebView with no back-forward list over
+        another WKWebView, and want to participate in gesture swipe as if they were actually
+        the page being overlaid.
+
+        * UIProcess/API/Cocoa/WKWebView.mm:
+        (-[WKWebView setAllowsBackForwardNavigationGestures:]):
+        * UIProcess/API/Cocoa/WKWebViewConfiguration.mm:
+        (-[WKWebViewConfiguration copyWithZone:]):
+        (-[WKWebViewConfiguration _alternateWebViewForNavigationGestures]):
+        (-[WKWebViewConfiguration _setAlternateWebViewForNavigationGestures:]):
+        * UIProcess/API/Cocoa/WKWebViewConfigurationPrivate.h:
+        Keep an "alternate" WKWebView "for navigation gestures", which ViewGestureController
+        will use as the real source of back-forward items, and the destination of the swipe navigation.
+        All swipe delegate callbacks will also fire from the alternate view, because it owns the items
+        and will be doing the navigation.
+
+        * UIProcess/ios/ViewGestureControllerIOS.mm:
+        (WebKit::ViewGestureController::setAlternateBackForwardListSourceView):
+        (WebKit::ViewGestureController::beginSwipeGesture):
+        Send navigationGestureDidBegin via the alternate view's WebPageProxy if it exists.
+        Record a new snapshot on the current page, but copy it to the alternate view if necessary,
+        so that when swiping forward from the alternate view, it will have the "right" snapshot.
+        Get the target back forward item from the alternate view.
+        Send navigationGestureWillEnd via the alternate view's WebPageProxy if it exists.
+
+        (WebKit::ViewGestureController::canSwipeInDirection):
+        Determine if we can swipe in a direction by looking at the alternate view's back-forward list if necessary.
+
+        (WebKit::ViewGestureController::endSwipeGesture):
+        Send navigationGestureDidEnd via the alternate view's WebPageProxy if it exists.
+        Perform the navigation on the alternate view if necessary.
+
+        (WebKit::ViewGestureController::removeSwipeSnapshot):
+        Send navigationGestureSnapshotWasRemoved via the alternate view's WebPageProxy if it exists.
+
+        * UIProcess/mac/ViewGestureController.h:
+
 2014-07-17  David Kilzer  <ddkilzer@apple.com>
 
         SECTORDER_FLAGS should be defined in target's xcconfig file, not Base.xcconfig
index 5815c88..bbe9995 100644 (file)
@@ -1481,6 +1481,7 @@ static WebCore::FloatPoint constrainContentOffset(WebCore::FloatPoint contentOff
         if (!_gestureController) {
             _gestureController = std::make_unique<WebKit::ViewGestureController>(*_page);
             _gestureController->installSwipeHandler(self, [self scrollView]);
+            _gestureController->setAlternateBackForwardListSourceView([_configuration _alternateWebViewForNavigationGestures]);
         }
     } else
         _gestureController = nullptr;
index 0e548e2..304a485 100644 (file)
@@ -73,6 +73,7 @@ private:
     LazyInitialized<_WKVisitedLinkProvider> _visitedLinkProvider;
     LazyInitialized<_WKWebsiteDataStore> _websiteDataStore;
     WebKit::WeakObjCPtr<WKWebView> _relatedWebView;
+    WebKit::WeakObjCPtr<WKWebView> _alternateWebViewForNavigationGestures;
     RetainPtr<NSString> _groupIdentifier;
 #if PLATFORM(IOS)
     LazyInitialized<WKWebViewContentProviderRegistry> _contentProviderRegistry;
@@ -107,6 +108,7 @@ private:
     configuration._visitedLinkProvider = self._visitedLinkProvider;
     configuration._websiteDataStore = self._websiteDataStore;
     configuration._relatedWebView = _relatedWebView.get().get();
+    configuration._alternateWebViewForNavigationGestures = _alternateWebViewForNavigationGestures.get().get();
 #if PLATFORM(IOS)
     configuration._contentProviderRegistry = self._contentProviderRegistry;
 #endif
@@ -221,6 +223,16 @@ private:
     _relatedWebView = relatedWebView;
 }
 
+- (WKWebView *)_alternateWebViewForNavigationGestures
+{
+    return _alternateWebViewForNavigationGestures.getAutoreleased();
+}
+
+- (void)_setAlternateWebViewForNavigationGestures:(WKWebView *)alternateView
+{
+    _alternateWebViewForNavigationGestures = alternateView;
+}
+
 - (NSString *)_groupIdentifier
 {
     return _groupIdentifier.get();
index 624f760..474f68a 100644 (file)
@@ -40,6 +40,8 @@
 
 @property (nonatomic, strong, setter=_setWebsiteDataStore:) _WKWebsiteDataStore *_websiteDataStore;
 
+@property (nonatomic, weak, setter=_setAlternateWebViewForNavigationGestures:) WKWebView *_alternateWebViewForNavigationGestures;
+
 @end
 
 #endif
index f570c72..5f6adba 100644 (file)
@@ -31,6 +31,8 @@
 #import "ViewGestureControllerMessages.h"
 #import "ViewGestureGeometryCollectorMessages.h"
 #import "ViewSnapshotStore.h"
+#import "WKBackForwardListItemInternal.h"
+#import "WKWebViewInternal.h"
 #import "WebBackForwardList.h"
 #import "WebPageGroup.h"
 #import "WebPageMessages.h"
@@ -146,6 +148,11 @@ ViewGestureController::~ViewGestureController()
     viewGestureControllersForAllPages().remove(m_webPageProxy.pageID());
 }
 
+void ViewGestureController::setAlternateBackForwardListSourceView(WKWebView *view)
+{
+    m_alternateBackForwardListSourceView = view;
+}
+
 void ViewGestureController::installSwipeHandler(UIView *gestureRecognizerView, UIView *swipingView)
 {
     ASSERT(!m_swipeInteractiveTransitionDelegate);
@@ -158,11 +165,20 @@ void ViewGestureController::beginSwipeGesture(_UINavigationInteractiveTransition
     if (m_activeGestureType != ViewGestureType::None)
         return;
 
-    m_webPageProxy.navigationGestureDidBegin();
+    m_webPageProxyForBackForwardListForCurrentSwipe = m_alternateBackForwardListSourceView.get() ? m_alternateBackForwardListSourceView.get()->_page : &m_webPageProxy;
+
+    m_webPageProxyForBackForwardListForCurrentSwipe->navigationGestureDidBegin();
+
+    m_webPageProxy.recordNavigationSnapshot();
 
-    ViewSnapshotStore::shared().recordSnapshot(m_webPageProxy);
+    auto backForwardList = m_webPageProxyForBackForwardListForCurrentSwipe->backForwardList();
 
-    WebKit::WebBackForwardListItem* targetItem = direction == SwipeDirection::Left ? m_webPageProxy.backForwardList().backItem() : m_webPageProxy.backForwardList().forwardItem();
+    // Copy the snapshot from this view to the one that owns the back forward list, so that
+    // swiping forward will have the correct snapshot.
+    if (m_webPageProxyForBackForwardListForCurrentSwipe != &m_webPageProxy)
+        backForwardList.currentItem()->setSnapshot(m_webPageProxy.backForwardList().currentItem()->snapshot());
+
+    WebBackForwardListItem* targetItem = direction == SwipeDirection::Left ? backForwardList.backItem() : backForwardList.forwardItem();
 
     CGRect liveSwipeViewFrame = [m_liveSwipeView frame];
 
@@ -213,7 +229,7 @@ void ViewGestureController::beginSwipeGesture(_UINavigationInteractiveTransition
     [transitionContext _setTransitionIsInFlight:YES];
     [transitionContext _setInteractiveUpdateHandler:^(BOOL finish, CGFloat percent, BOOL transitionCompleted, _UIViewControllerTransitionContext *) {
         if (finish)
-            m_webPageProxy.navigationGestureWillEnd(transitionCompleted, *targetItem);
+            m_webPageProxyForBackForwardListForCurrentSwipe->navigationGestureWillEnd(transitionCompleted, *targetItem);
     }];
     [transitionContext _setCompletionHandler:^(_UIViewControllerTransitionContext *context, BOOL didComplete) { endSwipeGesture(targetItem, context, !didComplete); }];
     [transitionContext _setInteractiveUpdateHandler:^(BOOL, CGFloat, BOOL, _UIViewControllerTransitionContext *) { }];
@@ -226,9 +242,10 @@ void ViewGestureController::beginSwipeGesture(_UINavigationInteractiveTransition
 
 bool ViewGestureController::canSwipeInDirection(SwipeDirection direction)
 {
+    auto backForwardList = m_alternateBackForwardListSourceView.get() ? m_alternateBackForwardListSourceView.get()->_page->backForwardList() : m_webPageProxy.backForwardList();
     if (direction == SwipeDirection::Left)
-        return !!m_webPageProxy.backForwardList().backItem();
-    return !!m_webPageProxy.backForwardList().forwardItem();
+        return !!backForwardList.backItem();
+    return !!backForwardList.forwardItem();
 }
 
 void ViewGestureController::endSwipeGesture(WebBackForwardListItem* targetItem, _UIViewControllerTransitionContext *context, bool cancelled)
@@ -243,10 +260,12 @@ void ViewGestureController::endSwipeGesture(WebBackForwardListItem* targetItem,
     m_liveSwipeViewClippingView = nullptr;
     [m_transitionContainerView removeFromSuperview];
     m_transitionContainerView = nullptr;
-    
+
     if (cancelled) {
+        // removeSwipeSnapshot will clear m_webPageProxyForBackForwardListForCurrentSwipe, so hold on to it here.
+        RefPtr<WebPageProxy> webPageProxyForBackForwardListForCurrentSwipe = m_webPageProxyForBackForwardListForCurrentSwipe;
         removeSwipeSnapshot();
-        m_webPageProxy.navigationGestureDidEnd(false, *targetItem);
+        webPageProxyForBackForwardListForCurrentSwipe->navigationGestureDidEnd(false, *targetItem);
         return;
     }
 
@@ -259,8 +278,9 @@ void ViewGestureController::endSwipeGesture(WebBackForwardListItem* targetItem,
     // displaying the destination item's snapshot.
     ViewSnapshotStore::shared().disableSnapshotting();
 
-    m_webPageProxy.navigationGestureDidEnd(true, *targetItem);
-    m_webPageProxy.goToBackForwardItem(targetItem);
+    m_webPageProxyForBackForwardListForCurrentSwipe->navigationGestureDidEnd(true, *targetItem);
+    m_webPageProxyForBackForwardListForCurrentSwipe->goToBackForwardItem(targetItem);
+
     ViewSnapshotStore::shared().enableSnapshotting();
 
     uint64_t pageID = m_webPageProxy.pageID();
@@ -324,7 +344,8 @@ void ViewGestureController::removeSwipeSnapshot()
     m_snapshotRemovalTargetRenderTreeSize = 0;
     m_activeGestureType = ViewGestureType::None;
 
-    m_webPageProxy.navigationGestureSnapshotWasRemoved();
+    m_webPageProxyForBackForwardListForCurrentSwipe->navigationGestureSnapshotWasRemoved();
+    m_webPageProxyForBackForwardListForCurrentSwipe = nullptr;
 }
 
 } // namespace WebKit
index 8e12d12..a8857a4 100644 (file)
@@ -27,6 +27,7 @@
 #define ViewGestureController_h
 
 #include "MessageReceiver.h"
+#include "WeakObjCPtr.h"
 #include <WebCore/FloatRect.h>
 #include <WebCore/Timer.h>
 #include <wtf/RetainPtr.h>
@@ -36,6 +37,7 @@ OBJC_CLASS CALayer;
 #if PLATFORM(IOS)
 OBJC_CLASS UIView;
 OBJC_CLASS WKSwipeTransitionController;
+OBJC_CLASS WKWebView;
 OBJC_CLASS _UIViewControllerTransitionContext;
 OBJC_CLASS _UINavigationInteractiveTransitionBase;
 #else
@@ -104,6 +106,7 @@ public:
     void setShouldIgnorePinnedState(bool ignore) { m_shouldIgnorePinnedState = ignore; }
 #else
     void installSwipeHandler(UIView *gestureRecognizerView, UIView *swipingView);
+    void setAlternateBackForwardListSourceView(WKWebView *);
     bool canSwipeInDirection(SwipeDirection);
     void beginSwipeGesture(_UINavigationInteractiveTransitionBase *, SwipeDirection);
     void endSwipeGesture(WebBackForwardListItem* targetItem, _UIViewControllerTransitionContext *, bool cancelled);
@@ -139,7 +142,7 @@ private:
     CALayer *determineLayerAdjacentToSnapshotForParent(SwipeDirection, CALayer *snapshotLayerParent) const;
     void applyDebuggingPropertiesToSwipeViews();
 #endif
-    
+
     WebPageProxy& m_webPageProxy;
     ViewGestureType m_activeGestureType;
     
@@ -186,6 +189,8 @@ private:
     RetainPtr<WKSwipeTransitionController> m_swipeInteractiveTransitionDelegate;
     uint64_t m_snapshotRemovalTargetRenderTreeSize;
     bool m_shouldRemoveSnapshotWhenTargetRenderTreeSizeHit;
+    WeakObjCPtr<WKWebView> m_alternateBackForwardListSourceView;
+    RefPtr<WebPageProxy> m_webPageProxyForBackForwardListForCurrentSwipe;
 #endif
 };