10ea4b22cd6d3fd8025c77a231546ea1dc329c32
[WebKit-https.git] / Source / WebKit / UIProcess / API / gtk / WebKitWebViewBase.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  * Portions Copyright (c) 2010 Motorola Mobility, Inc.  All rights reserved.
4  * Copyright (C) 2011 Igalia S.L.
5  * Copyright (C) 2013 Gustavo Noronha Silva <gns@gnome.org>.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  * THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "WebKitWebViewBase.h"
31
32 #include "APIPageConfiguration.h"
33 #include "AcceleratedBackingStore.h"
34 #include "DrawingAreaProxyCoordinatedGraphics.h"
35 #include "InputMethodFilter.h"
36 #include "KeyBindingTranslator.h"
37 #include "NativeWebKeyboardEvent.h"
38 #include "NativeWebMouseEvent.h"
39 #include "NativeWebWheelEvent.h"
40 #include "PageClientImpl.h"
41 #include "ViewGestureController.h"
42 #include "WebEventFactory.h"
43 #include "WebInspectorProxy.h"
44 #include "WebKit2Initialize.h"
45 #include "WebKitWebViewBaseAccessible.h"
46 #include "WebKitWebViewBasePrivate.h"
47 #include "WebPageGroup.h"
48 #include "WebPageProxy.h"
49 #include "WebPreferences.h"
50 #include "WebProcessPool.h"
51 #include "WebUserContentControllerProxy.h"
52 #include <WebCore/ActivityState.h>
53 #include <WebCore/CairoUtilities.h>
54 #include <WebCore/GUniquePtrGtk.h>
55 #include <WebCore/GtkUtilities.h>
56 #include <WebCore/GtkVersioning.h>
57 #include <WebCore/NotImplemented.h>
58 #include <WebCore/PasteboardHelper.h>
59 #include <WebCore/PlatformDisplay.h>
60 #include <WebCore/RefPtrCairo.h>
61 #include <WebCore/Region.h>
62 #include <gdk/gdk.h>
63 #include <gdk/gdkkeysyms.h>
64 #include <glib/gi18n-lib.h>
65 #include <memory>
66 #include <pal/system/SleepDisabler.h>
67 #include <wtf/Compiler.h>
68 #include <wtf/HashMap.h>
69 #include <wtf/glib/GRefPtr.h>
70 #include <wtf/glib/WTFGType.h>
71 #include <wtf/text/CString.h>
72
73 #if ENABLE(FULLSCREEN_API)
74 #include "WebFullScreenManagerProxy.h"
75 #endif
76
77 #if PLATFORM(X11)
78 #include <gdk/gdkx.h>
79 #endif
80
81 // gtk_widget_get_scale_factor() appeared in GTK 3.10, but we also need
82 // to make sure we have cairo new enough to support cairo_surface_set_device_scale
83 #define HAVE_GTK_SCALE_FACTOR HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE && GTK_CHECK_VERSION(3, 10, 0)
84
85 using namespace WebKit;
86 using namespace WebCore;
87
88 struct ClickCounter {
89 public:
90     void reset()
91     {
92         currentClickCount = 0;
93         previousClickPoint = IntPoint();
94         previousClickTime = 0;
95         previousClickButton = 0;
96     }
97
98     int currentClickCountForGdkButtonEvent(GdkEvent* event)
99     {
100         int doubleClickDistance = 250;
101         int doubleClickTime = 5;
102         g_object_get(gtk_settings_get_for_screen(gdk_event_get_screen(event)),
103             "gtk-double-click-distance", &doubleClickDistance, "gtk-double-click-time", &doubleClickTime, nullptr);
104
105         // GTK+ only counts up to triple clicks, but WebCore wants to know about
106         // quadruple clicks, quintuple clicks, ad infinitum. Here, we replicate the
107         // GDK logic for counting clicks.
108         guint32 eventTime = gdk_event_get_time(event);
109         if (!eventTime) {
110             // Real events always have a non-zero time, but events synthesized
111             // by the WTR do not and we must calculate a time manually. This time
112             // is not calculated in the WTR, because GTK+ does not work well with
113             // anything other than GDK_CURRENT_TIME on synthesized events.
114             GTimeVal timeValue;
115             g_get_current_time(&timeValue);
116             eventTime = (timeValue.tv_sec * 1000) + (timeValue.tv_usec / 1000);
117         }
118
119         if ((event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS)
120             || ((std::abs(event->button.x - previousClickPoint.x()) < doubleClickDistance)
121                 && (std::abs(event->button.y - previousClickPoint.y()) < doubleClickDistance)
122                 && (eventTime - previousClickTime < static_cast<unsigned>(doubleClickTime))
123                 && (event->button.button == previousClickButton)))
124             currentClickCount++;
125         else
126             currentClickCount = 1;
127
128         double x, y;
129         gdk_event_get_coords(event, &x, &y);
130         previousClickPoint = IntPoint(x, y);
131         previousClickButton = event->button.button;
132         previousClickTime = eventTime;
133
134         return currentClickCount;
135     }
136
137 private:
138     int currentClickCount;
139     IntPoint previousClickPoint;
140     unsigned previousClickButton;
141     int previousClickTime;
142 };
143
144 typedef HashMap<GtkWidget*, IntRect> WebKitWebViewChildrenMap;
145 typedef HashMap<uint32_t, GUniquePtr<GdkEvent>> TouchEventsMap;
146
147 struct _WebKitWebViewBasePrivate {
148     _WebKitWebViewBasePrivate()
149         : updateActivityStateTimer(RunLoop::main(), this, &_WebKitWebViewBasePrivate::updateActivityStateTimerFired)
150     {
151     }
152
153     void updateActivityStateTimerFired()
154     {
155         if (!pageProxy)
156             return;
157         pageProxy->activityStateDidChange(activityStateFlagsToUpdate);
158         activityStateFlagsToUpdate = { };
159     }
160
161     WebKitWebViewChildrenMap children;
162     std::unique_ptr<PageClientImpl> pageClient;
163     RefPtr<WebPageProxy> pageProxy;
164     bool shouldForwardNextKeyEvent { false };
165     bool shouldForwardNextWheelEvent { false };
166     ClickCounter clickCounter;
167     CString tooltipText;
168     IntRect tooltipArea;
169     GRefPtr<AtkObject> accessible;
170     GtkWidget* dialog { nullptr };
171     GtkWidget* inspectorView { nullptr };
172     AttachmentSide inspectorAttachmentSide { AttachmentSide::Bottom };
173     unsigned inspectorViewSize { 0 };
174     GUniquePtr<GdkEvent> contextMenuEvent;
175     WebContextMenuProxyGtk* activeContextMenuProxy { nullptr };
176     InputMethodFilter inputMethodFilter;
177     KeyBindingTranslator keyBindingTranslator;
178     TouchEventsMap touchEvents;
179     IntSize contentsSize;
180
181     GtkWindow* toplevelOnScreenWindow { nullptr };
182     unsigned long toplevelFocusInEventID { 0 };
183     unsigned long toplevelFocusOutEventID { 0 };
184     unsigned long toplevelWindowStateEventID { 0 };
185     unsigned long toplevelWindowRealizedID { 0 };
186     unsigned long themeChangedID { 0 };
187     unsigned long applicationPreferDarkThemeID { 0 };
188
189     // View State.
190     OptionSet<ActivityState::Flag> activityState;
191     OptionSet<ActivityState::Flag> activityStateFlagsToUpdate;
192     RunLoop::Timer<WebKitWebViewBasePrivate> updateActivityStateTimer;
193
194 #if ENABLE(FULLSCREEN_API)
195     bool fullScreenModeActive { false };
196     std::unique_ptr<PAL::SleepDisabler> sleepDisabler;
197 #endif
198
199     std::unique_ptr<AcceleratedBackingStore> acceleratedBackingStore;
200
201 #if ENABLE(DRAG_SUPPORT)
202     std::unique_ptr<DragAndDropHandler> dragAndDropHandler;
203 #endif
204
205 #if HAVE(GTK_GESTURES)
206     std::unique_ptr<GestureController> gestureController;
207 #endif
208     std::unique_ptr<ViewGestureController> viewGestureController;
209     bool isBackForwardNavigationGestureEnabled { false };
210 };
211
212 WEBKIT_DEFINE_TYPE(WebKitWebViewBase, webkit_web_view_base, GTK_TYPE_CONTAINER)
213
214 static void webkitWebViewBaseScheduleUpdateActivityState(WebKitWebViewBase* webViewBase, OptionSet<ActivityState::Flag> flagsToUpdate)
215 {
216     WebKitWebViewBasePrivate* priv = webViewBase->priv;
217     priv->activityStateFlagsToUpdate.add(flagsToUpdate);
218     if (priv->updateActivityStateTimer.isActive())
219         return;
220
221     priv->updateActivityStateTimer.startOneShot(0_s);
222 }
223
224 static gboolean toplevelWindowFocusInEvent(GtkWidget* widget, GdkEventFocus*, WebKitWebViewBase* webViewBase)
225 {
226     // Spurious focus in events can occur when the window is hidden.
227     if (!gtk_widget_get_visible(widget))
228         return FALSE;
229
230     WebKitWebViewBasePrivate* priv = webViewBase->priv;
231     if (priv->activityState & ActivityState::WindowIsActive)
232         return FALSE;
233
234     priv->activityState.add(ActivityState::WindowIsActive);
235     webkitWebViewBaseScheduleUpdateActivityState(webViewBase, ActivityState::WindowIsActive);
236
237     return FALSE;
238 }
239
240 static gboolean toplevelWindowFocusOutEvent(GtkWidget*, GdkEventFocus*, WebKitWebViewBase* webViewBase)
241 {
242     WebKitWebViewBasePrivate* priv = webViewBase->priv;
243     if (!(priv->activityState & ActivityState::WindowIsActive))
244         return FALSE;
245
246     priv->activityState.remove(ActivityState::WindowIsActive);
247     webkitWebViewBaseScheduleUpdateActivityState(webViewBase, ActivityState::WindowIsActive);
248
249     return FALSE;
250 }
251
252 static gboolean toplevelWindowStateEvent(GtkWidget*, GdkEventWindowState* event, WebKitWebViewBase* webViewBase)
253 {
254     WebKitWebViewBasePrivate* priv = webViewBase->priv;
255     if (!(event->changed_mask & GDK_WINDOW_STATE_ICONIFIED))
256         return FALSE;
257
258     bool visible = !(event->new_window_state & GDK_WINDOW_STATE_ICONIFIED);
259     if ((visible && priv->activityState & ActivityState::IsVisible) || (!visible && !(priv->activityState & ActivityState::IsVisible)))
260         return FALSE;
261
262     if (visible)
263         priv->activityState.add(ActivityState::IsVisible);
264     else
265         priv->activityState.remove(ActivityState::IsVisible);
266     webkitWebViewBaseScheduleUpdateActivityState(webViewBase, ActivityState::IsVisible);
267
268     return FALSE;
269 }
270
271 static void themeChanged(WebKitWebViewBase* webViewBase)
272 {
273     webViewBase->priv->pageProxy->effectiveAppearanceDidChange();
274 }
275
276 static void toplevelWindowRealized(WebKitWebViewBase* webViewBase)
277 {
278     gtk_widget_realize(GTK_WIDGET(webViewBase));
279
280     WebKitWebViewBasePrivate* priv = webViewBase->priv;
281     if (priv->toplevelWindowRealizedID) {
282         g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelWindowRealizedID);
283         priv->toplevelWindowRealizedID = 0;
284     }
285 }
286
287 static void webkitWebViewBaseSetToplevelOnScreenWindow(WebKitWebViewBase* webViewBase, GtkWindow* window)
288 {
289     WebKitWebViewBasePrivate* priv = webViewBase->priv;
290     if (priv->toplevelOnScreenWindow == window)
291         return;
292
293     if (priv->toplevelFocusInEventID) {
294         g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelFocusInEventID);
295         priv->toplevelFocusInEventID = 0;
296     }
297     if (priv->toplevelFocusOutEventID) {
298         g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelFocusOutEventID);
299         priv->toplevelFocusOutEventID = 0;
300     }
301     if (priv->toplevelWindowStateEventID) {
302         g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelWindowStateEventID);
303         priv->toplevelWindowStateEventID = 0;
304     }
305     if (priv->toplevelWindowRealizedID) {
306         g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelWindowRealizedID);
307         priv->toplevelWindowRealizedID = 0;
308     }
309     if (priv->themeChangedID || priv->applicationPreferDarkThemeID) {
310         auto* settings = gtk_widget_get_settings(GTK_WIDGET(priv->toplevelOnScreenWindow));
311         if (priv->themeChangedID) {
312             g_signal_handler_disconnect(settings, priv->themeChangedID);
313             priv->themeChangedID = 0;
314         }
315         if (priv->applicationPreferDarkThemeID) {
316             g_signal_handler_disconnect(settings, priv->applicationPreferDarkThemeID);
317             priv->applicationPreferDarkThemeID = 0;
318         }
319     }
320
321     priv->toplevelOnScreenWindow = window;
322
323     if (!priv->toplevelOnScreenWindow) {
324         OptionSet<ActivityState::Flag> flagsToUpdate;
325         if (priv->activityState & ActivityState::IsInWindow) {
326             priv->activityState.remove(ActivityState::IsInWindow);
327             flagsToUpdate.add(ActivityState::IsInWindow);
328         }
329         if (priv->activityState & ActivityState::WindowIsActive) {
330             priv->activityState.remove(ActivityState::WindowIsActive);
331             flagsToUpdate.add(ActivityState::IsInWindow);
332         }
333         if (flagsToUpdate)
334             webkitWebViewBaseScheduleUpdateActivityState(webViewBase, flagsToUpdate);
335
336         return;
337     }
338
339     priv->toplevelFocusInEventID =
340         g_signal_connect(priv->toplevelOnScreenWindow, "focus-in-event",
341                          G_CALLBACK(toplevelWindowFocusInEvent), webViewBase);
342     priv->toplevelFocusOutEventID =
343         g_signal_connect(priv->toplevelOnScreenWindow, "focus-out-event",
344                          G_CALLBACK(toplevelWindowFocusOutEvent), webViewBase);
345     priv->toplevelWindowStateEventID =
346         g_signal_connect(priv->toplevelOnScreenWindow, "window-state-event", G_CALLBACK(toplevelWindowStateEvent), webViewBase);
347
348     auto* settings = gtk_widget_get_settings(GTK_WIDGET(priv->toplevelOnScreenWindow));
349     priv->themeChangedID =
350         g_signal_connect_swapped(settings, "notify::gtk-theme-name", G_CALLBACK(themeChanged), webViewBase);
351     priv->applicationPreferDarkThemeID =
352         g_signal_connect_swapped(settings, "notify::gtk-application-prefer-dark-theme", G_CALLBACK(themeChanged), webViewBase);
353
354     if (gtk_widget_get_realized(GTK_WIDGET(window)))
355         gtk_widget_realize(GTK_WIDGET(webViewBase));
356     else
357         priv->toplevelWindowRealizedID = g_signal_connect_swapped(window, "realize", G_CALLBACK(toplevelWindowRealized), webViewBase);
358 }
359
360 static void webkitWebViewBaseRealize(GtkWidget* widget)
361 {
362     WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(widget);
363     WebKitWebViewBasePrivate* priv = webView->priv;
364
365     gtk_widget_set_realized(widget, TRUE);
366
367     GtkAllocation allocation;
368     gtk_widget_get_allocation(widget, &allocation);
369
370     GdkWindowAttr attributes;
371     attributes.window_type = GDK_WINDOW_CHILD;
372     attributes.x = allocation.x;
373     attributes.y = allocation.y;
374     attributes.width = allocation.width;
375     attributes.height = allocation.height;
376     attributes.wclass = GDK_INPUT_OUTPUT;
377     attributes.visual = gtk_widget_get_visual(widget);
378     attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK
379         | GDK_EXPOSURE_MASK
380         | GDK_BUTTON_PRESS_MASK
381         | GDK_BUTTON_RELEASE_MASK
382         | GDK_SCROLL_MASK
383         | GDK_SMOOTH_SCROLL_MASK
384         | GDK_POINTER_MOTION_MASK
385         | GDK_ENTER_NOTIFY_MASK
386         | GDK_LEAVE_NOTIFY_MASK
387         | GDK_KEY_PRESS_MASK
388         | GDK_KEY_RELEASE_MASK
389         | GDK_BUTTON_MOTION_MASK
390         | GDK_BUTTON1_MOTION_MASK
391         | GDK_BUTTON2_MOTION_MASK
392         | GDK_BUTTON3_MOTION_MASK
393         | GDK_TOUCH_MASK;
394 #if HAVE(GTK_GESTURES)
395     attributes.event_mask |= GDK_TOUCHPAD_GESTURE_MASK;
396 #endif
397
398     gint attributesMask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
399
400     GdkWindow* window = gdk_window_new(gtk_widget_get_parent_window(widget), &attributes, attributesMask);
401     gtk_widget_set_window(widget, window);
402     gdk_window_set_user_data(window, widget);
403
404 #if USE(TEXTURE_MAPPER_GL) && PLATFORM(X11) && !USE(REDIRECTED_XCOMPOSITE_WINDOW)
405     if (PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::X11) {
406         if (auto* drawingArea = static_cast<DrawingAreaProxyCoordinatedGraphics*>(priv->pageProxy->drawingArea()))
407             drawingArea->setNativeSurfaceHandleForCompositing(GDK_WINDOW_XID(window));
408     }
409 #endif
410
411     gtk_im_context_set_client_window(priv->inputMethodFilter.context(), window);
412 }
413
414 static void webkitWebViewBaseUnrealize(GtkWidget* widget)
415 {
416     WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(widget);
417 #if USE(TEXTURE_MAPPER_GL) && PLATFORM(X11) && !USE(REDIRECTED_XCOMPOSITE_WINDOW)
418     if (PlatformDisplay::sharedDisplay().type() == PlatformDisplay::Type::X11) {
419         if (auto* drawingArea = static_cast<DrawingAreaProxyCoordinatedGraphics*>(webView->priv->pageProxy->drawingArea()))
420             drawingArea->destroyNativeSurfaceHandleForCompositing();
421     }
422 #endif
423     gtk_im_context_set_client_window(webView->priv->inputMethodFilter.context(), nullptr);
424
425     GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->unrealize(widget);
426 }
427
428 static bool webkitWebViewChildIsInternalWidget(WebKitWebViewBase* webViewBase, GtkWidget* widget)
429 {
430     WebKitWebViewBasePrivate* priv = webViewBase->priv;
431     return widget == priv->inspectorView || widget == priv->dialog;
432 }
433
434 static void webkitWebViewBaseContainerAdd(GtkContainer* container, GtkWidget* widget)
435 {
436     WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(container);
437     WebKitWebViewBasePrivate* priv = webView->priv;
438
439     // Internal widgets like the web inspector and authentication dialog have custom
440     // allocations so we don't need to add them to our list of children.
441     if (!webkitWebViewChildIsInternalWidget(webView, widget)) {
442         GtkAllocation childAllocation;
443         gtk_widget_get_allocation(widget, &childAllocation);
444         priv->children.set(widget, childAllocation);
445     }
446
447     gtk_widget_set_parent(widget, GTK_WIDGET(container));
448 }
449
450 void webkitWebViewBaseAddDialog(WebKitWebViewBase* webViewBase, GtkWidget* dialog)
451 {
452     WebKitWebViewBasePrivate* priv = webViewBase->priv;
453     priv->dialog = dialog;
454     gtk_container_add(GTK_CONTAINER(webViewBase), dialog);
455     gtk_widget_show(dialog);
456
457     // We need to draw the shadow over the widget.
458     gtk_widget_queue_draw(GTK_WIDGET(webViewBase));
459 }
460
461 void webkitWebViewBaseAddWebInspector(WebKitWebViewBase* webViewBase, GtkWidget* inspector, AttachmentSide attachmentSide)
462 {
463     if (webViewBase->priv->inspectorView == inspector && webViewBase->priv->inspectorAttachmentSide == attachmentSide)
464         return;
465
466     webViewBase->priv->inspectorAttachmentSide = attachmentSide;
467
468     if (webViewBase->priv->inspectorView == inspector) {
469         gtk_widget_queue_resize(GTK_WIDGET(webViewBase));
470         return;
471     }
472
473     webViewBase->priv->inspectorView = inspector;
474     gtk_container_add(GTK_CONTAINER(webViewBase), inspector);
475 }
476
477 static void webkitWebViewBaseContainerRemove(GtkContainer* container, GtkWidget* widget)
478 {
479     WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(container);
480     WebKitWebViewBasePrivate* priv = webView->priv;
481     GtkWidget* widgetContainer = GTK_WIDGET(container);
482
483     gboolean wasVisible = gtk_widget_get_visible(widget);
484     gtk_widget_unparent(widget);
485
486     if (priv->inspectorView == widget) {
487         priv->inspectorView = 0;
488         priv->inspectorViewSize = 0;
489     } else if (priv->dialog == widget) {
490         priv->dialog = nullptr;
491         if (gtk_widget_get_visible(widgetContainer))
492             gtk_widget_grab_focus(widgetContainer);
493     } else {
494         ASSERT(priv->children.contains(widget));
495         priv->children.remove(widget);
496     }
497     if (wasVisible && gtk_widget_get_visible(widgetContainer))
498         gtk_widget_queue_resize(widgetContainer);
499 }
500
501 static void webkitWebViewBaseContainerForall(GtkContainer* container, gboolean includeInternals, GtkCallback callback, gpointer callbackData)
502 {
503     WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(container);
504     WebKitWebViewBasePrivate* priv = webView->priv;
505
506     for (const auto& child : copyToVector(priv->children.keys())) {
507         if (priv->children.contains(child))
508             (*callback)(child, callbackData);
509     }
510
511     if (includeInternals && priv->inspectorView)
512         (*callback)(priv->inspectorView, callbackData);
513
514     if (includeInternals && priv->dialog)
515         (*callback)(priv->dialog, callbackData);
516 }
517
518 void webkitWebViewBaseChildMoveResize(WebKitWebViewBase* webView, GtkWidget* child, const IntRect& childRect)
519 {
520     const IntRect& geometry = webView->priv->children.get(child);
521     if (geometry == childRect)
522         return;
523
524     webView->priv->children.set(child, childRect);
525     gtk_widget_queue_resize_no_redraw(GTK_WIDGET(webView));
526 }
527
528 static void webkitWebViewBaseDispose(GObject* gobject)
529 {
530     WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(gobject);
531     webkitWebViewBaseSetToplevelOnScreenWindow(webView, nullptr);
532     webView->priv->pageProxy->close();
533     webView->priv->acceleratedBackingStore = nullptr;
534     webView->priv->sleepDisabler = nullptr;
535     G_OBJECT_CLASS(webkit_web_view_base_parent_class)->dispose(gobject);
536 }
537
538 static void webkitWebViewBaseConstructed(GObject* object)
539 {
540     G_OBJECT_CLASS(webkit_web_view_base_parent_class)->constructed(object);
541
542     GtkWidget* viewWidget = GTK_WIDGET(object);
543     gtk_widget_set_can_focus(viewWidget, TRUE);
544     gtk_drag_dest_set(viewWidget, static_cast<GtkDestDefaults>(0), nullptr, 0,
545         static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_PRIVATE));
546     gtk_drag_dest_set_target_list(viewWidget, PasteboardHelper::singleton().targetList());
547
548     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(object)->priv;
549     priv->pageClient = std::make_unique<PageClientImpl>(viewWidget);
550     priv->dialog = nullptr;
551 }
552
553 static gboolean webkitWebViewBaseDraw(GtkWidget* widget, cairo_t* cr)
554 {
555     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
556     auto* drawingArea = static_cast<DrawingAreaProxyCoordinatedGraphics*>(webViewBase->priv->pageProxy->drawingArea());
557     if (!drawingArea)
558         return FALSE;
559
560     GdkRectangle clipRect;
561     if (!gdk_cairo_get_clip_rectangle(cr, &clipRect))
562         return FALSE;
563
564     bool showingNavigationSnapshot = webViewBase->priv->pageProxy->isShowingNavigationGestureSnapshot();
565     if (showingNavigationSnapshot)
566         cairo_push_group(cr);
567
568     if (webViewBase->priv->acceleratedBackingStore && drawingArea->isInAcceleratedCompositingMode())
569         webViewBase->priv->acceleratedBackingStore->paint(cr, clipRect);
570     else {
571         WebCore::Region unpaintedRegion; // This is simply unused.
572         drawingArea->paint(cr, clipRect, unpaintedRegion);
573     }
574
575     if (showingNavigationSnapshot) {
576         RefPtr<cairo_pattern_t> group = adoptRef(cairo_pop_group(cr));
577         if (auto* controller = webkitWebViewBaseViewGestureController(webViewBase))
578             controller->draw(cr, group.get());
579     }
580
581     GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->draw(widget, cr);
582
583     return FALSE;
584 }
585
586 static void webkitWebViewBaseChildAllocate(GtkWidget* child, gpointer userData)
587 {
588     if (!gtk_widget_get_visible(child))
589         return;
590
591     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(userData);
592     WebKitWebViewBasePrivate* priv = webViewBase->priv;
593     const IntRect& geometry = priv->children.get(child);
594     if (geometry.isEmpty())
595         return;
596
597     GtkAllocation childAllocation = geometry;
598     gtk_widget_size_allocate(child, &childAllocation);
599     priv->children.set(child, IntRect());
600 }
601
602 static void webkitWebViewBaseSizeAllocate(GtkWidget* widget, GtkAllocation* allocation)
603 {
604     GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->size_allocate(widget, allocation);
605
606     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
607     gtk_container_foreach(GTK_CONTAINER(webViewBase), webkitWebViewBaseChildAllocate, webViewBase);
608
609     IntRect viewRect(allocation->x, allocation->y, allocation->width, allocation->height);
610     WebKitWebViewBasePrivate* priv = webViewBase->priv;
611     if (priv->inspectorView) {
612         GtkAllocation childAllocation = viewRect;
613
614         if (priv->inspectorAttachmentSide == AttachmentSide::Bottom) {
615             int inspectorViewHeight = std::min(static_cast<int>(priv->inspectorViewSize), allocation->height);
616             childAllocation.x = 0;
617             childAllocation.y = allocation->height - inspectorViewHeight;
618             childAllocation.height = inspectorViewHeight;
619             viewRect.setHeight(std::max(allocation->height - inspectorViewHeight, 1));
620         } else {
621             int inspectorViewWidth = std::min(static_cast<int>(priv->inspectorViewSize), allocation->width);
622             childAllocation.y = 0;
623             childAllocation.x = allocation->width - inspectorViewWidth;
624             childAllocation.width = inspectorViewWidth;
625             viewRect.setWidth(std::max(allocation->width - inspectorViewWidth, 1));
626         }
627
628         gtk_widget_size_allocate(priv->inspectorView, &childAllocation);
629     }
630
631     // The dialogs are centered in the view rect, which means that it
632     // never overlaps the web inspector. Thus, we need to calculate the allocation here
633     // after calculating the inspector allocation.
634     if (priv->dialog) {
635         GtkRequisition minimumSize;
636         gtk_widget_get_preferred_size(priv->dialog, &minimumSize, nullptr);
637
638         GtkAllocation childAllocation = { 0, 0, std::max(minimumSize.width, viewRect.width()), std::max(minimumSize.height, viewRect.height()) };
639         gtk_widget_size_allocate(priv->dialog, &childAllocation);
640     }
641
642     if (auto* drawingArea = static_cast<DrawingAreaProxyCoordinatedGraphics*>(priv->pageProxy->drawingArea()))
643         drawingArea->setSize(viewRect.size());
644 }
645
646 static void webkitWebViewBaseGetPreferredWidth(GtkWidget* widget, gint* minimumSize, gint* naturalSize)
647 {
648     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
649     *minimumSize = 0;
650     *naturalSize = priv->contentsSize.width();
651 }
652
653 static void webkitWebViewBaseGetPreferredHeight(GtkWidget* widget, gint* minimumSize, gint* naturalSize)
654 {
655     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
656     *minimumSize = 0;
657     *naturalSize = priv->contentsSize.height();
658 }
659
660 static void webkitWebViewBaseMap(GtkWidget* widget)
661 {
662     GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->map(widget);
663
664     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
665     WebKitWebViewBasePrivate* priv = webViewBase->priv;
666     OptionSet<ActivityState::Flag> flagsToUpdate;
667     if (!(priv->activityState & ActivityState::IsVisible))
668         flagsToUpdate.add(ActivityState::IsVisible);
669     if (priv->toplevelOnScreenWindow) {
670         if (!(priv->activityState & ActivityState::IsInWindow))
671             flagsToUpdate.add(ActivityState::IsInWindow);
672         if (gtk_window_is_active(GTK_WINDOW(priv->toplevelOnScreenWindow)) && !(priv->activityState & ActivityState::WindowIsActive))
673             flagsToUpdate.add(ActivityState::WindowIsActive);
674     }
675     if (!flagsToUpdate)
676         return;
677
678     priv->activityState.add(flagsToUpdate);
679     webkitWebViewBaseScheduleUpdateActivityState(webViewBase, flagsToUpdate);
680 }
681
682 static void webkitWebViewBaseUnmap(GtkWidget* widget)
683 {
684     GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->unmap(widget);
685
686     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
687     WebKitWebViewBasePrivate* priv = webViewBase->priv;
688     if (!(priv->activityState & ActivityState::IsVisible))
689         return;
690
691     priv->activityState.remove(ActivityState::IsVisible);
692     webkitWebViewBaseScheduleUpdateActivityState(webViewBase, ActivityState::IsVisible);
693 }
694
695 static gboolean webkitWebViewBaseFocusInEvent(GtkWidget* widget, GdkEventFocus* event)
696 {
697     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
698     webkitWebViewBaseSetFocus(webViewBase, true);
699     webViewBase->priv->inputMethodFilter.notifyFocusedIn();
700
701     return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->focus_in_event(widget, event);
702 }
703
704 static gboolean webkitWebViewBaseFocusOutEvent(GtkWidget* widget, GdkEventFocus* event)
705 {
706     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
707     webkitWebViewBaseSetFocus(webViewBase, false);
708     webViewBase->priv->inputMethodFilter.notifyFocusedOut();
709
710     return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->focus_out_event(widget, event);
711 }
712
713 static gboolean webkitWebViewBaseKeyPressEvent(GtkWidget* widget, GdkEventKey* keyEvent)
714 {
715     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
716     WebKitWebViewBasePrivate* priv = webViewBase->priv;
717
718 #if ENABLE(DEVELOPER_MODE) && OS(LINUX)
719     if ((keyEvent->state & GDK_CONTROL_MASK) && (keyEvent->state & GDK_SHIFT_MASK) && keyEvent->keyval == GDK_KEY_G) {
720         auto& preferences = priv->pageProxy->preferences();
721         preferences.setResourceUsageOverlayVisible(!preferences.resourceUsageOverlayVisible());
722         priv->shouldForwardNextKeyEvent = FALSE;
723         return GDK_EVENT_STOP;
724     }
725 #endif
726
727     if (priv->dialog)
728         return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_press_event(widget, keyEvent);
729
730 #if ENABLE(FULLSCREEN_API)
731     if (priv->fullScreenModeActive) {
732         switch (keyEvent->keyval) {
733         case GDK_KEY_Escape:
734         case GDK_KEY_f:
735         case GDK_KEY_F:
736             priv->pageProxy->fullScreenManager()->requestExitFullScreen();
737             return GDK_EVENT_STOP;
738         default:
739             break;
740         }
741     }
742 #endif
743
744     // Since WebProcess key event handling is not synchronous, handle the event in two passes.
745     // When WebProcess processes the input event, it will call PageClientImpl::doneWithKeyEvent
746     // with event handled status which determines whether to pass the input event to parent or not
747     // using gtk_main_do_event().
748     if (priv->shouldForwardNextKeyEvent) {
749         priv->shouldForwardNextKeyEvent = FALSE;
750         return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_press_event(widget, keyEvent);
751     }
752
753     // We need to copy the event as otherwise it could be destroyed before we reach the lambda body.
754     GUniquePtr<GdkEvent> event(gdk_event_copy(reinterpret_cast<GdkEvent*>(keyEvent)));
755     priv->inputMethodFilter.filterKeyEvent(keyEvent, [priv, event = WTFMove(event)](const WebCore::CompositionResults& compositionResults, InputMethodFilter::EventFakedForComposition faked) {
756         priv->pageProxy->handleKeyboardEvent(NativeWebKeyboardEvent(event.get(), compositionResults, faked,
757             !compositionResults.compositionUpdated() ? priv->keyBindingTranslator.commandsForKeyEvent(&event->key) : Vector<String>()));
758     });
759
760     return GDK_EVENT_STOP;
761 }
762
763 static gboolean webkitWebViewBaseKeyReleaseEvent(GtkWidget* widget, GdkEventKey* keyEvent)
764 {
765     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
766     WebKitWebViewBasePrivate* priv = webViewBase->priv;
767
768     if (priv->shouldForwardNextKeyEvent) {
769         priv->shouldForwardNextKeyEvent = FALSE;
770         return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_release_event(widget, keyEvent);
771     }
772
773     // We need to copy the event as otherwise it could be destroyed before we reach the lambda body.
774     GUniquePtr<GdkEvent> event(gdk_event_copy(reinterpret_cast<GdkEvent*>(keyEvent)));
775     priv->inputMethodFilter.filterKeyEvent(keyEvent, [priv, event = WTFMove(event)](const WebCore::CompositionResults& compositionResults, InputMethodFilter::EventFakedForComposition faked) {
776         priv->pageProxy->handleKeyboardEvent(NativeWebKeyboardEvent(event.get(), compositionResults, faked, { }));
777     });
778
779     return GDK_EVENT_STOP;
780 }
781
782 static void webkitWebViewBaseHandleMouseEvent(WebKitWebViewBase* webViewBase, GdkEvent* event)
783 {
784     WebKitWebViewBasePrivate* priv = webViewBase->priv;
785     ASSERT(!priv->dialog);
786
787     int clickCount = 0;
788
789     switch (event->type) {
790     case GDK_BUTTON_PRESS:
791     case GDK_2BUTTON_PRESS:
792     case GDK_3BUTTON_PRESS: {
793         // For double and triple clicks GDK sends both a normal button press event
794         // and a specific type (like GDK_2BUTTON_PRESS). If we detect a special press
795         // coming up, ignore this event as it certainly generated the double or triple
796         // click. The consequence of not eating this event is two DOM button press events
797         // are generated.
798         GUniquePtr<GdkEvent> nextEvent(gdk_event_peek());
799         if (nextEvent && (nextEvent->any.type == GDK_2BUTTON_PRESS || nextEvent->any.type == GDK_3BUTTON_PRESS))
800             return;
801
802         priv->inputMethodFilter.notifyMouseButtonPress();
803
804         // If it's a right click event save it as a possible context menu event.
805         if (event->button.button == GDK_BUTTON_SECONDARY)
806             priv->contextMenuEvent.reset(gdk_event_copy(event));
807
808         clickCount = priv->clickCounter.currentClickCountForGdkButtonEvent(event);
809     }
810         FALLTHROUGH;
811     case GDK_BUTTON_RELEASE:
812         gtk_widget_grab_focus(GTK_WIDGET(webViewBase));
813         break;
814     case GDK_MOTION_NOTIFY:
815     case GDK_ENTER_NOTIFY:
816     case GDK_LEAVE_NOTIFY:
817         break;
818     default:
819         ASSERT_NOT_REACHED();
820     }
821
822     priv->pageProxy->handleMouseEvent(NativeWebMouseEvent(event, clickCount));
823 }
824
825 static gboolean webkitWebViewBaseButtonPressEvent(GtkWidget* widget, GdkEventButton* event)
826 {
827     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
828     WebKitWebViewBasePrivate* priv = webViewBase->priv;
829
830     if (priv->dialog)
831         return GDK_EVENT_STOP;
832
833     webkitWebViewBaseHandleMouseEvent(webViewBase, reinterpret_cast<GdkEvent*>(event));
834
835     return GDK_EVENT_STOP;
836 }
837
838 static gboolean webkitWebViewBaseButtonReleaseEvent(GtkWidget* widget, GdkEventButton* event)
839 {
840     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
841     WebKitWebViewBasePrivate* priv = webViewBase->priv;
842
843     if (priv->dialog)
844         return GDK_EVENT_STOP;
845
846     webkitWebViewBaseHandleMouseEvent(webViewBase, reinterpret_cast<GdkEvent*>(event));
847
848     return GDK_EVENT_STOP;
849 }
850
851 static void webkitWebViewBaseHandleWheelEvent(WebKitWebViewBase* webViewBase, GdkEvent* event, Optional<WebWheelEvent::Phase> phase = WTF::nullopt, Optional<WebWheelEvent::Phase> momentum = WTF::nullopt)
852 {
853     WebKitWebViewBasePrivate* priv = webViewBase->priv;
854     ASSERT(!priv->dialog);
855     if (phase)
856         priv->pageProxy->handleWheelEvent(NativeWebWheelEvent(event, phase.value(), momentum.valueOr(WebWheelEvent::Phase::PhaseNone)));
857     else
858         priv->pageProxy->handleWheelEvent(NativeWebWheelEvent(event));
859 }
860
861 static gboolean webkitWebViewBaseScrollEvent(GtkWidget* widget, GdkEventScroll* event)
862 {
863     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
864     WebKitWebViewBasePrivate* priv = webViewBase->priv;
865
866     if (std::exchange(priv->shouldForwardNextWheelEvent, false))
867         return GDK_EVENT_PROPAGATE;
868
869     if (priv->dialog)
870         return GDK_EVENT_PROPAGATE;
871
872     // Shift+Wheel scrolls in the perpendicular direction.
873     if (event->state & GDK_SHIFT_MASK) {
874         switch (event->direction) {
875         case GDK_SCROLL_UP:
876             event->direction = GDK_SCROLL_LEFT;
877             break;
878         case GDK_SCROLL_LEFT:
879             event->direction = GDK_SCROLL_UP;
880             break;
881         case GDK_SCROLL_DOWN:
882             event->direction = GDK_SCROLL_RIGHT;
883             break;
884         case GDK_SCROLL_RIGHT:
885             event->direction = GDK_SCROLL_DOWN;
886             break;
887         case GDK_SCROLL_SMOOTH:
888             std::swap(event->delta_x, event->delta_y);
889             break;
890         }
891     }
892
893     ViewGestureController* controller = webkitWebViewBaseViewGestureController(webViewBase);
894     if (controller && controller->isSwipeGestureEnabled() && controller->handleScrollWheelEvent(event))
895         return GDK_EVENT_STOP;
896
897     webkitWebViewBaseHandleWheelEvent(webViewBase, reinterpret_cast<GdkEvent*>(event));
898
899     return GDK_EVENT_STOP;
900 }
901
902 static gboolean webkitWebViewBasePopupMenu(GtkWidget* widget)
903 {
904     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
905     WebKitWebViewBasePrivate* priv = webViewBase->priv;
906
907     GdkEvent* currentEvent = gtk_get_current_event();
908     if (!currentEvent)
909         currentEvent = gdk_event_new(GDK_NOTHING);
910     priv->contextMenuEvent.reset(currentEvent);
911     priv->pageProxy->handleContextMenuKeyEvent();
912
913     return TRUE;
914 }
915
916 static gboolean webkitWebViewBaseMotionNotifyEvent(GtkWidget* widget, GdkEventMotion* event)
917 {
918     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
919     WebKitWebViewBasePrivate* priv = webViewBase->priv;
920
921     if (priv->dialog) {
922         auto* widgetClass = GTK_WIDGET_CLASS(webkit_web_view_base_parent_class);
923         return widgetClass->motion_notify_event ? widgetClass->motion_notify_event(widget, event) : GDK_EVENT_PROPAGATE;
924     }
925
926     webkitWebViewBaseHandleMouseEvent(webViewBase, reinterpret_cast<GdkEvent*>(event));
927
928     return GDK_EVENT_PROPAGATE;
929 }
930
931 static gboolean webkitWebViewBaseCrossingNotifyEvent(GtkWidget* widget, GdkEventCrossing* crossingEvent)
932 {
933     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
934     WebKitWebViewBasePrivate* priv = webViewBase->priv;
935
936     if (priv->dialog)
937         return GDK_EVENT_PROPAGATE;
938
939 #if ENABLE(DEVELOPER_MODE)
940     // Do not send mouse move events to the WebProcess for crossing events during testing.
941     // WTR never generates crossing events and they can confuse tests.
942     // https://bugs.webkit.org/show_bug.cgi?id=185072.
943     if (UNLIKELY(priv->pageProxy->process().processPool().configuration().fullySynchronousModeIsAllowedForTesting()))
944         return GDK_EVENT_PROPAGATE;
945 #endif
946
947     // In the case of crossing events, it's very important the actual coordinates the WebProcess receives, because once the mouse leaves
948     // 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
949     // event are not accurate, the WebProcess might not know the mouse left the view. This can happen because of double to integer conversion,
950     // 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
951     // because those coordinates are inside the web view.
952     GtkAllocation allocation;
953     gtk_widget_get_allocation(widget, &allocation);
954     double width = allocation.width;
955     double height = allocation.height;
956     double x = crossingEvent->x;
957     double y = crossingEvent->y;
958     if (x < 0 && x > -1)
959         x = -1;
960     else if (x >= width && x < width + 1)
961         x = width + 1;
962     if (y < 0 && y > -1)
963         y = -1;
964     else if (y >= height && y < height + 1)
965         y = height + 1;
966
967     GdkEvent* event = reinterpret_cast<GdkEvent*>(crossingEvent);
968     GUniquePtr<GdkEvent> copiedEvent;
969     if (x != crossingEvent->x || y != crossingEvent->y) {
970         copiedEvent.reset(gdk_event_copy(event));
971         copiedEvent->crossing.x = x;
972         copiedEvent->crossing.y = y;
973     }
974
975     webkitWebViewBaseHandleMouseEvent(webViewBase, copiedEvent ? copiedEvent.get() : event);
976
977     return GDK_EVENT_PROPAGATE;
978 }
979
980 #if ENABLE(TOUCH_EVENTS)
981 static void appendTouchEvent(Vector<WebPlatformTouchPoint>& touchPoints, const GdkEvent* event, WebPlatformTouchPoint::TouchPointState state)
982 {
983     gdouble x, y;
984     gdk_event_get_coords(event, &x, &y);
985
986     gdouble xRoot, yRoot;
987     gdk_event_get_root_coords(event, &xRoot, &yRoot);
988
989     uint32_t identifier = GPOINTER_TO_UINT(gdk_event_get_event_sequence(event));
990     touchPoints.uncheckedAppend(WebPlatformTouchPoint(identifier, state, IntPoint(xRoot, yRoot), IntPoint(x, y)));
991 }
992
993 static inline WebPlatformTouchPoint::TouchPointState touchPointStateForEvents(const GdkEvent* current, const GdkEvent* event)
994 {
995     if (gdk_event_get_event_sequence(current) != gdk_event_get_event_sequence(event))
996         return WebPlatformTouchPoint::TouchStationary;
997
998     switch (current->type) {
999     case GDK_TOUCH_UPDATE:
1000         return WebPlatformTouchPoint::TouchMoved;
1001     case GDK_TOUCH_BEGIN:
1002         return WebPlatformTouchPoint::TouchPressed;
1003     case GDK_TOUCH_END:
1004         return WebPlatformTouchPoint::TouchReleased;
1005     case GDK_TOUCH_CANCEL:
1006         return WebPlatformTouchPoint::TouchCancelled;
1007     default:
1008         return WebPlatformTouchPoint::TouchStationary;
1009     }
1010 }
1011
1012 static void webkitWebViewBaseGetTouchPointsForEvent(WebKitWebViewBase* webViewBase, GdkEvent* event, Vector<WebPlatformTouchPoint>& touchPoints)
1013 {
1014     WebKitWebViewBasePrivate* priv = webViewBase->priv;
1015     bool touchEnd = (event->type == GDK_TOUCH_END) || (event->type == GDK_TOUCH_CANCEL);
1016     touchPoints.reserveInitialCapacity(touchEnd ? priv->touchEvents.size() + 1 : priv->touchEvents.size());
1017
1018     for (const auto& it : priv->touchEvents)
1019         appendTouchEvent(touchPoints, it.value.get(), touchPointStateForEvents(it.value.get(), event));
1020
1021     // Touch was already removed from the TouchEventsMap, add it here.
1022     if (touchEnd)
1023         appendTouchEvent(touchPoints, event, WebPlatformTouchPoint::TouchReleased);
1024 }
1025
1026 static gboolean webkitWebViewBaseTouchEvent(GtkWidget* widget, GdkEventTouch* event)
1027 {
1028     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
1029     WebKitWebViewBasePrivate* priv = webViewBase->priv;
1030
1031     if (priv->dialog)
1032         return GDK_EVENT_STOP;
1033
1034     GdkEvent* touchEvent = reinterpret_cast<GdkEvent*>(event);
1035     uint32_t sequence = GPOINTER_TO_UINT(gdk_event_get_event_sequence(touchEvent));
1036
1037     switch (touchEvent->type) {
1038     case GDK_TOUCH_BEGIN: {
1039         ASSERT(!priv->touchEvents.contains(sequence));
1040         GUniquePtr<GdkEvent> event(gdk_event_copy(touchEvent));
1041         priv->touchEvents.add(sequence, WTFMove(event));
1042         break;
1043     }
1044     case GDK_TOUCH_UPDATE: {
1045         auto it = priv->touchEvents.find(sequence);
1046         ASSERT(it != priv->touchEvents.end());
1047         it->value.reset(gdk_event_copy(touchEvent));
1048         break;
1049     }
1050     case GDK_TOUCH_CANCEL:
1051         FALLTHROUGH;
1052     case GDK_TOUCH_END:
1053         ASSERT(priv->touchEvents.contains(sequence));
1054         priv->touchEvents.remove(sequence);
1055         break;
1056     default:
1057         break;
1058     }
1059
1060     Vector<WebPlatformTouchPoint> touchPoints;
1061     webkitWebViewBaseGetTouchPointsForEvent(webViewBase, touchEvent, touchPoints);
1062     priv->pageProxy->handleTouchEvent(NativeWebTouchEvent(reinterpret_cast<GdkEvent*>(event), WTFMove(touchPoints)));
1063
1064     return GDK_EVENT_STOP;
1065 }
1066 #endif // ENABLE(TOUCH_EVENTS)
1067
1068 #if HAVE(GTK_GESTURES)
1069 class TouchGestureController final : public GestureControllerClient {
1070     WTF_MAKE_FAST_ALLOCATED;
1071
1072 public:
1073     explicit TouchGestureController(WebKitWebViewBase* webViewBase)
1074         : m_webView(webViewBase)
1075     {
1076     }
1077
1078 private:
1079     static GUniquePtr<GdkEvent> createScrollEvent(GdkEventTouch* event, const FloatPoint& point, const FloatPoint& delta, bool isStop = false)
1080     {
1081         GUniquePtr<GdkEvent> scrollEvent(gdk_event_new(GDK_SCROLL));
1082         scrollEvent->scroll.time = event->time;
1083         scrollEvent->scroll.x = point.x();
1084         scrollEvent->scroll.y = point.y();
1085         scrollEvent->scroll.x_root = event->x_root;
1086         scrollEvent->scroll.y_root = event->y_root;
1087         scrollEvent->scroll.direction = GDK_SCROLL_SMOOTH;
1088         scrollEvent->scroll.delta_x = delta.x();
1089         scrollEvent->scroll.delta_y = delta.y();
1090         scrollEvent->scroll.state = event->state;
1091 #if GTK_CHECK_VERSION(3, 20, 0)
1092         scrollEvent->scroll.is_stop = isStop;
1093 #else
1094         UNUSED_PARAM(isStop);
1095 #endif
1096         scrollEvent->scroll.window = event->window ? GDK_WINDOW(g_object_ref(event->window)) : nullptr;
1097         auto* touchEvent = reinterpret_cast<GdkEvent*>(event);
1098         gdk_event_set_screen(scrollEvent.get(), gdk_event_get_screen(touchEvent));
1099         gdk_event_set_device(scrollEvent.get(), gdk_event_get_device(touchEvent));
1100         gdk_event_set_source_device(scrollEvent.get(), gdk_event_get_source_device(touchEvent));
1101         return scrollEvent;
1102     }
1103
1104     void simulateMouseClick(GdkEventTouch* event, unsigned button)
1105     {
1106         GUniquePtr<GdkEvent> pointerEvent(gdk_event_new(GDK_MOTION_NOTIFY));
1107         pointerEvent->motion.time = event->time;
1108         pointerEvent->motion.x = event->x;
1109         pointerEvent->motion.y = event->y;
1110         pointerEvent->motion.x_root = event->x_root;
1111         pointerEvent->motion.y_root = event->y_root;
1112         pointerEvent->motion.state = event->state;
1113         pointerEvent->motion.window = event->window ? GDK_WINDOW(g_object_ref(event->window)) : nullptr;
1114         auto* touchEvent = reinterpret_cast<GdkEvent*>(event);
1115         gdk_event_set_screen(pointerEvent.get(), gdk_event_get_screen(touchEvent));
1116         gdk_event_set_device(pointerEvent.get(), gdk_event_get_device(touchEvent));
1117         gdk_event_set_source_device(pointerEvent.get(), gdk_event_get_source_device(touchEvent));
1118         webkitWebViewBaseHandleMouseEvent(m_webView, pointerEvent.get());
1119
1120         pointerEvent.reset(gdk_event_new(GDK_BUTTON_PRESS));
1121         pointerEvent->button.button = button;
1122         pointerEvent->button.time = event->time;
1123         pointerEvent->button.x = event->x;
1124         pointerEvent->button.y = event->y;
1125         pointerEvent->button.x_root = event->x_root;
1126         pointerEvent->button.y_root = event->y_root;
1127         pointerEvent->button.window = event->window ? GDK_WINDOW(g_object_ref(event->window)) : nullptr;
1128         gdk_event_set_screen(pointerEvent.get(), gdk_event_get_screen(touchEvent));
1129         gdk_event_set_device(pointerEvent.get(), gdk_event_get_device(touchEvent));
1130         gdk_event_set_source_device(pointerEvent.get(), gdk_event_get_source_device(touchEvent));
1131         webkitWebViewBaseHandleMouseEvent(m_webView, pointerEvent.get());
1132
1133         pointerEvent->type = GDK_BUTTON_RELEASE;
1134         webkitWebViewBaseHandleMouseEvent(m_webView, pointerEvent.get());
1135     }
1136
1137     void tap(GdkEventTouch* event) final
1138     {
1139         simulateMouseClick(event, GDK_BUTTON_PRIMARY);
1140     }
1141
1142     void startDrag(GdkEventTouch* event, const FloatPoint& startPoint) final
1143     {
1144         GUniquePtr<GdkEvent> scrollEvent = createScrollEvent(event, startPoint, { });
1145         webkitWebViewBaseHandleWheelEvent(m_webView, scrollEvent.get(), WebWheelEvent::Phase::PhaseBegan);
1146     }
1147
1148     void drag(GdkEventTouch* event, const FloatPoint& point, const FloatPoint& delta) final
1149     {
1150         GUniquePtr<GdkEvent> scrollEvent = createScrollEvent(event, point, delta);
1151         webkitWebViewBaseHandleWheelEvent(m_webView, scrollEvent.get(), WebWheelEvent::Phase::PhaseChanged);
1152     }
1153
1154     void swipe(GdkEventTouch* event, const FloatPoint& velocity) final
1155     {
1156         GUniquePtr<GdkEvent> scrollEvent = createScrollEvent(event, FloatPoint::narrowPrecision(event->x, event->y), velocity, true);
1157         webkitWebViewBaseHandleWheelEvent(m_webView, scrollEvent.get(), WebWheelEvent::Phase::PhaseNone, WebWheelEvent::Phase::PhaseBegan);
1158     }
1159
1160     void startZoom(const IntPoint& center, double& initialScale, IntPoint& initialPoint) final
1161     {
1162         auto* page = m_webView->priv->pageProxy.get();
1163         ASSERT(page);
1164         initialScale = page->pageScaleFactor();
1165         page->getCenterForZoomGesture(center, initialPoint);
1166     }
1167
1168     void zoom(double scale, const IntPoint& origin) final
1169     {
1170         auto* page = m_webView->priv->pageProxy.get();
1171         ASSERT(page);
1172
1173         page->scalePage(scale, origin);
1174     }
1175
1176     void longPress(GdkEventTouch* event) final
1177     {
1178         simulateMouseClick(event, GDK_BUTTON_SECONDARY);
1179     }
1180
1181     WebKitWebViewBase* m_webView;
1182 };
1183
1184 GestureController& webkitWebViewBaseGestureController(WebKitWebViewBase* webViewBase)
1185 {
1186     WebKitWebViewBasePrivate* priv = webViewBase->priv;
1187     if (!priv->gestureController)
1188         priv->gestureController = std::make_unique<GestureController>(GTK_WIDGET(webViewBase), std::make_unique<TouchGestureController>(webViewBase));
1189     return *priv->gestureController;
1190 }
1191 #endif
1192
1193 void webkitWebViewBaseSetEnableBackForwardNavigationGesture(WebKitWebViewBase* webViewBase, bool enabled)
1194 {
1195     WebKitWebViewBasePrivate* priv = webViewBase->priv;
1196
1197     priv->isBackForwardNavigationGestureEnabled = enabled;
1198
1199     if (priv->pageProxy->hasRunningProcess())
1200         webViewBase->priv->viewGestureController->setSwipeGestureEnabled(enabled);
1201
1202     priv->pageProxy->setShouldRecordNavigationSnapshots(enabled);
1203 }
1204
1205 ViewGestureController* webkitWebViewBaseViewGestureController(WebKitWebViewBase* webViewBase)
1206 {
1207     return webViewBase->priv->viewGestureController.get();
1208 }
1209
1210 static gboolean webkitWebViewBaseQueryTooltip(GtkWidget* widget, gint /* x */, gint /* y */, gboolean keyboardMode, GtkTooltip* tooltip)
1211 {
1212     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1213
1214     if (keyboardMode) {
1215         // TODO: https://bugs.webkit.org/show_bug.cgi?id=61732.
1216         notImplemented();
1217         return FALSE;
1218     }
1219
1220     if (priv->tooltipText.length() <= 0)
1221         return FALSE;
1222
1223     if (!priv->tooltipArea.isEmpty()) {
1224         GdkRectangle area = priv->tooltipArea;
1225         gtk_tooltip_set_tip_area(tooltip, &area);
1226     } else
1227         gtk_tooltip_set_tip_area(tooltip, 0);
1228     gtk_tooltip_set_text(tooltip, priv->tooltipText.data());
1229
1230     return TRUE;
1231 }
1232
1233 #if ENABLE(DRAG_SUPPORT)
1234 static void webkitWebViewBaseDragDataGet(GtkWidget* widget, GdkDragContext* context, GtkSelectionData* selectionData, guint info, guint /* time */)
1235 {
1236     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1237     ASSERT(priv->dragAndDropHandler);
1238     priv->dragAndDropHandler->fillDragData(context, selectionData, info);
1239 }
1240
1241 static void webkitWebViewBaseDragEnd(GtkWidget* widget, GdkDragContext* context)
1242 {
1243     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1244     ASSERT(priv->dragAndDropHandler);
1245     priv->dragAndDropHandler->finishDrag(context);
1246 }
1247
1248 static void webkitWebViewBaseDragDataReceived(GtkWidget* widget, GdkDragContext* context, gint /* x */, gint /* y */, GtkSelectionData* selectionData, guint info, guint time)
1249 {
1250     webkitWebViewBaseDragAndDropHandler(WEBKIT_WEB_VIEW_BASE(widget)).dragEntered(context, selectionData, info, time);
1251 }
1252 #endif // ENABLE(DRAG_SUPPORT)
1253
1254 static gboolean webkitWebViewBaseEvent(GtkWidget* widget, GdkEvent* event)
1255 {
1256 #if HAVE(GTK_GESTURES)
1257     if (event->type == GDK_TOUCHPAD_PINCH)
1258         webkitWebViewBaseGestureController(WEBKIT_WEB_VIEW_BASE(widget)).handleEvent(event);
1259 #endif
1260
1261     return GDK_EVENT_PROPAGATE;
1262 }
1263
1264 static AtkObject* webkitWebViewBaseGetAccessible(GtkWidget* widget)
1265 {
1266     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1267     if (!priv->accessible) {
1268         // Create the accessible object and associate it to the widget.
1269         priv->accessible = adoptGRef(ATK_OBJECT(webkitWebViewBaseAccessibleNew(widget)));
1270
1271         // Set the parent to not break bottom-up navigation.
1272         if (auto* parentWidget = gtk_widget_get_parent(widget)) {
1273             if (auto* axParent = gtk_widget_get_accessible(parentWidget))
1274                 atk_object_set_parent(priv->accessible.get(), axParent);
1275         }
1276     }
1277
1278     return priv->accessible.get();
1279 }
1280
1281 #if ENABLE(DRAG_SUPPORT)
1282 static gboolean webkitWebViewBaseDragMotion(GtkWidget* widget, GdkDragContext* context, gint x, gint y, guint time)
1283 {
1284     webkitWebViewBaseDragAndDropHandler(WEBKIT_WEB_VIEW_BASE(widget)).dragMotion(context, IntPoint(x, y), time);
1285     return TRUE;
1286 }
1287
1288 static void webkitWebViewBaseDragLeave(GtkWidget* widget, GdkDragContext* context, guint /* time */)
1289 {
1290     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1291     ASSERT(priv->dragAndDropHandler);
1292     priv->dragAndDropHandler->dragLeave(context);
1293 }
1294
1295 static gboolean webkitWebViewBaseDragDrop(GtkWidget* widget, GdkDragContext* context, gint x, gint y, guint time)
1296 {
1297     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1298     ASSERT(priv->dragAndDropHandler);
1299     return priv->dragAndDropHandler->drop(context, IntPoint(x, y), time);
1300 }
1301 #endif // ENABLE(DRAG_SUPPORT)
1302
1303 static void webkitWebViewBaseHierarchyChanged(GtkWidget* widget, GtkWidget* oldToplevel)
1304 {
1305     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1306     if (widgetIsOnscreenToplevelWindow(oldToplevel) && GTK_WINDOW(oldToplevel) == priv->toplevelOnScreenWindow) {
1307         webkitWebViewBaseSetToplevelOnScreenWindow(WEBKIT_WEB_VIEW_BASE(widget), nullptr);
1308         return;
1309     }
1310
1311     if (!oldToplevel) {
1312         GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
1313         if (widgetIsOnscreenToplevelWindow(toplevel))
1314             webkitWebViewBaseSetToplevelOnScreenWindow(WEBKIT_WEB_VIEW_BASE(widget), GTK_WINDOW(toplevel));
1315     }
1316 }
1317
1318 static gboolean webkitWebViewBaseFocus(GtkWidget* widget, GtkDirectionType direction)
1319 {
1320     // If a dialog is active, we need to forward focus events there. This
1321     // ensures that you can tab between elements in the box.
1322     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1323     if (priv->dialog) {
1324         gboolean returnValue;
1325         g_signal_emit_by_name(priv->dialog, "focus", direction, &returnValue);
1326         return returnValue;
1327     }
1328
1329     return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->focus(widget, direction);
1330 }
1331
1332 static void webkitWebViewBaseDestroy(GtkWidget* widget)
1333 {
1334     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1335     if (priv->dialog)
1336         gtk_widget_destroy(priv->dialog);
1337
1338     GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->destroy(widget);
1339 }
1340
1341 static void webkit_web_view_base_class_init(WebKitWebViewBaseClass* webkitWebViewBaseClass)
1342 {
1343     GtkWidgetClass* widgetClass = GTK_WIDGET_CLASS(webkitWebViewBaseClass);
1344     widgetClass->realize = webkitWebViewBaseRealize;
1345     widgetClass->unrealize = webkitWebViewBaseUnrealize;
1346     widgetClass->draw = webkitWebViewBaseDraw;
1347     widgetClass->size_allocate = webkitWebViewBaseSizeAllocate;
1348     widgetClass->get_preferred_width = webkitWebViewBaseGetPreferredWidth;
1349     widgetClass->get_preferred_height = webkitWebViewBaseGetPreferredHeight;
1350     widgetClass->map = webkitWebViewBaseMap;
1351     widgetClass->unmap = webkitWebViewBaseUnmap;
1352     widgetClass->focus = webkitWebViewBaseFocus;
1353     widgetClass->focus_in_event = webkitWebViewBaseFocusInEvent;
1354     widgetClass->focus_out_event = webkitWebViewBaseFocusOutEvent;
1355     widgetClass->key_press_event = webkitWebViewBaseKeyPressEvent;
1356     widgetClass->key_release_event = webkitWebViewBaseKeyReleaseEvent;
1357     widgetClass->button_press_event = webkitWebViewBaseButtonPressEvent;
1358     widgetClass->button_release_event = webkitWebViewBaseButtonReleaseEvent;
1359     widgetClass->scroll_event = webkitWebViewBaseScrollEvent;
1360     widgetClass->popup_menu = webkitWebViewBasePopupMenu;
1361     widgetClass->motion_notify_event = webkitWebViewBaseMotionNotifyEvent;
1362     widgetClass->enter_notify_event = webkitWebViewBaseCrossingNotifyEvent;
1363     widgetClass->leave_notify_event = webkitWebViewBaseCrossingNotifyEvent;
1364 #if ENABLE(TOUCH_EVENTS)
1365     widgetClass->touch_event = webkitWebViewBaseTouchEvent;
1366 #endif
1367     widgetClass->query_tooltip = webkitWebViewBaseQueryTooltip;
1368 #if ENABLE(DRAG_SUPPORT)
1369     widgetClass->drag_end = webkitWebViewBaseDragEnd;
1370     widgetClass->drag_data_get = webkitWebViewBaseDragDataGet;
1371     widgetClass->drag_motion = webkitWebViewBaseDragMotion;
1372     widgetClass->drag_leave = webkitWebViewBaseDragLeave;
1373     widgetClass->drag_drop = webkitWebViewBaseDragDrop;
1374     widgetClass->drag_data_received = webkitWebViewBaseDragDataReceived;
1375 #endif // ENABLE(DRAG_SUPPORT)
1376     widgetClass->event = webkitWebViewBaseEvent;
1377     widgetClass->get_accessible = webkitWebViewBaseGetAccessible;
1378     widgetClass->hierarchy_changed = webkitWebViewBaseHierarchyChanged;
1379     widgetClass->destroy = webkitWebViewBaseDestroy;
1380
1381     GObjectClass* gobjectClass = G_OBJECT_CLASS(webkitWebViewBaseClass);
1382     gobjectClass->constructed = webkitWebViewBaseConstructed;
1383     gobjectClass->dispose = webkitWebViewBaseDispose;
1384
1385     GtkContainerClass* containerClass = GTK_CONTAINER_CLASS(webkitWebViewBaseClass);
1386     containerClass->add = webkitWebViewBaseContainerAdd;
1387     containerClass->remove = webkitWebViewBaseContainerRemove;
1388     containerClass->forall = webkitWebViewBaseContainerForall;
1389
1390     // Before creating a WebKitWebViewBasePriv we need to be sure that WebKit is started.
1391     // Usually starting a context triggers InitializeWebKit2, but in case
1392     // we create a view without asking before for a default_context we get a crash.
1393     WebKit::InitializeWebKit2();
1394 }
1395
1396 WebKitWebViewBase* webkitWebViewBaseCreate(const API::PageConfiguration& configuration)
1397 {
1398     WebKitWebViewBase* webkitWebViewBase = WEBKIT_WEB_VIEW_BASE(g_object_new(WEBKIT_TYPE_WEB_VIEW_BASE, nullptr));
1399     webkitWebViewBaseCreateWebPage(webkitWebViewBase, configuration.copy());
1400     return webkitWebViewBase;
1401 }
1402
1403 GtkIMContext* webkitWebViewBaseGetIMContext(WebKitWebViewBase* webkitWebViewBase)
1404 {
1405     return webkitWebViewBase->priv->inputMethodFilter.context();
1406 }
1407
1408 WebPageProxy* webkitWebViewBaseGetPage(WebKitWebViewBase* webkitWebViewBase)
1409 {
1410     return webkitWebViewBase->priv->pageProxy.get();
1411 }
1412
1413 #if HAVE(GTK_SCALE_FACTOR)
1414 static void deviceScaleFactorChanged(WebKitWebViewBase* webkitWebViewBase)
1415 {
1416     webkitWebViewBase->priv->pageProxy->setIntrinsicDeviceScaleFactor(gtk_widget_get_scale_factor(GTK_WIDGET(webkitWebViewBase)));
1417 }
1418 #endif // HAVE(GTK_SCALE_FACTOR)
1419
1420 void webkitWebViewBaseCreateWebPage(WebKitWebViewBase* webkitWebViewBase, Ref<API::PageConfiguration>&& configuration)
1421 {
1422     WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1423     WebProcessPool* processPool = configuration->processPool();
1424     priv->pageProxy = processPool->createWebPage(*priv->pageClient, WTFMove(configuration));
1425     priv->pageProxy->initializeWebPage();
1426
1427     priv->acceleratedBackingStore = AcceleratedBackingStore::create(*priv->pageProxy);
1428
1429     priv->inputMethodFilter.setPage(priv->pageProxy.get());
1430
1431 #if HAVE(GTK_SCALE_FACTOR)
1432     // We attach this here, because changes in scale factor are passed directly to the page proxy.
1433     priv->pageProxy->setIntrinsicDeviceScaleFactor(gtk_widget_get_scale_factor(GTK_WIDGET(webkitWebViewBase)));
1434     g_signal_connect(webkitWebViewBase, "notify::scale-factor", G_CALLBACK(deviceScaleFactorChanged), nullptr);
1435 #endif
1436 }
1437
1438 void webkitWebViewBaseSetTooltipText(WebKitWebViewBase* webViewBase, const char* tooltip)
1439 {
1440     WebKitWebViewBasePrivate* priv = webViewBase->priv;
1441     if (tooltip && tooltip[0] != '\0') {
1442         priv->tooltipText = tooltip;
1443         gtk_widget_set_has_tooltip(GTK_WIDGET(webViewBase), TRUE);
1444     } else {
1445         priv->tooltipText = "";
1446         gtk_widget_set_has_tooltip(GTK_WIDGET(webViewBase), FALSE);
1447     }
1448
1449     gtk_widget_trigger_tooltip_query(GTK_WIDGET(webViewBase));
1450 }
1451
1452 void webkitWebViewBaseSetTooltipArea(WebKitWebViewBase* webViewBase, const IntRect& tooltipArea)
1453 {
1454     webViewBase->priv->tooltipArea = tooltipArea;
1455 }
1456
1457 #if ENABLE(DRAG_SUPPORT)
1458 DragAndDropHandler& webkitWebViewBaseDragAndDropHandler(WebKitWebViewBase* webViewBase)
1459 {
1460     WebKitWebViewBasePrivate* priv = webViewBase->priv;
1461     if (!priv->dragAndDropHandler)
1462         priv->dragAndDropHandler = std::make_unique<DragAndDropHandler>(*priv->pageProxy);
1463     return *priv->dragAndDropHandler;
1464 }
1465 #endif // ENABLE(DRAG_SUPPORT)
1466
1467 void webkitWebViewBaseForwardNextKeyEvent(WebKitWebViewBase* webkitWebViewBase)
1468 {
1469     webkitWebViewBase->priv->shouldForwardNextKeyEvent = TRUE;
1470 }
1471
1472 void webkitWebViewBaseForwardNextWheelEvent(WebKitWebViewBase* webkitWebViewBase)
1473 {
1474     webkitWebViewBase->priv->shouldForwardNextWheelEvent = true;
1475 }
1476
1477 void webkitWebViewBaseEnterFullScreen(WebKitWebViewBase* webkitWebViewBase)
1478 {
1479 #if ENABLE(FULLSCREEN_API)
1480     WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1481     ASSERT(!priv->fullScreenModeActive);
1482
1483     WebFullScreenManagerProxy* fullScreenManagerProxy = priv->pageProxy->fullScreenManager();
1484     fullScreenManagerProxy->willEnterFullScreen();
1485
1486     GtkWidget* topLevelWindow = gtk_widget_get_toplevel(GTK_WIDGET(webkitWebViewBase));
1487     if (gtk_widget_is_toplevel(topLevelWindow))
1488         gtk_window_fullscreen(GTK_WINDOW(topLevelWindow));
1489     fullScreenManagerProxy->didEnterFullScreen();
1490     priv->fullScreenModeActive = true;
1491     priv->sleepDisabler = PAL::SleepDisabler::create(_("Website running in fullscreen mode"), PAL::SleepDisabler::Type::Display);
1492 #endif
1493 }
1494
1495 void webkitWebViewBaseExitFullScreen(WebKitWebViewBase* webkitWebViewBase)
1496 {
1497 #if ENABLE(FULLSCREEN_API)
1498     WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1499     ASSERT(priv->fullScreenModeActive);
1500
1501     WebFullScreenManagerProxy* fullScreenManagerProxy = priv->pageProxy->fullScreenManager();
1502     fullScreenManagerProxy->willExitFullScreen();
1503
1504     GtkWidget* topLevelWindow = gtk_widget_get_toplevel(GTK_WIDGET(webkitWebViewBase));
1505     if (gtk_widget_is_toplevel(topLevelWindow))
1506         gtk_window_unfullscreen(GTK_WINDOW(topLevelWindow));
1507     fullScreenManagerProxy->didExitFullScreen();
1508     priv->fullScreenModeActive = false;
1509     priv->sleepDisabler = nullptr;
1510 #endif
1511 }
1512
1513 bool webkitWebViewBaseIsFullScreen(WebKitWebViewBase* webkitWebViewBase)
1514 {
1515 #if ENABLE(FULLSCREEN_API)
1516     return webkitWebViewBase->priv->fullScreenModeActive;
1517 #else
1518     return false;
1519 #endif
1520 }
1521
1522 void webkitWebViewBaseSetInspectorViewSize(WebKitWebViewBase* webkitWebViewBase, unsigned size)
1523 {
1524     if (webkitWebViewBase->priv->inspectorViewSize == size)
1525         return;
1526     webkitWebViewBase->priv->inspectorViewSize = size;
1527     if (webkitWebViewBase->priv->inspectorView)
1528         gtk_widget_queue_resize_no_redraw(GTK_WIDGET(webkitWebViewBase));
1529 }
1530
1531 static void activeContextMenuUnmapped(GtkMenu* menu, WebKitWebViewBase* webViewBase)
1532 {
1533     if (webViewBase->priv->activeContextMenuProxy && webViewBase->priv->activeContextMenuProxy->gtkMenu() == menu)
1534         webViewBase->priv->activeContextMenuProxy = nullptr;
1535 }
1536
1537 void webkitWebViewBaseSetActiveContextMenuProxy(WebKitWebViewBase* webkitWebViewBase, WebContextMenuProxyGtk* contextMenuProxy)
1538 {
1539     webkitWebViewBase->priv->activeContextMenuProxy = contextMenuProxy;
1540     g_signal_connect_object(contextMenuProxy->gtkMenu(), "unmap", G_CALLBACK(activeContextMenuUnmapped), webkitWebViewBase, static_cast<GConnectFlags>(0));
1541 }
1542
1543 WebContextMenuProxyGtk* webkitWebViewBaseGetActiveContextMenuProxy(WebKitWebViewBase* webkitWebViewBase)
1544 {
1545     return webkitWebViewBase->priv->activeContextMenuProxy;
1546 }
1547
1548 GdkEvent* webkitWebViewBaseTakeContextMenuEvent(WebKitWebViewBase* webkitWebViewBase)
1549 {
1550     return webkitWebViewBase->priv->contextMenuEvent.release();
1551 }
1552
1553 void webkitWebViewBaseSetFocus(WebKitWebViewBase* webViewBase, bool focused)
1554 {
1555     WebKitWebViewBasePrivate* priv = webViewBase->priv;
1556     if ((focused && priv->activityState & ActivityState::IsFocused) || (!focused && !(priv->activityState & ActivityState::IsFocused)))
1557         return;
1558
1559     OptionSet<ActivityState::Flag> flagsToUpdate { ActivityState::IsFocused };
1560     if (focused) {
1561         priv->activityState.add(ActivityState::IsFocused);
1562
1563         // If the view has received the focus and the window is not active
1564         // mark the current window as active now. This can happen if the
1565         // toplevel window is a GTK_WINDOW_POPUP and the focus has been
1566         // set programatically like WebKitTestRunner does, because POPUP
1567         // can't be focused.
1568         if (!(priv->activityState & ActivityState::WindowIsActive)) {
1569             priv->activityState.add(ActivityState::WindowIsActive);
1570             flagsToUpdate.add(ActivityState::WindowIsActive);
1571         }
1572     } else
1573         priv->activityState.remove(ActivityState::IsFocused);
1574
1575     webkitWebViewBaseScheduleUpdateActivityState(webViewBase, flagsToUpdate);
1576 }
1577
1578 bool webkitWebViewBaseIsInWindowActive(WebKitWebViewBase* webViewBase)
1579 {
1580     return webViewBase->priv->activityState.contains(ActivityState::WindowIsActive);
1581 }
1582
1583 bool webkitWebViewBaseIsFocused(WebKitWebViewBase* webViewBase)
1584 {
1585     return webViewBase->priv->activityState.contains(ActivityState::IsFocused);
1586 }
1587
1588 bool webkitWebViewBaseIsVisible(WebKitWebViewBase* webViewBase)
1589 {
1590     return webViewBase->priv->activityState.contains(ActivityState::IsVisible);
1591 }
1592
1593 bool webkitWebViewBaseIsInWindow(WebKitWebViewBase* webViewBase)
1594 {
1595     return webViewBase->priv->activityState.contains(ActivityState::IsInWindow);
1596 }
1597
1598 void webkitWebViewBaseSetInputMethodState(WebKitWebViewBase* webkitWebViewBase, bool enabled)
1599 {
1600     webkitWebViewBase->priv->inputMethodFilter.setEnabled(enabled);
1601 }
1602
1603 void webkitWebViewBaseUpdateTextInputState(WebKitWebViewBase* webkitWebViewBase)
1604 {
1605     const auto& editorState = webkitWebViewBase->priv->pageProxy->editorState();
1606     if (!editorState.isMissingPostLayoutData)
1607         webkitWebViewBase->priv->inputMethodFilter.setCursorRect(editorState.postLayoutData().caretRectAtStart);
1608 }
1609
1610 void webkitWebViewBaseSetContentsSize(WebKitWebViewBase* webkitWebViewBase, const IntSize& contentsSize)
1611 {
1612     WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1613     if (priv->contentsSize == contentsSize)
1614         return;
1615     priv->contentsSize = contentsSize;
1616 }
1617
1618 void webkitWebViewBaseResetClickCounter(WebKitWebViewBase* webkitWebViewBase)
1619 {
1620     webkitWebViewBase->priv->clickCounter.reset();
1621 }
1622
1623 void webkitWebViewBaseEnterAcceleratedCompositingMode(WebKitWebViewBase* webkitWebViewBase, const LayerTreeContext& layerTreeContext)
1624 {
1625     if (webkitWebViewBase->priv->acceleratedBackingStore)
1626         webkitWebViewBase->priv->acceleratedBackingStore->update(layerTreeContext);
1627 }
1628
1629 void webkitWebViewBaseUpdateAcceleratedCompositingMode(WebKitWebViewBase* webkitWebViewBase, const LayerTreeContext& layerTreeContext)
1630 {
1631     if (webkitWebViewBase->priv->acceleratedBackingStore)
1632         webkitWebViewBase->priv->acceleratedBackingStore->update(layerTreeContext);
1633 }
1634
1635 void webkitWebViewBaseExitAcceleratedCompositingMode(WebKitWebViewBase* webkitWebViewBase)
1636 {
1637     if (webkitWebViewBase->priv->acceleratedBackingStore)
1638         webkitWebViewBase->priv->acceleratedBackingStore->update(LayerTreeContext());
1639 }
1640
1641 bool webkitWebViewBaseMakeGLContextCurrent(WebKitWebViewBase* webkitWebViewBase)
1642 {
1643     if (webkitWebViewBase->priv->acceleratedBackingStore)
1644         return webkitWebViewBase->priv->acceleratedBackingStore->makeContextCurrent();
1645     return false;
1646 }
1647
1648 void webkitWebViewBaseDidRelaunchWebProcess(WebKitWebViewBase* webkitWebViewBase)
1649 {
1650     // Queue a resize to ensure the new DrawingAreaProxy is resized.
1651     gtk_widget_queue_resize_no_redraw(GTK_WIDGET(webkitWebViewBase));
1652
1653     WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1654
1655 #if PLATFORM(X11) && USE(TEXTURE_MAPPER_GL) && !USE(REDIRECTED_XCOMPOSITE_WINDOW)
1656     if (PlatformDisplay::sharedDisplay().type() != PlatformDisplay::Type::X11)
1657         return;
1658
1659     auto* drawingArea = static_cast<DrawingAreaProxyCoordinatedGraphics*>(priv->pageProxy->drawingArea());
1660     ASSERT(drawingArea);
1661
1662     if (!gtk_widget_get_realized(GTK_WIDGET(webkitWebViewBase)))
1663         return;
1664
1665     uint64_t windowID = GDK_WINDOW_XID(gtk_widget_get_window(GTK_WIDGET(webkitWebViewBase)));
1666     drawingArea->setNativeSurfaceHandleForCompositing(windowID);
1667 #else
1668     UNUSED_PARAM(webkitWebViewBase);
1669 #endif
1670
1671     priv->viewGestureController = std::make_unique<WebKit::ViewGestureController>(*priv->pageProxy);
1672     priv->viewGestureController->setSwipeGestureEnabled(priv->isBackForwardNavigationGestureEnabled);
1673 }
1674
1675 void webkitWebViewBasePageClosed(WebKitWebViewBase* webkitWebViewBase)
1676 {
1677     if (webkitWebViewBase->priv->acceleratedBackingStore)
1678         webkitWebViewBase->priv->acceleratedBackingStore->update(LayerTreeContext());
1679 #if PLATFORM(X11) && USE(TEXTURE_MAPPER_GL) && !USE(REDIRECTED_XCOMPOSITE_WINDOW)
1680     if (PlatformDisplay::sharedDisplay().type() != PlatformDisplay::Type::X11)
1681         return;
1682
1683     if (!gtk_widget_get_realized(GTK_WIDGET(webkitWebViewBase)))
1684         return;
1685
1686     WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1687     auto* drawingArea = static_cast<DrawingAreaProxyCoordinatedGraphics*>(priv->pageProxy->drawingArea());
1688     ASSERT(drawingArea);
1689     drawingArea->destroyNativeSurfaceHandleForCompositing();
1690 #endif
1691 }
1692
1693 RefPtr<WebKit::ViewSnapshot> webkitWebViewBaseTakeViewSnapshot(WebKitWebViewBase* webkitWebViewBase)
1694 {
1695     WebPageProxy* page = webkitWebViewBase->priv->pageProxy.get();
1696
1697     IntSize size = page->viewSize();
1698
1699 #if HAVE_GTK_SCALE_FACTOR
1700     float deviceScale = page->deviceScaleFactor();
1701     size.scale(deviceScale);
1702 #endif
1703
1704     RefPtr<cairo_surface_t> surface = adoptRef(cairo_image_surface_create(CAIRO_FORMAT_RGB24, size.width(), size.height()));
1705
1706 #if HAVE_GTK_SCALE_FACTOR
1707     cairoSurfaceSetDeviceScale(surface.get(), deviceScale, deviceScale);
1708 #endif
1709
1710     RefPtr<cairo_t> cr = adoptRef(cairo_create(surface.get()));
1711     webkitWebViewBaseDraw(GTK_WIDGET(webkitWebViewBase), cr.get());
1712
1713     return ViewSnapshot::create(WTFMove(surface));
1714 }
1715
1716 void webkitWebViewBaseDidStartProvisionalLoadForMainFrame(WebKitWebViewBase* webkitWebViewBase)
1717 {
1718     ViewGestureController* controller = webkitWebViewBaseViewGestureController(webkitWebViewBase);
1719     if (controller && controller->isSwipeGestureEnabled())
1720         controller->didStartProvisionalLoadForMainFrame();
1721 }
1722
1723 void webkitWebViewBaseDidFirstVisuallyNonEmptyLayoutForMainFrame(WebKitWebViewBase* webkitWebViewBase)
1724 {
1725     ViewGestureController* controller = webkitWebViewBaseViewGestureController(webkitWebViewBase);
1726     if (controller && controller->isSwipeGestureEnabled())
1727         controller->didFirstVisuallyNonEmptyLayoutForMainFrame();
1728 }
1729
1730 void webkitWebViewBaseDidFinishLoadForMainFrame(WebKitWebViewBase* webkitWebViewBase)
1731 {
1732     ViewGestureController* controller = webkitWebViewBaseViewGestureController(webkitWebViewBase);
1733     if (controller && controller->isSwipeGestureEnabled())
1734         controller->didFinishLoadForMainFrame();
1735 }
1736
1737 void webkitWebViewBaseDidFailLoadForMainFrame(WebKitWebViewBase* webkitWebViewBase)
1738 {
1739     ViewGestureController* controller = webkitWebViewBaseViewGestureController(webkitWebViewBase);
1740     if (controller && controller->isSwipeGestureEnabled())
1741         controller->didFailLoadForMainFrame();
1742 }
1743
1744 void webkitWebViewBaseDidSameDocumentNavigationForMainFrame(WebKitWebViewBase* webkitWebViewBase, SameDocumentNavigationType type)
1745 {
1746     ViewGestureController* controller = webkitWebViewBaseViewGestureController(webkitWebViewBase);
1747     if (controller && controller->isSwipeGestureEnabled())
1748         controller->didSameDocumentNavigationForMainFrame(type);
1749 }
1750
1751 void webkitWebViewBaseDidRestoreScrollPosition(WebKitWebViewBase* webkitWebViewBase)
1752 {
1753     ViewGestureController* controller = webkitWebViewBaseViewGestureController(webkitWebViewBase);
1754     if (controller && controller->isSwipeGestureEnabled())
1755         webkitWebViewBase->priv->viewGestureController->didRestoreScrollPosition();
1756 }