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