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 "DrawingAreaProxyImpl.h"
32#include "NativeWebKeyboardEvent.h"
33#include "NativeWebMouseEvent.h"
34#include "NotImplemented.h"
35#include "WebContext.h"
36#include "WebContextMenuProxyGtk.h"
37#include "WebEventFactory.h"
38#include "WebKitWebViewBasePrivate.h"
39#include "WebPageProxy.h"
40#include "WebPopupMenuProxyGtk.h"
41#include <WebCore/Cursor.h>
42#include <WebCore/EventNames.h>
43#include <WebCore/GtkUtilities.h>
44#include <wtf/text/CString.h>
45#include <wtf/text/WTFString.h>
46
47using namespace WebCore;
48
49namespace WebKit {
50
51PageClientImpl::PageClientImpl(GtkWidget* viewWidget)
52    : m_viewWidget(viewWidget)
53{
54}
55
56void PageClientImpl::getEditorCommandsForKeyEvent(const NativeWebKeyboardEvent& event, const AtomicString& eventType, Vector<WTF::String>& commandList)
57{
58    ASSERT(eventType == eventNames().keydownEvent || eventType == eventNames().keypressEvent);
59
60    KeyBindingTranslator::EventType type = eventType == eventNames().keydownEvent ?
61        KeyBindingTranslator::KeyDown : KeyBindingTranslator::KeyPress;
62    m_keyBindingTranslator.getEditorCommandsForKeyEvent(const_cast<GdkEventKey*>(&event.nativeEvent()->key), type, commandList);
63}
64
65// PageClient's pure virtual functions
66std::unique_ptr<DrawingAreaProxy> PageClientImpl::createDrawingAreaProxy()
67{
68    return std::make_unique<DrawingAreaProxyImpl>(webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(m_viewWidget)));
69}
70
71void PageClientImpl::setViewNeedsDisplay(const WebCore::IntRect& rect)
72{
73    gtk_widget_queue_draw_area(m_viewWidget, rect.x(), rect.y(), rect.width(), rect.height());
74}
75
76void PageClientImpl::displayView()
77{
78    notImplemented();
79}
80
81void PageClientImpl::scrollView(const WebCore::IntRect& scrollRect, const WebCore::IntSize& /* scrollOffset */)
82{
83    setViewNeedsDisplay(scrollRect);
84}
85
86void PageClientImpl::requestScroll(const WebCore::FloatPoint&, bool)
87{
88    notImplemented();
89}
90
91WebCore::IntSize PageClientImpl::viewSize()
92{
93    if (!gtk_widget_get_realized(m_viewWidget))
94        return IntSize();
95    GtkAllocation allocation;
96    gtk_widget_get_allocation(m_viewWidget, &allocation);
97    return IntSize(allocation.width, allocation.height);
98}
99
100bool PageClientImpl::isViewWindowActive()
101{
102    return webkitWebViewBaseIsInWindowActive(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
103}
104
105bool PageClientImpl::isViewFocused()
106{
107    return webkitWebViewBaseIsFocused(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
108}
109
110bool PageClientImpl::isViewVisible()
111{
112    return webkitWebViewBaseIsVisible(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
113}
114
115bool PageClientImpl::isViewInWindow()
116{
117    return webkitWebViewBaseIsInWindow(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
118}
119
120void PageClientImpl::PageClientImpl::processDidExit()
121{
122    notImplemented();
123}
124
125void PageClientImpl::didRelaunchProcess()
126{
127    notImplemented();
128}
129
130void PageClientImpl::toolTipChanged(const String&, const String& newToolTip)
131{
132    webkitWebViewBaseSetTooltipText(WEBKIT_WEB_VIEW_BASE(m_viewWidget), newToolTip.utf8().data());
133}
134
135void PageClientImpl::setCursor(const Cursor& cursor)
136{
137    if (!gtk_widget_get_realized(m_viewWidget))
138        return;
139
140    // [GTK] Widget::setCursor() gets called frequently
141    // http://bugs.webkit.org/show_bug.cgi?id=16388
142    // Setting the cursor may be an expensive operation in some backends,
143    // so don't re-set the cursor if it's already set to the target value.
144    GdkWindow* window = gtk_widget_get_window(m_viewWidget);
145    GdkCursor* currentCursor = gdk_window_get_cursor(window);
146    GdkCursor* newCursor = cursor.platformCursor().get();
147    if (currentCursor != newCursor)
148        gdk_window_set_cursor(window, newCursor);
149}
150
151void PageClientImpl::setCursorHiddenUntilMouseMoves(bool /* hiddenUntilMouseMoves */)
152{
153    notImplemented();
154}
155
156void PageClientImpl::didChangeViewportProperties(const WebCore::ViewportAttributes&)
157{
158    notImplemented();
159}
160
161void PageClientImpl::registerEditCommand(PassRefPtr<WebEditCommandProxy> command, WebPageProxy::UndoOrRedo undoOrRedo)
162{
163    m_undoController.registerEditCommand(command, undoOrRedo);
164}
165
166void PageClientImpl::clearAllEditCommands()
167{
168    m_undoController.clearAllEditCommands();
169}
170
171bool PageClientImpl::canUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
172{
173    return m_undoController.canUndoRedo(undoOrRedo);
174}
175
176void PageClientImpl::executeUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
177{
178    m_undoController.executeUndoRedo(undoOrRedo);
179}
180
181FloatRect PageClientImpl::convertToDeviceSpace(const FloatRect& viewRect)
182{
183    notImplemented();
184    return viewRect;
185}
186
187FloatRect PageClientImpl::convertToUserSpace(const FloatRect& viewRect)
188{
189    notImplemented();
190    return viewRect;
191}
192
193IntPoint PageClientImpl::screenToRootView(const IntPoint& point)
194{
195    IntPoint widgetPositionOnScreen = convertWidgetPointToScreenPoint(m_viewWidget, IntPoint());
196    IntPoint result(point);
197    result.move(-widgetPositionOnScreen.x(), -widgetPositionOnScreen.y());
198    return result;
199}
200
201IntRect PageClientImpl::rootViewToScreen(const IntRect& rect)
202{
203    return IntRect(convertWidgetPointToScreenPoint(m_viewWidget, rect.location()), rect.size());
204}
205
206void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool wasEventHandled)
207{
208    if (wasEventHandled)
209        return;
210    if (event.isFakeEventForComposition())
211        return;
212
213    WebKitWebViewBase* webkitWebViewBase = WEBKIT_WEB_VIEW_BASE(m_viewWidget);
214    webkitWebViewBaseForwardNextKeyEvent(webkitWebViewBase);
215    gtk_main_do_event(event.nativeEvent());
216}
217
218PassRefPtr<WebPopupMenuProxy> PageClientImpl::createPopupMenuProxy(WebPageProxy* page)
219{
220    return WebPopupMenuProxyGtk::create(m_viewWidget, page);
221}
222
223PassRefPtr<WebContextMenuProxy> PageClientImpl::createContextMenuProxy(WebPageProxy* page)
224{
225    return WebContextMenuProxyGtk::create(m_viewWidget, page);
226}
227
228#if ENABLE(INPUT_TYPE_COLOR)
229PassRefPtr<WebColorPicker> PageClientImpl::createColorPicker(WebPageProxy*, const WebCore::Color&, const WebCore::IntRect&)
230{
231    notImplemented();
232    return 0;
233}
234#endif
235
236void PageClientImpl::setFindIndicator(PassRefPtr<FindIndicator>, bool /* fadeOut */, bool /* animate */)
237{
238    notImplemented();
239}
240
241void PageClientImpl::enterAcceleratedCompositingMode(const LayerTreeContext&)
242{
243    notImplemented();
244}
245
246void PageClientImpl::exitAcceleratedCompositingMode()
247{
248    notImplemented();
249}
250
251void PageClientImpl::updateAcceleratedCompositingMode(const LayerTreeContext&)
252{
253    notImplemented();
254}
255
256void PageClientImpl::pageClosed()
257{
258    notImplemented();
259}
260
261void PageClientImpl::preferencesDidChange()
262{
263    notImplemented();
264}
265
266void PageClientImpl::updateTextInputState()
267{
268    webkitWebViewBaseUpdateTextInputState(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
269}
270
271void PageClientImpl::startDrag(const WebCore::DragData& dragData, PassRefPtr<ShareableBitmap> dragImage)
272{
273    webkitWebViewBaseStartDrag(WEBKIT_WEB_VIEW_BASE(m_viewWidget), dragData, dragImage);
274}
275
276void PageClientImpl::handleDownloadRequest(DownloadProxy* download)
277{
278    webkitWebViewBaseHandleDownloadRequest(WEBKIT_WEB_VIEW_BASE(m_viewWidget), download);
279}
280
281void PageClientImpl::didCommitLoadForMainFrame(const String& /* mimeType */, bool /* useCustomContentProvider */ )
282{
283    webkitWebViewBaseResetClickCounter(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
284}
285
286#if ENABLE(FULLSCREEN_API)
287WebFullScreenManagerProxyClient& PageClientImpl::fullScreenManagerProxyClient()
288{
289    return *this;
290}
291
292void PageClientImpl::closeFullScreenManager()
293{
294    notImplemented();
295}
296
297bool PageClientImpl::isFullScreen()
298{
299    notImplemented();
300    return false;
301}
302
303void PageClientImpl::enterFullScreen()
304{
305    if (!m_viewWidget)
306        return;
307
308    webkitWebViewBaseEnterFullScreen(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
309}
310
311void PageClientImpl::exitFullScreen()
312{
313    if (!m_viewWidget)
314        return;
315
316    webkitWebViewBaseExitFullScreen(WEBKIT_WEB_VIEW_BASE(m_viewWidget));
317}
318
319void PageClientImpl::beganEnterFullScreen(const IntRect& /* initialFrame */, const IntRect& /* finalFrame */)
320{
321    notImplemented();
322}
323
324void PageClientImpl::beganExitFullScreen(const IntRect& /* initialFrame */, const IntRect& /* finalFrame */)
325{
326    notImplemented();
327}
328
329#endif // ENABLE(FULLSCREEN_API)
330
331void PageClientImpl::doneWithTouchEvent(const NativeWebTouchEvent& event, bool wasEventHandled)
332{
333    if (wasEventHandled)
334        return;
335
336    // Emulate pointer events if unhandled.
337    const GdkEvent* touchEvent = event.nativeEvent();
338
339    if (!touchEvent->touch.emulating_pointer)
340        return;
341
342    GUniquePtr<GdkEvent> pointerEvent;
343
344    if (touchEvent->type == GDK_TOUCH_UPDATE) {
345        pointerEvent.reset(gdk_event_new(GDK_MOTION_NOTIFY));
346        pointerEvent->motion.time = touchEvent->touch.time;
347        pointerEvent->motion.x = touchEvent->touch.x;
348        pointerEvent->motion.y = touchEvent->touch.y;
349        pointerEvent->motion.x_root = touchEvent->touch.x_root;
350        pointerEvent->motion.y_root = touchEvent->touch.y_root;
351        pointerEvent->motion.state = touchEvent->touch.state | GDK_BUTTON1_MASK;
352    } else {
353        switch (touchEvent->type) {
354        case GDK_TOUCH_END:
355            pointerEvent.reset(gdk_event_new(GDK_BUTTON_RELEASE));
356            pointerEvent->button.state = touchEvent->touch.state | GDK_BUTTON1_MASK;
357            break;
358        case GDK_TOUCH_BEGIN:
359            pointerEvent.reset(gdk_event_new(GDK_BUTTON_PRESS));
360            break;
361        default:
362            ASSERT_NOT_REACHED();
363        }
364
365        pointerEvent->button.button = 1;
366        pointerEvent->button.time = touchEvent->touch.time;
367        pointerEvent->button.x = touchEvent->touch.x;
368        pointerEvent->button.y = touchEvent->touch.y;
369        pointerEvent->button.x_root = touchEvent->touch.x_root;
370        pointerEvent->button.y_root = touchEvent->touch.y_root;
371    }
372
373    gdk_event_set_device(pointerEvent.get(), gdk_event_get_device(touchEvent));
374    gdk_event_set_source_device(pointerEvent.get(), gdk_event_get_source_device(touchEvent));
375    pointerEvent->any.window = GDK_WINDOW(g_object_ref(touchEvent->any.window));
376    pointerEvent->any.send_event = TRUE;
377
378    gtk_widget_event(m_viewWidget, pointerEvent.get());
379}
380
381void PageClientImpl::didFinishLoadingDataForCustomContentProvider(const String&, const IPC::DataReference&)
382{
383}
384
385void PageClientImpl::navigationGestureDidBegin()
386{
387}
388
389void PageClientImpl::navigationGestureWillEnd(bool, WebBackForwardListItem&)
390{
391}
392
393void PageClientImpl::navigationGestureDidEnd(bool, WebBackForwardListItem&)
394{
395}
396
397void PageClientImpl::willRecordNavigationSnapshot(WebBackForwardListItem&)
398{
399}
400
401} // namespace WebKit
402