diff options
Diffstat (limited to 'Source/WebKit2/UIProcess/API/gtk/WebKitWebViewBase.cpp')
-rw-r--r-- | Source/WebKit2/UIProcess/API/gtk/WebKitWebViewBase.cpp | 1059 |
1 files changed, 688 insertions, 371 deletions
diff --git a/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewBase.cpp b/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewBase.cpp index b22c71fa1..b057a5a44 100644 --- a/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewBase.cpp +++ b/Source/WebKit2/UIProcess/API/gtk/WebKitWebViewBase.cpp @@ -29,15 +29,20 @@ #include "config.h" #include "WebKitWebViewBase.h" +#include "APIPageConfiguration.h" +#include "AcceleratedBackingStore.h" +#include "ActivityState.h" #include "DrawingAreaProxyImpl.h" +#include "InputMethodFilter.h" +#include "KeyBindingTranslator.h" +#include "NativeWebKeyboardEvent.h" #include "NativeWebMouseEvent.h" #include "NativeWebWheelEvent.h" #include "PageClientImpl.h" -#include "ViewState.h" -#include "WebContext.h" #include "WebEventFactory.h" #include "WebFullScreenClientGtk.h" #include "WebInspectorProxy.h" +#include "WebKit2Initialize.h" #include "WebKitAuthenticationDialog.h" #include "WebKitPrivate.h" #include "WebKitWebViewBaseAccessible.h" @@ -45,37 +50,31 @@ #include "WebPageGroup.h" #include "WebPageProxy.h" #include "WebPreferences.h" -#include "WebViewBaseInputMethodFilter.h" +#include "WebProcessPool.h" +#include "WebUserContentControllerProxy.h" #include <WebCore/CairoUtilities.h> -#include <WebCore/ClipboardUtilitiesGtk.h> -#include <WebCore/DataObjectGtk.h> -#include <WebCore/DragData.h> -#include <WebCore/DragIcon.h> #include <WebCore/GUniquePtrGtk.h> -#include <WebCore/GtkClickCounter.h> -#include <WebCore/GtkDragAndDropHelper.h> -#include <WebCore/GtkTouchContextHelper.h> #include <WebCore/GtkUtilities.h> #include <WebCore/GtkVersioning.h> #include <WebCore/NotImplemented.h> #include <WebCore/PasteboardHelper.h> +#include <WebCore/PlatformDisplay.h> #include <WebCore/RefPtrCairo.h> #include <WebCore/Region.h> #include <gdk/gdk.h> #include <gdk/gdkkeysyms.h> -#ifdef GDK_WINDOWING_X11 -#include <gdk/gdkx.h> -#endif +#include <glib/gi18n-lib.h> +#include <memory> #include <wtf/HashMap.h> -#include <wtf/gobject/GRefPtr.h> +#include <wtf/glib/GRefPtr.h> #include <wtf/text/CString.h> #if ENABLE(FULLSCREEN_API) #include "WebFullScreenManagerProxy.h" #endif -#if USE(TEXTURE_MAPPER_GL) && defined(GDK_WINDOWING_X11) -#include <WebCore/RedirectedXCompositeWindow.h> +#if PLATFORM(X11) +#include <gdk/gdkx.h> #endif // gtk_widget_get_scale_factor() appeared in GTK 3.10, but we also need @@ -85,130 +84,200 @@ using namespace WebKit; using namespace WebCore; -typedef HashMap<GtkWidget*, IntRect> WebKitWebViewChildrenMap; +struct ClickCounter { +public: + void reset() + { + currentClickCount = 0; + previousClickPoint = IntPoint(); + previousClickTime = 0; + previousClickButton = 0; + } -#if USE(TEXTURE_MAPPER_GL) -void redirectedWindowDamagedCallback(void* data); -#endif + int currentClickCountForGdkButtonEvent(GdkEventButton* buttonEvent) + { + GdkEvent* event = reinterpret_cast<GdkEvent*>(buttonEvent); + int doubleClickDistance = 250; + int doubleClickTime = 5; + g_object_get(gtk_settings_get_for_screen(gdk_event_get_screen(event)), + "gtk-double-click-distance", &doubleClickDistance, "gtk-double-click-time", &doubleClickTime, nullptr); + + // GTK+ only counts up to triple clicks, but WebCore wants to know about + // quadruple clicks, quintuple clicks, ad infinitum. Here, we replicate the + // GDK logic for counting clicks. + guint32 eventTime = gdk_event_get_time(event); + if (!eventTime) { + // Real events always have a non-zero time, but events synthesized + // by the WTR do not and we must calculate a time manually. This time + // is not calculated in the WTR, because GTK+ does not work well with + // anything other than GDK_CURRENT_TIME on synthesized events. + GTimeVal timeValue; + g_get_current_time(&timeValue); + eventTime = (timeValue.tv_sec * 1000) + (timeValue.tv_usec / 1000); + } + + if ((event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS) + || ((std::abs(buttonEvent->x - previousClickPoint.x()) < doubleClickDistance) + && (std::abs(buttonEvent->y - previousClickPoint.y()) < doubleClickDistance) + && (eventTime - previousClickTime < static_cast<unsigned>(doubleClickTime)) + && (buttonEvent->button == previousClickButton))) + currentClickCount++; + else + currentClickCount = 1; + + double x, y; + gdk_event_get_coords(event, &x, &y); + previousClickPoint = IntPoint(x, y); + previousClickButton = buttonEvent->button; + previousClickTime = eventTime; + + return currentClickCount; + } + +private: + int currentClickCount; + IntPoint previousClickPoint; + unsigned previousClickButton; + int previousClickTime; +}; + +typedef HashMap<GtkWidget*, IntRect> WebKitWebViewChildrenMap; +typedef HashMap<uint32_t, GUniquePtr<GdkEvent>> TouchEventsMap; struct _WebKitWebViewBasePrivate { + _WebKitWebViewBasePrivate() + : updateActivityStateTimer(RunLoop::main(), this, &_WebKitWebViewBasePrivate::updateActivityStateTimerFired) + { + } + + void updateActivityStateTimerFired() + { + if (!pageProxy) + return; + pageProxy->activityStateDidChange(activityStateFlagsToUpdate); + activityStateFlagsToUpdate = ActivityState::NoFlags; + } + WebKitWebViewChildrenMap children; - OwnPtr<PageClientImpl> pageClient; + std::unique_ptr<PageClientImpl> pageClient; RefPtr<WebPageProxy> pageProxy; bool shouldForwardNextKeyEvent; - GtkClickCounter clickCounter; + bool shouldForwardNextWheelEvent; + ClickCounter clickCounter; CString tooltipText; IntRect tooltipArea; -#if ENABLE(DRAG_SUPPORT) - GtkDragAndDropHelper dragAndDropHelper; -#endif - DragIcon dragIcon; -#if !GTK_CHECK_VERSION(3, 13, 4) - IntSize resizerSize; -#endif GRefPtr<AtkObject> accessible; - bool needsResizeOnMap; GtkWidget* authenticationDialog; GtkWidget* inspectorView; AttachmentSide inspectorAttachmentSide; unsigned inspectorViewSize; GUniquePtr<GdkEvent> contextMenuEvent; WebContextMenuProxyGtk* activeContextMenuProxy; - WebViewBaseInputMethodFilter inputMethodFilter; - GtkTouchContextHelper touchContext; + InputMethodFilter inputMethodFilter; + KeyBindingTranslator keyBindingTranslator; + TouchEventsMap touchEvents; + IntSize contentsSize; GtkWindow* toplevelOnScreenWindow; -#if !GTK_CHECK_VERSION(3, 13, 4) - unsigned long toplevelResizeGripVisibilityID; -#endif unsigned long toplevelFocusInEventID; unsigned long toplevelFocusOutEventID; - unsigned long toplevelVisibilityEventID; + unsigned long toplevelWindowStateEventID; + unsigned long toplevelWindowRealizedID; // View State. - bool isInWindowActive : 1; - bool isFocused : 1; - bool isVisible : 1; - bool isWindowVisible : 1; + ActivityState::Flags activityState; + ActivityState::Flags activityStateFlagsToUpdate; + RunLoop::Timer<WebKitWebViewBasePrivate> updateActivityStateTimer; WebKitWebViewBaseDownloadRequestHandler downloadHandler; #if ENABLE(FULLSCREEN_API) bool fullScreenModeActive; WebFullScreenClientGtk fullScreenClient; + GRefPtr<GDBusProxy> screenSaverProxy; + GRefPtr<GCancellable> screenSaverInhibitCancellable; + unsigned screenSaverCookie; +#endif + + std::unique_ptr<AcceleratedBackingStore> acceleratedBackingStore; + +#if ENABLE(DRAG_SUPPORT) + std::unique_ptr<DragAndDropHandler> dragAndDropHandler; #endif -#if USE(TEXTURE_MAPPER_GL) - OwnPtr<RedirectedXCompositeWindow> redirectedWindow; +#if HAVE(GTK_GESTURES) + std::unique_ptr<GestureController> gestureController; #endif }; WEBKIT_DEFINE_TYPE(WebKitWebViewBase, webkit_web_view_base, GTK_TYPE_CONTAINER) -#if !GTK_CHECK_VERSION(3, 13, 4) -static void webkitWebViewBaseNotifyResizerSize(WebKitWebViewBase* webViewBase) +static void webkitWebViewBaseScheduleUpdateActivityState(WebKitWebViewBase* webViewBase, ActivityState::Flags flagsToUpdate) { WebKitWebViewBasePrivate* priv = webViewBase->priv; - if (!priv->toplevelOnScreenWindow) + priv->activityStateFlagsToUpdate |= flagsToUpdate; + if (priv->updateActivityStateTimer.isActive()) return; - gboolean resizerVisible; - g_object_get(G_OBJECT(priv->toplevelOnScreenWindow), "resize-grip-visible", &resizerVisible, NULL); - - IntSize resizerSize; - if (resizerVisible) { - GdkRectangle resizerRect; - gtk_window_get_resize_grip_area(priv->toplevelOnScreenWindow, &resizerRect); - GdkRectangle allocation; - gtk_widget_get_allocation(GTK_WIDGET(webViewBase), &allocation); - if (gdk_rectangle_intersect(&resizerRect, &allocation, 0)) - resizerSize = IntSize(resizerRect.width, resizerRect.height); - } - - if (resizerSize != priv->resizerSize) { - priv->resizerSize = resizerSize; - priv->pageProxy->setWindowResizerSize(resizerSize); - } + priv->updateActivityStateTimer.startOneShot(0); } -static void toplevelWindowResizeGripVisibilityChanged(GObject*, GParamSpec*, WebKitWebViewBase* webViewBase) +static gboolean toplevelWindowFocusInEvent(GtkWidget* widget, GdkEventFocus*, WebKitWebViewBase* webViewBase) { - webkitWebViewBaseNotifyResizerSize(webViewBase); + // Spurious focus in events can occur when the window is hidden. + if (!gtk_widget_get_visible(widget)) + return FALSE; + + WebKitWebViewBasePrivate* priv = webViewBase->priv; + if (priv->activityState & ActivityState::WindowIsActive) + return FALSE; + + priv->activityState |= ActivityState::WindowIsActive; + webkitWebViewBaseScheduleUpdateActivityState(webViewBase, ActivityState::WindowIsActive); + + return FALSE; } -#endif -static gboolean toplevelWindowFocusInEvent(GtkWidget* widget, GdkEventFocus*, WebKitWebViewBase* webViewBase) +static gboolean toplevelWindowFocusOutEvent(GtkWidget*, GdkEventFocus*, WebKitWebViewBase* webViewBase) { WebKitWebViewBasePrivate* priv = webViewBase->priv; - if (!priv->isInWindowActive) { - priv->isInWindowActive = true; - priv->pageProxy->viewStateDidChange(ViewState::WindowIsActive); - } + if (!(priv->activityState & ActivityState::WindowIsActive)) + return FALSE; + + priv->activityState &= ~ActivityState::WindowIsActive; + webkitWebViewBaseScheduleUpdateActivityState(webViewBase, ActivityState::WindowIsActive); return FALSE; } -static gboolean toplevelWindowFocusOutEvent(GtkWidget* widget, GdkEventFocus*, WebKitWebViewBase* webViewBase) +static gboolean toplevelWindowStateEvent(GtkWidget*, GdkEventWindowState* event, WebKitWebViewBase* webViewBase) { WebKitWebViewBasePrivate* priv = webViewBase->priv; - if (priv->isInWindowActive) { - priv->isInWindowActive = false; - priv->pageProxy->viewStateDidChange(ViewState::WindowIsActive); - } + if (!(event->changed_mask & GDK_WINDOW_STATE_ICONIFIED)) + return FALSE; + + bool visible = !(event->new_window_state & GDK_WINDOW_STATE_ICONIFIED); + if ((visible && priv->activityState & ActivityState::IsVisible) || (!visible && !(priv->activityState & ActivityState::IsVisible))) + return FALSE; + + if (visible) + priv->activityState |= ActivityState::IsVisible; + else + priv->activityState &= ~ActivityState::IsVisible; + webkitWebViewBaseScheduleUpdateActivityState(webViewBase, ActivityState::IsVisible); return FALSE; } -static gboolean toplevelWindowVisibilityEvent(GtkWidget*, GdkEventVisibility* visibilityEvent, WebKitWebViewBase* webViewBase) +static void toplevelWindowRealized(WebKitWebViewBase* webViewBase) { + gtk_widget_realize(GTK_WIDGET(webViewBase)); + WebKitWebViewBasePrivate* priv = webViewBase->priv; - bool isWindowVisible = visibilityEvent->state != GDK_VISIBILITY_FULLY_OBSCURED; - if (priv->isWindowVisible != isWindowVisible) { - priv->isWindowVisible = isWindowVisible; - priv->pageProxy->viewStateDidChange(ViewState::IsVisible); + if (priv->toplevelWindowRealizedID) { + g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelWindowRealizedID); + priv->toplevelWindowRealizedID = 0; } - - return FALSE; } static void webkitWebViewBaseSetToplevelOnScreenWindow(WebKitWebViewBase* webViewBase, GtkWindow* window) @@ -217,12 +286,6 @@ static void webkitWebViewBaseSetToplevelOnScreenWindow(WebKitWebViewBase* webVie if (priv->toplevelOnScreenWindow == window) return; -#if !GTK_CHECK_VERSION(3, 13, 4) - if (priv->toplevelResizeGripVisibilityID) { - g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelResizeGripVisibilityID); - priv->toplevelResizeGripVisibilityID = 0; - } -#endif if (priv->toplevelFocusInEventID) { g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelFocusInEventID); priv->toplevelFocusInEventID = 0; @@ -231,36 +294,53 @@ static void webkitWebViewBaseSetToplevelOnScreenWindow(WebKitWebViewBase* webVie g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelFocusOutEventID); priv->toplevelFocusOutEventID = 0; } - if (priv->toplevelVisibilityEventID) { - g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelVisibilityEventID); - priv->toplevelVisibilityEventID = 0; + if (priv->toplevelWindowStateEventID) { + g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelWindowStateEventID); + priv->toplevelWindowStateEventID = 0; + } + if (priv->toplevelWindowRealizedID) { + g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelWindowRealizedID); + priv->toplevelWindowRealizedID = 0; } priv->toplevelOnScreenWindow = window; - priv->pageProxy->viewStateDidChange(ViewState::IsInWindow); - if (!priv->toplevelOnScreenWindow) - return; -#if !GTK_CHECK_VERSION(3, 13, 4) - webkitWebViewBaseNotifyResizerSize(webViewBase); + if (!priv->toplevelOnScreenWindow) { + ActivityState::Flags flagsToUpdate = 0; + if (priv->activityState & ActivityState::IsInWindow) { + priv->activityState &= ~ActivityState::IsInWindow; + flagsToUpdate |= ActivityState::IsInWindow; + } + if (priv->activityState & ActivityState::WindowIsActive) { + priv->activityState &= ~ActivityState::WindowIsActive; + flagsToUpdate |= ActivityState::IsInWindow; + } + if (flagsToUpdate) + webkitWebViewBaseScheduleUpdateActivityState(webViewBase, flagsToUpdate); + + return; + } - priv->toplevelResizeGripVisibilityID = - g_signal_connect(priv->toplevelOnScreenWindow, "notify::resize-grip-visible", - G_CALLBACK(toplevelWindowResizeGripVisibilityChanged), webViewBase); -#endif priv->toplevelFocusInEventID = g_signal_connect(priv->toplevelOnScreenWindow, "focus-in-event", G_CALLBACK(toplevelWindowFocusInEvent), webViewBase); priv->toplevelFocusOutEventID = g_signal_connect(priv->toplevelOnScreenWindow, "focus-out-event", G_CALLBACK(toplevelWindowFocusOutEvent), webViewBase); - priv->toplevelVisibilityEventID = - g_signal_connect(priv->toplevelOnScreenWindow, "visibility-notify-event", - G_CALLBACK(toplevelWindowVisibilityEvent), webViewBase); + priv->toplevelWindowStateEventID = + g_signal_connect(priv->toplevelOnScreenWindow, "window-state-event", G_CALLBACK(toplevelWindowStateEvent), webViewBase); + + if (gtk_widget_get_realized(GTK_WIDGET(window))) + gtk_widget_realize(GTK_WIDGET(webViewBase)); + else + priv->toplevelWindowRealizedID = g_signal_connect_swapped(window, "realize", G_CALLBACK(toplevelWindowRealized), webViewBase); } static void webkitWebViewBaseRealize(GtkWidget* widget) { + WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(widget); + WebKitWebViewBasePrivate* priv = webView->priv; + gtk_widget_set_realized(widget, TRUE); GtkAllocation allocation; @@ -281,6 +361,8 @@ static void webkitWebViewBaseRealize(GtkWidget* widget) | GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK | GDK_POINTER_MOTION_MASK + | GDK_ENTER_NOTIFY_MASK + | GDK_LEAVE_NOTIFY_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_BUTTON_MOTION_MASK @@ -295,12 +377,30 @@ static void webkitWebViewBaseRealize(GtkWidget* widget) gtk_widget_set_window(widget, window); gdk_window_set_user_data(window, widget); +#if USE(TEXTURE_MAPPER_GL) && PLATFORM(X11) && !USE(REDIRECTED_XCOMPOSITE_WINDOW) + if (PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::X11) { + if (DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(priv->pageProxy->drawingArea())) + drawingArea->setNativeSurfaceHandleForCompositing(GDK_WINDOW_XID(window)); + } +#endif + gtk_style_context_set_background(gtk_widget_get_style_context(widget), window); + gtk_im_context_set_client_window(priv->inputMethodFilter.context(), window); +} + +static void webkitWebViewBaseUnrealize(GtkWidget* widget) +{ WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(widget); - GtkWidget* toplevel = gtk_widget_get_toplevel(widget); - if (widgetIsOnscreenToplevelWindow(toplevel)) - webkitWebViewBaseSetToplevelOnScreenWindow(webView, GTK_WINDOW(toplevel)); +#if USE(TEXTURE_MAPPER_GL) && PLATFORM(X11) && !USE(REDIRECTED_XCOMPOSITE_WINDOW) + if (PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::X11) { + if (DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(webView->priv->pageProxy->drawingArea())) + drawingArea->destroyNativeSurfaceHandleForCompositing(); + } +#endif + gtk_im_context_set_client_window(webView->priv->inputMethodFilter.context(), nullptr); + + GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->unrealize(widget); } static bool webkitWebViewChildIsInternalWidget(WebKitWebViewBase* webViewBase, GtkWidget* widget) @@ -406,8 +506,10 @@ void webkitWebViewBaseChildMoveResize(WebKitWebViewBase* webView, GtkWidget* chi static void webkitWebViewBaseDispose(GObject* gobject) { WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(gobject); + g_cancellable_cancel(webView->priv->screenSaverInhibitCancellable.get()); webkitWebViewBaseSetToplevelOnScreenWindow(webView, nullptr); webView->priv->pageProxy->close(); + webView->priv->acceleratedBackingStore = nullptr; G_OBJECT_CLASS(webkit_web_view_base_parent_class)->dispose(gobject); } @@ -417,48 +519,15 @@ static void webkitWebViewBaseConstructed(GObject* object) GtkWidget* viewWidget = GTK_WIDGET(object); gtk_widget_set_can_focus(viewWidget, TRUE); - gtk_drag_dest_set(viewWidget, static_cast<GtkDestDefaults>(0), 0, 0, - static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_PRIVATE)); - gtk_drag_dest_set_target_list(viewWidget, PasteboardHelper::defaultPasteboardHelper()->targetList()); + gtk_drag_dest_set(viewWidget, static_cast<GtkDestDefaults>(0), nullptr, 0, + static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_PRIVATE)); + gtk_drag_dest_set_target_list(viewWidget, PasteboardHelper::singleton().targetList()); WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(object)->priv; - priv->pageClient = PageClientImpl::create(viewWidget); -#if ENABLE(DRAG_SUPPORT) - priv->dragAndDropHelper.setWidget(viewWidget); -#endif - -#if USE(TEXTURE_MAPPER_GL) && defined(GDK_WINDOWING_X11) - GdkDisplay* display = gdk_display_manager_get_default_display(gdk_display_manager_get()); - if (GDK_IS_X11_DISPLAY(display)) { - priv->redirectedWindow = RedirectedXCompositeWindow::create(IntSize(1, 1), RedirectedXCompositeWindow::DoNotCreateGLContext); - if (priv->redirectedWindow) - priv->redirectedWindow->setDamageNotifyCallback(redirectedWindowDamagedCallback, object); - } -#endif - + priv->pageClient = std::make_unique<PageClientImpl>(viewWidget); priv->authenticationDialog = 0; } -#if USE(TEXTURE_MAPPER_GL) -static bool webkitWebViewRenderAcceleratedCompositingResults(WebKitWebViewBase* webViewBase, DrawingAreaProxyImpl* drawingArea, cairo_t* cr, GdkRectangle* clipRect) -{ - if (!drawingArea->isInAcceleratedCompositingMode()) - return false; - - // To avoid flashes when initializing accelerated compositing for the first - // time, we wait until we know there's a frame ready before rendering. - WebKitWebViewBasePrivate* priv = webViewBase->priv; - if (!priv->redirectedWindow) - return false; - - cairo_rectangle(cr, clipRect->x, clipRect->y, clipRect->width, clipRect->height); - cairo_surface_t* surface = priv->redirectedWindow->cairoSurfaceForWidget(GTK_WIDGET(webViewBase)); - cairo_set_source_surface(cr, surface, 0, 0); - cairo_fill(cr); - return true; -} -#endif - static gboolean webkitWebViewBaseDraw(GtkWidget* widget, cairo_t* cr) { WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget); @@ -470,18 +539,11 @@ static gboolean webkitWebViewBaseDraw(GtkWidget* widget, cairo_t* cr) if (!gdk_cairo_get_clip_rectangle(cr, &clipRect)) return FALSE; -#if USE(TEXTURE_MAPPER_GL) - if (webkitWebViewRenderAcceleratedCompositingResults(webViewBase, drawingArea, cr, &clipRect)) - return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->draw(widget, cr); -#endif - - WebCore::Region unpaintedRegion; // This is simply unused. - drawingArea->paint(cr, clipRect, unpaintedRegion); - - if (webViewBase->priv->authenticationDialog) { - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_source_rgba(cr, 0, 0, 0, 0.5); - cairo_paint(cr); + if (webViewBase->priv->acceleratedBackingStore && drawingArea->isInAcceleratedCompositingMode()) + webViewBase->priv->acceleratedBackingStore->paint(cr, clipRect); + else { + WebCore::Region unpaintedRegion; // This is simply unused. + drawingArea->paint(cr, clipRect, unpaintedRegion); } GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->draw(widget, cr); @@ -505,8 +567,11 @@ static void webkitWebViewBaseChildAllocate(GtkWidget* child, gpointer userData) priv->children.set(child, IntRect()); } -static void resizeWebKitWebViewBaseFromAllocation(WebKitWebViewBase* webViewBase, GtkAllocation* allocation, bool sizeChanged) +static void webkitWebViewBaseSizeAllocate(GtkWidget* widget, GtkAllocation* allocation) { + GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->size_allocate(widget, allocation); + + WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget); gtk_container_foreach(GTK_CONTAINER(webViewBase), webkitWebViewBaseChildAllocate, webViewBase); IntRect viewRect(allocation->x, allocation->y, allocation->width, allocation->height); @@ -514,7 +579,7 @@ static void resizeWebKitWebViewBaseFromAllocation(WebKitWebViewBase* webViewBase if (priv->inspectorView) { GtkAllocation childAllocation = viewRect; - if (priv->inspectorAttachmentSide == AttachmentSideBottom) { + if (priv->inspectorAttachmentSide == AttachmentSide::Bottom) { int inspectorViewHeight = std::min(static_cast<int>(priv->inspectorViewSize), allocation->height); childAllocation.x = 0; childAllocation.y = allocation->height - inspectorViewHeight; @@ -535,45 +600,29 @@ static void resizeWebKitWebViewBaseFromAllocation(WebKitWebViewBase* webViewBase // never overlaps the web inspector. Thus, we need to calculate the allocation here // after calculating the inspector allocation. if (priv->authenticationDialog) { - GtkRequisition naturalSize; - gtk_widget_get_preferred_size(priv->authenticationDialog, 0, &naturalSize); - - GtkAllocation childAllocation = { - (viewRect.width() - naturalSize.width) / 2, - (viewRect.height() - naturalSize.height) / 2, - naturalSize.width, - naturalSize.height - }; + GtkRequisition minimumSize; + gtk_widget_get_preferred_size(priv->authenticationDialog, &minimumSize, nullptr); + + GtkAllocation childAllocation = { 0, 0, std::max(minimumSize.width, viewRect.width()), std::max(minimumSize.height, viewRect.height()) }; gtk_widget_size_allocate(priv->authenticationDialog, &childAllocation); } -#if USE(TEXTURE_MAPPER_GL) - if (sizeChanged && webViewBase->priv->redirectedWindow) - webViewBase->priv->redirectedWindow->resize(viewRect.size()); -#endif - - if (priv->pageProxy->drawingArea()) - priv->pageProxy->drawingArea()->setSize(viewRect.size(), IntSize(), IntSize()); - -#if !GTK_CHECK_VERSION(3, 13, 4) - webkitWebViewBaseNotifyResizerSize(webViewBase); -#endif + if (DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(priv->pageProxy->drawingArea())) + drawingArea->setSize(viewRect.size(), IntSize(), IntSize()); } -static void webkitWebViewBaseSizeAllocate(GtkWidget* widget, GtkAllocation* allocation) +static void webkitWebViewBaseGetPreferredWidth(GtkWidget* widget, gint* minimumSize, gint* naturalSize) { - bool sizeChanged = gtk_widget_get_allocated_width(widget) != allocation->width - || gtk_widget_get_allocated_height(widget) != allocation->height; - - GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->size_allocate(widget, allocation); - - WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget); - if (sizeChanged && !gtk_widget_get_mapped(widget)) { - webViewBase->priv->needsResizeOnMap = true; - return; - } + WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv; + *minimumSize = 0; + *naturalSize = priv->contentsSize.width(); +} - resizeWebKitWebViewBaseFromAllocation(webViewBase, allocation, sizeChanged); +static void webkitWebViewBaseGetPreferredHeight(GtkWidget* widget, gint* minimumSize, gint* naturalSize) +{ + WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv; + *minimumSize = 0; + *naturalSize = priv->contentsSize.height(); } static void webkitWebViewBaseMap(GtkWidget* widget) @@ -582,29 +631,33 @@ static void webkitWebViewBaseMap(GtkWidget* widget) WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget); WebKitWebViewBasePrivate* priv = webViewBase->priv; - if (!priv->isVisible) { - priv->isVisible = true; - priv->pageProxy->viewStateDidChange(ViewState::IsVisible); + ActivityState::Flags flagsToUpdate = 0; + if (!(priv->activityState & ActivityState::IsVisible)) + flagsToUpdate |= ActivityState::IsVisible; + if (priv->toplevelOnScreenWindow) { + if (!(priv->activityState & ActivityState::IsInWindow)) + flagsToUpdate |= ActivityState::IsInWindow; + if (gtk_window_is_active(GTK_WINDOW(priv->toplevelOnScreenWindow)) && !(priv->activityState & ActivityState::WindowIsActive)) + flagsToUpdate |= ActivityState::WindowIsActive; } - - if (!priv->needsResizeOnMap) + if (!flagsToUpdate) return; - GtkAllocation allocation; - gtk_widget_get_allocation(widget, &allocation); - resizeWebKitWebViewBaseFromAllocation(webViewBase, &allocation, true /* sizeChanged */); - priv->needsResizeOnMap = false; + priv->activityState |= flagsToUpdate; + webkitWebViewBaseScheduleUpdateActivityState(webViewBase, flagsToUpdate); } static void webkitWebViewBaseUnmap(GtkWidget* widget) { GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->unmap(widget); - WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv; - if (priv->isVisible) { - priv->isVisible = false; - priv->pageProxy->viewStateDidChange(ViewState::IsVisible); - } + WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget); + WebKitWebViewBasePrivate* priv = webViewBase->priv; + if (!(priv->activityState & ActivityState::IsVisible)) + return; + + priv->activityState &= ~ActivityState::IsVisible; + webkitWebViewBaseScheduleUpdateActivityState(webViewBase, ActivityState::IsVisible); } static gboolean webkitWebViewBaseFocusInEvent(GtkWidget* widget, GdkEventFocus* event) @@ -625,17 +678,26 @@ static gboolean webkitWebViewBaseFocusOutEvent(GtkWidget* widget, GdkEventFocus* return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->focus_out_event(widget, event); } -static gboolean webkitWebViewBaseKeyPressEvent(GtkWidget* widget, GdkEventKey* event) +static gboolean webkitWebViewBaseKeyPressEvent(GtkWidget* widget, GdkEventKey* keyEvent) { WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget); WebKitWebViewBasePrivate* priv = webViewBase->priv; +#if ENABLE(DEVELOPER_MODE) && OS(LINUX) + if ((keyEvent->state & GDK_CONTROL_MASK) && (keyEvent->state & GDK_SHIFT_MASK) && keyEvent->keyval == GDK_KEY_G) { + auto& preferences = priv->pageProxy->preferences(); + preferences.setResourceUsageOverlayVisible(!preferences.resourceUsageOverlayVisible()); + priv->shouldForwardNextKeyEvent = FALSE; + return TRUE; + } +#endif + if (priv->authenticationDialog) - return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_press_event(widget, event); + return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_press_event(widget, keyEvent); #if ENABLE(FULLSCREEN_API) if (priv->fullScreenModeActive) { - switch (event->keyval) { + switch (keyEvent->keyval) { case GDK_KEY_Escape: case GDK_KEY_f: case GDK_KEY_F: @@ -653,22 +715,35 @@ static gboolean webkitWebViewBaseKeyPressEvent(GtkWidget* widget, GdkEventKey* e // using gtk_main_do_event(). if (priv->shouldForwardNextKeyEvent) { priv->shouldForwardNextKeyEvent = FALSE; - return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_press_event(widget, event); + return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_press_event(widget, keyEvent); } - priv->inputMethodFilter.filterKeyEvent(event); + + // We need to copy the event as otherwise it could be destroyed before we reach the lambda body. + GUniquePtr<GdkEvent> event(gdk_event_copy(reinterpret_cast<GdkEvent*>(keyEvent))); + priv->inputMethodFilter.filterKeyEvent(keyEvent, [priv, event = WTFMove(event)](const WebCore::CompositionResults& compositionResults, InputMethodFilter::EventFakedForComposition faked) { + priv->pageProxy->handleKeyboardEvent(NativeWebKeyboardEvent(event.get(), compositionResults, faked, + !compositionResults.compositionUpdated() ? priv->keyBindingTranslator.commandsForKeyEvent(&event->key) : Vector<String>())); + }); + return TRUE; } -static gboolean webkitWebViewBaseKeyReleaseEvent(GtkWidget* widget, GdkEventKey* event) +static gboolean webkitWebViewBaseKeyReleaseEvent(GtkWidget* widget, GdkEventKey* keyEvent) { WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget); WebKitWebViewBasePrivate* priv = webViewBase->priv; if (priv->shouldForwardNextKeyEvent) { priv->shouldForwardNextKeyEvent = FALSE; - return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_release_event(widget, event); + return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_release_event(widget, keyEvent); } - priv->inputMethodFilter.filterKeyEvent(event); + + // We need to copy the event as otherwise it could be destroyed before we reach the lambda body. + GUniquePtr<GdkEvent> event(gdk_event_copy(reinterpret_cast<GdkEvent*>(keyEvent))); + priv->inputMethodFilter.filterKeyEvent(keyEvent, [priv, event = WTFMove(event)](const WebCore::CompositionResults& compositionResults, InputMethodFilter::EventFakedForComposition faked) { + priv->pageProxy->handleKeyboardEvent(NativeWebKeyboardEvent(event.get(), compositionResults, faked, { })); + }); + return TRUE; } @@ -684,14 +759,21 @@ static gboolean webkitWebViewBaseButtonPressEvent(GtkWidget* widget, GdkEventBut priv->inputMethodFilter.notifyMouseButtonPress(); - if (!priv->clickCounter.shouldProcessButtonEvent(buttonEvent)) + // For double and triple clicks GDK sends both a normal button press event + // and a specific type (like GDK_2BUTTON_PRESS). If we detect a special press + // coming up, ignore this event as it certainly generated the double or triple + // click. The consequence of not eating this event is two DOM button press events + // are generated. + GUniquePtr<GdkEvent> nextEvent(gdk_event_peek()); + if (nextEvent && (nextEvent->any.type == GDK_2BUTTON_PRESS || nextEvent->any.type == GDK_3BUTTON_PRESS)) return TRUE; // If it's a right click event save it as a possible context menu event. if (buttonEvent->button == 3) priv->contextMenuEvent.reset(gdk_event_copy(reinterpret_cast<GdkEvent*>(buttonEvent))); + priv->pageProxy->handleMouseEvent(NativeWebMouseEvent(reinterpret_cast<GdkEvent*>(buttonEvent), - priv->clickCounter.clickCountForGdkButtonEvent(widget, buttonEvent))); + priv->clickCounter.currentClickCountForGdkButtonEvent(buttonEvent))); return TRUE; } @@ -714,41 +796,195 @@ static gboolean webkitWebViewBaseScrollEvent(GtkWidget* widget, GdkEventScroll* WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget); WebKitWebViewBasePrivate* priv = webViewBase->priv; + if (std::exchange(priv->shouldForwardNextWheelEvent, false)) + return FALSE; + if (priv->authenticationDialog) - return TRUE; + return FALSE; priv->pageProxy->handleWheelEvent(NativeWebWheelEvent(reinterpret_cast<GdkEvent*>(event))); return TRUE; } +static gboolean webkitWebViewBasePopupMenu(GtkWidget* widget) +{ + WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget); + WebKitWebViewBasePrivate* priv = webViewBase->priv; + + GdkEvent* currentEvent = gtk_get_current_event(); + if (!currentEvent) + currentEvent = gdk_event_new(GDK_NOTHING); + priv->contextMenuEvent.reset(currentEvent); + priv->pageProxy->handleContextMenuKeyEvent(); + + return TRUE; +} + static gboolean webkitWebViewBaseMotionNotifyEvent(GtkWidget* widget, GdkEventMotion* event) { WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget); WebKitWebViewBasePrivate* priv = webViewBase->priv; - if (priv->authenticationDialog) - return TRUE; + if (priv->authenticationDialog) { + auto* widgetClass = GTK_WIDGET_CLASS(webkit_web_view_base_parent_class); + return widgetClass->motion_notify_event ? widgetClass->motion_notify_event(widget, event) : FALSE; + } priv->pageProxy->handleMouseEvent(NativeWebMouseEvent(reinterpret_cast<GdkEvent*>(event), 0 /* currentClickCount */)); - return TRUE; + return FALSE; +} + +static gboolean webkitWebViewBaseCrossingNotifyEvent(GtkWidget* widget, GdkEventCrossing* crosssingEvent) +{ + WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget); + WebKitWebViewBasePrivate* priv = webViewBase->priv; + + if (priv->authenticationDialog) + return FALSE; + + // In the case of crossing events, it's very important the actual coordinates the WebProcess receives, because once the mouse leaves + // the web view, the WebProcess won't receive more events until the mouse enters again in the web view. So, if the coordinates of the leave + // event are not accurate, the WebProcess might not know the mouse left the view. This can happen because of double to integer conversion, + // if the coordinates of the leave event are for example (25.2, -0.9), the WebProcess will receive (25, 0) and any hit test will succeed + // because those coordinates are inside the web view. + GtkAllocation allocation; + gtk_widget_get_allocation(widget, &allocation); + double width = allocation.width; + double height = allocation.height; + double x = crosssingEvent->x; + double y = crosssingEvent->y; + if (x < 0 && x > -1) + x = -1; + else if (x >= width && x < width + 1) + x = width + 1; + if (y < 0 && y > -1) + y = -1; + else if (y >= height && y < height + 1) + y = height + 1; + + GdkEvent* event = reinterpret_cast<GdkEvent*>(crosssingEvent); + GUniquePtr<GdkEvent> copiedEvent; + if (x != crosssingEvent->x || y != crosssingEvent->y) { + copiedEvent.reset(gdk_event_copy(event)); + copiedEvent->crossing.x = x; + copiedEvent->crossing.y = y; + } + + priv->pageProxy->handleMouseEvent(NativeWebMouseEvent(copiedEvent ? copiedEvent.get() : event, 0 /* currentClickCount */)); + + return FALSE; +} + +#if ENABLE(TOUCH_EVENTS) +static void appendTouchEvent(Vector<WebPlatformTouchPoint>& touchPoints, const GdkEvent* event, WebPlatformTouchPoint::TouchPointState state) +{ + gdouble x, y; + gdk_event_get_coords(event, &x, &y); + + gdouble xRoot, yRoot; + gdk_event_get_root_coords(event, &xRoot, &yRoot); + + uint32_t identifier = GPOINTER_TO_UINT(gdk_event_get_event_sequence(event)); + touchPoints.uncheckedAppend(WebPlatformTouchPoint(identifier, state, IntPoint(xRoot, yRoot), IntPoint(x, y))); +} + +static inline WebPlatformTouchPoint::TouchPointState touchPointStateForEvents(const GdkEvent* current, const GdkEvent* event) +{ + if (gdk_event_get_event_sequence(current) != gdk_event_get_event_sequence(event)) + return WebPlatformTouchPoint::TouchStationary; + + switch (current->type) { + case GDK_TOUCH_UPDATE: + return WebPlatformTouchPoint::TouchMoved; + case GDK_TOUCH_BEGIN: + return WebPlatformTouchPoint::TouchPressed; + case GDK_TOUCH_END: + return WebPlatformTouchPoint::TouchReleased; + default: + return WebPlatformTouchPoint::TouchStationary; + } +} + +static void webkitWebViewBaseGetTouchPointsForEvent(WebKitWebViewBase* webViewBase, GdkEvent* event, Vector<WebPlatformTouchPoint>& touchPoints) +{ + WebKitWebViewBasePrivate* priv = webViewBase->priv; + touchPoints.reserveInitialCapacity(event->type == GDK_TOUCH_END ? priv->touchEvents.size() + 1 : priv->touchEvents.size()); + + for (const auto& it : priv->touchEvents) + appendTouchEvent(touchPoints, it.value.get(), touchPointStateForEvents(it.value.get(), event)); + + // Touch was already removed from the TouchEventsMap, add it here. + if (event->type == GDK_TOUCH_END) + appendTouchEvent(touchPoints, event, WebPlatformTouchPoint::TouchReleased); } static gboolean webkitWebViewBaseTouchEvent(GtkWidget* widget, GdkEventTouch* event) { - WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv; + WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget); + WebKitWebViewBasePrivate* priv = webViewBase->priv; if (priv->authenticationDialog) return TRUE; - priv->touchContext.handleEvent(reinterpret_cast<GdkEvent*>(event)); - priv->pageProxy->handleTouchEvent(NativeWebTouchEvent(reinterpret_cast<GdkEvent*>(event), priv->touchContext)); + GdkEvent* touchEvent = reinterpret_cast<GdkEvent*>(event); + uint32_t sequence = GPOINTER_TO_UINT(gdk_event_get_event_sequence(touchEvent)); + +#if HAVE(GTK_GESTURES) + GestureController& gestureController = webkitWebViewBaseGestureController(webViewBase); + if (gestureController.isProcessingGestures()) { + // If we are already processing gestures is because the WebProcess didn't handle the + // BEGIN touch event, so pass subsequent events to the GestureController. + gestureController.handleEvent(touchEvent); + // Remove the gesture event sequence from the handled touch events + // list to avoid the gesure sequence and a touch sequence of same + // ID to conflict. + priv->touchEvents.remove(sequence); + return TRUE; + } +#endif + + switch (touchEvent->type) { + case GDK_TOUCH_BEGIN: { + ASSERT(!priv->touchEvents.contains(sequence)); + GUniquePtr<GdkEvent> event(gdk_event_copy(touchEvent)); + priv->touchEvents.add(sequence, WTFMove(event)); + break; + } + case GDK_TOUCH_UPDATE: { + auto it = priv->touchEvents.find(sequence); + ASSERT(it != priv->touchEvents.end()); + it->value.reset(gdk_event_copy(touchEvent)); + break; + } + case GDK_TOUCH_END: + ASSERT(priv->touchEvents.contains(sequence)); + priv->touchEvents.remove(sequence); + break; + default: + break; + } + + Vector<WebPlatformTouchPoint> touchPoints; + webkitWebViewBaseGetTouchPointsForEvent(webViewBase, touchEvent, touchPoints); + priv->pageProxy->handleTouchEvent(NativeWebTouchEvent(reinterpret_cast<GdkEvent*>(event), WTFMove(touchPoints))); return TRUE; } +#endif // ENABLE(TOUCH_EVENTS) + +#if HAVE(GTK_GESTURES) +GestureController& webkitWebViewBaseGestureController(WebKitWebViewBase* webViewBase) +{ + WebKitWebViewBasePrivate* priv = webViewBase->priv; + if (!priv->gestureController) + priv->gestureController = std::make_unique<GestureController>(*priv->pageProxy); + return *priv->gestureController; +} +#endif -static gboolean webkitWebViewBaseQueryTooltip(GtkWidget* widget, gint x, gint y, gboolean keyboardMode, GtkTooltip* tooltip) +static gboolean webkitWebViewBaseQueryTooltip(GtkWidget* widget, gint /* x */, gint /* y */, gboolean keyboardMode, GtkTooltip* tooltip) { WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv; @@ -772,39 +1008,23 @@ static gboolean webkitWebViewBaseQueryTooltip(GtkWidget* widget, gint x, gint y, } #if ENABLE(DRAG_SUPPORT) -static void webkitWebViewBaseDragDataGet(GtkWidget* widget, GdkDragContext* context, GtkSelectionData* selectionData, guint info, guint time) +static void webkitWebViewBaseDragDataGet(GtkWidget* widget, GdkDragContext* context, GtkSelectionData* selectionData, guint info, guint /* time */) { - WEBKIT_WEB_VIEW_BASE(widget)->priv->dragAndDropHelper.handleGetDragData(context, selectionData, info); + WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv; + ASSERT(priv->dragAndDropHandler); + priv->dragAndDropHandler->fillDragData(context, selectionData, info); } static void webkitWebViewBaseDragEnd(GtkWidget* widget, GdkDragContext* context) { - WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget); - if (!webViewBase->priv->dragAndDropHelper.handleDragEnd(context)) - return; - - GdkDevice* device = gdk_drag_context_get_device(context); - int x = 0, y = 0; - gdk_device_get_window_at_position(device, &x, &y); - int xRoot = 0, yRoot = 0; - gdk_device_get_position(device, 0, &xRoot, &yRoot); - webViewBase->priv->pageProxy->dragEnded(IntPoint(x, y), IntPoint(xRoot, yRoot), - gdkDragActionToDragOperation(gdk_drag_context_get_selected_action(context))); + WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv; + ASSERT(priv->dragAndDropHandler); + priv->dragAndDropHandler->finishDrag(context); } -static void webkitWebViewBaseDragDataReceived(GtkWidget* widget, GdkDragContext* context, gint x, gint y, GtkSelectionData* selectionData, guint info, guint time) +static void webkitWebViewBaseDragDataReceived(GtkWidget* widget, GdkDragContext* context, gint /* x */, gint /* y */, GtkSelectionData* selectionData, guint info, guint time) { - WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget); - IntPoint position; - DataObjectGtk* dataObject = webViewBase->priv->dragAndDropHelper.handleDragDataReceived(context, selectionData, info, position); - if (!dataObject) - return; - - DragData dragData(dataObject, position, convertWidgetPointToScreenPoint(widget, position), gdkDragActionToDragOperation(gdk_drag_context_get_actions(context))); - webViewBase->priv->pageProxy->resetDragOperation(); - webViewBase->priv->pageProxy->dragEntered(dragData); - DragOperation operation = webViewBase->priv->pageProxy->dragSession().operation; - gdk_drag_status(context, dragOperationToSingleGdkDragAction(operation), time); + webkitWebViewBaseDragAndDropHandler(WEBKIT_WEB_VIEW_BASE(widget)).dragEntered(context, selectionData, info, time); } #endif // ENABLE(DRAG_SUPPORT) @@ -839,57 +1059,38 @@ static AtkObject* webkitWebViewBaseGetAccessible(GtkWidget* widget) #if ENABLE(DRAG_SUPPORT) static gboolean webkitWebViewBaseDragMotion(GtkWidget* widget, GdkDragContext* context, gint x, gint y, guint time) { - WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget); - IntPoint position(x, y); - DataObjectGtk* dataObject = webViewBase->priv->dragAndDropHelper.handleDragMotion(context, position, time); - if (!dataObject) - return TRUE; - - DragData dragData(dataObject, position, convertWidgetPointToScreenPoint(widget, position), gdkDragActionToDragOperation(gdk_drag_context_get_actions(context))); - webViewBase->priv->pageProxy->dragUpdated(dragData); - DragOperation operation = webViewBase->priv->pageProxy->dragSession().operation; - gdk_drag_status(context, dragOperationToSingleGdkDragAction(operation), time); + webkitWebViewBaseDragAndDropHandler(WEBKIT_WEB_VIEW_BASE(widget)).dragMotion(context, IntPoint(x, y), time); return TRUE; } -static void dragExitedCallback(GtkWidget* widget, DragData& dragData, bool dropHappened) -{ - // Don't call dragExited if we have just received a drag-drop signal. This - // happens in the case of a successful drop onto the view. - if (dropHappened) - return; - - WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget); - webViewBase->priv->pageProxy->dragExited(dragData); - webViewBase->priv->pageProxy->resetDragOperation(); -} - -static void webkitWebViewBaseDragLeave(GtkWidget* widget, GdkDragContext* context, guint time) +static void webkitWebViewBaseDragLeave(GtkWidget* widget, GdkDragContext* context, guint /* time */) { - WEBKIT_WEB_VIEW_BASE(widget)->priv->dragAndDropHelper.handleDragLeave(context, dragExitedCallback); + WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv; + ASSERT(priv->dragAndDropHandler); + priv->dragAndDropHandler->dragLeave(context); } static gboolean webkitWebViewBaseDragDrop(GtkWidget* widget, GdkDragContext* context, gint x, gint y, guint time) { - WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget); - DataObjectGtk* dataObject = webViewBase->priv->dragAndDropHelper.handleDragDrop(context); - if (!dataObject) - return FALSE; - - IntPoint position(x, y); - DragData dragData(dataObject, position, convertWidgetPointToScreenPoint(widget, position), gdkDragActionToDragOperation(gdk_drag_context_get_actions(context))); - SandboxExtension::Handle handle; - SandboxExtension::HandleArray sandboxExtensionForUpload; - webViewBase->priv->pageProxy->performDrag(dragData, String(), handle, sandboxExtensionForUpload); - gtk_drag_finish(context, TRUE, FALSE, time); - return TRUE; + WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv; + ASSERT(priv->dragAndDropHandler); + return priv->dragAndDropHandler->drop(context, IntPoint(x, y), time); } #endif // ENABLE(DRAG_SUPPORT) -static void webkitWebViewBaseParentSet(GtkWidget* widget, GtkWidget* oldParent) +static void webkitWebViewBaseHierarchyChanged(GtkWidget* widget, GtkWidget* oldToplevel) { - if (!gtk_widget_get_parent(widget)) - webkitWebViewBaseSetToplevelOnScreenWindow(WEBKIT_WEB_VIEW_BASE(widget), 0); + WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv; + if (widgetIsOnscreenToplevelWindow(oldToplevel) && GTK_WINDOW(oldToplevel) == priv->toplevelOnScreenWindow) { + webkitWebViewBaseSetToplevelOnScreenWindow(WEBKIT_WEB_VIEW_BASE(widget), nullptr); + return; + } + + if (!oldToplevel) { + GtkWidget* toplevel = gtk_widget_get_toplevel(widget); + if (widgetIsOnscreenToplevelWindow(toplevel)) + webkitWebViewBaseSetToplevelOnScreenWindow(WEBKIT_WEB_VIEW_BASE(widget), GTK_WINDOW(toplevel)); + } } static gboolean webkitWebViewBaseFocus(GtkWidget* widget, GtkDirectionType direction) @@ -919,8 +1120,11 @@ static void webkit_web_view_base_class_init(WebKitWebViewBaseClass* webkitWebVie { GtkWidgetClass* widgetClass = GTK_WIDGET_CLASS(webkitWebViewBaseClass); widgetClass->realize = webkitWebViewBaseRealize; + widgetClass->unrealize = webkitWebViewBaseUnrealize; widgetClass->draw = webkitWebViewBaseDraw; widgetClass->size_allocate = webkitWebViewBaseSizeAllocate; + widgetClass->get_preferred_width = webkitWebViewBaseGetPreferredWidth; + widgetClass->get_preferred_height = webkitWebViewBaseGetPreferredHeight; widgetClass->map = webkitWebViewBaseMap; widgetClass->unmap = webkitWebViewBaseUnmap; widgetClass->focus = webkitWebViewBaseFocus; @@ -931,8 +1135,13 @@ static void webkit_web_view_base_class_init(WebKitWebViewBaseClass* webkitWebVie widgetClass->button_press_event = webkitWebViewBaseButtonPressEvent; widgetClass->button_release_event = webkitWebViewBaseButtonReleaseEvent; widgetClass->scroll_event = webkitWebViewBaseScrollEvent; + widgetClass->popup_menu = webkitWebViewBasePopupMenu; widgetClass->motion_notify_event = webkitWebViewBaseMotionNotifyEvent; + widgetClass->enter_notify_event = webkitWebViewBaseCrossingNotifyEvent; + widgetClass->leave_notify_event = webkitWebViewBaseCrossingNotifyEvent; +#if ENABLE(TOUCH_EVENTS) widgetClass->touch_event = webkitWebViewBaseTouchEvent; +#endif widgetClass->query_tooltip = webkitWebViewBaseQueryTooltip; #if ENABLE(DRAG_SUPPORT) widgetClass->drag_end = webkitWebViewBaseDragEnd; @@ -943,7 +1152,7 @@ static void webkit_web_view_base_class_init(WebKitWebViewBaseClass* webkitWebVie widgetClass->drag_data_received = webkitWebViewBaseDragDataReceived; #endif // ENABLE(DRAG_SUPPORT) widgetClass->get_accessible = webkitWebViewBaseGetAccessible; - widgetClass->parent_set = webkitWebViewBaseParentSet; + widgetClass->hierarchy_changed = webkitWebViewBaseHierarchyChanged; widgetClass->destroy = webkitWebViewBaseDestroy; GObjectClass* gobjectClass = G_OBJECT_CLASS(webkitWebViewBaseClass); @@ -954,12 +1163,17 @@ static void webkit_web_view_base_class_init(WebKitWebViewBaseClass* webkitWebVie containerClass->add = webkitWebViewBaseContainerAdd; containerClass->remove = webkitWebViewBaseContainerRemove; containerClass->forall = webkitWebViewBaseContainerForall; + + // Before creating a WebKitWebViewBasePriv we need to be sure that WebKit is started. + // Usually starting a context triggers InitializeWebKit2, but in case + // we create a view without asking before for a default_context we get a crash. + WebKit::InitializeWebKit2(); } -WebKitWebViewBase* webkitWebViewBaseCreate(WebContext* context, WebPageGroup* pageGroup, WebPageProxy* relatedPage) +WebKitWebViewBase* webkitWebViewBaseCreate(const API::PageConfiguration& configuration) { - WebKitWebViewBase* webkitWebViewBase = WEBKIT_WEB_VIEW_BASE(g_object_new(WEBKIT_TYPE_WEB_VIEW_BASE, NULL)); - webkitWebViewBaseCreateWebPage(webkitWebViewBase, context, pageGroup, relatedPage); + WebKitWebViewBase* webkitWebViewBase = WEBKIT_WEB_VIEW_BASE(g_object_new(WEBKIT_TYPE_WEB_VIEW_BASE, nullptr)); + webkitWebViewBaseCreateWebPage(webkitWebViewBase, configuration.copy()); return webkitWebViewBase; } @@ -973,18 +1187,6 @@ WebPageProxy* webkitWebViewBaseGetPage(WebKitWebViewBase* webkitWebViewBase) return webkitWebViewBase->priv->pageProxy.get(); } -void webkitWebViewBaseUpdatePreferences(WebKitWebViewBase* webkitWebViewBase) -{ - WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv; - -#if USE(TEXTURE_MAPPER_GL) - if (priv->redirectedWindow) - return; -#endif - - priv->pageProxy->pageGroup().preferences()->setAcceleratedCompositingEnabled(false); -} - #if HAVE(GTK_SCALE_FACTOR) static void deviceScaleFactorChanged(WebKitWebViewBase* webkitWebViewBase) { @@ -992,32 +1194,22 @@ static void deviceScaleFactorChanged(WebKitWebViewBase* webkitWebViewBase) } #endif // HAVE(GTK_SCALE_FACTOR) -void webkitWebViewBaseCreateWebPage(WebKitWebViewBase* webkitWebViewBase, WebContext* context, WebPageGroup* pageGroup, WebPageProxy* relatedPage) +void webkitWebViewBaseCreateWebPage(WebKitWebViewBase* webkitWebViewBase, Ref<API::PageConfiguration>&& configuration) { WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv; - - WebPageConfiguration webPageConfiguration; - webPageConfiguration.pageGroup = pageGroup; - webPageConfiguration.relatedPage = relatedPage; - priv->pageProxy = context->createWebPage(*priv->pageClient, std::move(webPageConfiguration)); + WebProcessPool* processPool = configuration->processPool(); + priv->pageProxy = processPool->createWebPage(*priv->pageClient, WTFMove(configuration)); priv->pageProxy->initializeWebPage(); -#if USE(TEXTURE_MAPPER_GL) - if (priv->redirectedWindow) - priv->pageProxy->setAcceleratedCompositingWindowId(priv->redirectedWindow->windowId()); -#endif + priv->acceleratedBackingStore = AcceleratedBackingStore::create(*priv->pageProxy); + + priv->inputMethodFilter.setPage(priv->pageProxy.get()); #if HAVE(GTK_SCALE_FACTOR) // We attach this here, because changes in scale factor are passed directly to the page proxy. priv->pageProxy->setIntrinsicDeviceScaleFactor(gtk_widget_get_scale_factor(GTK_WIDGET(webkitWebViewBase))); g_signal_connect(webkitWebViewBase, "notify::scale-factor", G_CALLBACK(deviceScaleFactorChanged), nullptr); #endif - - webkitWebViewBaseUpdatePreferences(webkitWebViewBase); - - // This must happen here instead of the instance initializer, because the input method - // filter must have access to the page. - priv->inputMethodFilter.setWebView(webkitWebViewBase); } void webkitWebViewBaseSetTooltipText(WebKitWebViewBase* webViewBase, const char* tooltip) @@ -1040,31 +1232,12 @@ void webkitWebViewBaseSetTooltipArea(WebKitWebViewBase* webViewBase, const IntRe } #if ENABLE(DRAG_SUPPORT) -void webkitWebViewBaseStartDrag(WebKitWebViewBase* webViewBase, const DragData& dragData, PassRefPtr<ShareableBitmap> dragImage) +DragAndDropHandler& webkitWebViewBaseDragAndDropHandler(WebKitWebViewBase* webViewBase) { WebKitWebViewBasePrivate* priv = webViewBase->priv; - - RefPtr<DataObjectGtk> dataObject = adoptRef(dragData.platformData()); - GRefPtr<GtkTargetList> targetList = adoptGRef(PasteboardHelper::defaultPasteboardHelper()->targetListForDataObject(dataObject.get())); - GUniquePtr<GdkEvent> currentEvent(gtk_get_current_event()); - GdkDragContext* context = gtk_drag_begin(GTK_WIDGET(webViewBase), - targetList.get(), - dragOperationToGdkDragActions(dragData.draggingSourceOperationMask()), - 1, /* button */ - currentEvent.get()); - priv->dragAndDropHelper.startedDrag(context, dataObject.get()); - - - // A drag starting should prevent a double-click from happening. This might - // happen if a drag is followed very quickly by another click (like in the DRT). - priv->clickCounter.reset(); - - if (dragImage) { - RefPtr<cairo_surface_t> image(dragImage->createCairoSurface()); - priv->dragIcon.setImage(image.get()); - priv->dragIcon.useForDrag(context); - } else - gtk_drag_set_icon_default(context); + if (!priv->dragAndDropHandler) + priv->dragAndDropHandler = std::make_unique<DragAndDropHandler>(*priv->pageProxy); + return *priv->dragAndDropHandler; } #endif // ENABLE(DRAG_SUPPORT) @@ -1073,6 +1246,80 @@ void webkitWebViewBaseForwardNextKeyEvent(WebKitWebViewBase* webkitWebViewBase) webkitWebViewBase->priv->shouldForwardNextKeyEvent = TRUE; } +void webkitWebViewBaseForwardNextWheelEvent(WebKitWebViewBase* webkitWebViewBase) +{ + webkitWebViewBase->priv->shouldForwardNextWheelEvent = true; +} + +#if ENABLE(FULLSCREEN_API) +static void screenSaverInhibitedCallback(GDBusProxy* screenSaverProxy, GAsyncResult* result, WebKitWebViewBase* webViewBase) +{ + GRefPtr<GVariant> returnValue = adoptGRef(g_dbus_proxy_call_finish(screenSaverProxy, result, nullptr)); + if (returnValue) + g_variant_get(returnValue.get(), "(u)", &webViewBase->priv->screenSaverCookie); + webViewBase->priv->screenSaverInhibitCancellable = nullptr; +} + +static void webkitWebViewBaseSendInhibitMessageToScreenSaver(WebKitWebViewBase* webViewBase) +{ + WebKitWebViewBasePrivate* priv = webViewBase->priv; + ASSERT(priv->screenSaverProxy); + priv->screenSaverCookie = 0; + if (!priv->screenSaverInhibitCancellable) + priv->screenSaverInhibitCancellable = adoptGRef(g_cancellable_new()); + g_dbus_proxy_call(priv->screenSaverProxy.get(), "Inhibit", g_variant_new("(ss)", g_get_prgname(), _("Website running in fullscreen mode")), + G_DBUS_CALL_FLAGS_NONE, -1, priv->screenSaverInhibitCancellable.get(), reinterpret_cast<GAsyncReadyCallback>(screenSaverInhibitedCallback), webViewBase); +} + +static void screenSaverProxyCreatedCallback(GObject*, GAsyncResult* result, WebKitWebViewBase* webViewBase) +{ + // WebKitWebViewBase cancels the proxy creation on dispose, which means this could be called + // after the web view has been destroyed and g_dbus_proxy_new_for_bus_finish will return nullptr. + // So, make sure we don't use the web view unless we have a valid proxy. + // See https://bugs.webkit.org/show_bug.cgi?id=151653. + GRefPtr<GDBusProxy> proxy = adoptGRef(g_dbus_proxy_new_for_bus_finish(result, nullptr)); + if (!proxy) + return; + + webViewBase->priv->screenSaverProxy = proxy; + webkitWebViewBaseSendInhibitMessageToScreenSaver(webViewBase); +} + +static void webkitWebViewBaseInhibitScreenSaver(WebKitWebViewBase* webViewBase) +{ + WebKitWebViewBasePrivate* priv = webViewBase->priv; + if (priv->screenSaverCookie) { + // Already inhibited. + return; + } + + if (priv->screenSaverProxy) { + webkitWebViewBaseSendInhibitMessageToScreenSaver(webViewBase); + return; + } + + priv->screenSaverInhibitCancellable = adoptGRef(g_cancellable_new()); + g_dbus_proxy_new_for_bus(G_BUS_TYPE_SESSION, static_cast<GDBusProxyFlags>(G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS), + nullptr, "org.freedesktop.ScreenSaver", "/ScreenSaver", "org.freedesktop.ScreenSaver", priv->screenSaverInhibitCancellable.get(), + reinterpret_cast<GAsyncReadyCallback>(screenSaverProxyCreatedCallback), webViewBase); +} + +static void webkitWebViewBaseUninhibitScreenSaver(WebKitWebViewBase* webViewBase) +{ + WebKitWebViewBasePrivate* priv = webViewBase->priv; + if (!priv->screenSaverCookie) { + // Not inhibited or it's being inhibited. + g_cancellable_cancel(priv->screenSaverInhibitCancellable.get()); + return; + } + + // If we have a cookie we should have a proxy. + ASSERT(priv->screenSaverProxy); + g_dbus_proxy_call(priv->screenSaverProxy.get(), "UnInhibit", g_variant_new("(u)", priv->screenSaverCookie), G_DBUS_CALL_FLAGS_NONE, -1, nullptr, nullptr, nullptr); + priv->screenSaverCookie = 0; +} +#endif + void webkitWebViewBaseEnterFullScreen(WebKitWebViewBase* webkitWebViewBase) { #if ENABLE(FULLSCREEN_API) @@ -1091,6 +1338,7 @@ void webkitWebViewBaseEnterFullScreen(WebKitWebViewBase* webkitWebViewBase) gtk_window_fullscreen(GTK_WINDOW(topLevelWindow)); fullScreenManagerProxy->didEnterFullScreen(); priv->fullScreenModeActive = true; + webkitWebViewBaseInhibitScreenSaver(webkitWebViewBase); #endif } @@ -1112,6 +1360,7 @@ void webkitWebViewBaseExitFullScreen(WebKitWebViewBase* webkitWebViewBase) gtk_window_unfullscreen(GTK_WINDOW(topLevelWindow)); fullScreenManagerProxy->didExitFullScreen(); priv->fullScreenModeActive = false; + webkitWebViewBaseUninhibitScreenSaver(webkitWebViewBase); #endif } @@ -1129,9 +1378,16 @@ void webkitWebViewBaseSetInspectorViewSize(WebKitWebViewBase* webkitWebViewBase, gtk_widget_queue_resize_no_redraw(GTK_WIDGET(webkitWebViewBase)); } +static void activeContextMenuUnmapped(GtkMenu* menu, WebKitWebViewBase* webViewBase) +{ + if (webViewBase->priv->activeContextMenuProxy && webViewBase->priv->activeContextMenuProxy->gtkMenu() == menu) + webViewBase->priv->activeContextMenuProxy = nullptr; +} + void webkitWebViewBaseSetActiveContextMenuProxy(WebKitWebViewBase* webkitWebViewBase, WebContextMenuProxyGtk* contextMenuProxy) { webkitWebViewBase->priv->activeContextMenuProxy = contextMenuProxy; + g_signal_connect_object(contextMenuProxy->gtkMenu(), "unmap", G_CALLBACK(activeContextMenuUnmapped), webkitWebViewBase, static_cast<GConnectFlags>(0)); } WebContextMenuProxyGtk* webkitWebViewBaseGetActiveContextMenuProxy(WebKitWebViewBase* webkitWebViewBase) @@ -1144,57 +1400,49 @@ GdkEvent* webkitWebViewBaseTakeContextMenuEvent(WebKitWebViewBase* webkitWebView return webkitWebViewBase->priv->contextMenuEvent.release(); } -#if USE(TEXTURE_MAPPER_GL) -void redirectedWindowDamagedCallback(void* data) -{ - gtk_widget_queue_draw(GTK_WIDGET(data)); -} -#endif - void webkitWebViewBaseSetFocus(WebKitWebViewBase* webViewBase, bool focused) { WebKitWebViewBasePrivate* priv = webViewBase->priv; - if (priv->isFocused == focused) + if ((focused && priv->activityState & ActivityState::IsFocused) || (!focused && !(priv->activityState & ActivityState::IsFocused))) return; - unsigned viewStateFlags = ViewState::IsFocused; - priv->isFocused = focused; - - // If the view has received the focus and the window is not active - // mark the current window as active now. This can happen if the - // toplevel window is a GTK_WINDOW_POPUP and the focus has been - // set programatically like WebKitTestRunner does, because POPUP - // can't be focused. - if (priv->isFocused && !priv->isInWindowActive) { - priv->isInWindowActive = true; - viewStateFlags |= ViewState::WindowIsActive; - } - priv->pageProxy->viewStateDidChange(viewStateFlags); + ActivityState::Flags flagsToUpdate = ActivityState::IsFocused; + if (focused) { + priv->activityState |= ActivityState::IsFocused; + + // If the view has received the focus and the window is not active + // mark the current window as active now. This can happen if the + // toplevel window is a GTK_WINDOW_POPUP and the focus has been + // set programatically like WebKitTestRunner does, because POPUP + // can't be focused. + if (!(priv->activityState & ActivityState::WindowIsActive)) { + priv->activityState |= ActivityState::WindowIsActive; + flagsToUpdate |= ActivityState::WindowIsActive; + } + } else + priv->activityState &= ~ActivityState::IsFocused; + + webkitWebViewBaseScheduleUpdateActivityState(webViewBase, flagsToUpdate); } bool webkitWebViewBaseIsInWindowActive(WebKitWebViewBase* webViewBase) { - return webViewBase->priv->isInWindowActive; + return webViewBase->priv->activityState & ActivityState::WindowIsActive; } bool webkitWebViewBaseIsFocused(WebKitWebViewBase* webViewBase) { - return webViewBase->priv->isFocused; + return webViewBase->priv->activityState & ActivityState::IsFocused; } bool webkitWebViewBaseIsVisible(WebKitWebViewBase* webViewBase) { - return webViewBase->priv->isVisible; + return webViewBase->priv->activityState & ActivityState::IsVisible; } bool webkitWebViewBaseIsInWindow(WebKitWebViewBase* webViewBase) { - return webViewBase->priv->toplevelOnScreenWindow; -} - -bool webkitWebViewBaseIsWindowVisible(WebKitWebViewBase* webViewBase) -{ - return webViewBase->priv->isWindowVisible; + return webViewBase->priv->activityState & ActivityState::IsInWindow; } void webkitWebViewBaseSetDownloadRequestHandler(WebKitWebViewBase* webViewBase, WebKitWebViewBaseDownloadRequestHandler downloadHandler) @@ -1215,10 +1463,79 @@ void webkitWebViewBaseSetInputMethodState(WebKitWebViewBase* webkitWebViewBase, void webkitWebViewBaseUpdateTextInputState(WebKitWebViewBase* webkitWebViewBase) { - webkitWebViewBase->priv->inputMethodFilter.setCursorRect(webkitWebViewBase->priv->pageProxy->editorState().cursorRect); + const auto& editorState = webkitWebViewBase->priv->pageProxy->editorState(); + if (!editorState.isMissingPostLayoutData) + webkitWebViewBase->priv->inputMethodFilter.setCursorRect(editorState.postLayoutData().caretRectAtStart); +} + +void webkitWebViewBaseSetContentsSize(WebKitWebViewBase* webkitWebViewBase, const IntSize& contentsSize) +{ + WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv; + if (priv->contentsSize == contentsSize) + return; + priv->contentsSize = contentsSize; } void webkitWebViewBaseResetClickCounter(WebKitWebViewBase* webkitWebViewBase) { webkitWebViewBase->priv->clickCounter.reset(); } + +void webkitWebViewBaseEnterAcceleratedCompositingMode(WebKitWebViewBase* webkitWebViewBase, const LayerTreeContext& layerTreeContext) +{ + if (webkitWebViewBase->priv->acceleratedBackingStore) + webkitWebViewBase->priv->acceleratedBackingStore->update(layerTreeContext); +} + +void webkitWebViewBaseUpdateAcceleratedCompositingMode(WebKitWebViewBase* webkitWebViewBase, const LayerTreeContext& layerTreeContext) +{ + if (webkitWebViewBase->priv->acceleratedBackingStore) + webkitWebViewBase->priv->acceleratedBackingStore->update(layerTreeContext); +} + +void webkitWebViewBaseExitAcceleratedCompositingMode(WebKitWebViewBase* webkitWebViewBase) +{ + if (webkitWebViewBase->priv->acceleratedBackingStore) + webkitWebViewBase->priv->acceleratedBackingStore->update(LayerTreeContext()); +} + +void webkitWebViewBaseDidRelaunchWebProcess(WebKitWebViewBase* webkitWebViewBase) +{ + // Queue a resize to ensure the new DrawingAreaProxy is resized. + gtk_widget_queue_resize_no_redraw(GTK_WIDGET(webkitWebViewBase)); + +#if PLATFORM(X11) && USE(TEXTURE_MAPPER_GL) && !USE(REDIRECTED_XCOMPOSITE_WINDOW) + if (PlatformDisplay::sharedDisplay().type() != PlatformDisplay::Type::X11) + return; + + WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv; + DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(priv->pageProxy->drawingArea()); + ASSERT(drawingArea); + + if (!gtk_widget_get_realized(GTK_WIDGET(webkitWebViewBase))) + return; + + uint64_t windowID = GDK_WINDOW_XID(gtk_widget_get_window(GTK_WIDGET(webkitWebViewBase))); + drawingArea->setNativeSurfaceHandleForCompositing(windowID); +#else + UNUSED_PARAM(webkitWebViewBase); +#endif +} + +void webkitWebViewBasePageClosed(WebKitWebViewBase* webkitWebViewBase) +{ + if (webkitWebViewBase->priv->acceleratedBackingStore) + webkitWebViewBase->priv->acceleratedBackingStore->update(LayerTreeContext()); +#if PLATFORM(X11) && USE(TEXTURE_MAPPER_GL) && !USE(REDIRECTED_XCOMPOSITE_WINDOW) + if (PlatformDisplay::sharedDisplay().type() != PlatformDisplay::Type::X11) + return; + + if (!gtk_widget_get_realized(GTK_WIDGET(webkitWebViewBase))) + return; + + WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv; + DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(priv->pageProxy->drawingArea()); + ASSERT(drawingArea); + drawingArea->destroyNativeSurfaceHandleForCompositing(); +#endif +} |