Avoid the Vector<> copy in WebTouchEvent constructor
[WebKit-https.git] / Source / WebKit2 / 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 "DrawingAreaProxyImpl.h"
33 #include "InputMethodFilter.h"
34 #include "NativeWebMouseEvent.h"
35 #include "NativeWebWheelEvent.h"
36 #include "PageClientImpl.h"
37 #include "RedirectedXCompositeWindow.h"
38 #include "ViewState.h"
39 #include "WebEventFactory.h"
40 #include "WebFullScreenClientGtk.h"
41 #include "WebInspectorProxy.h"
42 #include "WebKitAuthenticationDialog.h"
43 #include "WebKitPrivate.h"
44 #include "WebKitWebViewBaseAccessible.h"
45 #include "WebKitWebViewBasePrivate.h"
46 #include "WebPageGroup.h"
47 #include "WebPageProxy.h"
48 #include "WebPreferences.h"
49 #include "WebProcessPool.h"
50 #include "WebUserContentControllerProxy.h"
51 #include <WebCore/CairoUtilities.h>
52 #include <WebCore/GUniquePtrGtk.h>
53 #include <WebCore/GtkUtilities.h>
54 #include <WebCore/GtkVersioning.h>
55 #include <WebCore/NotImplemented.h>
56 #include <WebCore/PasteboardHelper.h>
57 #include <WebCore/RefPtrCairo.h>
58 #include <WebCore/Region.h>
59 #include <gdk/gdk.h>
60 #include <gdk/gdkkeysyms.h>
61 #include <memory>
62 #include <wtf/HashMap.h>
63 #include <wtf/gobject/GRefPtr.h>
64 #include <wtf/text/CString.h>
65
66 #if ENABLE(FULLSCREEN_API)
67 #include "WebFullScreenManagerProxy.h"
68 #endif
69
70 #if USE(REDIRECTED_XCOMPOSITE_WINDOW)
71 #include <gdk/gdkx.h>
72 #endif
73
74 #if PLATFORM(WAYLAND)
75 #include <gdk/gdkwayland.h>
76 #endif
77
78 // gtk_widget_get_scale_factor() appeared in GTK 3.10, but we also need
79 // to make sure we have cairo new enough to support cairo_surface_set_device_scale
80 #define HAVE_GTK_SCALE_FACTOR HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE && GTK_CHECK_VERSION(3, 10, 0)
81
82 using namespace WebKit;
83 using namespace WebCore;
84
85 struct ClickCounter {
86 public:
87     void reset()
88     {
89         currentClickCount = 0;
90         previousClickPoint = IntPoint();
91         previousClickTime = 0;
92         previousClickButton = 0;
93     }
94
95     int currentClickCountForGdkButtonEvent(GdkEventButton* buttonEvent)
96     {
97         GdkEvent* event = reinterpret_cast<GdkEvent*>(buttonEvent);
98         int doubleClickDistance = 250;
99         int doubleClickTime = 5;
100         g_object_get(gtk_settings_get_for_screen(gdk_event_get_screen(event)),
101             "gtk-double-click-distance", &doubleClickDistance, "gtk-double-click-time", &doubleClickTime, nullptr);
102
103         // GTK+ only counts up to triple clicks, but WebCore wants to know about
104         // quadruple clicks, quintuple clicks, ad infinitum. Here, we replicate the
105         // GDK logic for counting clicks.
106         guint32 eventTime = gdk_event_get_time(event);
107         if (!eventTime) {
108             // Real events always have a non-zero time, but events synthesized
109             // by the WTR do not and we must calculate a time manually. This time
110             // is not calculated in the WTR, because GTK+ does not work well with
111             // anything other than GDK_CURRENT_TIME on synthesized events.
112             GTimeVal timeValue;
113             g_get_current_time(&timeValue);
114             eventTime = (timeValue.tv_sec * 1000) + (timeValue.tv_usec / 1000);
115         }
116
117         if ((event->type == GDK_2BUTTON_PRESS || event->type == GDK_3BUTTON_PRESS)
118             || ((std::abs(buttonEvent->x - previousClickPoint.x()) < doubleClickDistance)
119                 && (std::abs(buttonEvent->y - previousClickPoint.y()) < doubleClickDistance)
120                 && (eventTime - previousClickTime < static_cast<unsigned>(doubleClickTime))
121                 && (buttonEvent->button == previousClickButton)))
122             currentClickCount++;
123         else
124             currentClickCount = 1;
125
126         double x, y;
127         gdk_event_get_coords(event, &x, &y);
128         previousClickPoint = IntPoint(x, y);
129         previousClickButton = buttonEvent->button;
130         previousClickTime = eventTime;
131
132         return currentClickCount;
133     }
134
135 private:
136     int currentClickCount;
137     IntPoint previousClickPoint;
138     unsigned previousClickButton;
139     int previousClickTime;
140 };
141
142 typedef HashMap<GtkWidget*, IntRect> WebKitWebViewChildrenMap;
143 typedef HashMap<uint32_t, GUniquePtr<GdkEvent>> TouchEventsMap;
144
145 struct _WebKitWebViewBasePrivate {
146     WebKitWebViewChildrenMap children;
147     std::unique_ptr<PageClientImpl> pageClient;
148     RefPtr<WebPageProxy> pageProxy;
149     bool shouldForwardNextKeyEvent;
150     ClickCounter clickCounter;
151     CString tooltipText;
152     IntRect tooltipArea;
153 #if !GTK_CHECK_VERSION(3, 13, 4)
154     IntSize resizerSize;
155 #endif
156     GRefPtr<AtkObject> accessible;
157     bool needsResizeOnMap;
158     GtkWidget* authenticationDialog;
159     GtkWidget* inspectorView;
160     AttachmentSide inspectorAttachmentSide;
161     unsigned inspectorViewSize;
162     GUniquePtr<GdkEvent> contextMenuEvent;
163     WebContextMenuProxyGtk* activeContextMenuProxy;
164     InputMethodFilter inputMethodFilter;
165     TouchEventsMap touchEvents;
166
167     GtkWindow* toplevelOnScreenWindow;
168 #if !GTK_CHECK_VERSION(3, 13, 4)
169     unsigned long toplevelResizeGripVisibilityID;
170 #endif
171     unsigned long toplevelFocusInEventID;
172     unsigned long toplevelFocusOutEventID;
173     unsigned long toplevelVisibilityEventID;
174
175     // View State.
176     bool isInWindowActive : 1;
177     bool isFocused : 1;
178     bool isVisible : 1;
179     bool isWindowVisible : 1;
180
181     WebKitWebViewBaseDownloadRequestHandler downloadHandler;
182
183 #if ENABLE(FULLSCREEN_API)
184     bool fullScreenModeActive;
185     WebFullScreenClientGtk fullScreenClient;
186 #endif
187
188 #if USE(REDIRECTED_XCOMPOSITE_WINDOW)
189     std::unique_ptr<RedirectedXCompositeWindow> redirectedWindow;
190 #endif
191
192 #if ENABLE(DRAG_SUPPORT)
193     std::unique_ptr<DragAndDropHandler> dragAndDropHandler;
194 #endif
195
196 #if HAVE(GTK_GESTURES)
197     std::unique_ptr<GestureController> gestureController;
198 #endif
199 };
200
201 WEBKIT_DEFINE_TYPE(WebKitWebViewBase, webkit_web_view_base, GTK_TYPE_CONTAINER)
202
203 #if !GTK_CHECK_VERSION(3, 13, 4)
204 static void webkitWebViewBaseNotifyResizerSize(WebKitWebViewBase* webViewBase)
205 {
206     WebKitWebViewBasePrivate* priv = webViewBase->priv;
207     if (!priv->toplevelOnScreenWindow)
208         return;
209
210     gboolean resizerVisible;
211     g_object_get(G_OBJECT(priv->toplevelOnScreenWindow), "resize-grip-visible", &resizerVisible, NULL);
212
213     IntSize resizerSize;
214     if (resizerVisible) {
215         GdkRectangle resizerRect;
216         gtk_window_get_resize_grip_area(priv->toplevelOnScreenWindow, &resizerRect);
217         GdkRectangle allocation;
218         gtk_widget_get_allocation(GTK_WIDGET(webViewBase), &allocation);
219         if (gdk_rectangle_intersect(&resizerRect, &allocation, 0))
220             resizerSize = IntSize(resizerRect.width, resizerRect.height);
221     }
222
223     if (resizerSize != priv->resizerSize) {
224         priv->resizerSize = resizerSize;
225         priv->pageProxy->setWindowResizerSize(resizerSize);
226     }
227 }
228
229 static void toplevelWindowResizeGripVisibilityChanged(GObject*, GParamSpec*, WebKitWebViewBase* webViewBase)
230 {
231     webkitWebViewBaseNotifyResizerSize(webViewBase);
232 }
233 #endif
234
235 static gboolean toplevelWindowFocusInEvent(GtkWidget*, GdkEventFocus*, WebKitWebViewBase* webViewBase)
236 {
237     WebKitWebViewBasePrivate* priv = webViewBase->priv;
238     if (!priv->isInWindowActive) {
239         priv->isInWindowActive = true;
240         priv->pageProxy->viewStateDidChange(ViewState::WindowIsActive);
241     }
242
243     return FALSE;
244 }
245
246 static gboolean toplevelWindowFocusOutEvent(GtkWidget*, GdkEventFocus*, WebKitWebViewBase* webViewBase)
247 {
248     WebKitWebViewBasePrivate* priv = webViewBase->priv;
249     if (priv->isInWindowActive) {
250         priv->isInWindowActive = false;
251         priv->pageProxy->viewStateDidChange(ViewState::WindowIsActive);
252     }
253
254     return FALSE;
255 }
256
257 static gboolean toplevelWindowVisibilityEvent(GtkWidget*, GdkEventVisibility* visibilityEvent, WebKitWebViewBase* webViewBase)
258 {
259     WebKitWebViewBasePrivate* priv = webViewBase->priv;
260     bool isWindowVisible = visibilityEvent->state != GDK_VISIBILITY_FULLY_OBSCURED;
261     if (priv->isWindowVisible != isWindowVisible) {
262         priv->isWindowVisible = isWindowVisible;
263         priv->pageProxy->viewStateDidChange(ViewState::IsVisible);
264     }
265
266     return FALSE;
267 }
268
269 static void webkitWebViewBaseSetToplevelOnScreenWindow(WebKitWebViewBase* webViewBase, GtkWindow* window)
270 {
271     WebKitWebViewBasePrivate* priv = webViewBase->priv;
272     if (priv->toplevelOnScreenWindow == window)
273         return;
274
275 #if !GTK_CHECK_VERSION(3, 13, 4)
276     if (priv->toplevelResizeGripVisibilityID) {
277         g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelResizeGripVisibilityID);
278         priv->toplevelResizeGripVisibilityID = 0;
279     }
280 #endif
281     if (priv->toplevelFocusInEventID) {
282         g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelFocusInEventID);
283         priv->toplevelFocusInEventID = 0;
284     }
285     if (priv->toplevelFocusOutEventID) {
286         g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelFocusOutEventID);
287         priv->toplevelFocusOutEventID = 0;
288     }
289     if (priv->toplevelVisibilityEventID) {
290         g_signal_handler_disconnect(priv->toplevelOnScreenWindow, priv->toplevelVisibilityEventID);
291         priv->toplevelVisibilityEventID = 0;
292     }
293
294     priv->toplevelOnScreenWindow = window;
295     priv->pageProxy->viewStateDidChange(ViewState::IsInWindow);
296     if (!priv->toplevelOnScreenWindow)
297         return;
298
299 #if !GTK_CHECK_VERSION(3, 13, 4)
300     webkitWebViewBaseNotifyResizerSize(webViewBase);
301
302     priv->toplevelResizeGripVisibilityID =
303         g_signal_connect(priv->toplevelOnScreenWindow, "notify::resize-grip-visible",
304                          G_CALLBACK(toplevelWindowResizeGripVisibilityChanged), webViewBase);
305 #endif
306     priv->toplevelFocusInEventID =
307         g_signal_connect(priv->toplevelOnScreenWindow, "focus-in-event",
308                          G_CALLBACK(toplevelWindowFocusInEvent), webViewBase);
309     priv->toplevelFocusOutEventID =
310         g_signal_connect(priv->toplevelOnScreenWindow, "focus-out-event",
311                          G_CALLBACK(toplevelWindowFocusOutEvent), webViewBase);
312     priv->toplevelVisibilityEventID =
313         g_signal_connect(priv->toplevelOnScreenWindow, "visibility-notify-event",
314                          G_CALLBACK(toplevelWindowVisibilityEvent), webViewBase);
315 }
316
317 static void webkitWebViewBaseRealize(GtkWidget* widget)
318 {
319     WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(widget);
320     WebKitWebViewBasePrivate* priv = webView->priv;
321
322 #if USE(REDIRECTED_XCOMPOSITE_WINDOW)
323     GdkDisplay* display = gdk_display_manager_get_default_display(gdk_display_manager_get());
324     if (GDK_IS_X11_DISPLAY(display)) {
325         priv->redirectedWindow = RedirectedXCompositeWindow::create(
326             gtk_widget_get_parent_window(widget),
327             [webView] {
328                 DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(webView->priv->pageProxy->drawingArea());
329                 if (drawingArea && drawingArea->isInAcceleratedCompositingMode())
330                     gtk_widget_queue_draw(GTK_WIDGET(webView));
331             });
332         if (priv->redirectedWindow) {
333             DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(priv->pageProxy->drawingArea());
334             drawingArea->setNativeSurfaceHandleForCompositing(priv->redirectedWindow->windowID());
335         }
336     }
337 #endif
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_KEY_PRESS_MASK
360         | GDK_KEY_RELEASE_MASK
361         | GDK_BUTTON_MOTION_MASK
362         | GDK_BUTTON1_MOTION_MASK
363         | GDK_BUTTON2_MOTION_MASK
364         | GDK_BUTTON3_MOTION_MASK
365         | GDK_TOUCH_MASK;
366
367     gint attributesMask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
368
369     GdkWindow* window = gdk_window_new(gtk_widget_get_parent_window(widget), &attributes, attributesMask);
370     gtk_widget_set_window(widget, window);
371     gdk_window_set_user_data(window, widget);
372
373 #if USE(TEXTURE_MAPPER_GL) && PLATFORM(X11) && !USE(REDIRECTED_XCOMPOSITE_WINDOW)
374     DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(priv->pageProxy->drawingArea());
375     drawingArea->setNativeSurfaceHandleForCompositing(GDK_WINDOW_XID(window));
376 #endif
377
378     gtk_style_context_set_background(gtk_widget_get_style_context(widget), window);
379
380     gtk_im_context_set_client_window(priv->inputMethodFilter.context(), window);
381
382     GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
383     if (widgetIsOnscreenToplevelWindow(toplevel))
384         webkitWebViewBaseSetToplevelOnScreenWindow(webView, GTK_WINDOW(toplevel));
385 }
386
387 static void webkitWebViewBaseUnrealize(GtkWidget* widget)
388 {
389     WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(widget);
390     gtk_im_context_set_client_window(webView->priv->inputMethodFilter.context(), nullptr);
391
392     GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->unrealize(widget);
393 }
394
395 static bool webkitWebViewChildIsInternalWidget(WebKitWebViewBase* webViewBase, GtkWidget* widget)
396 {
397     WebKitWebViewBasePrivate* priv = webViewBase->priv;
398     return widget == priv->inspectorView || widget == priv->authenticationDialog;
399 }
400
401 static void webkitWebViewBaseContainerAdd(GtkContainer* container, GtkWidget* widget)
402 {
403     WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(container);
404     WebKitWebViewBasePrivate* priv = webView->priv;
405
406     // Internal widgets like the web inspector and authentication dialog have custom
407     // allocations so we don't need to add them to our list of children.
408     if (!webkitWebViewChildIsInternalWidget(webView, widget)) {
409         GtkAllocation childAllocation;
410         gtk_widget_get_allocation(widget, &childAllocation);
411         priv->children.set(widget, childAllocation);
412     }
413
414     gtk_widget_set_parent(widget, GTK_WIDGET(container));
415 }
416
417 void webkitWebViewBaseAddAuthenticationDialog(WebKitWebViewBase* webViewBase, GtkWidget* dialog)
418 {
419     WebKitWebViewBasePrivate* priv = webViewBase->priv;
420     priv->authenticationDialog = dialog;
421     gtk_container_add(GTK_CONTAINER(webViewBase), dialog);
422     gtk_widget_show(dialog);
423
424     // We need to draw the shadow over the widget.
425     gtk_widget_queue_draw(GTK_WIDGET(webViewBase));
426 }
427
428 void webkitWebViewBaseAddWebInspector(WebKitWebViewBase* webViewBase, GtkWidget* inspector, AttachmentSide attachmentSide)
429 {
430     if (webViewBase->priv->inspectorView == inspector && webViewBase->priv->inspectorAttachmentSide == attachmentSide)
431         return;
432
433     webViewBase->priv->inspectorAttachmentSide = attachmentSide;
434
435     if (webViewBase->priv->inspectorView == inspector) {
436         gtk_widget_queue_resize(GTK_WIDGET(webViewBase));
437         return;
438     }
439
440     webViewBase->priv->inspectorView = inspector;
441     gtk_container_add(GTK_CONTAINER(webViewBase), inspector);
442 }
443
444 static void webkitWebViewBaseContainerRemove(GtkContainer* container, GtkWidget* widget)
445 {
446     WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(container);
447     WebKitWebViewBasePrivate* priv = webView->priv;
448     GtkWidget* widgetContainer = GTK_WIDGET(container);
449
450     gboolean wasVisible = gtk_widget_get_visible(widget);
451     gtk_widget_unparent(widget);
452
453     if (priv->inspectorView == widget) {
454         priv->inspectorView = 0;
455         priv->inspectorViewSize = 0;
456     } else if (priv->authenticationDialog == widget) {
457         priv->authenticationDialog = 0;
458     } else {
459         ASSERT(priv->children.contains(widget));
460         priv->children.remove(widget);
461     }
462     if (wasVisible && gtk_widget_get_visible(widgetContainer))
463         gtk_widget_queue_resize(widgetContainer);
464 }
465
466 static void webkitWebViewBaseContainerForall(GtkContainer* container, gboolean includeInternals, GtkCallback callback, gpointer callbackData)
467 {
468     WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(container);
469     WebKitWebViewBasePrivate* priv = webView->priv;
470
471     Vector<GtkWidget*> children;
472     copyKeysToVector(priv->children, children);
473     for (const auto& child : children) {
474         if (priv->children.contains(child))
475             (*callback)(child, callbackData);
476     }
477
478     if (includeInternals && priv->inspectorView)
479         (*callback)(priv->inspectorView, callbackData);
480
481     if (includeInternals && priv->authenticationDialog)
482         (*callback)(priv->authenticationDialog, callbackData);
483 }
484
485 void webkitWebViewBaseChildMoveResize(WebKitWebViewBase* webView, GtkWidget* child, const IntRect& childRect)
486 {
487     const IntRect& geometry = webView->priv->children.get(child);
488     if (geometry == childRect)
489         return;
490
491     webView->priv->children.set(child, childRect);
492     gtk_widget_queue_resize_no_redraw(GTK_WIDGET(webView));
493 }
494
495 static void webkitWebViewBaseDispose(GObject* gobject)
496 {
497     WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(gobject);
498     webkitWebViewBaseSetToplevelOnScreenWindow(webView, nullptr);
499     webView->priv->pageProxy->close();
500     G_OBJECT_CLASS(webkit_web_view_base_parent_class)->dispose(gobject);
501 }
502
503 static void webkitWebViewBaseConstructed(GObject* object)
504 {
505     G_OBJECT_CLASS(webkit_web_view_base_parent_class)->constructed(object);
506
507     GtkWidget* viewWidget = GTK_WIDGET(object);
508     gtk_widget_set_can_focus(viewWidget, TRUE);
509     gtk_drag_dest_set(viewWidget, static_cast<GtkDestDefaults>(0), nullptr, 0,
510         static_cast<GdkDragAction>(GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK | GDK_ACTION_PRIVATE));
511     gtk_drag_dest_set_target_list(viewWidget, PasteboardHelper::defaultPasteboardHelper()->targetList());
512
513     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(object)->priv;
514     priv->pageClient = std::make_unique<PageClientImpl>(viewWidget);
515     priv->authenticationDialog = 0;
516 }
517
518 #if USE(TEXTURE_MAPPER_GL)
519 static bool webkitWebViewRenderAcceleratedCompositingResults(WebKitWebViewBase* webViewBase, DrawingAreaProxyImpl* drawingArea, cairo_t* cr, GdkRectangle* clipRect)
520 {
521     ASSERT(drawingArea);
522
523     if (!drawingArea->isInAcceleratedCompositingMode())
524         return false;
525
526 #if USE(REDIRECTED_XCOMPOSITE_WINDOW)
527     // To avoid flashes when initializing accelerated compositing for the first
528     // time, we wait until we know there's a frame ready before rendering.
529     WebKitWebViewBasePrivate* priv = webViewBase->priv;
530     if (!priv->redirectedWindow)
531         return false;
532
533     priv->redirectedWindow->resize(drawingArea->size());
534
535     if (cairo_surface_t* surface = priv->redirectedWindow->surface()) {
536         cairo_rectangle(cr, clipRect->x, clipRect->y, clipRect->width, clipRect->height);
537         cairo_set_source_surface(cr, surface, 0, 0);
538         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
539         cairo_fill(cr);
540     }
541
542     return true;
543 #else
544     return false;
545 #endif
546 }
547 #endif
548
549 static gboolean webkitWebViewBaseDraw(GtkWidget* widget, cairo_t* cr)
550 {
551     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
552     DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(webViewBase->priv->pageProxy->drawingArea());
553     if (!drawingArea)
554         return FALSE;
555
556     GdkRectangle clipRect;
557     if (!gdk_cairo_get_clip_rectangle(cr, &clipRect))
558         return FALSE;
559
560 #if USE(TEXTURE_MAPPER_GL)
561     if (webkitWebViewRenderAcceleratedCompositingResults(webViewBase, drawingArea, cr, &clipRect))
562         return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->draw(widget, cr);
563 #endif
564
565     WebCore::Region unpaintedRegion; // This is simply unused.
566     drawingArea->paint(cr, clipRect, unpaintedRegion);
567
568     if (webViewBase->priv->authenticationDialog) {
569         cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
570         cairo_set_source_rgba(cr, 0, 0, 0, 0.5);
571         cairo_paint(cr);
572     }
573
574     GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->draw(widget, cr);
575
576     return FALSE;
577 }
578
579 static void webkitWebViewBaseChildAllocate(GtkWidget* child, gpointer userData)
580 {
581     if (!gtk_widget_get_visible(child))
582         return;
583
584     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(userData);
585     WebKitWebViewBasePrivate* priv = webViewBase->priv;
586     const IntRect& geometry = priv->children.get(child);
587     if (geometry.isEmpty())
588         return;
589
590     GtkAllocation childAllocation = geometry;
591     gtk_widget_size_allocate(child, &childAllocation);
592     priv->children.set(child, IntRect());
593 }
594
595 static void resizeWebKitWebViewBaseFromAllocation(WebKitWebViewBase* webViewBase, GtkAllocation* allocation, bool sizeChanged)
596 {
597     gtk_container_foreach(GTK_CONTAINER(webViewBase), webkitWebViewBaseChildAllocate, webViewBase);
598
599     IntRect viewRect(allocation->x, allocation->y, allocation->width, allocation->height);
600     WebKitWebViewBasePrivate* priv = webViewBase->priv;
601     if (priv->inspectorView) {
602         GtkAllocation childAllocation = viewRect;
603
604         if (priv->inspectorAttachmentSide == AttachmentSide::Bottom) {
605             int inspectorViewHeight = std::min(static_cast<int>(priv->inspectorViewSize), allocation->height);
606             childAllocation.x = 0;
607             childAllocation.y = allocation->height - inspectorViewHeight;
608             childAllocation.height = inspectorViewHeight;
609             viewRect.setHeight(std::max(allocation->height - inspectorViewHeight, 1));
610         } else {
611             int inspectorViewWidth = std::min(static_cast<int>(priv->inspectorViewSize), allocation->width);
612             childAllocation.y = 0;
613             childAllocation.x = allocation->width - inspectorViewWidth;
614             childAllocation.width = inspectorViewWidth;
615             viewRect.setWidth(std::max(allocation->width - inspectorViewWidth, 1));
616         }
617
618         gtk_widget_size_allocate(priv->inspectorView, &childAllocation);
619     }
620
621     // The authentication dialog is centered in the view rect, which means that it
622     // never overlaps the web inspector. Thus, we need to calculate the allocation here
623     // after calculating the inspector allocation.
624     if (priv->authenticationDialog) {
625         GtkRequisition naturalSize;
626         gtk_widget_get_preferred_size(priv->authenticationDialog, 0, &naturalSize);
627
628         GtkAllocation childAllocation = {
629             (viewRect.width() - naturalSize.width) / 2,
630             (viewRect.height() - naturalSize.height) / 2,
631             naturalSize.width,
632             naturalSize.height
633         };
634         gtk_widget_size_allocate(priv->authenticationDialog, &childAllocation);
635     }
636
637     DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(priv->pageProxy->drawingArea());
638
639 #if USE(REDIRECTED_XCOMPOSITE_WINDOW)
640     if (sizeChanged && priv->redirectedWindow && drawingArea && drawingArea->isInAcceleratedCompositingMode())
641         priv->redirectedWindow->resize(viewRect.size());
642 #endif
643
644     if (drawingArea)
645         drawingArea->setSize(viewRect.size(), IntSize(), IntSize());
646
647 #if !GTK_CHECK_VERSION(3, 13, 4)
648     webkitWebViewBaseNotifyResizerSize(webViewBase);
649 #endif
650 }
651
652 static void webkitWebViewBaseSizeAllocate(GtkWidget* widget, GtkAllocation* allocation)
653 {
654     bool sizeChanged = gtk_widget_get_allocated_width(widget) != allocation->width
655                        || gtk_widget_get_allocated_height(widget) != allocation->height;
656
657     GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->size_allocate(widget, allocation);
658
659     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
660     if (sizeChanged && !gtk_widget_get_mapped(widget)) {
661         webViewBase->priv->needsResizeOnMap = true;
662         return;
663     }
664
665     resizeWebKitWebViewBaseFromAllocation(webViewBase, allocation, sizeChanged);
666 }
667
668 static void webkitWebViewBaseMap(GtkWidget* widget)
669 {
670     GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->map(widget);
671
672     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
673     WebKitWebViewBasePrivate* priv = webViewBase->priv;
674     if (!priv->isVisible) {
675         priv->isVisible = true;
676         priv->pageProxy->viewStateDidChange(ViewState::IsVisible);
677     }
678
679     if (!priv->needsResizeOnMap)
680         return;
681
682     GtkAllocation allocation;
683     gtk_widget_get_allocation(widget, &allocation);
684     resizeWebKitWebViewBaseFromAllocation(webViewBase, &allocation, true /* sizeChanged */);
685     priv->needsResizeOnMap = false;
686 }
687
688 static void webkitWebViewBaseUnmap(GtkWidget* widget)
689 {
690     GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->unmap(widget);
691
692     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
693     if (priv->isVisible) {
694         priv->isVisible = false;
695         priv->pageProxy->viewStateDidChange(ViewState::IsVisible);
696     }
697 }
698
699 static gboolean webkitWebViewBaseFocusInEvent(GtkWidget* widget, GdkEventFocus* event)
700 {
701     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
702     webkitWebViewBaseSetFocus(webViewBase, true);
703     webViewBase->priv->inputMethodFilter.notifyFocusedIn();
704
705     return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->focus_in_event(widget, event);
706 }
707
708 static gboolean webkitWebViewBaseFocusOutEvent(GtkWidget* widget, GdkEventFocus* event)
709 {
710     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
711     webkitWebViewBaseSetFocus(webViewBase, false);
712     webViewBase->priv->inputMethodFilter.notifyFocusedOut();
713
714     return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->focus_out_event(widget, event);
715 }
716
717 static gboolean webkitWebViewBaseKeyPressEvent(GtkWidget* widget, GdkEventKey* event)
718 {
719     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
720     WebKitWebViewBasePrivate* priv = webViewBase->priv;
721
722     if (priv->authenticationDialog)
723         return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_press_event(widget, event);
724
725 #if ENABLE(FULLSCREEN_API)
726     if (priv->fullScreenModeActive) {
727         switch (event->keyval) {
728         case GDK_KEY_Escape:
729         case GDK_KEY_f:
730         case GDK_KEY_F:
731             priv->pageProxy->fullScreenManager()->requestExitFullScreen();
732             return TRUE;
733         default:
734             break;
735         }
736     }
737 #endif
738
739     // Since WebProcess key event handling is not synchronous, handle the event in two passes.
740     // When WebProcess processes the input event, it will call PageClientImpl::doneWithKeyEvent
741     // with event handled status which determines whether to pass the input event to parent or not
742     // using gtk_main_do_event().
743     if (priv->shouldForwardNextKeyEvent) {
744         priv->shouldForwardNextKeyEvent = FALSE;
745         return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_press_event(widget, event);
746     }
747     priv->inputMethodFilter.filterKeyEvent(event);
748     return TRUE;
749 }
750
751 static gboolean webkitWebViewBaseKeyReleaseEvent(GtkWidget* widget, GdkEventKey* event)
752 {
753     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
754     WebKitWebViewBasePrivate* priv = webViewBase->priv;
755
756     if (priv->shouldForwardNextKeyEvent) {
757         priv->shouldForwardNextKeyEvent = FALSE;
758         return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->key_release_event(widget, event);
759     }
760     priv->inputMethodFilter.filterKeyEvent(event);
761     return TRUE;
762 }
763
764 static gboolean webkitWebViewBaseButtonPressEvent(GtkWidget* widget, GdkEventButton* buttonEvent)
765 {
766     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
767     WebKitWebViewBasePrivate* priv = webViewBase->priv;
768
769     if (priv->authenticationDialog)
770         return TRUE;
771
772     gtk_widget_grab_focus(widget);
773
774     priv->inputMethodFilter.notifyMouseButtonPress();
775
776     // For double and triple clicks GDK sends both a normal button press event
777     // and a specific type (like GDK_2BUTTON_PRESS). If we detect a special press
778     // coming up, ignore this event as it certainly generated the double or triple
779     // click. The consequence of not eating this event is two DOM button press events
780     // are generated.
781     GUniquePtr<GdkEvent> nextEvent(gdk_event_peek());
782     if (nextEvent && (nextEvent->any.type == GDK_2BUTTON_PRESS || nextEvent->any.type == GDK_3BUTTON_PRESS))
783         return TRUE;
784
785     // If it's a right click event save it as a possible context menu event.
786     if (buttonEvent->button == 3)
787         priv->contextMenuEvent.reset(gdk_event_copy(reinterpret_cast<GdkEvent*>(buttonEvent)));
788
789     priv->pageProxy->handleMouseEvent(NativeWebMouseEvent(reinterpret_cast<GdkEvent*>(buttonEvent),
790         priv->clickCounter.currentClickCountForGdkButtonEvent(buttonEvent)));
791     return TRUE;
792 }
793
794 static gboolean webkitWebViewBaseButtonReleaseEvent(GtkWidget* widget, GdkEventButton* event)
795 {
796     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
797     WebKitWebViewBasePrivate* priv = webViewBase->priv;
798
799     if (priv->authenticationDialog)
800         return TRUE;
801
802     gtk_widget_grab_focus(widget);
803     priv->pageProxy->handleMouseEvent(NativeWebMouseEvent(reinterpret_cast<GdkEvent*>(event), 0 /* currentClickCount */));
804
805     return TRUE;
806 }
807
808 static gboolean webkitWebViewBaseScrollEvent(GtkWidget* widget, GdkEventScroll* event)
809 {
810     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
811     WebKitWebViewBasePrivate* priv = webViewBase->priv;
812
813     if (priv->authenticationDialog)
814         return TRUE;
815
816     priv->pageProxy->handleWheelEvent(NativeWebWheelEvent(reinterpret_cast<GdkEvent*>(event)));
817
818     return TRUE;
819 }
820
821 static gboolean webkitWebViewBaseMotionNotifyEvent(GtkWidget* widget, GdkEventMotion* event)
822 {
823     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
824     WebKitWebViewBasePrivate* priv = webViewBase->priv;
825
826     if (priv->authenticationDialog)
827         return TRUE;
828
829     priv->pageProxy->handleMouseEvent(NativeWebMouseEvent(reinterpret_cast<GdkEvent*>(event), 0 /* currentClickCount */));
830
831     return TRUE;
832 }
833
834 static void appendTouchEvent(Vector<WebPlatformTouchPoint>& touchPoints, const GdkEvent* event, WebPlatformTouchPoint::TouchPointState state)
835 {
836     gdouble x, y;
837     gdk_event_get_coords(event, &x, &y);
838
839     gdouble xRoot, yRoot;
840     gdk_event_get_root_coords(event, &xRoot, &yRoot);
841
842     uint32_t identifier = GPOINTER_TO_UINT(gdk_event_get_event_sequence(event));
843     touchPoints.uncheckedAppend(WebPlatformTouchPoint(identifier, state, IntPoint(xRoot, yRoot), IntPoint(x, y)));
844 }
845
846 static inline WebPlatformTouchPoint::TouchPointState touchPointStateForEvents(const GdkEvent* current, const GdkEvent* event)
847 {
848     if (gdk_event_get_event_sequence(current) != gdk_event_get_event_sequence(event))
849         return WebPlatformTouchPoint::TouchStationary;
850
851     switch (current->type) {
852     case GDK_TOUCH_UPDATE:
853         return WebPlatformTouchPoint::TouchMoved;
854     case GDK_TOUCH_BEGIN:
855         return WebPlatformTouchPoint::TouchPressed;
856     case GDK_TOUCH_END:
857         return WebPlatformTouchPoint::TouchReleased;
858     default:
859         return WebPlatformTouchPoint::TouchStationary;
860     }
861 }
862
863 static void webkitWebViewBaseGetTouchPointsForEvent(WebKitWebViewBase* webViewBase, GdkEvent* event, Vector<WebPlatformTouchPoint>& touchPoints)
864 {
865     WebKitWebViewBasePrivate* priv = webViewBase->priv;
866     touchPoints.reserveInitialCapacity(event->type == GDK_TOUCH_END ? priv->touchEvents.size() + 1 : priv->touchEvents.size());
867
868     for (const auto& it : priv->touchEvents)
869         appendTouchEvent(touchPoints, it.value.get(), touchPointStateForEvents(it.value.get(), event));
870
871     // Touch was already removed from the TouchEventsMap, add it here.
872     if (event->type == GDK_TOUCH_END)
873         appendTouchEvent(touchPoints, event, WebPlatformTouchPoint::TouchReleased);
874 }
875
876 static gboolean webkitWebViewBaseTouchEvent(GtkWidget* widget, GdkEventTouch* event)
877 {
878     WebKitWebViewBase* webViewBase = WEBKIT_WEB_VIEW_BASE(widget);
879     WebKitWebViewBasePrivate* priv = webViewBase->priv;
880
881     if (priv->authenticationDialog)
882         return TRUE;
883
884     GdkEvent* touchEvent = reinterpret_cast<GdkEvent*>(event);
885
886 #if HAVE(GTK_GESTURES)
887     GestureController& gestureController = webkitWebViewBaseGestureController(webViewBase);
888     if (gestureController.isProcessingGestures()) {
889         // If we are already processing gestures is because the WebProcess didn't handle the
890         // BEGIN touch event, so pass subsequent events to the GestureController.
891         gestureController.handleEvent(touchEvent);
892         return TRUE;
893     }
894 #endif
895
896     uint32_t sequence = GPOINTER_TO_UINT(gdk_event_get_event_sequence(touchEvent));
897     switch (touchEvent->type) {
898     case GDK_TOUCH_BEGIN: {
899         ASSERT(!priv->touchEvents.contains(sequence));
900         GUniquePtr<GdkEvent> event(gdk_event_copy(touchEvent));
901         priv->touchEvents.add(sequence, WTF::move(event));
902         break;
903     }
904     case GDK_TOUCH_UPDATE: {
905         auto it = priv->touchEvents.find(sequence);
906         ASSERT(it != priv->touchEvents.end());
907         it->value.reset(gdk_event_copy(touchEvent));
908         break;
909     }
910     case GDK_TOUCH_END:
911         ASSERT(priv->touchEvents.contains(sequence));
912         priv->touchEvents.remove(sequence);
913         break;
914     default:
915         break;
916     }
917
918     Vector<WebPlatformTouchPoint> touchPoints;
919     webkitWebViewBaseGetTouchPointsForEvent(webViewBase, touchEvent, touchPoints);
920     priv->pageProxy->handleTouchEvent(NativeWebTouchEvent(reinterpret_cast<GdkEvent*>(event), WTF::move(touchPoints)));
921
922     return TRUE;
923 }
924
925 #if HAVE(GTK_GESTURES)
926 GestureController& webkitWebViewBaseGestureController(WebKitWebViewBase* webViewBase)
927 {
928     WebKitWebViewBasePrivate* priv = webViewBase->priv;
929     if (!priv->gestureController)
930         priv->gestureController = std::make_unique<GestureController>(*priv->pageProxy);
931     return *priv->gestureController;
932 }
933 #endif
934
935 static gboolean webkitWebViewBaseQueryTooltip(GtkWidget* widget, gint /* x */, gint /* y */, gboolean keyboardMode, GtkTooltip* tooltip)
936 {
937     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
938
939     if (keyboardMode) {
940         // TODO: https://bugs.webkit.org/show_bug.cgi?id=61732.
941         notImplemented();
942         return FALSE;
943     }
944
945     if (priv->tooltipText.length() <= 0)
946         return FALSE;
947
948     if (!priv->tooltipArea.isEmpty()) {
949         GdkRectangle area = priv->tooltipArea;
950         gtk_tooltip_set_tip_area(tooltip, &area);
951     } else
952         gtk_tooltip_set_tip_area(tooltip, 0);
953     gtk_tooltip_set_text(tooltip, priv->tooltipText.data());
954
955     return TRUE;
956 }
957
958 #if ENABLE(DRAG_SUPPORT)
959 static void webkitWebViewBaseDragDataGet(GtkWidget* widget, GdkDragContext* context, GtkSelectionData* selectionData, guint info, guint /* time */)
960 {
961     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
962     ASSERT(priv->dragAndDropHandler);
963     priv->dragAndDropHandler->fillDragData(context, selectionData, info);
964 }
965
966 static void webkitWebViewBaseDragEnd(GtkWidget* widget, GdkDragContext* context)
967 {
968     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
969     ASSERT(priv->dragAndDropHandler);
970     priv->dragAndDropHandler->finishDrag(context);
971 }
972
973 static void webkitWebViewBaseDragDataReceived(GtkWidget* widget, GdkDragContext* context, gint /* x */, gint /* y */, GtkSelectionData* selectionData, guint info, guint time)
974 {
975     webkitWebViewBaseDragAndDropHandler(WEBKIT_WEB_VIEW_BASE(widget)).dragEntered(context, selectionData, info, time);
976 }
977 #endif // ENABLE(DRAG_SUPPORT)
978
979 static AtkObject* webkitWebViewBaseGetAccessible(GtkWidget* widget)
980 {
981     // If the socket has already been created and embedded a plug ID, return it.
982     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
983     if (priv->accessible && atk_socket_is_occupied(ATK_SOCKET(priv->accessible.get())))
984         return priv->accessible.get();
985
986     // Create the accessible object and associate it to the widget.
987     if (!priv->accessible) {
988         priv->accessible = adoptGRef(ATK_OBJECT(webkitWebViewBaseAccessibleNew(widget)));
989
990         // Set the parent not to break bottom-up navigation.
991         GtkWidget* parentWidget = gtk_widget_get_parent(widget);
992         AtkObject* axParent = parentWidget ? gtk_widget_get_accessible(parentWidget) : 0;
993         if (axParent)
994             atk_object_set_parent(priv->accessible.get(), axParent);
995     }
996
997     // Try to embed the plug in the socket, if posssible.
998     String plugID = priv->pageProxy->accessibilityPlugID();
999     if (plugID.isNull())
1000         return priv->accessible.get();
1001
1002     atk_socket_embed(ATK_SOCKET(priv->accessible.get()), const_cast<gchar*>(plugID.utf8().data()));
1003
1004     return priv->accessible.get();
1005 }
1006
1007 #if ENABLE(DRAG_SUPPORT)
1008 static gboolean webkitWebViewBaseDragMotion(GtkWidget* widget, GdkDragContext* context, gint x, gint y, guint time)
1009 {
1010     webkitWebViewBaseDragAndDropHandler(WEBKIT_WEB_VIEW_BASE(widget)).dragMotion(context, IntPoint(x, y), time);
1011     return TRUE;
1012 }
1013
1014 static void webkitWebViewBaseDragLeave(GtkWidget* widget, GdkDragContext* context, guint /* time */)
1015 {
1016     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1017     ASSERT(priv->dragAndDropHandler);
1018     priv->dragAndDropHandler->dragLeave(context);
1019 }
1020
1021 static gboolean webkitWebViewBaseDragDrop(GtkWidget* widget, GdkDragContext* context, gint x, gint y, guint time)
1022 {
1023     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1024     ASSERT(priv->dragAndDropHandler);
1025     return priv->dragAndDropHandler->drop(context, IntPoint(x, y), time);
1026 }
1027 #endif // ENABLE(DRAG_SUPPORT)
1028
1029 static void webkitWebViewBaseParentSet(GtkWidget* widget, GtkWidget* /* oldParent */)
1030 {
1031     if (!gtk_widget_get_parent(widget))
1032         webkitWebViewBaseSetToplevelOnScreenWindow(WEBKIT_WEB_VIEW_BASE(widget), 0);
1033 }
1034
1035 static gboolean webkitWebViewBaseFocus(GtkWidget* widget, GtkDirectionType direction)
1036 {
1037     // If the authentication dialog is active, we need to forward focus events there. This
1038     // ensures that you can tab between elements in the box.
1039     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1040     if (priv->authenticationDialog) {
1041         gboolean returnValue;
1042         g_signal_emit_by_name(priv->authenticationDialog, "focus", direction, &returnValue);
1043         return returnValue;
1044     }
1045
1046     return GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->focus(widget, direction);
1047 }
1048
1049 static void webkitWebViewBaseDestroy(GtkWidget* widget)
1050 {
1051     WebKitWebViewBasePrivate* priv = WEBKIT_WEB_VIEW_BASE(widget)->priv;
1052     if (priv->authenticationDialog)
1053         gtk_widget_destroy(priv->authenticationDialog);
1054
1055     GTK_WIDGET_CLASS(webkit_web_view_base_parent_class)->destroy(widget);
1056 }
1057
1058 static void webkit_web_view_base_class_init(WebKitWebViewBaseClass* webkitWebViewBaseClass)
1059 {
1060     GtkWidgetClass* widgetClass = GTK_WIDGET_CLASS(webkitWebViewBaseClass);
1061     widgetClass->realize = webkitWebViewBaseRealize;
1062     widgetClass->unrealize = webkitWebViewBaseUnrealize;
1063     widgetClass->draw = webkitWebViewBaseDraw;
1064     widgetClass->size_allocate = webkitWebViewBaseSizeAllocate;
1065     widgetClass->map = webkitWebViewBaseMap;
1066     widgetClass->unmap = webkitWebViewBaseUnmap;
1067     widgetClass->focus = webkitWebViewBaseFocus;
1068     widgetClass->focus_in_event = webkitWebViewBaseFocusInEvent;
1069     widgetClass->focus_out_event = webkitWebViewBaseFocusOutEvent;
1070     widgetClass->key_press_event = webkitWebViewBaseKeyPressEvent;
1071     widgetClass->key_release_event = webkitWebViewBaseKeyReleaseEvent;
1072     widgetClass->button_press_event = webkitWebViewBaseButtonPressEvent;
1073     widgetClass->button_release_event = webkitWebViewBaseButtonReleaseEvent;
1074     widgetClass->scroll_event = webkitWebViewBaseScrollEvent;
1075     widgetClass->motion_notify_event = webkitWebViewBaseMotionNotifyEvent;
1076     widgetClass->touch_event = webkitWebViewBaseTouchEvent;
1077     widgetClass->query_tooltip = webkitWebViewBaseQueryTooltip;
1078 #if ENABLE(DRAG_SUPPORT)
1079     widgetClass->drag_end = webkitWebViewBaseDragEnd;
1080     widgetClass->drag_data_get = webkitWebViewBaseDragDataGet;
1081     widgetClass->drag_motion = webkitWebViewBaseDragMotion;
1082     widgetClass->drag_leave = webkitWebViewBaseDragLeave;
1083     widgetClass->drag_drop = webkitWebViewBaseDragDrop;
1084     widgetClass->drag_data_received = webkitWebViewBaseDragDataReceived;
1085 #endif // ENABLE(DRAG_SUPPORT)
1086     widgetClass->get_accessible = webkitWebViewBaseGetAccessible;
1087     widgetClass->parent_set = webkitWebViewBaseParentSet;
1088     widgetClass->destroy = webkitWebViewBaseDestroy;
1089
1090     GObjectClass* gobjectClass = G_OBJECT_CLASS(webkitWebViewBaseClass);
1091     gobjectClass->constructed = webkitWebViewBaseConstructed;
1092     gobjectClass->dispose = webkitWebViewBaseDispose;
1093
1094     GtkContainerClass* containerClass = GTK_CONTAINER_CLASS(webkitWebViewBaseClass);
1095     containerClass->add = webkitWebViewBaseContainerAdd;
1096     containerClass->remove = webkitWebViewBaseContainerRemove;
1097     containerClass->forall = webkitWebViewBaseContainerForall;
1098 }
1099
1100 WebKitWebViewBase* webkitWebViewBaseCreate(WebProcessPool* context, WebPreferences* preferences, WebPageGroup* pageGroup, WebUserContentControllerProxy* userContentController, WebPageProxy* relatedPage)
1101 {
1102     WebKitWebViewBase* webkitWebViewBase = WEBKIT_WEB_VIEW_BASE(g_object_new(WEBKIT_TYPE_WEB_VIEW_BASE, NULL));
1103     webkitWebViewBaseCreateWebPage(webkitWebViewBase, context, preferences, pageGroup, userContentController, relatedPage);
1104     return webkitWebViewBase;
1105 }
1106
1107 GtkIMContext* webkitWebViewBaseGetIMContext(WebKitWebViewBase* webkitWebViewBase)
1108 {
1109     return webkitWebViewBase->priv->inputMethodFilter.context();
1110 }
1111
1112 WebPageProxy* webkitWebViewBaseGetPage(WebKitWebViewBase* webkitWebViewBase)
1113 {
1114     return webkitWebViewBase->priv->pageProxy.get();
1115 }
1116
1117 #if HAVE(GTK_SCALE_FACTOR)
1118 static void deviceScaleFactorChanged(WebKitWebViewBase* webkitWebViewBase)
1119 {
1120     webkitWebViewBase->priv->pageProxy->setIntrinsicDeviceScaleFactor(gtk_widget_get_scale_factor(GTK_WIDGET(webkitWebViewBase)));
1121 }
1122 #endif // HAVE(GTK_SCALE_FACTOR)
1123
1124 void webkitWebViewBaseCreateWebPage(WebKitWebViewBase* webkitWebViewBase, WebProcessPool* context, WebPreferences* preferences, WebPageGroup* pageGroup, WebUserContentControllerProxy* userContentController, WebPageProxy* relatedPage)
1125 {
1126     WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1127
1128 #if PLATFORM(WAYLAND)
1129     // FIXME: Accelerated compositing under Wayland is not yet supported.
1130     // https://bugs.webkit.org/show_bug.cgi?id=115803
1131     GdkDisplay* display = gdk_display_manager_get_default_display(gdk_display_manager_get());
1132     if (GDK_IS_WAYLAND_DISPLAY(display))
1133         preferences->setAcceleratedCompositingEnabled(false);
1134 #endif
1135
1136     WebPageConfiguration webPageConfiguration;
1137     webPageConfiguration.preferences = preferences;
1138     webPageConfiguration.pageGroup = pageGroup;
1139     webPageConfiguration.relatedPage = relatedPage;
1140     webPageConfiguration.userContentController = userContentController;
1141     priv->pageProxy = context->createWebPage(*priv->pageClient, WTF::move(webPageConfiguration));
1142     priv->pageProxy->initializeWebPage();
1143
1144     priv->inputMethodFilter.setPage(priv->pageProxy.get());
1145
1146 #if HAVE(GTK_SCALE_FACTOR)
1147     // We attach this here, because changes in scale factor are passed directly to the page proxy.
1148     priv->pageProxy->setIntrinsicDeviceScaleFactor(gtk_widget_get_scale_factor(GTK_WIDGET(webkitWebViewBase)));
1149     g_signal_connect(webkitWebViewBase, "notify::scale-factor", G_CALLBACK(deviceScaleFactorChanged), nullptr);
1150 #endif
1151 }
1152
1153 void webkitWebViewBaseSetTooltipText(WebKitWebViewBase* webViewBase, const char* tooltip)
1154 {
1155     WebKitWebViewBasePrivate* priv = webViewBase->priv;
1156     if (tooltip && tooltip[0] != '\0') {
1157         priv->tooltipText = tooltip;
1158         gtk_widget_set_has_tooltip(GTK_WIDGET(webViewBase), TRUE);
1159     } else {
1160         priv->tooltipText = "";
1161         gtk_widget_set_has_tooltip(GTK_WIDGET(webViewBase), FALSE);
1162     }
1163
1164     gtk_widget_trigger_tooltip_query(GTK_WIDGET(webViewBase));
1165 }
1166
1167 void webkitWebViewBaseSetTooltipArea(WebKitWebViewBase* webViewBase, const IntRect& tooltipArea)
1168 {
1169     webViewBase->priv->tooltipArea = tooltipArea;
1170 }
1171
1172 #if ENABLE(DRAG_SUPPORT)
1173 DragAndDropHandler& webkitWebViewBaseDragAndDropHandler(WebKitWebViewBase* webViewBase)
1174 {
1175     WebKitWebViewBasePrivate* priv = webViewBase->priv;
1176     if (!priv->dragAndDropHandler)
1177         priv->dragAndDropHandler = std::make_unique<DragAndDropHandler>(*priv->pageProxy);
1178     return *priv->dragAndDropHandler;
1179 }
1180 #endif // ENABLE(DRAG_SUPPORT)
1181
1182 void webkitWebViewBaseForwardNextKeyEvent(WebKitWebViewBase* webkitWebViewBase)
1183 {
1184     webkitWebViewBase->priv->shouldForwardNextKeyEvent = TRUE;
1185 }
1186
1187 void webkitWebViewBaseEnterFullScreen(WebKitWebViewBase* webkitWebViewBase)
1188 {
1189 #if ENABLE(FULLSCREEN_API)
1190     WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1191     if (priv->fullScreenModeActive)
1192         return;
1193
1194     if (!priv->fullScreenClient.willEnterFullScreen())
1195         return;
1196
1197     WebFullScreenManagerProxy* fullScreenManagerProxy = priv->pageProxy->fullScreenManager();
1198     fullScreenManagerProxy->willEnterFullScreen();
1199
1200     GtkWidget* topLevelWindow = gtk_widget_get_toplevel(GTK_WIDGET(webkitWebViewBase));
1201     if (gtk_widget_is_toplevel(topLevelWindow))
1202         gtk_window_fullscreen(GTK_WINDOW(topLevelWindow));
1203     fullScreenManagerProxy->didEnterFullScreen();
1204     priv->fullScreenModeActive = true;
1205 #endif
1206 }
1207
1208 void webkitWebViewBaseExitFullScreen(WebKitWebViewBase* webkitWebViewBase)
1209 {
1210 #if ENABLE(FULLSCREEN_API)
1211     WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1212     if (!priv->fullScreenModeActive)
1213         return;
1214
1215     if (!priv->fullScreenClient.willExitFullScreen())
1216         return;
1217
1218     WebFullScreenManagerProxy* fullScreenManagerProxy = priv->pageProxy->fullScreenManager();
1219     fullScreenManagerProxy->willExitFullScreen();
1220
1221     GtkWidget* topLevelWindow = gtk_widget_get_toplevel(GTK_WIDGET(webkitWebViewBase));
1222     if (gtk_widget_is_toplevel(topLevelWindow))
1223         gtk_window_unfullscreen(GTK_WINDOW(topLevelWindow));
1224     fullScreenManagerProxy->didExitFullScreen();
1225     priv->fullScreenModeActive = false;
1226 #endif
1227 }
1228
1229 void webkitWebViewBaseInitializeFullScreenClient(WebKitWebViewBase* webkitWebViewBase, const WKFullScreenClientGtkBase* wkClient)
1230 {
1231     webkitWebViewBase->priv->fullScreenClient.initialize(wkClient);
1232 }
1233
1234 void webkitWebViewBaseSetInspectorViewSize(WebKitWebViewBase* webkitWebViewBase, unsigned size)
1235 {
1236     if (webkitWebViewBase->priv->inspectorViewSize == size)
1237         return;
1238     webkitWebViewBase->priv->inspectorViewSize = size;
1239     if (webkitWebViewBase->priv->inspectorView)
1240         gtk_widget_queue_resize_no_redraw(GTK_WIDGET(webkitWebViewBase));
1241 }
1242
1243 void webkitWebViewBaseSetActiveContextMenuProxy(WebKitWebViewBase* webkitWebViewBase, WebContextMenuProxyGtk* contextMenuProxy)
1244 {
1245     webkitWebViewBase->priv->activeContextMenuProxy = contextMenuProxy;
1246 }
1247
1248 WebContextMenuProxyGtk* webkitWebViewBaseGetActiveContextMenuProxy(WebKitWebViewBase* webkitWebViewBase)
1249 {
1250     return webkitWebViewBase->priv->activeContextMenuProxy;
1251 }
1252
1253 GdkEvent* webkitWebViewBaseTakeContextMenuEvent(WebKitWebViewBase* webkitWebViewBase)
1254 {
1255     return webkitWebViewBase->priv->contextMenuEvent.release();
1256 }
1257
1258 void webkitWebViewBaseSetFocus(WebKitWebViewBase* webViewBase, bool focused)
1259 {
1260     WebKitWebViewBasePrivate* priv = webViewBase->priv;
1261     if (priv->isFocused == focused)
1262         return;
1263
1264     unsigned viewStateFlags = ViewState::IsFocused;
1265     priv->isFocused = focused;
1266
1267     // If the view has received the focus and the window is not active
1268     // mark the current window as active now. This can happen if the
1269     // toplevel window is a GTK_WINDOW_POPUP and the focus has been
1270     // set programatically like WebKitTestRunner does, because POPUP
1271     // can't be focused.
1272     if (priv->isFocused && !priv->isInWindowActive) {
1273         priv->isInWindowActive = true;
1274         viewStateFlags |= ViewState::WindowIsActive;
1275     }
1276     priv->pageProxy->viewStateDidChange(viewStateFlags);
1277 }
1278
1279 bool webkitWebViewBaseIsInWindowActive(WebKitWebViewBase* webViewBase)
1280 {
1281     return webViewBase->priv->isInWindowActive;
1282 }
1283
1284 bool webkitWebViewBaseIsFocused(WebKitWebViewBase* webViewBase)
1285 {
1286     return webViewBase->priv->isFocused;
1287 }
1288
1289 bool webkitWebViewBaseIsVisible(WebKitWebViewBase* webViewBase)
1290 {
1291     return webViewBase->priv->isVisible;
1292 }
1293
1294 bool webkitWebViewBaseIsInWindow(WebKitWebViewBase* webViewBase)
1295 {
1296     return webViewBase->priv->toplevelOnScreenWindow;
1297 }
1298
1299 bool webkitWebViewBaseIsWindowVisible(WebKitWebViewBase* webViewBase)
1300 {
1301     return webViewBase->priv->isWindowVisible;
1302 }
1303
1304 void webkitWebViewBaseSetDownloadRequestHandler(WebKitWebViewBase* webViewBase, WebKitWebViewBaseDownloadRequestHandler downloadHandler)
1305 {
1306     webViewBase->priv->downloadHandler = downloadHandler;
1307 }
1308
1309 void webkitWebViewBaseHandleDownloadRequest(WebKitWebViewBase* webViewBase, DownloadProxy* download)
1310 {
1311     if (webViewBase->priv->downloadHandler)
1312         webViewBase->priv->downloadHandler(webViewBase, download);
1313 }
1314
1315 void webkitWebViewBaseSetInputMethodState(WebKitWebViewBase* webkitWebViewBase, bool enabled)
1316 {
1317     webkitWebViewBase->priv->inputMethodFilter.setEnabled(enabled);
1318 }
1319
1320 void webkitWebViewBaseUpdateTextInputState(WebKitWebViewBase* webkitWebViewBase)
1321 {
1322     webkitWebViewBase->priv->inputMethodFilter.setCursorRect(webkitWebViewBase->priv->pageProxy->editorState().cursorRect);
1323 }
1324
1325 void webkitWebViewBaseResetClickCounter(WebKitWebViewBase* webkitWebViewBase)
1326 {
1327     webkitWebViewBase->priv->clickCounter.reset();
1328 }
1329
1330 void webkitWebViewBaseEnterAcceleratedCompositingMode(WebKitWebViewBase* webkitWebViewBase)
1331 {
1332 #if USE(REDIRECTED_XCOMPOSITE_WINDOW)
1333     WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1334     if (!priv->redirectedWindow)
1335         return;
1336     DrawingAreaProxyImpl* drawingArea = static_cast<DrawingAreaProxyImpl*>(priv->pageProxy->drawingArea());
1337     if (!drawingArea)
1338         return;
1339
1340     priv->redirectedWindow->resize(drawingArea->size());
1341     // Force a resize to ensure the new redirected window size is used by the WebProcess.
1342     drawingArea->forceResize();
1343 #else
1344     UNUSED_PARAM(webkitWebViewBase);
1345 #endif
1346 }
1347
1348 void webkitWebViewBaseExitAcceleratedCompositingMode(WebKitWebViewBase* webkitWebViewBase)
1349 {
1350 #if USE(REDIRECTED_XCOMPOSITE_WINDOW)
1351     WebKitWebViewBasePrivate* priv = webkitWebViewBase->priv;
1352     if (priv->redirectedWindow)
1353         priv->redirectedWindow->resize(IntSize());
1354 #else
1355     UNUSED_PARAM(webkitWebViewBase);
1356 #endif
1357 }