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