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