WebKit Bugzilla
Attachment 360363 Details for
Bug 193919
: [GTK] Implement back/forward touchpad gesture
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-193919-20190129020200.patch (text/plain), 87.02 KB, created by
Alice Mikhaylenko
on 2019-01-28 13:02:03 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Alice Mikhaylenko
Created:
2019-01-28 13:02:03 PST
Size:
87.02 KB
patch
obsolete
>Subversion Revision: 240553 >diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog >index e9db9426e4b591f6f5accaec840d937717d1a23d..d36a99cba15a774ecac5a40f71973fec9f766be8 100644 >--- a/Source/WebKit/ChangeLog >+++ b/Source/WebKit/ChangeLog >@@ -1,3 +1,180 @@ >+2019-01-28 Alexander Mikhaylenko <exalm7659@gmail.com> >+ >+ [GTK] Implement back/forward touchpad gesture >+ https://bugs.webkit.org/show_bug.cgi?id=193919 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Add a 2-finger touchpad swipe to back-forward gesture, based on Cocoa/macOS >+ implementation. Since GTK gestures can only work with 3 or 4 fingers, treat >+ horizontal scrolling events as a swipe as long as there's nowhere to scroll >+ in that direction and web page doesn't intercept the scrolling. >+ >+ This is only enabled on Wayland, since on X11 we don't get any events when >+ the gesture ends. Also, it's only allowed for touchpads, even though it can >+ theoretically work with touch mice and trackpoints. >+ >+ The gesture requires every item in back-forward list to have a snapshot. >+ There's already an existing infrastructure for that, so the patch changes >+ a bunch of #if PLATFORM(COCOA) statements to also check for GTK platform. >+ The snapshots have to be taken in sync, so the implementation draws webview >+ widget into a Cairo image surface. >+ >+ The gesture is disabled by default, and can be enabled by setting the newly >+ added 'allow-back-forward-navigation-gestures' property in WebKitSettings to >+ true. >+ >+ Gesture drawing is implemented via Cairo. When the gesture is active, the >+ actual page is drawn into a Cairo group, which is then drawn together with >+ a given snapshot, as well as dimming and a drop shadow over the "lower" layer. >+ >+ * Shared/SessionState.h: Add snapshot to back-forward items for GTK. >+ * Shared/WebBackForwardListItem.h: Add snapshot to back-forward items for GTK. >+ * SourcesGTK.txt: Add BackForwardGestureController.cpp and ViewSnapshotStore.cpp. >+ * UIProcess/API/glib/WebKitSettings.cpp: >+ Added 'allow-back-forward-navigation-gestures' property for enabling the gesture. >+ (webKitSettingsSetProperty): >+ (webKitSettingsGetProperty): >+ (webkit_settings_class_init): >+ (webkit_settings_get_allow_back_forward_navigation_gestures): Added, GTK only. >+ (webkit_settings_set_allow_back_forward_navigation_gestures): Added, GTK only. >+ * UIProcess/API/glib/WebKitWebView.cpp: >+ (allowBackForwardNavigationGesturesChanged): Added, GTK only. >+ (webkitWebViewUpdateSettings): >+ (webkitWebViewDisconnectSettingsSignalHandlers): >+ * UIProcess/API/gtk/PageClientImpl.cpp: >+ (WebKit::PageClientImpl::setViewNeedsDisplay): Redraw the whole screen instead of a region during the gesture. >+ (WebKit::PageClientImpl::takeViewSnapshot): Added. >+ (WebKit::PageClientImpl::wheelEventWasNotHandledByWebCore): Pass unhandled events to the gesture controller. >+ (WebKit::PageClientImpl::didStartProvisionalLoadForMainFrame): Added, send a notification to the gesture controller. >+ (WebKit::PageClientImpl::didFirstVisuallyNonEmptyLayoutForMainFrame): Send a notification to the gesture controller. >+ (WebKit::PageClientImpl::didFinishLoadForMainFrame): Send a notification to the gesture controller. >+ (WebKit::PageClientImpl::didFailLoadForMainFrame): Added, send a notification to the gesture controller. >+ (WebKit::PageClientImpl::didSameDocumentNavigationForMainFrame): Send a notification to the gesture controller. >+ (WebKit::PageClientImpl::didRestoreScrollPosition): Added, send a notification to the gesture controller. >+ * UIProcess/API/gtk/PageClientImpl.h: >+ * UIProcess/API/gtk/WebKitSettings.h: >+ Add webkit_settings_get_allow_back_forward_navigation_gestures() and webkit_settings_get_allow_back_forward_navigation_gestures() >+ to public API. >+ * UIProcess/API/gtk/WebKitWebViewBase.cpp: >+ (webkitWebViewBaseDraw): Pass drawing to BackForwardGestureController during the gesture. >+ (webkitWebViewBaseScrollEvent): Pass scroll events to BackForwardGestureController during the gesture. >+ (webkitWebViewBaseBackForwardGestureController): Added. >+ (webkitWebViewBaseTakeViewSnapshot): Added. >+ (webkitWebViewBaseDidStartProvisionalLoadForMainFrame): Added. >+ (webkitWebViewBaseDidFirstVisuallyNonEmptyLayoutForMainFrame): Added. >+ (webkitWebViewBaseDidFinishLoadForMainFrame): Added. >+ (webkitWebViewBaseDidFailLoadForMainFrame): Added. >+ (webkitWebViewBaseDidSameDocumentNavigationForMainFrame): Added. >+ (webkitWebViewBaseDidRestoreScrollPosition): Added. >+ * UIProcess/API/gtk/WebKitWebViewBasePrivate.h: >+ * UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt: Mentioned the added functions in docs. >+ * UIProcess/PageClient.h: Add takeViewSnapshot() for GTK. >+ * UIProcess/WebBackForwardList.cpp: >+ (WebKit::WebBackForwardList::didRemoveItem): Unset snapshot for GTK. >+ * UIProcess/WebPageProxy.cpp: >+ (WebKit::WebPageProxy::recordNavigationSnapshot): Take snapshots for GTK. >+ * UIProcess/WebPageProxy.h: >+ * UIProcess/gtk/BackForwardGestureController.cpp: Added. This is more or less a port >+ of UIProcess/Cocoa/ViewGestureController.cpp and UIProcess/mac/ViewGestureControllerMac.mm. >+ SwipeProgressTracker class is a re-implementation of trackSwipeEventWithOptions. >+ (WebKit::BackForwardGestureController::BackForwardGestureController): >+ (WebKit::BackForwardGestureController::~BackForwardGestureController): >+ (WebKit::BackForwardGestureController::controllerForGesture): >+ (WebKit::BackForwardGestureController::takeNextGestureID): >+ (WebKit::BackForwardGestureController::willBeginGesture): >+ (WebKit::BackForwardGestureController::didEndGesture): >+ (WebKit::BackForwardGestureController::canSwipeInDirection const): >+ (WebKit::BackForwardGestureController::didStartProvisionalLoadForMainFrame): >+ (WebKit::BackForwardGestureController::didFirstVisuallyNonEmptyLayoutForMainFrame): >+ (WebKit::BackForwardGestureController::didRestoreScrollPosition): >+ (WebKit::BackForwardGestureController::didReachMainFrameLoadTerminalState): >+ (WebKit::BackForwardGestureController::didSameDocumentNavigationForMainFrame): >+ (WebKit::BackForwardGestureController::checkForActiveLoads): >+ (WebKit::BackForwardGestureController::SnapshotRemovalTracker::SnapshotRemovalTracker): >+ (WebKit::BackForwardGestureController::SnapshotRemovalTracker::eventsDescription): >+ (WebKit::BackForwardGestureController::SnapshotRemovalTracker::log const): >+ (WebKit::BackForwardGestureController::SnapshotRemovalTracker::resume): >+ (WebKit::BackForwardGestureController::SnapshotRemovalTracker::start): >+ (WebKit::BackForwardGestureController::SnapshotRemovalTracker::reset): >+ (WebKit::BackForwardGestureController::SnapshotRemovalTracker::stopWaitingForEvent): >+ (WebKit::BackForwardGestureController::SnapshotRemovalTracker::eventOccurred): >+ (WebKit::BackForwardGestureController::SnapshotRemovalTracker::cancelOutstandingEvent): >+ (WebKit::BackForwardGestureController::SnapshotRemovalTracker::fireRemovalCallbackIfPossible): >+ (WebKit::BackForwardGestureController::SnapshotRemovalTracker::fireRemovalCallbackImmediately): >+ (WebKit::BackForwardGestureController::SnapshotRemovalTracker::watchdogTimerFired): >+ (WebKit::BackForwardGestureController::SnapshotRemovalTracker::startWatchdog): >+ (WebKit::BackForwardGestureController::PendingSwipeTracker::PendingSwipeTracker): >+ (WebKit::scrollEventCanInfluenceSwipe): >+ (WebKit::deltaShouldCancelSwipe): >+ (WebKit::BackForwardGestureController::PendingSwipeTracker::scrollEventCanBecomeSwipe): >+ (WebKit::BackForwardGestureController::handleScrollWheelEvent): >+ (WebKit::BackForwardGestureController::PendingSwipeTracker::handleEvent): >+ (WebKit::BackForwardGestureController::PendingSwipeTracker::eventWasNotHandledByWebCore): >+ (WebKit::BackForwardGestureController::PendingSwipeTracker::tryToStartSwipe): >+ (WebKit::BackForwardGestureController::PendingSwipeTracker::reset): >+ (WebKit::BackForwardGestureController::trackSwipeGesture): >+ (WebKit::BackForwardGestureController::isPhysicallySwipingLeft const): >+ (WebKit::BackForwardGestureController::SwipeProgressTracker::SwipeProgressTracker): >+ (WebKit::BackForwardGestureController::SwipeProgressTracker::startTracking): >+ (WebKit::BackForwardGestureController::SwipeProgressTracker::reset): >+ (WebKit::BackForwardGestureController::SwipeProgressTracker::handleEvent): >+ (WebKit::BackForwardGestureController::SwipeProgressTracker::getProgress): >+ (WebKit::BackForwardGestureController::SwipeProgressTracker::startAnimation): >+ (WebKit::easeOutCubic): >+ (WebKit::BackForwardGestureController::SwipeProgressTracker::onAnimationTick): >+ (WebKit::BackForwardGestureController::SwipeProgressTracker::endAnimation): >+ (WebKit::BackForwardGestureController::queueDraw): >+ (WebKit::BackForwardGestureController::beginSwipeGesture): >+ (WebKit::BackForwardGestureController::willEndSwipeGesture): >+ (WebKit::BackForwardGestureController::endSwipeGesture): >+ (WebKit::BackForwardGestureController::forceRepaintIfNeeded): >+ (WebKit::BackForwardGestureController::shouldUseSnapshotForSize): >+ (WebKit::BackForwardGestureController::draw): >+ (WebKit::BackForwardGestureController::removeSwipeSnapshot): >+ * UIProcess/gtk/BackForwardGestureController.h: Added. >+ This is a port of UIProcess/Cocoa/ViewGestureController.h. >+ (WebKit::BackForwardGestureController::wheelEventWasNotHandledByWebCore): >+ (WebKit::BackForwardGestureController::backgroundColorForCurrentSnapshot const): >+ (WebKit::BackForwardGestureController::didFinishLoadForMainFrame): >+ (WebKit::BackForwardGestureController::didFailLoadForMainFrame): >+ (WebKit::BackForwardGestureController::setSwipeGestureEnabled): >+ (WebKit::BackForwardGestureController::isSwipeGestureEnabled): >+ (WebKit::BackForwardGestureController::isGestureActive): >+ (WebKit::BackForwardGestureController::SnapshotRemovalTracker::pause): >+ (WebKit::BackForwardGestureController::SnapshotRemovalTracker::isPaused const): >+ (WebKit::BackForwardGestureController::PendingSwipeTracker::shouldIgnorePinnedState): >+ (WebKit::BackForwardGestureController::PendingSwipeTracker::setShouldIgnorePinnedState): >+ (WebKit::BackForwardGestureController::SwipeProgressTracker::getDirection): >+ * UIProcess/gtk/ViewSnapshotStore.cpp: Added. >+ This is a straightforward port of UIProcess/mac/ViewSnapshotStore.mm. >+ (WebKit::ViewSnapshotStore::ViewSnapshotStore): >+ (WebKit::ViewSnapshotStore::~ViewSnapshotStore): >+ (WebKit::ViewSnapshotStore::singleton): >+ (WebKit::ViewSnapshotStore::didAddImageToSnapshot): >+ (WebKit::ViewSnapshotStore::willRemoveImageFromSnapshot): >+ (WebKit::ViewSnapshotStore::pruneSnapshots): >+ (WebKit::ViewSnapshotStore::recordSnapshot): >+ (WebKit::ViewSnapshotStore::discardSnapshotImages): >+ (WebKit::ViewSnapshot::create): >+ (WebKit::ViewSnapshot::ViewSnapshot): >+ (WebKit::ViewSnapshot::~ViewSnapshot): >+ (WebKit::ViewSnapshot::hasImage const): >+ (WebKit::ViewSnapshot::clearImage): >+ (WebKit::ViewSnapshot::imageSizeInBytes const): >+ (WebKit::ViewSnapshot::size const): >+ * UIProcess/gtk/ViewSnapshotStore.h: Added. >+ This is a straightforward port of UIProcess/mac/ViewSnapshotStore.h. >+ (WebKit::ViewSnapshot::setBackgroundColor): >+ (WebKit::ViewSnapshot::backgroundColor const): >+ (WebKit::ViewSnapshot::setViewScrollPosition): >+ (WebKit::ViewSnapshot::viewScrollPosition const): >+ (WebKit::ViewSnapshot::setDeviceScaleFactor): >+ (WebKit::ViewSnapshot::deviceScaleFactor const): >+ (WebKit::ViewSnapshot::surface const): >+ (WebKit::ViewSnapshotStore::setDisableSnapshotVolatilityForTesting): >+ (WebKit::ViewSnapshotStore::disableSnapshotVolatilityForTesting const): >+ > 2019-01-26 Simon Fraser <simon.fraser@apple.com> > > Have composited RenderIFrame layers make FrameHosting scrolling tree nodes to parent the iframe's scrolling node >diff --git a/Source/WebKit/Shared/SessionState.h b/Source/WebKit/Shared/SessionState.h >index d26791da99c36d284ff2e7d50ce082678d0f08b0..fb0e27aa9a56be0f66f1195c38d6d7627d7d4dc9 100644 >--- a/Source/WebKit/Shared/SessionState.h >+++ b/Source/WebKit/Shared/SessionState.h >@@ -25,7 +25,7 @@ > > #pragma once > >-#if PLATFORM(COCOA) >+#if PLATFORM(COCOA) || PLATFORM(GTK) > #include "ViewSnapshotStore.h" > #endif > >@@ -133,7 +133,7 @@ struct BackForwardListItemState { > WebCore::BackForwardItemIdentifier identifier; > > PageState pageState; >-#if PLATFORM(COCOA) >+#if PLATFORM(COCOA) || PLATFORM(GTK) > RefPtr<ViewSnapshot> snapshot; > #endif > }; >diff --git a/Source/WebKit/Shared/WebBackForwardListItem.h b/Source/WebKit/Shared/WebBackForwardListItem.h >index aaf6514e7a67c36187b11f99d7ad4e7d03efd4f2..bff0c882041f6a9aa8332166fd7b377ec3f1b583 100644 >--- a/Source/WebKit/Shared/WebBackForwardListItem.h >+++ b/Source/WebKit/Shared/WebBackForwardListItem.h >@@ -66,7 +66,7 @@ public: > bool itemIsInSameDocument(const WebBackForwardListItem&) const; > bool itemIsClone(const WebBackForwardListItem&); > >-#if PLATFORM(COCOA) >+#if PLATFORM(COCOA) || PLATFORM(GTK) > ViewSnapshot* snapshot() const { return m_itemState.snapshot.get(); } > void setSnapshot(RefPtr<ViewSnapshot>&& snapshot) { m_itemState.snapshot = WTFMove(snapshot); } > #endif >diff --git a/Source/WebKit/SourcesGTK.txt b/Source/WebKit/SourcesGTK.txt >index a7188051594fec735130c6ef68cf402688624336..a7275172f0af74127d73bf7de04970ba71128a86 100644 >--- a/Source/WebKit/SourcesGTK.txt >+++ b/Source/WebKit/SourcesGTK.txt >@@ -231,6 +231,7 @@ UIProcess/gstreamer/WebPageProxyGStreamer.cpp > UIProcess/gtk/AcceleratedBackingStore.cpp @no-unify > UIProcess/gtk/AcceleratedBackingStoreWayland.cpp @no-unify > UIProcess/gtk/AcceleratedBackingStoreX11.cpp @no-unify >+UIProcess/gtk/BackForwardGestureController.cpp @no-unify > UIProcess/gtk/DragAndDropHandler.cpp > UIProcess/gtk/GestureController.cpp > UIProcess/gtk/HardwareAccelerationManager.cpp >@@ -238,6 +239,7 @@ UIProcess/gtk/InputMethodFilter.cpp @no-unify > UIProcess/gtk/KeyBindingTranslator.cpp > UIProcess/gtk/RemoteWebInspectorProxyGtk.cpp @no-unify > UIProcess/gtk/TextCheckerGtk.cpp @no-unify >+UIProcess/gtk/ViewSnapshotStore.cpp @no-unify > UIProcess/gtk/WaylandCompositor.cpp @no-unify > UIProcess/gtk/WebColorPickerGtk.cpp @no-unify > UIProcess/gtk/WebContextMenuProxyGtk.cpp >diff --git a/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp b/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp >index 4ec7f98139a071fcbd1682a2066d90a7a9f4a712..dba6210fe5f726562d22514515d3ffdcc89c9d27 100644 >--- a/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp >+++ b/Source/WebKit/UIProcess/API/glib/WebKitSettings.cpp >@@ -80,6 +80,9 @@ struct _WebKitSettingsPrivate { > bool allowModalDialogs { false }; > bool zoomTextOnly { false }; > double screenDpi { 96 }; >+#if PLATFORM(GTK) >+ bool allowBackForwardNavigationGestures { false }; >+#endif > }; > > /** >@@ -161,6 +164,7 @@ enum { > PROP_ALLOW_UNIVERSAL_ACCESS_FROM_FILE_URLS, > #if PLATFORM(GTK) > PROP_HARDWARE_ACCELERATION_POLICY, >+ PROP_ALLOW_BACK_FORWARD_NAVIGATION_GESTURES, > #endif > }; > >@@ -381,6 +385,9 @@ static void webKitSettingsSetProperty(GObject* object, guint propId, const GValu > case PROP_HARDWARE_ACCELERATION_POLICY: > webkit_settings_set_hardware_acceleration_policy(settings, static_cast<WebKitHardwareAccelerationPolicy>(g_value_get_enum(value))); > break; >+ case PROP_ALLOW_BACK_FORWARD_NAVIGATION_GESTURES: >+ webkit_settings_set_allow_back_forward_navigation_gestures(settings, g_value_get_boolean(value)); >+ break; > #endif > default: > G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec); >@@ -560,6 +567,9 @@ static void webKitSettingsGetProperty(GObject* object, guint propId, GValue* val > case PROP_HARDWARE_ACCELERATION_POLICY: > g_value_set_enum(value, webkit_settings_get_hardware_acceleration_policy(settings)); > break; >+ case PROP_ALLOW_BACK_FORWARD_NAVIGATION_GESTURES: >+ g_value_set_boolean(value, webkit_settings_get_allow_back_forward_navigation_gestures(settings)); >+ break; > #endif > default: > G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec); >@@ -1443,6 +1453,19 @@ static void webkit_settings_class_init(WebKitSettingsClass* klass) > WEBKIT_TYPE_HARDWARE_ACCELERATION_POLICY, > WEBKIT_HARDWARE_ACCELERATION_POLICY_ON_DEMAND, > readWriteConstructParamFlags)); >+ >+ /** >+ * WebKitSettings:allow-back-forward-navigation-gestures: >+ * >+ * Enable or disable horizontal swipe gesture for back-forward navigation. >+ */ >+ g_object_class_install_property(gObjectClass, >+ PROP_ALLOW_BACK_FORWARD_NAVIGATION_GESTURES, >+ g_param_spec_boolean("allow-back-forward-navigation-gestures", >+ _("Allow back-forward navigation gestures"), >+ _("Whether horizontal swipe gesture will trigger back-forward navigation"), >+ FALSE, >+ readWriteConstructParamFlags)); > #endif // PLATFOTM(GTK) > } > >@@ -3512,6 +3535,44 @@ void webkit_settings_set_hardware_acceleration_policy(WebKitSettings* settings, > g_object_notify(G_OBJECT(settings), "hardware-acceleration-policy"); > } > >+/** >+ * webkit_settings_get_allow_back_forward_navigation_gestures: >+ * @settings: a #WebKitSettings >+ * >+ * Get the #WebKitSettings:allow-back-forward-navigation-gestures property. >+ * >+ * Returns: %TRUE If horizontal swipe gesture will trigger back-forward navigaiton or %FALSE otherwise. >+ * >+ * Since: 2.24 >+ */ >+gboolean webkit_settings_get_allow_back_forward_navigation_gestures(WebKitSettings* settings) >+{ >+ g_return_val_if_fail(WEBKIT_IS_SETTINGS(settings), FALSE); >+ >+ return settings->priv->allowBackForwardNavigationGestures; >+} >+ >+/** >+ * webkit_settings_set_allow_back_forward_navigation_gestures: >+ * @settings: a #WebKitSettings >+ * @allowed: Value to be set >+ * >+ * Set the #WebKitSettings:allow-back-forward-navigation-gestures property. >+ * >+ * Since: 2.24 >+ */ >+void webkit_settings_set_allow_back_forward_navigation_gestures(WebKitSettings* settings, gboolean allowed) >+{ >+ g_return_if_fail(WEBKIT_IS_SETTINGS(settings)); >+ >+ WebKitSettingsPrivate* priv = settings->priv; >+ if (priv->allowBackForwardNavigationGestures == allowed) >+ return; >+ >+ priv->allowBackForwardNavigationGestures = allowed; >+ g_object_notify(G_OBJECT(settings), "allow-back-forward-navigation-gestures"); >+} >+ > /** > * webkit_settings_font_size_to_points: > * @pixels: the font size in pixels to convert to points >diff --git a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp >index 67201d89eaa1f3f20df8b91f1da15d9c258b638f..146ec5a8453edb5c005be1fd3af601bb0f40c68a 100644 >--- a/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp >+++ b/Source/WebKit/UIProcess/API/glib/WebKitWebView.cpp >@@ -501,6 +501,17 @@ static void userAgentChanged(WebKitSettings* settings, GParamSpec*, WebKitWebVie > } > > #if PLATFORM(GTK) >+static void allowBackForwardNavigationGesturesChanged(WebKitSettings *settings, GParamSpec*, WebKitWebView* webView) >+{ >+ gboolean allowsBackForwardNavigationGestures = webkit_settings_get_allow_back_forward_navigation_gestures(settings); >+ BackForwardGestureController* controller = &webkitWebViewBaseBackForwardGestureController(WEBKIT_WEB_VIEW_BASE(webView)); >+ >+ if (controller) >+ controller->setSwipeGestureEnabled(allowsBackForwardNavigationGestures); >+ >+ getPage(webView).setShouldRecordNavigationSnapshots(allowsBackForwardNavigationGestures); >+} >+ > static void webkitWebViewUpdateFavicon(WebKitWebView* webView, cairo_surface_t* favicon) > { > WebKitWebViewPrivate* priv = webView->priv; >@@ -581,10 +592,16 @@ static void webkitWebViewUpdateSettings(WebKitWebView* webView) > page.setPreferences(*webkitSettingsGetPreferences(settings)); > page.setCanRunModal(webkit_settings_get_allow_modal_dialogs(settings)); > page.setCustomUserAgent(String::fromUTF8(webkit_settings_get_user_agent(settings))); >+#if PLATFORM(GTK) >+ allowBackForwardNavigationGesturesChanged(settings, nullptr, webView); >+#endif > > g_signal_connect(settings, "notify::allow-modal-dialogs", G_CALLBACK(allowModalDialogsChanged), webView); > g_signal_connect(settings, "notify::zoom-text-only", G_CALLBACK(zoomTextOnlyChanged), webView); > g_signal_connect(settings, "notify::user-agent", G_CALLBACK(userAgentChanged), webView); >+#if PLATFORM(GTK) >+ g_signal_connect(settings, "notify::allow-back-forward-navigation-gestures", G_CALLBACK(allowBackForwardNavigationGesturesChanged), webView); >+#endif > } > > static void webkitWebViewDisconnectSettingsSignalHandlers(WebKitWebView* webView) >@@ -596,6 +613,9 @@ static void webkitWebViewDisconnectSettingsSignalHandlers(WebKitWebView* webView > g_signal_handlers_disconnect_by_func(settings, reinterpret_cast<gpointer>(allowModalDialogsChanged), webView); > g_signal_handlers_disconnect_by_func(settings, reinterpret_cast<gpointer>(zoomTextOnlyChanged), webView); > g_signal_handlers_disconnect_by_func(settings, reinterpret_cast<gpointer>(userAgentChanged), webView); >+#if PLATFORM(GTK) >+ g_signal_handlers_disconnect_by_func(settings, reinterpret_cast<gpointer>(allowBackForwardNavigationGesturesChanged), webView); >+#endif > } > > #if PLATFORM(GTK) >diff --git a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp >index 317859d75335e7ddca0307204dcce5e4de1e012e..b2c4c5c0061186b685df168efb4a32c6e8d13729 100644 >--- a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp >+++ b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.cpp >@@ -32,6 +32,7 @@ > #include "NativeWebKeyboardEvent.h" > #include "NativeWebMouseEvent.h" > #include "NativeWebWheelEvent.h" >+#include "ViewSnapshotStore.h" > #include "WebColorPickerGtk.h" > #include "WebContextMenuProxyGtk.h" > #include "WebEventFactory.h" >@@ -67,6 +68,15 @@ std::unique_ptr<DrawingAreaProxy> PageClientImpl::createDrawingAreaProxy(WebProc > > void PageClientImpl::setViewNeedsDisplay(const WebCore::Region& region) > { >+ WebPageProxy* pageProxy = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(m_viewWidget)); >+ >+ // During the gesture, the page may be displayed with an offset. >+ // To avoid visual glitches, redraw the whole page. >+ if (pageProxy->isShowingNavigationGestureSnapshot()) { >+ gtk_widget_queue_draw(m_viewWidget); >+ return; >+ } >+ > gtk_widget_queue_draw_region(m_viewWidget, toCairoRegion(region).get()); > } > >@@ -255,6 +265,11 @@ void PageClientImpl::selectionDidChange() > webkitWebViewSelectionDidChange(WEBKIT_WEB_VIEW(m_viewWidget)); > } > >+RefPtr<ViewSnapshot> PageClientImpl::takeViewSnapshot() >+{ >+ return webkitWebViewBaseTakeViewSnapshot(WEBKIT_WEB_VIEW_BASE(m_viewWidget)); >+} >+ > void PageClientImpl::didChangeContentSize(const IntSize& size) > { > webkitWebViewBaseSetContentsSize(WEBKIT_WEB_VIEW_BASE(m_viewWidget), size); >@@ -404,6 +419,13 @@ void PageClientImpl::doneWithTouchEvent(const NativeWebTouchEvent& event, bool w > > void PageClientImpl::wheelEventWasNotHandledByWebCore(const NativeWebWheelEvent& event) > { >+ BackForwardGestureController& controller = webkitWebViewBaseBackForwardGestureController(WEBKIT_WEB_VIEW_BASE(m_viewWidget)); >+ >+ if (controller.isSwipeGestureEnabled()) { >+ controller.wheelEventWasNotHandledByWebCore(&event.nativeEvent()->scroll); >+ return; >+ } >+ > webkitWebViewBaseForwardNextWheelEvent(WEBKIT_WEB_VIEW_BASE(m_viewWidget)); > gtk_main_do_event(event.nativeEvent()); > } >@@ -436,16 +458,34 @@ void PageClientImpl::didRemoveNavigationGestureSnapshot() > { > } > >+void PageClientImpl::didStartProvisionalLoadForMainFrame() >+{ >+ webkitWebViewBaseDidStartProvisionalLoadForMainFrame(WEBKIT_WEB_VIEW_BASE(m_viewWidget)); >+} >+ > void PageClientImpl::didFirstVisuallyNonEmptyLayoutForMainFrame() > { >+ webkitWebViewBaseDidFirstVisuallyNonEmptyLayoutForMainFrame(WEBKIT_WEB_VIEW_BASE(m_viewWidget)); > } > > void PageClientImpl::didFinishLoadForMainFrame() > { >+ webkitWebViewBaseDidFinishLoadForMainFrame(WEBKIT_WEB_VIEW_BASE(m_viewWidget)); >+} >+ >+void PageClientImpl::didFailLoadForMainFrame() >+{ >+ webkitWebViewBaseDidFailLoadForMainFrame(WEBKIT_WEB_VIEW_BASE(m_viewWidget)); >+} >+ >+void PageClientImpl::didSameDocumentNavigationForMainFrame(SameDocumentNavigationType type) >+{ >+ webkitWebViewBaseDidSameDocumentNavigationForMainFrame(WEBKIT_WEB_VIEW_BASE(m_viewWidget), type); > } > >-void PageClientImpl::didSameDocumentNavigationForMainFrame(SameDocumentNavigationType) >+void PageClientImpl::didRestoreScrollPosition() > { >+ webkitWebViewBaseDidRestoreScrollPosition(WEBKIT_WEB_VIEW_BASE(m_viewWidget)); > } > > void PageClientImpl::didChangeBackgroundColor() >diff --git a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.h b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.h >index 6dea8f39fd8151d464ce64a15e530ce96f9c4de3..a84542e5309cd8fe87325e4ea75c8342d5dbc8ae 100644 >--- a/Source/WebKit/UIProcess/API/gtk/PageClientImpl.h >+++ b/Source/WebKit/UIProcess/API/gtk/PageClientImpl.h >@@ -87,6 +87,7 @@ private: > RefPtr<WebColorPicker> createColorPicker(WebPageProxy*, const WebCore::Color& initialColor, const WebCore::IntRect&, Vector<WebCore::Color>&&) override; > #endif > void selectionDidChange() override; >+ RefPtr<ViewSnapshot> takeViewSnapshot() override; > #if ENABLE(DRAG_SUPPORT) > void startDrag(Ref<WebCore::SelectionData>&&, WebCore::DragOperation, RefPtr<ShareableBitmap>&& dragImage) override; > #endif >@@ -98,7 +99,7 @@ private: > void handleDownloadRequest(DownloadProxy*) override; > void didChangeContentSize(const WebCore::IntSize&) override; > void didCommitLoadForMainFrame(const String& mimeType, bool useCustomContentProvider) override; >- void didFailLoadForMainFrame() override { } >+ void didFailLoadForMainFrame() override; > > // Auxiliary Client Creation > #if ENABLE(FULLSCREEN_API) >@@ -124,6 +125,7 @@ private: > void willRecordNavigationSnapshot(WebBackForwardListItem&) override; > void didRemoveNavigationGestureSnapshot() override; > >+ void didStartProvisionalLoadForMainFrame() override; > void didFirstVisuallyNonEmptyLayoutForMainFrame() override; > void didFinishLoadForMainFrame() override; > void didSameDocumentNavigationForMainFrame(SameDocumentNavigationType) override; >@@ -139,7 +141,7 @@ private: > void refView() override; > void derefView() override; > >- void didRestoreScrollPosition() override { } >+ void didRestoreScrollPosition() override; > void isPlayingAudioWillChange() final { } > void isPlayingAudioDidChange() final { } > >diff --git a/Source/WebKit/UIProcess/API/gtk/WebKitSettings.h b/Source/WebKit/UIProcess/API/gtk/WebKitSettings.h >index cb2c206e2f6879d7377e209538c56ce5b03ab391..3ecf852181115680d5baac1d42d54c8426ffaf6d 100644 >--- a/Source/WebKit/UIProcess/API/gtk/WebKitSettings.h >+++ b/Source/WebKit/UIProcess/API/gtk/WebKitSettings.h >@@ -472,6 +472,13 @@ WEBKIT_API void > webkit_settings_set_hardware_acceleration_policy (WebKitSettings *settings, > WebKitHardwareAccelerationPolicy policy); > >+WEBKIT_API gboolean >+webkit_settings_get_allow_back_forward_navigation_gestures (WebKitSettings *settings); >+ >+WEBKIT_API void >+webkit_settings_set_allow_back_forward_navigation_gestures (WebKitSettings *settings, >+ gboolean allowed); >+ > WEBKIT_API guint32 > webkit_settings_font_size_to_points (guint32 pixels); > >diff --git a/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp b/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp >index 50f83ba2b8d7a45d75a101610ef62daa56daec02..ae2f8b3f5fcf7eaeea8f1f18f28f3d5f1fdf68f1 100644 >--- a/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp >+++ b/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBase.cpp >@@ -31,6 +31,7 @@ > > #include "APIPageConfiguration.h" > #include "AcceleratedBackingStore.h" >+#include "BackForwardGestureController.h" > #include "DrawingAreaProxyImpl.h" > #include "InputMethodFilter.h" > #include "KeyBindingTranslator.h" >@@ -202,6 +203,7 @@ struct _WebKitWebViewBasePrivate { > #if HAVE(GTK_GESTURES) > std::unique_ptr<GestureController> gestureController; > #endif >+ std::unique_ptr<BackForwardGestureController> backForwardGestureController; > }; > > WEBKIT_DEFINE_TYPE(WebKitWebViewBase, webkit_web_view_base, GTK_TYPE_CONTAINER) >@@ -533,6 +535,12 @@ static gboolean webkitWebViewBaseDraw(GtkWidget* widget, cairo_t* cr) > if (!gdk_cairo_get_clip_rectangle(cr, &clipRect)) > return FALSE; > >+ bool showingNavigationSnapshot = webViewBase->priv->pageProxy->isShowingNavigationGestureSnapshot(); >+ >+ BackForwardGestureController& controller = webkitWebViewBaseBackForwardGestureController(webViewBase); >+ if (showingNavigationSnapshot) >+ cairo_push_group(cr); >+ > if (webViewBase->priv->acceleratedBackingStore && drawingArea->isInAcceleratedCompositingMode()) > webViewBase->priv->acceleratedBackingStore->paint(cr, clipRect); > else { >@@ -540,6 +548,12 @@ static gboolean webkitWebViewBaseDraw(GtkWidget* widget, cairo_t* cr) > drawingArea->paint(cr, clipRect, unpaintedRegion); > } > >+ if (showingNavigationSnapshot) { >+ cairo_pattern_t* group = cairo_pop_group(cr); >+ controller.draw(cr, group); >+ cairo_pattern_destroy(group); >+ } >+ > GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->draw(widget, cr); > > return FALSE; >@@ -852,6 +866,10 @@ static gboolean webkitWebViewBaseScrollEvent(GtkWidget* widget, GdkEventScroll* > } > } > >+ WebKit::BackForwardGestureController& controller = webkitWebViewBaseBackForwardGestureController(webViewBase); >+ if (controller.isSwipeGestureEnabled() && controller.handleScrollWheelEvent(event)) >+ return GDK_EVENT_STOP; >+ > webkitWebViewBaseHandleWheelEvent(webViewBase, reinterpret_cast<GdkEvent*>(event)); > > return GDK_EVENT_STOP; >@@ -1148,6 +1166,14 @@ GestureController& webkitWebViewBaseGestureController(WebKitWebViewBase* webView > } > #endif > >+BackForwardGestureController& webkitWebViewBaseBackForwardGestureController(WebKitWebViewBase* webViewBase) >+{ >+ WebKitWebViewBasePrivate* priv = webViewBase->priv; >+ if (!priv->backForwardGestureController) >+ priv->backForwardGestureController = std::make_unique<WebKit::BackForwardGestureController>(*priv->pageProxy); >+ return *priv->backForwardGestureController; >+} >+ > static gboolean webkitWebViewBaseQueryTooltip(GtkWidget* widget, gint /* x */, gint /* y */, gboolean keyboardMode, GtkTooltip* tooltip) > { > WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv; >@@ -1619,3 +1645,65 @@ void webkitWebViewBasePageClosed(WebKitWebViewBase* webkitWebViewBase) > drawingArea->destroyNativeSurfaceHandleForCompositing(); > #endif > } >+ >+RefPtr<WebKit::ViewSnapshot> webkitWebViewBaseTakeViewSnapshot(WebKitWebViewBase* webkitWebViewBase) >+{ >+ WebPageProxy* proxy = webkitWebViewBase->priv->pageProxy.get(); >+ >+ IntSize size = proxy->viewSize(); >+ >+#if HAVE_GTK_SCALE_FACTOR >+ float deviceScale = proxy->deviceScaleFactor(); >+ size.scale(deviceScale); >+#endif >+ >+ RefPtr<cairo_surface_t> surface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_RGB24, size.width(), size.height())); >+ >+#if HAVE_GTK_SCALE_FACTOR >+ cairoSurfaceSetDeviceScale(surface.get(), deviceScale, deviceScale); >+#endif >+ >+ cairo_t* cr = cairo_create(surface.get()); >+ >+ webkitWebViewBaseDraw(GTK_WIDGET(webkitWebViewBase), cr); >+ >+ RefPtr<ViewSnapshot> snapshot = ViewSnapshot::create(WTFMove(surface)); >+ >+ return WTFMove(snapshot); >+} >+ >+void webkitWebViewBaseDidStartProvisionalLoadForMainFrame(WebKitWebViewBase* webkitWebViewBase) >+{ >+ if (webkitWebViewBase->priv->backForwardGestureController) >+ webkitWebViewBase->priv->backForwardGestureController->didStartProvisionalLoadForMainFrame(); >+} >+ >+void webkitWebViewBaseDidFirstVisuallyNonEmptyLayoutForMainFrame(WebKitWebViewBase* webkitWebViewBase) >+{ >+ if (webkitWebViewBase->priv->backForwardGestureController) >+ webkitWebViewBase->priv->backForwardGestureController->didFirstVisuallyNonEmptyLayoutForMainFrame(); >+} >+ >+void webkitWebViewBaseDidFinishLoadForMainFrame(WebKitWebViewBase* webkitWebViewBase) >+{ >+ if (webkitWebViewBase->priv->backForwardGestureController) >+ webkitWebViewBase->priv->backForwardGestureController->didFinishLoadForMainFrame(); >+} >+ >+void webkitWebViewBaseDidFailLoadForMainFrame(WebKitWebViewBase* webkitWebViewBase) >+{ >+ if (webkitWebViewBase->priv->backForwardGestureController) >+ webkitWebViewBase->priv->backForwardGestureController->didFailLoadForMainFrame(); >+} >+ >+void webkitWebViewBaseDidSameDocumentNavigationForMainFrame(WebKitWebViewBase* webkitWebViewBase, SameDocumentNavigationType type) >+{ >+ if (webkitWebViewBase->priv->backForwardGestureController) >+ webkitWebViewBase->priv->backForwardGestureController->didSameDocumentNavigationForMainFrame(type); >+} >+ >+void webkitWebViewBaseDidRestoreScrollPosition(WebKitWebViewBase* webkitWebViewBase) >+{ >+ if (webkitWebViewBase->priv->backForwardGestureController) >+ webkitWebViewBase->priv->backForwardGestureController->didRestoreScrollPosition(); >+} >diff --git a/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h b/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h >index a24d67a69ff42373ac8f2a002e851b6272ab68bb..d5b6cbd3ea60b9986802f45099037001fa16e09f 100644 >--- a/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h >+++ b/Source/WebKit/UIProcess/API/gtk/WebKitWebViewBasePrivate.h >@@ -28,8 +28,11 @@ > #pragma once > > #include "APIPageConfiguration.h" >+#include "BackForwardGestureController.h" > #include "DragAndDropHandler.h" > #include "GestureController.h" >+#include "SameDocumentNavigationType.h" >+#include "ViewSnapshotStore.h" > #include "WebContextMenuProxyGtk.h" > #include "WebInspectorProxy.h" > #include "WebKitWebViewBase.h" >@@ -77,3 +80,14 @@ WebKit::DragAndDropHandler& webkitWebViewBaseDragAndDropHandler(WebKitWebViewBas > #if HAVE(GTK_GESTURES) > WebKit::GestureController& webkitWebViewBaseGestureController(WebKitWebViewBase*); > #endif >+ >+RefPtr<WebKit::ViewSnapshot> webkitWebViewBaseTakeViewSnapshot(WebKitWebViewBase*); >+ >+WebKit::BackForwardGestureController& webkitWebViewBaseBackForwardGestureController(WebKitWebViewBase*); >+ >+void webkitWebViewBaseDidStartProvisionalLoadForMainFrame(WebKitWebViewBase*); >+void webkitWebViewBaseDidFirstVisuallyNonEmptyLayoutForMainFrame(WebKitWebViewBase*); >+void webkitWebViewBaseDidFinishLoadForMainFrame(WebKitWebViewBase*); >+void webkitWebViewBaseDidFailLoadForMainFrame(WebKitWebViewBase*); >+void webkitWebViewBaseDidSameDocumentNavigationForMainFrame(WebKitWebViewBase*, WebKit::SameDocumentNavigationType); >+void webkitWebViewBaseDidRestoreScrollPosition(WebKitWebViewBase*); >diff --git a/Source/WebKit/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt b/Source/WebKit/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt >index 1b7b5b865638491c6d033b55588ca34e8d3b8f6a..aaeb3821d0e74fbe85906272942a896a4d3f2874 100644 >--- a/Source/WebKit/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt >+++ b/Source/WebKit/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt >@@ -488,6 +488,8 @@ webkit_settings_get_allow_universal_access_from_file_urls > webkit_settings_set_allow_universal_access_from_file_urls > webkit_settings_get_hardware_acceleration_policy > webkit_settings_set_hardware_acceleration_policy >+webkit_settings_get_allow_back_forward_navigation_gestures >+webkit_settings_set_allow_back_forward_navigation_gestures > webkit_settings_font_size_to_points > webkit_settings_font_size_to_pixels > >diff --git a/Source/WebKit/UIProcess/PageClient.h b/Source/WebKit/UIProcess/PageClient.h >index 43413af421aaa8c8a8d834342b9626ecce6cb113..7cd3b3f5089ace1f96b63a38488cb56444478d49 100644 >--- a/Source/WebKit/UIProcess/PageClient.h >+++ b/Source/WebKit/UIProcess/PageClient.h >@@ -253,7 +253,6 @@ public: > virtual void assistiveTechnologyMakeFirstResponder() = 0; > virtual void setRemoteLayerTreeRootNode(RemoteLayerTreeNode*) = 0; > virtual CALayer *acceleratedCompositingRootLayer() const = 0; >- virtual RefPtr<ViewSnapshot> takeViewSnapshot() = 0; > #if ENABLE(MAC_GESTURE_EVENTS) > virtual void gestureEventWasNotHandledByWebCore(const NativeWebGestureEvent&) = 0; > #endif >@@ -261,6 +260,7 @@ public: > > #if PLATFORM(COCOA) || PLATFORM(GTK) > virtual void selectionDidChange() = 0; >+ virtual RefPtr<ViewSnapshot> takeViewSnapshot() = 0; > #endif > > #if USE(APPKIT) >diff --git a/Source/WebKit/UIProcess/WebBackForwardList.cpp b/Source/WebKit/UIProcess/WebBackForwardList.cpp >index 7ae26b2f3b832df30abf5cf2b24d1be6231a5407..6c0a37f3f4562a8f7293ea3d6f1c7439c12dbe6a 100644 >--- a/Source/WebKit/UIProcess/WebBackForwardList.cpp >+++ b/Source/WebKit/UIProcess/WebBackForwardList.cpp >@@ -468,7 +468,7 @@ void WebBackForwardList::didRemoveItem(WebBackForwardListItem& backForwardListIt > m_page->backForwardRemovedItem(backForwardListItem.itemID()); > > backForwardListItem.setSuspendedPage(nullptr); >-#if PLATFORM(COCOA) >+#if PLATFORM(COCOA) || PLATFORM(GTK) > backForwardListItem.setSnapshot(nullptr); > #endif > } >diff --git a/Source/WebKit/UIProcess/WebPageProxy.cpp b/Source/WebKit/UIProcess/WebPageProxy.cpp >index 1207c67a2c2f98bff095f569d42539488d650743..26e4bd37f03fdaf78b3fbb07d4f6f361360b8bf6 100644 >--- a/Source/WebKit/UIProcess/WebPageProxy.cpp >+++ b/Source/WebKit/UIProcess/WebPageProxy.cpp >@@ -189,12 +189,15 @@ > #include "TouchBarMenuItemData.h" > #include "VideoFullscreenManagerProxy.h" > #include "VideoFullscreenManagerProxyMessages.h" >-#include "ViewSnapshotStore.h" > #include <WebCore/RunLoopObserver.h> > #include <WebCore/TextIndicatorWindow.h> > #include <wtf/MachSendRight.h> > #endif > >+#if PLATFORM(COCOA) || PLATFORM(GTK) >+#include "ViewSnapshotStore.h" >+#endif >+ > #if PLATFORM(GTK) > #include "WebSelectionData.h" > #endif >@@ -1341,7 +1344,7 @@ void WebPageProxy::recordNavigationSnapshot(WebBackForwardListItem& item) > if (!m_shouldRecordNavigationSnapshots) > return; > >-#if PLATFORM(COCOA) >+#if PLATFORM(COCOA) || PLATFORM(GTK) > ViewSnapshotStore::singleton().recordSnapshot(*this, item); > #else > UNUSED_PARAM(item); >@@ -7431,7 +7434,7 @@ void WebPageProxy::setEditableElementIsFocused(bool editableElementIsFocused) > > #endif // PLATFORM(MAC) > >-#if PLATFORM(COCOA) >+#if PLATFORM(COCOA) || PLATFORM(GTK) > RefPtr<ViewSnapshot> WebPageProxy::takeViewSnapshot() > { > return pageClient().takeViewSnapshot(); >diff --git a/Source/WebKit/UIProcess/WebPageProxy.h b/Source/WebKit/UIProcess/WebPageProxy.h >index 6c8f85ca72c95fa3fb73e55f0f33227ad4a3df6b..249bb40612e1a0d566b0e456a01f795a2e72030c 100644 >--- a/Source/WebKit/UIProcess/WebPageProxy.h >+++ b/Source/WebKit/UIProcess/WebPageProxy.h >@@ -1216,7 +1216,7 @@ public: > void recordNavigationSnapshot(WebBackForwardListItem&); > void requestFocusedElementInformation(Function<void(const FocusedElementInformation&, CallbackBase::Error)>&&); > >-#if PLATFORM(COCOA) >+#if PLATFORM(COCOA) || PLATFORM(GTK) > RefPtr<ViewSnapshot> takeViewSnapshot(); > #endif > >diff --git a/Source/WebKit/UIProcess/gtk/BackForwardGestureController.cpp b/Source/WebKit/UIProcess/gtk/BackForwardGestureController.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..8802a3f49ec7d5d345d53cd294fac48c7fd46950 >--- /dev/null >+++ b/Source/WebKit/UIProcess/gtk/BackForwardGestureController.cpp >@@ -0,0 +1,797 @@ >+/* >+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "BackForwardGestureController.h" >+ >+#include "APINavigation.h" >+#include "DrawingAreaProxy.h" >+#include "Logging.h" >+#include "PlatformDisplay.h" >+#include "WebBackForwardList.h" >+#include "WebFullScreenManagerProxy.h" >+#include "WebPageProxy.h" >+#include "WebProcessProxy.h" >+#include <wtf/text/StringBuilder.h> >+ >+namespace WebKit { >+using namespace WebCore; >+ >+static const Seconds swipeSnapshotRemovalWatchdogAfterFirstVisuallyNonEmptyLayoutDuration { 3_s }; >+static const Seconds swipeSnapshotRemovalActiveLoadMonitoringInterval { 250_ms }; >+ >+static const Seconds swipeSnapshotRemovalWatchdogDuration = 5_s; >+ >+static const double swipeBaseAnimationSpeed = 40; >+static const Seconds swipeMinAnimationDuration = 100_ms; >+static const Seconds swipeMaxAnimationDuration = 400_ms; >+ >+static const float minimumHorizontalSwipeDistance = 15; >+static const float minimumScrollEventRatioForSwipe = 0.5; >+ >+static const double swipeOverlayShadowOpacity = 0.06; >+static const double swipeOverlayDimmingOpacity = 0.12; >+static const double swipeOverlayShadowWidth = 81; >+static const double swipeOverlayShadowGradientOffsets[] = { 0, 0.03125, 0.0625, 0.0938, 0.125, 0.1875, 0.25, 0.375, 0.4375, 0.5, 0.5625, 0.625, 0.6875, 0.75, 0.875, 1. }; >+static const double swipeOverlayShadowGradientAlpha[] = { 1, 0.99, 0.98, 0.95, 0.92, 0.82, 0.71, 0.46, 0.35, 0.25, 0.17, 0.11, 0.07, 0.04, 0.01, 0. }; >+ >+static HashMap<uint64_t, BackForwardGestureController*>& BackForwardGestureControllersForAllPages() >+{ >+ // The key in this map is the associated page ID. >+ static NeverDestroyed<HashMap<uint64_t, BackForwardGestureController*>> BackForwardGestureControllers; >+ return BackForwardGestureControllers.get(); >+} >+ >+BackForwardGestureController::BackForwardGestureController(WebPageProxy& webPageProxy) >+ : m_webPageProxy(webPageProxy) >+ , m_swipeActiveLoadMonitoringTimer(RunLoop::main(), this, &BackForwardGestureController::checkForActiveLoads) >+ , m_pendingSwipeTracker(webPageProxy, *this) >+ , m_swipeProgressTracker(webPageProxy, *this) >+{ >+ BackForwardGestureControllersForAllPages().add(webPageProxy.pageID(), this); >+} >+ >+BackForwardGestureController::~BackForwardGestureController() >+{ >+ m_swipeProgressTracker.reset(); >+ >+ if (m_activeGesture) >+ removeSwipeSnapshot(); >+ >+ BackForwardGestureControllersForAllPages().remove(m_webPageProxy.pageID()); >+} >+ >+BackForwardGestureController* BackForwardGestureController::controllerForGesture(uint64_t pageID, BackForwardGestureController::GestureID gestureID) >+{ >+ auto gestureControllerIter = BackForwardGestureControllersForAllPages().find(pageID); >+ if (gestureControllerIter == BackForwardGestureControllersForAllPages().end()) >+ return nullptr; >+ if (gestureControllerIter->value->m_currentGestureID != gestureID) >+ return nullptr; >+ return gestureControllerIter->value; >+} >+ >+BackForwardGestureController::GestureID BackForwardGestureController::takeNextGestureID() >+{ >+ static GestureID nextGestureID; >+ return ++nextGestureID; >+} >+ >+void BackForwardGestureController::willBeginGesture() >+{ >+ m_activeGesture = true; >+ m_currentGestureID = takeNextGestureID(); >+ >+ m_webPageProxy.setSuppressScrollbarAnimations(true); >+} >+ >+void BackForwardGestureController::didEndGesture() >+{ >+ m_activeGesture = false; >+ m_currentGestureID = 0; >+ >+ m_webPageProxy.setSuppressScrollbarAnimations(false); >+} >+ >+bool BackForwardGestureController::canSwipeInDirection(SwipeDirection direction) const >+{ >+ if (!m_swipeGestureEnabled) >+ return false; >+ >+#if ENABLE(FULLSCREEN_API) >+ if (m_webPageProxy.fullScreenManager() && m_webPageProxy.fullScreenManager()->isFullScreen()) >+ return false; >+#endif >+ >+ auto& backForwardList = m_webPageProxy.backForwardList(); >+ if (direction == SwipeDirection::Back) >+ return !!backForwardList.backItem(); >+ return !!backForwardList.forwardItem(); >+} >+ >+void BackForwardGestureController::didStartProvisionalLoadForMainFrame() >+{ >+ m_snapshotRemovalTracker.resume(); >+} >+ >+void BackForwardGestureController::didFirstVisuallyNonEmptyLayoutForMainFrame() >+{ >+ if (!m_snapshotRemovalTracker.eventOccurred(SnapshotRemovalTracker::VisuallyNonEmptyLayout)) >+ return; >+ >+ m_snapshotRemovalTracker.cancelOutstandingEvent(SnapshotRemovalTracker::MainFrameLoad); >+ m_snapshotRemovalTracker.cancelOutstandingEvent(SnapshotRemovalTracker::SubresourceLoads); >+ m_snapshotRemovalTracker.startWatchdog(swipeSnapshotRemovalWatchdogAfterFirstVisuallyNonEmptyLayoutDuration); >+} >+ >+void BackForwardGestureController::didRestoreScrollPosition() >+{ >+ m_snapshotRemovalTracker.eventOccurred(SnapshotRemovalTracker::ScrollPositionRestoration); >+} >+ >+void BackForwardGestureController::didReachMainFrameLoadTerminalState() >+{ >+ if (m_snapshotRemovalTracker.isPaused()) { >+ removeSwipeSnapshot(); >+ return; >+ } >+ >+ if (!m_snapshotRemovalTracker.eventOccurred(SnapshotRemovalTracker::MainFrameLoad)) >+ return; >+ >+ // Coming back from the page cache will result in getting a load event, but no first visually non-empty layout. >+ // WebCore considers a loaded document enough to be considered visually non-empty, so that's good >+ // enough for us too. >+ m_snapshotRemovalTracker.cancelOutstandingEvent(SnapshotRemovalTracker::VisuallyNonEmptyLayout); >+ >+ checkForActiveLoads(); >+} >+ >+void BackForwardGestureController::didSameDocumentNavigationForMainFrame(SameDocumentNavigationType type) >+{ >+ m_snapshotRemovalTracker.resume(); >+ >+ bool cancelledOutstandingEvent = false; >+ >+ // Same-document navigations don't have a main frame load or first visually non-empty layout. >+ cancelledOutstandingEvent |= m_snapshotRemovalTracker.cancelOutstandingEvent(SnapshotRemovalTracker::MainFrameLoad); >+ cancelledOutstandingEvent |= m_snapshotRemovalTracker.cancelOutstandingEvent(SnapshotRemovalTracker::VisuallyNonEmptyLayout); >+ >+ if (!cancelledOutstandingEvent) >+ return; >+ >+ if (type != SameDocumentNavigationSessionStateReplace && type != SameDocumentNavigationSessionStatePop) >+ return; >+ >+ checkForActiveLoads(); >+} >+ >+void BackForwardGestureController::checkForActiveLoads() >+{ >+ if (m_webPageProxy.pageLoadState().isLoading()) { >+ if (!m_swipeActiveLoadMonitoringTimer.isActive()) >+ m_swipeActiveLoadMonitoringTimer.startRepeating(swipeSnapshotRemovalActiveLoadMonitoringInterval); >+ return; >+ } >+ >+ m_swipeActiveLoadMonitoringTimer.stop(); >+ m_snapshotRemovalTracker.eventOccurred(SnapshotRemovalTracker::SubresourceLoads); >+} >+ >+BackForwardGestureController::SnapshotRemovalTracker::SnapshotRemovalTracker() >+ : m_watchdogTimer(RunLoop::main(), this, &SnapshotRemovalTracker::watchdogTimerFired) >+{ >+} >+ >+String BackForwardGestureController::SnapshotRemovalTracker::eventsDescription(Events event) >+{ >+ StringBuilder description; >+ >+ if (event & BackForwardGestureController::SnapshotRemovalTracker::VisuallyNonEmptyLayout) >+ description.append("VisuallyNonEmptyLayout "); >+ >+ if (event & BackForwardGestureController::SnapshotRemovalTracker::MainFrameLoad) >+ description.append("MainFrameLoad "); >+ >+ if (event & BackForwardGestureController::SnapshotRemovalTracker::SubresourceLoads) >+ description.append("SubresourceLoads "); >+ >+ if (event & BackForwardGestureController::SnapshotRemovalTracker::ScrollPositionRestoration) >+ description.append("ScrollPositionRestoration "); >+ >+ return description.toString(); >+} >+ >+void BackForwardGestureController::SnapshotRemovalTracker::log(const String& log) const >+{ >+ auto sinceStart = MonotonicTime::now() - m_startTime; >+ RELEASE_LOG(ViewGestures, "Swipe Snapshot Removal (%0.2f ms) - %{public}s", sinceStart.milliseconds(), log.utf8().data()); >+} >+ >+void BackForwardGestureController::SnapshotRemovalTracker::resume() >+{ >+ if (isPaused() && m_outstandingEvents) >+ log("resume"); >+ m_paused = false; >+} >+ >+void BackForwardGestureController::SnapshotRemovalTracker::start(Events desiredEvents, WTF::Function<void()>&& removalCallback) >+{ >+ m_outstandingEvents = desiredEvents; >+ m_removalCallback = WTFMove(removalCallback); >+ m_startTime = MonotonicTime::now(); >+ >+ log("start"); >+ >+ startWatchdog(swipeSnapshotRemovalWatchdogDuration); >+ >+ // Initially start out paused; we'll resume when the load is committed. >+ // This avoids processing callbacks from earlier loads. >+ pause(); >+} >+ >+void BackForwardGestureController::SnapshotRemovalTracker::reset() >+{ >+ if (m_outstandingEvents) >+ log("reset; had outstanding events: " + eventsDescription(m_outstandingEvents)); >+ m_outstandingEvents = 0; >+ m_watchdogTimer.stop(); >+ m_removalCallback = nullptr; >+} >+ >+bool BackForwardGestureController::SnapshotRemovalTracker::stopWaitingForEvent(Events event, const String& logReason) >+{ >+ ASSERT(hasOneBitSet(event)); >+ >+ if (!(m_outstandingEvents & event)) >+ return false; >+ >+ if (isPaused()) { >+ log("is paused; ignoring event: " + eventsDescription(event)); >+ return false; >+ } >+ >+ log(logReason + eventsDescription(event)); >+ >+ m_outstandingEvents &= ~event; >+ >+ fireRemovalCallbackIfPossible(); >+ return true; >+} >+ >+bool BackForwardGestureController::SnapshotRemovalTracker::eventOccurred(Events event) >+{ >+ return stopWaitingForEvent(event, "outstanding event occurred: "); >+} >+ >+bool BackForwardGestureController::SnapshotRemovalTracker::cancelOutstandingEvent(Events event) >+{ >+ return stopWaitingForEvent(event, "wait for event cancelled: "); >+} >+ >+void BackForwardGestureController::SnapshotRemovalTracker::fireRemovalCallbackIfPossible() >+{ >+ if (m_outstandingEvents) { >+ log("deferring removal; had outstanding events: " + eventsDescription(m_outstandingEvents)); >+ return; >+ } >+ >+ fireRemovalCallbackImmediately(); >+} >+ >+void BackForwardGestureController::SnapshotRemovalTracker::fireRemovalCallbackImmediately() >+{ >+ m_watchdogTimer.stop(); >+ >+ auto removalCallback = WTFMove(m_removalCallback); >+ if (removalCallback) { >+ log("removing snapshot"); >+ reset(); >+ removalCallback(); >+ } >+} >+ >+void BackForwardGestureController::SnapshotRemovalTracker::watchdogTimerFired() >+{ >+ log("watchdog timer fired"); >+ fireRemovalCallbackImmediately(); >+} >+ >+void BackForwardGestureController::SnapshotRemovalTracker::startWatchdog(Seconds duration) >+{ >+ log(String::format("(re)started watchdog timer for %.1f seconds", duration.seconds())); >+ m_watchdogTimer.startOneShot(duration); >+} >+ >+BackForwardGestureController::PendingSwipeTracker::PendingSwipeTracker(WebPageProxy& webPageProxy, BackForwardGestureController& backForwardGestureController) >+ : m_backForwardGestureController(backForwardGestureController) >+ , m_webPageProxy(webPageProxy) >+{ >+} >+ >+static bool scrollEventCanInfluenceSwipe(GdkEventScroll* event) >+{ >+ GdkDevice* device = gdk_event_get_source_device((GdkEvent*) event); >+ GdkInputSource source = gdk_device_get_source(device); >+ >+ // TODO: Should it maybe be allowed on mice/trackpoints as well? The GDK_SCROLL_SMOOTH >+ // requirement already filters out most mice, and it works pretty well on a trackpoint >+ return event->direction == GDK_SCROLL_SMOOTH && source == GDK_SOURCE_TOUCHPAD; >+} >+ >+static bool deltaShouldCancelSwipe(float x, float y) >+{ >+ return std::abs(y) >= std::abs(x) * minimumScrollEventRatioForSwipe; >+} >+ >+bool BackForwardGestureController::PendingSwipeTracker::scrollEventCanBecomeSwipe(GdkEventScroll *event, BackForwardGestureController::SwipeDirection& potentialSwipeDirection) >+{ >+ if (!scrollEventCanInfluenceSwipe(event)) >+ return false; >+ >+ if (deltaShouldCancelSwipe(event->delta_x, event->delta_y)) >+ return false; >+ >+ bool isPinnedToLeft = m_shouldIgnorePinnedState || m_webPageProxy.isPinnedToLeftSide(); >+ bool isPinnedToRight = m_shouldIgnorePinnedState || m_webPageProxy.isPinnedToRightSide(); >+ >+ bool tryingToSwipeBack = event->delta_x < 0 && isPinnedToLeft; >+ bool tryingToSwipeForward = event->delta_x > 0 && isPinnedToRight; >+ if (m_webPageProxy.userInterfaceLayoutDirection() != WebCore::UserInterfaceLayoutDirection::LTR) >+ std::swap(tryingToSwipeBack, tryingToSwipeForward); >+ >+ if (!tryingToSwipeBack && !tryingToSwipeForward) >+ return false; >+ >+ potentialSwipeDirection = tryingToSwipeBack ? SwipeDirection::Back : SwipeDirection::Forward; >+ return m_backForwardGestureController.canSwipeInDirection(potentialSwipeDirection); >+} >+ >+bool BackForwardGestureController::handleScrollWheelEvent(GdkEventScroll* event) >+{ >+ // We cannot tell when the gesture has stopped on X11, so only allow it on Wayland >+ if (PlatformDisplay::sharedDisplay().type() != PlatformDisplay::Type::Wayland) >+ return false; >+ >+ return m_swipeProgressTracker.handleEvent(event) || m_pendingSwipeTracker.handleEvent(event); >+} >+ >+bool BackForwardGestureController::PendingSwipeTracker::handleEvent(GdkEventScroll *event) >+{ >+// FIXME: Tools/Scripts/prepare-ChangeLog sees an extra { here and stops processing the file >+#if GTK_CHECK_VERSION(3, 20, 0) >+ if (event->is_stop) { >+#else >+ if (!event->delta_x && !event->delta_y) { >+#endif >+ reset("gesture ended"); >+ return false; >+ } >+ >+ if (m_state == State::None) { >+ if (!scrollEventCanBecomeSwipe(event, m_direction)) >+ return false; >+ >+ if (!m_shouldIgnorePinnedState && m_webPageProxy.willHandleHorizontalScrollEvents()) { >+ m_state = State::WaitingForWebCore; >+ LOG(ViewGestures, "Swipe Start Hysteresis - waiting for WebCore to handle event"); >+ } >+ } >+ >+ if (m_state == State::WaitingForWebCore) >+ return false; >+ >+ return tryToStartSwipe(event); >+} >+ >+void BackForwardGestureController::PendingSwipeTracker::eventWasNotHandledByWebCore(GdkEventScroll* event) >+{ >+ if (m_state != State::WaitingForWebCore) >+ return; >+ >+ LOG(ViewGestures, "Swipe Start Hysteresis - WebCore didn't handle event"); >+ m_state = State::None; >+ m_cumulativeDelta = FloatSize(); >+ tryToStartSwipe(event); >+} >+ >+bool BackForwardGestureController::PendingSwipeTracker::tryToStartSwipe(GdkEventScroll* event) >+{ >+ ASSERT(m_state != State::WaitingForWebCore); >+ >+ if (m_state == State::None) { >+ SwipeDirection direction; >+ if (!scrollEventCanBecomeSwipe(event, direction)) >+ return false; >+ } >+ >+ if (!scrollEventCanInfluenceSwipe(event)) >+ return false; >+ >+ m_cumulativeDelta += FloatSize(event->delta_x, event->delta_y); >+ LOG(ViewGestures, "Swipe Start Hysteresis - consumed event, cumulative delta (%0.2f, %0.2f)", m_cumulativeDelta.width(), m_cumulativeDelta.height()); >+ >+ if (deltaShouldCancelSwipe(m_cumulativeDelta.width(), m_cumulativeDelta.height())) { >+ reset("cumulative delta became too vertical"); >+ return false; >+ } >+ >+ if (std::abs(m_cumulativeDelta.width()) >= minimumHorizontalSwipeDistance) >+ m_backForwardGestureController.trackSwipeGesture(event, m_direction); >+ else >+ m_state = State::InsufficientMagnitude; >+ >+ return true; >+} >+ >+void BackForwardGestureController::PendingSwipeTracker::reset(const char* resetReasonForLogging) >+{ >+ if (m_state != State::None) >+ LOG(ViewGestures, "Swipe Start Hysteresis - reset; %s", resetReasonForLogging); >+ >+ m_state = State::None; >+ m_cumulativeDelta = FloatSize(); >+} >+ >+void BackForwardGestureController::trackSwipeGesture(GdkEventScroll* event, SwipeDirection direction) >+{ >+ ASSERT(!m_activeGesture); >+ >+ m_pendingSwipeTracker.reset("starting to track swipe"); >+ >+ m_webPageProxy.recordAutomaticNavigationSnapshot(); >+ >+ RefPtr<WebBackForwardListItem> targetItem = (direction == SwipeDirection::Back) ? m_webPageProxy.backForwardList().backItem() : m_webPageProxy.backForwardList().forwardItem(); >+ if (!targetItem) >+ return; >+ >+ m_swipeProgressTracker.startTracking(targetItem, direction); >+ m_swipeProgressTracker.handleEvent(event); >+} >+ >+bool BackForwardGestureController::isPhysicallySwipingLeft(SwipeDirection direction) const >+{ >+ bool isLTR = m_webPageProxy.userInterfaceLayoutDirection() == WebCore::UserInterfaceLayoutDirection::LTR; >+ bool isSwipingForward = direction == SwipeDirection::Forward; >+ return isLTR != isSwipingForward; >+} >+ >+BackForwardGestureController::SwipeProgressTracker::SwipeProgressTracker(WebPageProxy& webPageProxy, BackForwardGestureController& backForwardGestureController) >+ : m_backForwardGestureController(backForwardGestureController) >+ , m_webPageProxy(webPageProxy) >+{ >+} >+ >+void BackForwardGestureController::SwipeProgressTracker::startTracking(RefPtr<WebBackForwardListItem> targetItem, SwipeDirection direction) >+{ >+ if (m_state != State::None) >+ return; >+ >+ m_targetItem = targetItem; >+ m_direction = direction; >+ m_state = State::Pending; >+} >+ >+void BackForwardGestureController::SwipeProgressTracker::reset() >+{ >+ m_targetItem = nullptr; >+ m_state = State::None; >+ >+ if (m_tickCallbackID) { >+ GtkWidget* widget = m_backForwardGestureController.m_webPageProxy.viewWidget(); >+ gtk_widget_remove_tick_callback(widget, m_tickCallbackID); >+ m_tickCallbackID = 0; >+ } >+ >+ m_progress = 0; >+ m_startProgress = 0; >+ m_endProgress = 0; >+ >+ m_startTime = 0_ms; >+ m_endTime = 0_ms; >+ m_prevTime = 0_ms; >+ m_velocity = 0; >+ m_cancelled = false; >+} >+ >+bool BackForwardGestureController::SwipeProgressTracker::handleEvent(GdkEventScroll *event) >+{ >+ if (m_state == State::Pending) { >+ m_backForwardGestureController.beginSwipeGesture(m_targetItem.get(), m_direction); >+ m_state = State::Scrolling; >+ } >+ >+ // Don't allow scrolling during animation >+ if (m_state == State::Animating) >+ return true; >+ >+ if (m_state != State::Scrolling) >+ return false; >+ >+// FIXME: Tools/Scripts/prepare-ChangeLog sees an extra { here and stops processing the file >+#if GTK_CHECK_VERSION(3, 20, 0) >+ if (event->is_stop) { >+#else >+ if (!event->delta_x && !event->delta_y) { >+#endif >+ startAnimation(); >+ return false; >+ } >+ >+ Seconds time = Seconds::fromMilliseconds(event->time); >+ m_velocity = -event->delta_x / (time - m_prevTime).milliseconds(); >+ >+ m_prevTime = time; >+ m_progress -= event->delta_x / Scrollbar::pixelsPerLineStep(); >+ >+ bool swipingLeft = m_backForwardGestureController.isPhysicallySwipingLeft(m_direction); >+ float maxProgress = swipingLeft ? 1 : 0; >+ float minProgress = !swipingLeft ? -1 : 0; >+ m_progress = std::min(std::max(m_progress, minProgress), maxProgress); >+ >+ m_backForwardGestureController.queueDraw(); >+ >+ return true; >+} >+ >+float BackForwardGestureController::SwipeProgressTracker::getProgress() >+{ >+ return m_progress; >+} >+ >+void BackForwardGestureController::SwipeProgressTracker::startAnimation() >+{ >+ bool swipingLeft = m_backForwardGestureController.isPhysicallySwipingLeft(m_direction); >+ m_cancelled = swipingLeft ? (m_velocity <= 0) : (m_velocity >= 0); >+ >+ m_state = State::Animating; >+ m_backForwardGestureController.willEndSwipeGesture(*m_targetItem, m_cancelled); >+ >+ m_startProgress = m_progress; >+ if (m_cancelled) >+ m_endProgress = 0; >+ else >+ m_endProgress = swipingLeft ? 1 : -1; >+ >+ Seconds duration = Seconds::fromMilliseconds(std::abs((m_progress - m_endProgress) / m_velocity) * swipeBaseAnimationSpeed); >+ duration = std::min(std::max(duration, swipeMinAnimationDuration), swipeMaxAnimationDuration); >+ >+ GtkWidget* widget = m_backForwardGestureController.m_webPageProxy.viewWidget(); >+ m_startTime = Seconds::fromMicroseconds(gdk_frame_clock_get_frame_time(gtk_widget_get_frame_clock(widget))); >+ m_endTime = m_startTime + duration; >+ >+ m_tickCallbackID = gtk_widget_add_tick_callback(widget, [](GtkWidget*, GdkFrameClock* frameClock, gpointer userData) -> gboolean { >+ auto* tracker = static_cast<SwipeProgressTracker*>(userData); >+ return tracker->onAnimationTick(frameClock); >+ }, this, nullptr); >+} >+ >+static inline double easeOutCubic(double t) >+{ >+ double p = t - 1; >+ return p * p * p + 1; >+} >+ >+gboolean BackForwardGestureController::SwipeProgressTracker::onAnimationTick(GdkFrameClock* frameClock) >+{ >+ ASSERT(m_state == State::Animating); >+ ASSERT(m_endTime > m_startTime); >+ >+ Seconds frameTime = Seconds::fromMicroseconds(gdk_frame_clock_get_frame_time(frameClock)); >+ >+ double animationProgress = (frameTime - m_startTime) / (m_endTime - m_startTime); >+ if (animationProgress > 1) >+ animationProgress = 1; >+ >+ m_progress = m_startProgress + (m_endProgress - m_startProgress) * easeOutCubic(animationProgress); >+ >+ m_backForwardGestureController.queueDraw(); >+ if (frameTime >= m_endTime) { >+ m_tickCallbackID = 0; >+ endAnimation(); >+ return G_SOURCE_REMOVE; >+ } >+ >+ return G_SOURCE_CONTINUE; >+} >+ >+void BackForwardGestureController::SwipeProgressTracker::endAnimation() >+{ >+ m_backForwardGestureController.endSwipeGesture(m_targetItem.get(), m_cancelled); >+} >+ >+void BackForwardGestureController::queueDraw() >+{ >+ gtk_widget_queue_draw(m_webPageProxy.viewWidget()); >+} >+ >+void BackForwardGestureController::beginSwipeGesture(WebBackForwardListItem* targetItem, SwipeDirection direction) >+{ >+ m_webPageProxy.navigationGestureDidBegin(); >+ >+ willBeginGesture(); >+ >+ ViewSnapshot* snapshot = targetItem->snapshot(); >+ if (snapshot) { >+ m_currentSwipeSnapshot = snapshot; >+ >+ FloatSize viewSize = FloatSize(m_webPageProxy.viewSize()); >+ if (snapshot->hasImage() && shouldUseSnapshotForSize(*snapshot, viewSize, 0)) >+ m_currentSwipeSnapshotPattern = cairo_pattern_create_for_surface(snapshot->surface()); >+ >+ Color color = snapshot->backgroundColor(); >+ if (color.isValid()) { >+ m_backgroundColorForCurrentSnapshot = color; >+ if (!m_currentSwipeSnapshotPattern) >+ m_currentSwipeSnapshotPattern = cairo_pattern_create_rgba(color.red(), color.green(), color.blue(), color.alpha()); >+ } >+ } >+ >+ if (!m_currentSwipeSnapshotPattern) >+ m_currentSwipeSnapshotPattern = cairo_pattern_create_rgb(1, 1, 1); >+} >+ >+void BackForwardGestureController::willEndSwipeGesture(WebBackForwardListItem& targetItem, bool cancelled) >+{ >+ m_webPageProxy.navigationGestureWillEnd(!cancelled, targetItem); >+} >+ >+void BackForwardGestureController::endSwipeGesture(WebBackForwardListItem* targetItem, bool cancelled) >+{ >+ if (cancelled) { >+ removeSwipeSnapshot(); >+ m_webPageProxy.navigationGestureDidEnd(false, *targetItem); >+ return; >+ } >+ >+ m_webPageProxy.navigationGestureDidEnd(true, *targetItem); >+ m_webPageProxy.goToBackForwardItem(*targetItem); >+ >+ auto* currentItem = m_webPageProxy.backForwardList().currentItem(); >+ // The main frame will not be navigated so hide the snapshot right away. >+ if (currentItem && currentItem->itemIsClone(*targetItem)) { >+ removeSwipeSnapshot(); >+ return; >+ } >+ >+ SnapshotRemovalTracker::Events desiredEvents = SnapshotRemovalTracker::VisuallyNonEmptyLayout >+ | SnapshotRemovalTracker::MainFrameLoad >+ | SnapshotRemovalTracker::SubresourceLoads >+ | SnapshotRemovalTracker::ScrollPositionRestoration; >+ m_snapshotRemovalTracker.start(desiredEvents, [this] { this->forceRepaintIfNeeded(); }); >+ >+ ViewSnapshot* snapshot = targetItem->snapshot(); >+ if (snapshot) >+ m_backgroundColorForCurrentSnapshot = snapshot->backgroundColor(); >+} >+ >+void BackForwardGestureController::forceRepaintIfNeeded() >+{ >+ if (!m_activeGesture) >+ return; >+ >+ if (m_hasOutstandingRepaintRequest) >+ return; >+ >+ m_hasOutstandingRepaintRequest = true; >+ >+ uint64_t pageID = m_webPageProxy.pageID(); >+ GestureID gestureID = m_currentGestureID; >+ m_webPageProxy.forceRepaint(VoidCallback::create([pageID, gestureID] (CallbackBase::Error error) { >+ if (auto gestureController = controllerForGesture(pageID, gestureID)) >+ gestureController->removeSwipeSnapshot(); >+ })); >+} >+ >+bool BackForwardGestureController::shouldUseSnapshotForSize(ViewSnapshot& snapshot, FloatSize swipeLayerSize, float topContentInset) >+{ >+ float deviceScaleFactor = m_webPageProxy.deviceScaleFactor(); >+ if (snapshot.deviceScaleFactor() != deviceScaleFactor) >+ return false; >+ >+ FloatSize unobscuredSwipeLayerSizeInDeviceCoordinates = swipeLayerSize - FloatSize(0, topContentInset); >+ unobscuredSwipeLayerSizeInDeviceCoordinates.scale(deviceScaleFactor); >+ if (snapshot.size() != unobscuredSwipeLayerSizeInDeviceCoordinates) >+ return false; >+ >+ return true; >+} >+ >+void BackForwardGestureController::draw(cairo_t* cr, cairo_pattern_t* pageGroup) >+{ >+ bool swipingLeft = isPhysicallySwipingLeft(m_swipeProgressTracker.getDirection()); >+ float progress = m_swipeProgressTracker.getProgress(); >+ >+ double width = m_webPageProxy.drawingArea()->size().width(); >+ double height = m_webPageProxy.drawingArea()->size().height(); >+ >+ double swipingLayerOffset = (swipingLeft ? 0 : width) + floor(width * progress); >+ >+ double dimmingProgress = swipingLeft ? 1 - progress : -progress; >+ >+ double remainingSwipeDistance = dimmingProgress * width; >+ double shadowFadeDistance = swipeOverlayShadowWidth; >+ >+ double shadowOpacity = swipeOverlayShadowOpacity; >+ if (remainingSwipeDistance < shadowFadeDistance) >+ shadowOpacity = (remainingSwipeDistance / shadowFadeDistance) * swipeOverlayShadowOpacity; >+ >+ cairo_pattern_t* shadowPattern = cairo_pattern_create_linear(0, 0, -swipeOverlayShadowWidth, 0); >+ for (int i = 0; i < 16; i++) { >+ double offset = swipeOverlayShadowGradientOffsets[i]; >+ double alpha = swipeOverlayShadowGradientAlpha[i] * shadowOpacity; >+ cairo_pattern_add_color_stop_rgba(shadowPattern, offset, 0, 0, 0, alpha); >+ } >+ >+ cairo_save(cr); >+ >+ cairo_rectangle(cr, 0, 0, swipingLayerOffset, height); >+ cairo_set_source(cr, swipingLeft ? m_currentSwipeSnapshotPattern : pageGroup); >+ cairo_fill_preserve(cr); >+ >+ cairo_set_source_rgba(cr, 0, 0, 0, dimmingProgress * swipeOverlayDimmingOpacity); >+ cairo_fill(cr); >+ >+ cairo_translate(cr, swipingLayerOffset, 0); >+ >+ if (progress) { >+ cairo_rectangle(cr, -swipeOverlayShadowWidth, 0, swipeOverlayShadowWidth, height); >+ cairo_set_source(cr, shadowPattern); >+ cairo_fill(cr); >+ } >+ >+ cairo_rectangle(cr, 0, 0, width - swipingLayerOffset, height); >+ cairo_set_source(cr, swipingLeft ? pageGroup : m_currentSwipeSnapshotPattern); >+ cairo_fill(cr); >+ >+ cairo_pattern_destroy(shadowPattern); >+ cairo_restore(cr); >+} >+ >+void BackForwardGestureController::removeSwipeSnapshot() >+{ >+ m_swipeProgressTracker.reset(); >+ m_snapshotRemovalTracker.reset(); >+ >+ m_hasOutstandingRepaintRequest = false; >+ >+ if (!m_activeGesture) >+ return; >+ >+ cairo_pattern_destroy(m_currentSwipeSnapshotPattern); >+ m_currentSwipeSnapshotPattern = nullptr; >+ >+ m_currentSwipeSnapshot = nullptr; >+ >+ m_webPageProxy.navigationGestureSnapshotWasRemoved(); >+ >+ m_backgroundColorForCurrentSnapshot = Color(); >+ >+ didEndGesture(); >+ >+ queueDraw(); >+} >+ >+} // namespace WebKit >diff --git a/Source/WebKit/UIProcess/gtk/BackForwardGestureController.h b/Source/WebKit/UIProcess/gtk/BackForwardGestureController.h >new file mode 100644 >index 0000000000000000000000000000000000000000..dfce1e8eced9be6873928061aa456521f1527b6e >--- /dev/null >+++ b/Source/WebKit/UIProcess/gtk/BackForwardGestureController.h >@@ -0,0 +1,242 @@ >+/* >+ * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#include "SameDocumentNavigationType.h" >+#include <WebCore/CairoUtilities.h> >+#include <WebCore/Color.h> >+#include <WebCore/FloatRect.h> >+#include <gtk/gtk.h> >+#include <wtf/MonotonicTime.h> >+#include <wtf/RetainPtr.h> >+#include <wtf/RunLoop.h> >+ >+typedef struct _GdkEventScroll GdkEventScroll; >+ >+namespace WebKit { >+ >+class ViewSnapshot; >+class WebBackForwardListItem; >+class WebPageProxy; >+ >+class BackForwardGestureController { >+ WTF_MAKE_NONCOPYABLE(BackForwardGestureController); >+public: >+ BackForwardGestureController(WebPageProxy&); >+ ~BackForwardGestureController(); >+ >+ enum class SwipeDirection { >+ Back, >+ Forward >+ }; >+ >+ typedef uint64_t GestureID; >+ >+ bool handleScrollWheelEvent(GdkEventScroll*); >+ void wheelEventWasNotHandledByWebCore(GdkEventScroll* event) { m_pendingSwipeTracker.eventWasNotHandledByWebCore(event); } >+ >+ WebCore::Color backgroundColorForCurrentSnapshot() const { return m_backgroundColorForCurrentSnapshot; } >+ >+ void didStartProvisionalLoadForMainFrame(); >+ void didFinishLoadForMainFrame() { didReachMainFrameLoadTerminalState(); } >+ void didFailLoadForMainFrame() { didReachMainFrameLoadTerminalState(); } >+ void didFirstVisuallyNonEmptyLayoutForMainFrame(); >+ void didRestoreScrollPosition(); >+ void didReachMainFrameLoadTerminalState(); >+ void didSameDocumentNavigationForMainFrame(SameDocumentNavigationType); >+ >+ void checkForActiveLoads(); >+ >+ void removeSwipeSnapshot(); >+ >+ void setSwipeGestureEnabled(bool enabled) { m_swipeGestureEnabled = enabled; } >+ bool isSwipeGestureEnabled() { return m_swipeGestureEnabled; } >+ >+ bool isGestureActive() { return m_activeGesture; } >+ >+ void draw(cairo_t*, cairo_pattern_t*); >+private: >+ static BackForwardGestureController* controllerForGesture(uint64_t pageID, GestureID); >+ >+ static GestureID takeNextGestureID(); >+ void willBeginGesture(); >+ void didEndGesture(); >+ >+ class SnapshotRemovalTracker { >+ public: >+ enum Event : uint8_t { >+ VisuallyNonEmptyLayout = 1 << 0, >+ MainFrameLoad = 1 << 1, >+ SubresourceLoads = 1 << 2, >+ ScrollPositionRestoration = 1 << 3 >+ }; >+ typedef uint8_t Events; >+ >+ SnapshotRemovalTracker(); >+ >+ void start(Events, WTF::Function<void()>&&); >+ void reset(); >+ >+ void pause() { m_paused = true; } >+ void resume(); >+ bool isPaused() const { return m_paused; } >+ >+ bool eventOccurred(Events); >+ bool cancelOutstandingEvent(Events); >+ >+ void startWatchdog(Seconds); >+ >+ private: >+ static String eventsDescription(Events); >+ void log(const String&) const; >+ >+ void fireRemovalCallbackImmediately(); >+ void fireRemovalCallbackIfPossible(); >+ void watchdogTimerFired(); >+ >+ bool stopWaitingForEvent(Events, const String& logReason); >+ >+ Events m_outstandingEvents { 0 }; >+ WTF::Function<void()> m_removalCallback; >+ MonotonicTime m_startTime; >+ >+ RunLoop::Timer<SnapshotRemovalTracker> m_watchdogTimer; >+ >+ bool m_paused { true }; >+ }; >+ >+ bool canSwipeInDirection(SwipeDirection) const; >+ bool isPhysicallySwipingLeft(SwipeDirection) const; >+ >+ void queueDraw(); >+ >+ void trackSwipeGesture(GdkEventScroll*, SwipeDirection); >+ >+ void beginSwipeGesture(WebBackForwardListItem* targetItem, SwipeDirection); >+ >+ void willEndSwipeGesture(WebBackForwardListItem& targetItem, bool cancelled); >+ void endSwipeGesture(WebBackForwardListItem* targetItem, bool cancelled); >+ >+ bool shouldUseSnapshotForSize(ViewSnapshot&, WebCore::FloatSize swipeLayerSize, float topContentInset); >+ >+ void forceRepaintIfNeeded(); >+ >+ class PendingSwipeTracker { >+ public: >+ PendingSwipeTracker(WebPageProxy&, BackForwardGestureController&); >+ bool handleEvent(GdkEventScroll*); >+ void eventWasNotHandledByWebCore(GdkEventScroll*); >+ >+ void reset(const char* resetReasonForLogging); >+ >+ bool shouldIgnorePinnedState() { return m_shouldIgnorePinnedState; } >+ void setShouldIgnorePinnedState(bool ignore) { m_shouldIgnorePinnedState = ignore; } >+ >+ private: >+ bool tryToStartSwipe(GdkEventScroll*); >+ bool scrollEventCanBecomeSwipe(GdkEventScroll*, SwipeDirection&); >+ >+ enum class State { >+ None, >+ WaitingForWebCore, >+ InsufficientMagnitude >+ }; >+ >+ State m_state { State::None }; >+ SwipeDirection m_direction; >+ WebCore::FloatSize m_cumulativeDelta; >+ >+ bool m_shouldIgnorePinnedState { false }; >+ >+ BackForwardGestureController& m_backForwardGestureController; >+ WebPageProxy& m_webPageProxy; >+ }; >+ >+ WebPageProxy& m_webPageProxy; >+ bool m_activeGesture { false }; >+ >+ bool m_swipeGestureEnabled { false }; >+ >+ RunLoop::Timer<BackForwardGestureController> m_swipeActiveLoadMonitoringTimer; >+ >+ WebCore::Color m_backgroundColorForCurrentSnapshot; >+ >+ GestureID m_currentGestureID; >+ >+ ViewSnapshot* m_currentSwipeSnapshot { nullptr }; >+ cairo_pattern_t* m_currentSwipeSnapshotPattern { nullptr }; >+ >+ class SwipeProgressTracker { >+ public: >+ SwipeProgressTracker(WebPageProxy&, BackForwardGestureController&); >+ void startTracking(RefPtr<WebBackForwardListItem>, SwipeDirection); >+ void reset(); >+ bool handleEvent(GdkEventScroll*); >+ float getProgress(); >+ SwipeDirection getDirection() { return m_direction; } >+ >+ private: >+ enum class State { >+ None, >+ Pending, >+ Scrolling, >+ Animating >+ }; >+ >+ void startAnimation(); >+ gboolean onAnimationTick(GdkFrameClock*); >+ void endAnimation(); >+ >+ State m_state { State::None }; >+ >+ SwipeDirection m_direction; >+ RefPtr<WebBackForwardListItem> m_targetItem; >+ unsigned m_tickCallbackID { 0 }; >+ >+ Seconds m_prevTime; >+ double m_velocity; >+ >+ Seconds m_startTime; >+ Seconds m_endTime; >+ >+ float m_progress { 0 }; >+ float m_startProgress; >+ float m_endProgress; >+ bool m_cancelled; >+ >+ BackForwardGestureController& m_backForwardGestureController; >+ WebPageProxy& m_webPageProxy; >+ }; >+ >+ PendingSwipeTracker m_pendingSwipeTracker; >+ SwipeProgressTracker m_swipeProgressTracker; >+ >+ bool m_hasOutstandingRepaintRequest { false }; >+ >+ SnapshotRemovalTracker m_snapshotRemovalTracker; >+}; >+ >+} // namespace WebKit >diff --git a/Source/WebKit/UIProcess/gtk/ViewSnapshotStore.cpp b/Source/WebKit/UIProcess/gtk/ViewSnapshotStore.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..1cf2b0268798283dde9ee37a86c385d8fd183b7c >--- /dev/null >+++ b/Source/WebKit/UIProcess/gtk/ViewSnapshotStore.cpp >@@ -0,0 +1,162 @@ >+/* >+ * Copyright (C) 2014 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#include "config.h" >+#include "ViewSnapshotStore.h" >+ >+#include "WebBackForwardList.h" >+#include "WebPageProxy.h" >+ >+static const size_t maximumSnapshotCacheSize = 400 * (1024 * 1024); >+ >+namespace WebKit { >+using namespace WebCore; >+ >+ViewSnapshotStore::ViewSnapshotStore() >+{ >+} >+ >+ViewSnapshotStore::~ViewSnapshotStore() >+{ >+ discardSnapshotImages(); >+} >+ >+ViewSnapshotStore& ViewSnapshotStore::singleton() >+{ >+ static ViewSnapshotStore& store = *new ViewSnapshotStore; >+ return store; >+} >+ >+void ViewSnapshotStore::didAddImageToSnapshot(ViewSnapshot& snapshot) >+{ >+ bool isNewEntry = m_snapshotsWithImages.add(&snapshot).isNewEntry; >+ ASSERT_UNUSED(isNewEntry, isNewEntry); >+ m_snapshotCacheSize += snapshot.imageSizeInBytes(); >+} >+ >+void ViewSnapshotStore::willRemoveImageFromSnapshot(ViewSnapshot& snapshot) >+{ >+ bool removed = m_snapshotsWithImages.remove(&snapshot); >+ ASSERT_UNUSED(removed, removed); >+ m_snapshotCacheSize -= snapshot.imageSizeInBytes(); >+} >+ >+void ViewSnapshotStore::pruneSnapshots(WebPageProxy& webPageProxy) >+{ >+ if (m_snapshotCacheSize <= maximumSnapshotCacheSize) >+ return; >+ >+ ASSERT(!m_snapshotsWithImages.isEmpty()); >+ >+ // FIXME: We have enough information to do smarter-than-LRU eviction (making use of the back-forward lists, etc.) >+ >+ m_snapshotsWithImages.first()->clearImage(); >+} >+ >+void ViewSnapshotStore::recordSnapshot(WebPageProxy& webPageProxy, WebBackForwardListItem& item) >+{ >+ if (webPageProxy.isShowingNavigationGestureSnapshot()) >+ return; >+ >+ pruneSnapshots(webPageProxy); >+ >+ webPageProxy.willRecordNavigationSnapshot(item); >+ >+ auto snapshot = webPageProxy.takeViewSnapshot(); >+ if (!snapshot) >+ return; >+ >+ snapshot->setDeviceScaleFactor(webPageProxy.deviceScaleFactor()); >+ snapshot->setBackgroundColor(webPageProxy.pageExtendedBackgroundColor()); >+ snapshot->setViewScrollPosition(WebCore::roundedIntPoint(webPageProxy.viewScrollPosition())); >+ >+ item.setSnapshot(WTFMove(snapshot)); >+} >+ >+void ViewSnapshotStore::discardSnapshotImages() >+{ >+ while (!m_snapshotsWithImages.isEmpty()) >+ m_snapshotsWithImages.first()->clearImage(); >+} >+ >+Ref<ViewSnapshot> ViewSnapshot::create(RefPtr<cairo_surface_t> surface) >+{ >+ return adoptRef(*new ViewSnapshot(WTFMove(surface))); >+} >+ >+ViewSnapshot::ViewSnapshot(RefPtr<cairo_surface_t> surface) >+ : m_surface(WTFMove(surface)) >+{ >+ if (hasImage()) >+ ViewSnapshotStore::singleton().didAddImageToSnapshot(*this); >+} >+ >+ViewSnapshot::~ViewSnapshot() >+{ >+ clearImage(); >+} >+ >+bool ViewSnapshot::hasImage() const >+{ >+ return !!m_surface; >+} >+ >+void ViewSnapshot::clearImage() >+{ >+ if (!hasImage()) >+ return; >+ >+ ViewSnapshotStore::singleton().willRemoveImageFromSnapshot(*this); >+ >+ cairo_surface_destroy(m_surface.get()); >+ m_surface = nullptr; >+} >+ >+ >+size_t ViewSnapshot::imageSizeInBytes() const >+{ >+ if (!m_surface) >+ return 0; >+ >+ cairo_surface_t* surface = m_surface.get(); >+ int stride = cairo_image_surface_get_stride(surface); >+ int height = cairo_image_surface_get_width(surface); >+ >+ return stride*height; >+} >+ >+WebCore::IntSize ViewSnapshot::size() const >+{ >+ if (!m_surface) >+ return WebCore::IntSize(); >+ >+ cairo_surface_t* surface = m_surface.get(); >+ int width = cairo_image_surface_get_width(surface); >+ int height = cairo_image_surface_get_height(surface); >+ >+ return WebCore::IntSize(width, height); >+} >+ >+} // namespace WebKit >diff --git a/Source/WebKit/UIProcess/gtk/ViewSnapshotStore.h b/Source/WebKit/UIProcess/gtk/ViewSnapshotStore.h >new file mode 100644 >index 0000000000000000000000000000000000000000..ffd013db9c425e72f387e7a5c3033c995168059c >--- /dev/null >+++ b/Source/WebKit/UIProcess/gtk/ViewSnapshotStore.h >@@ -0,0 +1,102 @@ >+/* >+ * Copyright (C) 2014 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. Redistributions in binary form must reproduce the above copyright >+ * notice, this list of conditions and the following disclaimer in the >+ * documentation and/or other materials provided with the distribution. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' >+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, >+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS >+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR >+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF >+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS >+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN >+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) >+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF >+ * THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#include <WebCore/Color.h> >+#include <WebCore/IntPoint.h> >+#include <WebCore/IntSize.h> >+#include <wtf/ListHashSet.h> >+#include <wtf/Noncopyable.h> >+#include <wtf/RefCounted.h> >+#include <wtf/text/WTFString.h> >+ >+namespace WebKit { >+ >+class ViewSnapshotStore; >+class WebBackForwardListItem; >+class WebPageProxy; >+ >+class ViewSnapshot : public RefCounted<ViewSnapshot> { >+public: >+ static Ref<ViewSnapshot> create(RefPtr<cairo_surface_t>); >+ >+ ~ViewSnapshot(); >+ >+ void clearImage(); >+ bool hasImage() const; >+ >+ void setBackgroundColor(WebCore::Color color) { m_backgroundColor = color; } >+ WebCore::Color backgroundColor() const { return m_backgroundColor; } >+ >+ void setViewScrollPosition(WebCore::IntPoint scrollPosition) { m_viewScrollPosition = scrollPosition; } >+ WebCore::IntPoint viewScrollPosition() const { return m_viewScrollPosition; } >+ >+ void setDeviceScaleFactor(float deviceScaleFactor) { m_deviceScaleFactor = deviceScaleFactor; } >+ float deviceScaleFactor() const { return m_deviceScaleFactor; } >+ >+ cairo_surface_t* surface() const { return m_surface.get(); } >+ >+ size_t imageSizeInBytes() const; >+ WebCore::IntSize size() const; >+ >+private: >+ explicit ViewSnapshot(RefPtr<cairo_surface_t>); >+ >+ RefPtr<cairo_surface_t> m_surface { nullptr }; >+ >+ float m_deviceScaleFactor; >+ WebCore::Color m_backgroundColor; >+ WebCore::IntPoint m_viewScrollPosition; // Scroll position at snapshot time. Integral to make comparison reliable. >+}; >+ >+class ViewSnapshotStore { >+ WTF_MAKE_NONCOPYABLE(ViewSnapshotStore); >+ friend class ViewSnapshot; >+public: >+ ViewSnapshotStore(); >+ ~ViewSnapshotStore(); >+ >+ static ViewSnapshotStore& singleton(); >+ >+ void recordSnapshot(WebPageProxy&, WebBackForwardListItem&); >+ >+ void discardSnapshotImages(); >+ >+ void setDisableSnapshotVolatilityForTesting(bool disable) { m_disableSnapshotVolatility = disable; } >+ bool disableSnapshotVolatilityForTesting() const { return m_disableSnapshotVolatility; } >+ >+private: >+ void didAddImageToSnapshot(ViewSnapshot&); >+ void willRemoveImageFromSnapshot(ViewSnapshot&); >+ void pruneSnapshots(WebPageProxy&); >+ >+ size_t m_snapshotCacheSize { 0 }; >+ >+ ListHashSet<ViewSnapshot*> m_snapshotsWithImages; >+ bool m_disableSnapshotVolatility { false }; >+}; >+ >+} // namespace WebKit >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index d0b9672233cf8278bc2eb6c7335725895fb8b4dd..f236e6524fb009b4d4249d02ec0b0ff1a0662cbc 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,13 @@ >+2019-01-28 Alexander Mikhaylenko <exalm7659@gmail.com> >+ >+ [GTK] Implement back/forward touchpad gesture >+ https://bugs.webkit.org/show_bug.cgi?id=193919 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * TestWebKitAPI/Tests/WebKitGLib/TestWebKitSettings.cpp: >+ (testWebKitSettings): Add a test for 'allow-back-forward-navigation-gestures' property. >+ > 2019-01-27 Chris Fleizach <cfleizach@apple.com> > > AX: Introduce a static accessibility tree >diff --git a/Tools/TestWebKitAPI/Tests/WebKitGLib/TestWebKitSettings.cpp b/Tools/TestWebKitAPI/Tests/WebKitGLib/TestWebKitSettings.cpp >index 3edd53ced97d32e9934adaa56bd612943788e49f..5133428b7850623b130b95cc21838242fbfe5b29 100644 >--- a/Tools/TestWebKitAPI/Tests/WebKitGLib/TestWebKitSettings.cpp >+++ b/Tools/TestWebKitAPI/Tests/WebKitGLib/TestWebKitSettings.cpp >@@ -348,6 +348,11 @@ static void testWebKitSettings(Test*, gconstpointer) > g_assert_cmpuint(webkit_settings_get_hardware_acceleration_policy(settings), ==, WEBKIT_HARDWARE_ACCELERATION_POLICY_ALWAYS); > webkit_settings_set_hardware_acceleration_policy(settings, WEBKIT_HARDWARE_ACCELERATION_POLICY_ON_DEMAND); > g_assert_cmpuint(webkit_settings_get_hardware_acceleration_policy(settings), ==, WEBKIT_HARDWARE_ACCELERATION_POLICY_ON_DEMAND); >+ >+ // Back-forward navigation gesture is disabled by default >+ g_assert_false(webkit_settings_get_allow_back_forward_navigation_gestures(settings)); >+ webkit_settings_set_allow_back_forward_navigation_gestures(settings, TRUE); >+ g_assert_true(webkit_settings_get_allow_back_forward_navigation_gestures(settings)); > #endif > > g_object_unref(G_OBJECT(settings));
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 193919
:
360363
|
360378
|
360724
|
360725
|
360726
|
360728
|
360745
|
360753
|
360755
|
360763
|
360765
|
360770
|
360780
|
360785
|
360789
|
360795
|
360800
|
360846
|
360848
|
360858
|
361024
|
361026
|
361027
|
361050
|
361056
|
361074
|
361084
|
361184
|
361185
|
361187
|
361188
|
361190
|
361287
|
361288
|
361512
|
361519
|
361522
|
361524
|
361527
|
361528