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