Implement DownloadMonitor to prevent long-running slow downloads from background...
[WebKit-https.git] / Source / WebKit / UIProcess / API / gtk / PageClientImpl.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  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
19  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
25  * THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include "config.h"
29 #include "PageClientImpl.h"
30
31 #include "DrawingAreaProxyCoordinatedGraphics.h"
32 #include "NativeWebKeyboardEvent.h"
33 #include "NativeWebMouseEvent.h"
34 #include "NativeWebWheelEvent.h"
35 #include "ViewSnapshotStore.h"
36 #include "WebColorPickerGtk.h"
37 #include "WebContextMenuProxyGtk.h"
38 #include "WebEventFactory.h"
39 #include "WebKitColorChooser.h"
40 #include "WebKitPopupMenu.h"
41 #include "WebKitWebViewBasePrivate.h"
42 #include "WebKitWebViewPrivate.h"
43 #include "WebPageProxy.h"
44 #include "WebProcessPool.h"
45 #include <WebCore/CairoUtilities.h>
46 #include <WebCore/Cursor.h>
47 #include <WebCore/DOMPasteAccess.h>
48 #include <WebCore/EventNames.h>
49 #include <WebCore/GtkUtilities.h>
50 #include <WebCore/NotImplemented.h>
51 #include <WebCore/RefPtrCairo.h>
52 #include <wtf/Compiler.h>
53 #include <wtf/text/CString.h>
54 #include <wtf/text/WTFString.h>
55
56 namespace WebKit {
57 using namespace WebCore;
58
59 PageClientImpl::PageClientImpl(GtkWidget* viewWidget)
60     : m_viewWidget(viewWidget)
61 {
62 }
63
64 // PageClient's pure virtual functions
65 std::unique_ptr<DrawingAreaProxy> PageClientImpl::createDrawingAreaProxy(WebProcessProxy& process)
66 {
67     return std::make_unique<DrawingAreaProxyCoordinatedGraphics>(*webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(m_viewWidget)), process);
68 }
69
70 void PageClientImpl::setViewNeedsDisplay(const WebCore::Region& region)
71 {
72     WebPageProxy* pageProxy = webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
73     ASSERT(pageProxy);
74
75     // During the gesture, the page may be displayed with an offset.
76     // To avoid visual glitches, redraw the whole page.
77     if (pageProxy->isShowingNavigationGestureSnapshot()) {
78         gtk_widget_queue_draw(m_viewWidget);
79         return;
80     }
81
82     gtk_widget_queue_draw_region(m_viewWidget, toCairoRegion(region).get());
83 }
84
85 void PageClientImpl::requestScroll(const WebCore::FloatPoint&, const WebCore::IntPoint&, bool)
86 {
87     notImplemented();
88 }
89
90 WebCore::FloatPoint PageClientImpl::viewScrollPosition()
91 {
92     return { };
93 }
94
95 WebCore::IntSize PageClientImpl::viewSize()
96 {
97     auto* drawingArea = static_cast<DrawingAreaProxyCoordinatedGraphics*>(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(m_viewWidget))->drawingArea());
98     return drawingArea ? drawingArea->size() : IntSize();
99 }
100
101 bool PageClientImpl::isViewWindowActive()
102 {
103     return webkitWebViewBaseIsInWindowActive(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
104 }
105
106 bool PageClientImpl::isViewFocused()
107 {
108     return webkitWebViewBaseIsFocused(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
109 }
110
111 bool PageClientImpl::isViewVisible()
112 {
113     return webkitWebViewBaseIsVisible(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
114 }
115
116 bool PageClientImpl::isViewInWindow()
117 {
118     return webkitWebViewBaseIsInWindow(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
119 }
120
121 void PageClientImpl::PageClientImpl::processDidExit()
122 {
123     notImplemented();
124 }
125
126 void PageClientImpl::didRelaunchProcess()
127 {
128     webkitWebViewBaseDidRelaunchWebProcess(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
129 }
130
131 void PageClientImpl::toolTipChanged(const String&, const String& newToolTip)
132 {
133     webkitWebViewBaseSetTooltipText(WEBKIT_WEB_VIEW_BASE(m_viewWidget), newToolTip.utf8().data());
134 }
135
136 void PageClientImpl::setCursor(const WebCore::Cursor& cursor)
137 {
138     if (!gtk_widget_get_realized(m_viewWidget))
139         return;
140
141     // [GTK] Widget::setCursor() gets called frequently
142     // http://bugs.webkit.org/show_bug.cgi?id=16388
143     // Setting the cursor may be an expensive operation in some backends,
144     // so don't re-set the cursor if it's already set to the target value.
145     GdkWindow* window = gtk_widget_get_window(m_viewWidget);
146     GdkCursor* currentCursor = gdk_window_get_cursor(window);
147     GdkCursor* newCursor = cursor.platformCursor().get();
148     if (currentCursor != newCursor)
149         gdk_window_set_cursor(window, newCursor);
150 }
151
152 void PageClientImpl::setCursorHiddenUntilMouseMoves(bool /* hiddenUntilMouseMoves */)
153 {
154     notImplemented();
155 }
156
157 void PageClientImpl::didChangeViewportProperties(const WebCore::ViewportAttributes&)
158 {
159     notImplemented();
160 }
161
162 void PageClientImpl::registerEditCommand(Ref<WebEditCommandProxy>&& command, UndoOrRedo undoOrRedo)
163 {
164     m_undoController.registerEditCommand(WTFMove(command), undoOrRedo);
165 }
166
167 void PageClientImpl::clearAllEditCommands()
168 {
169     m_undoController.clearAllEditCommands();
170 }
171
172 bool PageClientImpl::canUndoRedo(UndoOrRedo undoOrRedo)
173 {
174     return m_undoController.canUndoRedo(undoOrRedo);
175 }
176
177 void PageClientImpl::executeUndoRedo(UndoOrRedo undoOrRedo)
178 {
179     m_undoController.executeUndoRedo(undoOrRedo);
180 }
181
182 FloatRect PageClientImpl::convertToDeviceSpace(const FloatRect& viewRect)
183 {
184     notImplemented();
185     return viewRect;
186 }
187
188 FloatRect PageClientImpl::convertToUserSpace(const FloatRect& viewRect)
189 {
190     notImplemented();
191     return viewRect;
192 }
193
194 IntPoint PageClientImpl::screenToRootView(const IntPoint& point)
195 {
196     IntPoint widgetPositionOnScreen = convertWidgetPointToScreenPoint(m_viewWidget, IntPoint());
197     IntPoint result(point);
198     result.move(-widgetPositionOnScreen.x(), -widgetPositionOnScreen.y());
199     return result;
200 }
201
202 IntRect PageClientImpl::rootViewToScreen(const IntRect& rect)
203 {
204     return IntRect(convertWidgetPointToScreenPoint(m_viewWidget, rect.location()), rect.size());
205 }
206
207 WebCore::IntPoint PageClientImpl::accessibilityScreenToRootView(const WebCore::IntPoint& point)
208 {
209     return screenToRootView(point);
210 }
211
212 WebCore::IntRect PageClientImpl::rootViewToAccessibilityScreen(const WebCore::IntRect& rect)    
213 {
214     return rootViewToScreen(rect);
215 }
216
217 void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool wasEventHandled)
218 {
219     if (wasEventHandled)
220         return;
221     if (event.isFakeEventForComposition())
222         return;
223
224     WebKitWebViewBase* webkitWebViewBase = WEBKIT_WEB_VIEW_BASE(m_viewWidget);
225     webkitWebViewBaseForwardNextKeyEvent(webkitWebViewBase);
226     gtk_main_do_event(event.nativeEvent());
227 }
228
229 RefPtr<WebPopupMenuProxy> PageClientImpl::createPopupMenuProxy(WebPageProxy& page)
230 {
231     if (WEBKIT_IS_WEB_VIEW(m_viewWidget))
232         return WebKitPopupMenu::create(m_viewWidget, page);
233     return WebPopupMenuProxyGtk::create(m_viewWidget, page);
234 }
235
236 Ref<WebContextMenuProxy> PageClientImpl::createContextMenuProxy(WebPageProxy& page, ContextMenuContextData&& context, const UserData& userData)
237 {
238     return WebContextMenuProxyGtk::create(m_viewWidget, page, WTFMove(context), userData);
239 }
240
241 RefPtr<WebColorPicker> PageClientImpl::createColorPicker(WebPageProxy* page, const WebCore::Color& color, const WebCore::IntRect& rect, Vector<WebCore::Color>&&)
242 {
243     if (WEBKIT_IS_WEB_VIEW(m_viewWidget))
244         return WebKitColorChooser::create(*page, color, rect);
245     return WebColorPickerGtk::create(*page, color, rect);
246 }
247
248 void PageClientImpl::enterAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
249 {
250     webkitWebViewBaseEnterAcceleratedCompositingMode(WEBKIT_WEB_VIEW_BASE(m_viewWidget), layerTreeContext);
251 }
252
253 void PageClientImpl::exitAcceleratedCompositingMode()
254 {
255     webkitWebViewBaseExitAcceleratedCompositingMode(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
256 }
257
258 void PageClientImpl::updateAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
259 {
260     webkitWebViewBaseUpdateAcceleratedCompositingMode(WEBKIT_WEB_VIEW_BASE(m_viewWidget), layerTreeContext);
261 }
262
263 void PageClientImpl::pageClosed()
264 {
265     webkitWebViewBasePageClosed(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
266 }
267
268 void PageClientImpl::preferencesDidChange()
269 {
270     notImplemented();
271 }
272
273 void PageClientImpl::selectionDidChange()
274 {
275     webkitWebViewBaseUpdateTextInputState(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
276     if (WEBKIT_IS_WEB_VIEW(m_viewWidget))
277         webkitWebViewSelectionDidChange(WEBKIT_WEB_VIEW(m_viewWidget));
278 }
279
280 RefPtr<ViewSnapshot> PageClientImpl::takeViewSnapshot()
281 {
282     return webkitWebViewBaseTakeViewSnapshot(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
283 }
284
285 void PageClientImpl::didChangeContentSize(const IntSize& size)
286 {
287     webkitWebViewBaseSetContentsSize(WEBKIT_WEB_VIEW_BASE(m_viewWidget), size);
288 }
289
290 #if ENABLE(DRAG_SUPPORT)
291 void PageClientImpl::startDrag(Ref<SelectionData>&& selection, DragOperation dragOperation, RefPtr<ShareableBitmap>&& dragImage)
292 {
293     WebKitWebViewBase* webView = WEBKIT_WEB_VIEW_BASE(m_viewWidget);
294     webkitWebViewBaseDragAndDropHandler(webView).startDrag(WTFMove(selection), dragOperation, WTFMove(dragImage));
295
296     // A drag starting should prevent a double-click from happening. This might
297     // happen if a drag is followed very quickly by another click (like in the WTR).
298     webkitWebViewBaseResetClickCounter(webView);
299 }
300 #endif
301
302 void PageClientImpl::handleDownloadRequest(DownloadProxy& download)
303 {
304     if (WEBKIT_IS_WEB_VIEW(m_viewWidget))
305         webkitWebViewHandleDownloadRequest(WEBKIT_WEB_VIEW(m_viewWidget), &download);
306 }
307
308 void PageClientImpl::didCommitLoadForMainFrame(const String& /* mimeType */, bool /* useCustomContentProvider */ )
309 {
310     webkitWebViewBaseResetClickCounter(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
311 }
312
313 #if ENABLE(FULLSCREEN_API)
314 WebFullScreenManagerProxyClient& PageClientImpl::fullScreenManagerProxyClient()
315 {
316     return *this;
317 }
318
319 void PageClientImpl::closeFullScreenManager()
320 {
321     notImplemented();
322 }
323
324 bool PageClientImpl::isFullScreen()
325 {
326     return webkitWebViewBaseIsFullScreen(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
327 }
328
329 void PageClientImpl::enterFullScreen()
330 {
331     if (!m_viewWidget)
332         return;
333
334     if (isFullScreen())
335         return;
336
337     if (WEBKIT_IS_WEB_VIEW(m_viewWidget))
338         webkitWebViewEnterFullScreen(WEBKIT_WEB_VIEW(m_viewWidget));
339     else
340         webkitWebViewBaseEnterFullScreen(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
341 }
342
343 void PageClientImpl::exitFullScreen()
344 {
345     if (!m_viewWidget)
346         return;
347
348     if (!isFullScreen())
349         return;
350
351     if (WEBKIT_IS_WEB_VIEW(m_viewWidget))
352         webkitWebViewExitFullScreen(WEBKIT_WEB_VIEW(m_viewWidget));
353     else
354         webkitWebViewBaseExitFullScreen(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
355 }
356
357 void PageClientImpl::beganEnterFullScreen(const IntRect& /* initialFrame */, const IntRect& /* finalFrame */)
358 {
359     notImplemented();
360 }
361
362 void PageClientImpl::beganExitFullScreen(const IntRect& /* initialFrame */, const IntRect& /* finalFrame */)
363 {
364     notImplemented();
365 }
366
367 #endif // ENABLE(FULLSCREEN_API)
368
369 #if ENABLE(TOUCH_EVENTS)
370 void PageClientImpl::doneWithTouchEvent(const NativeWebTouchEvent& event, bool wasEventHandled)
371 {
372     const GdkEvent* touchEvent = event.nativeEvent();
373
374 #if HAVE(GTK_GESTURES)
375     GestureController& gestureController = webkitWebViewBaseGestureController(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
376     if (wasEventHandled) {
377         gestureController.reset();
378         return;
379     }
380     wasEventHandled = gestureController.handleEvent(const_cast<GdkEvent*>(event.nativeEvent()));
381 #endif
382
383     if (wasEventHandled)
384         return;
385
386     // Emulate pointer events if unhandled.
387     if (!touchEvent->touch.emulating_pointer)
388         return;
389
390     GUniquePtr<GdkEvent> pointerEvent;
391
392     if (touchEvent->type == GDK_TOUCH_UPDATE) {
393         pointerEvent.reset(gdk_event_new(GDK_MOTION_NOTIFY));
394         pointerEvent->motion.time = touchEvent->touch.time;
395         pointerEvent->motion.x = touchEvent->touch.x;
396         pointerEvent->motion.y = touchEvent->touch.y;
397         pointerEvent->motion.x_root = touchEvent->touch.x_root;
398         pointerEvent->motion.y_root = touchEvent->touch.y_root;
399         pointerEvent->motion.state = touchEvent->touch.state | GDK_BUTTON1_MASK;
400     } else {
401         switch (touchEvent->type) {
402         case GDK_TOUCH_CANCEL:
403             FALLTHROUGH;
404         case GDK_TOUCH_END:
405             pointerEvent.reset(gdk_event_new(GDK_BUTTON_RELEASE));
406             pointerEvent->button.state = touchEvent->touch.state | GDK_BUTTON1_MASK;
407             break;
408         case GDK_TOUCH_BEGIN:
409             pointerEvent.reset(gdk_event_new(GDK_BUTTON_PRESS));
410             break;
411         default:
412             ASSERT_NOT_REACHED();
413         }
414
415         pointerEvent->button.button = 1;
416         pointerEvent->button.time = touchEvent->touch.time;
417         pointerEvent->button.x = touchEvent->touch.x;
418         pointerEvent->button.y = touchEvent->touch.y;
419         pointerEvent->button.x_root = touchEvent->touch.x_root;
420         pointerEvent->button.y_root = touchEvent->touch.y_root;
421     }
422
423     gdk_event_set_device(pointerEvent.get(), gdk_event_get_device(touchEvent));
424     gdk_event_set_source_device(pointerEvent.get(), gdk_event_get_source_device(touchEvent));
425     pointerEvent->any.window = GDK_WINDOW(g_object_ref(touchEvent->any.window));
426     pointerEvent->any.send_event = TRUE;
427
428     gtk_widget_event(m_viewWidget, pointerEvent.get());
429 }
430 #endif // ENABLE(TOUCH_EVENTS)
431
432 void PageClientImpl::wheelEventWasNotHandledByWebCore(const NativeWebWheelEvent& event)
433 {
434     ViewGestureController& controller = webkitWebViewBaseViewGestureController(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
435     if (controller.isSwipeGestureEnabled()) {
436         controller.wheelEventWasNotHandledByWebCore(&event.nativeEvent()->scroll);
437         return;
438     }
439
440     webkitWebViewBaseForwardNextWheelEvent(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
441     gtk_main_do_event(event.nativeEvent());
442 }
443
444 void PageClientImpl::didFinishLoadingDataForCustomContentProvider(const String&, const IPC::DataReference&)
445 {
446 }
447
448 void PageClientImpl::navigationGestureDidBegin()
449 {
450 }
451
452 void PageClientImpl::navigationGestureWillEnd(bool, WebBackForwardListItem&)
453 {
454 }
455
456 void PageClientImpl::navigationGestureDidEnd(bool, WebBackForwardListItem&)
457 {
458 }
459
460 void PageClientImpl::navigationGestureDidEnd()
461 {
462 }
463
464 void PageClientImpl::willRecordNavigationSnapshot(WebBackForwardListItem&)
465 {
466 }
467
468 void PageClientImpl::didRemoveNavigationGestureSnapshot()
469 {
470     gtk_widget_queue_draw(m_viewWidget);
471 }
472
473 void PageClientImpl::didStartProvisionalLoadForMainFrame()
474 {
475     if (WEBKIT_IS_WEB_VIEW(m_viewWidget))
476         webkitWebViewWillStartLoad(WEBKIT_WEB_VIEW(m_viewWidget));
477
478     webkitWebViewBaseDidStartProvisionalLoadForMainFrame(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
479 }
480
481 void PageClientImpl::didFirstVisuallyNonEmptyLayoutForMainFrame()
482 {
483     webkitWebViewBaseDidFirstVisuallyNonEmptyLayoutForMainFrame(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
484 }
485
486 void PageClientImpl::didFinishLoadForMainFrame()
487 {
488     webkitWebViewBaseDidFinishLoadForMainFrame(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
489 }
490
491 void PageClientImpl::didFailLoadForMainFrame()
492 {
493     webkitWebViewBaseDidFailLoadForMainFrame(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
494 }
495
496 void PageClientImpl::didSameDocumentNavigationForMainFrame(SameDocumentNavigationType type)
497 {
498     webkitWebViewBaseDidSameDocumentNavigationForMainFrame(WEBKIT_WEB_VIEW_BASE(m_viewWidget), type);
499 }
500
501 void PageClientImpl::didRestoreScrollPosition()
502 {
503     webkitWebViewBaseDidRestoreScrollPosition(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
504 }
505
506 void PageClientImpl::didChangeBackgroundColor()
507 {
508 }
509
510 void PageClientImpl::refView()
511 {
512     g_object_ref(m_viewWidget);
513 }
514
515 void PageClientImpl::derefView()
516 {
517     g_object_unref(m_viewWidget);
518 }
519
520 #if ENABLE(VIDEO) && USE(GSTREAMER)
521 bool PageClientImpl::decidePolicyForInstallMissingMediaPluginsPermissionRequest(InstallMissingMediaPluginsPermissionRequest& request)
522 {
523     if (!WEBKIT_IS_WEB_VIEW(m_viewWidget))
524         return false;
525
526     webkitWebViewRequestInstallMissingMediaPlugins(WEBKIT_WEB_VIEW(m_viewWidget), request);
527     return true;
528 }
529 #endif
530
531 void PageClientImpl::requestDOMPasteAccess(const IntRect&, const String&, CompletionHandler<void(WebCore::DOMPasteAccessResponse)>&& completionHandler)
532 {
533     completionHandler(WebCore::DOMPasteAccessResponse::DeniedForGesture);
534 }
535
536 } // namespace WebKit