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