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