2010-10-05 Sheriff Bot <webkit.review.bot@gmail.com>
[WebKit-https.git] / WebKit2 / UIProcess / API / qt / qwkpage.cpp
1 /*
2  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this program; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  *
19  */
20
21 #include "qwkpage.h"
22 #include "qwkpage_p.h"
23
24 #include "qwkpreferences_p.h"
25
26 #include "ClientImpl.h"
27 #include "LocalizedStrings.h"
28 #include "NativeWebKeyboardEvent.h"
29 #include "WebContext.h"
30 #include "WebEventFactoryQt.h"
31 #include "WebPlatformStrategies.h"
32 #include "WKStringQt.h"
33 #include "WKURLQt.h"
34 #include "ViewportArguments.h"
35 #include <QAction>
36 #include <QApplication>
37 #include <QGraphicsSceneMouseEvent>
38 #include <QStyle>
39 #include <QTouchEvent>
40 #include <QtDebug>
41 #include <WebKit2/WKFrame.h>
42 #include <WebKit2/WKRetainPtr.h>
43
44
45 using namespace WebKit;
46 using namespace WebCore;
47
48 QWKPagePrivate::QWKPagePrivate(QWKPage* qq, WKPageNamespaceRef namespaceRef)
49     : q(qq)
50     , preferences(0)
51     , createNewPageFn(0)
52 {
53     // We want to use the LocalizationStrategy at the UI side as well.
54     // FIXME: this should be avoided.
55     WebPlatformStrategies::initialize();
56
57     memset(actions, 0, sizeof(actions));
58     page = toWK(namespaceRef)->createWebPage();
59     page->setPageClient(this);
60     pageNamespaceRef = namespaceRef;
61 }
62
63 QWKPagePrivate::~QWKPagePrivate()
64 {
65     page->close();
66 }
67
68 void QWKPagePrivate::init(const QSize& viewportSize, PassOwnPtr<DrawingAreaProxy> proxy)
69 {
70     page->setDrawingArea(proxy);
71     page->initializeWebPage(IntSize(viewportSize));
72 }
73
74 void QWKPagePrivate::setCursor(const WebCore::Cursor& cursor)
75 {
76 #ifndef QT_NO_CURSOR
77     emit q->cursorChanged(*cursor.platformCursor());
78 #endif
79 }
80
81 void QWKPagePrivate::toolTipChanged(const String&, const String& newTooltip)
82 {
83     emit q->statusBarMessage(QString(newTooltip));
84 }
85
86 void QWKPagePrivate::registerEditCommand(PassRefPtr<WebEditCommandProxy>, UndoOrRedo)
87 {
88 }
89
90 void QWKPagePrivate::clearAllEditCommands()
91 {
92 }
93
94 void QWKPagePrivate::paint(QPainter* painter, QRect area)
95 {
96     painter->save();
97
98     painter->setBrush(Qt::white);
99     painter->drawRect(area);
100
101     if (page->isValid() && page->drawingArea())
102         page->drawingArea()->paint(IntRect(area), painter);
103
104     painter->restore();
105 }
106
107 void QWKPagePrivate::keyPressEvent(QKeyEvent* ev)
108 {
109     page->handleKeyboardEvent(NativeWebKeyboardEvent(ev));
110 }
111
112 void QWKPagePrivate::keyReleaseEvent(QKeyEvent* ev)
113 {
114     page->handleKeyboardEvent(NativeWebKeyboardEvent(ev));
115 }
116
117 void QWKPagePrivate::mouseMoveEvent(QGraphicsSceneMouseEvent* ev)
118 {
119     // For some reason mouse press results in mouse hover (which is
120     // converted to mouse move for WebKit). We ignore these hover
121     // events by comparing lastPos with newPos.
122     // NOTE: lastPos from the event always comes empty, so we work
123     // around that here.
124     static QPointF lastPos = QPointF();
125     if (lastPos == ev->pos())
126         return;
127     lastPos = ev->pos();
128
129     WebMouseEvent mouseEvent = WebEventFactory::createWebMouseEvent(ev, 0);
130     page->handleMouseEvent(mouseEvent);
131 }
132
133 void QWKPagePrivate::mousePressEvent(QGraphicsSceneMouseEvent* ev)
134 {
135     if (tripleClickTimer.isActive() && (ev->pos() - tripleClick).manhattanLength() < QApplication::startDragDistance()) {
136         WebMouseEvent mouseEvent = WebEventFactory::createWebMouseEvent(ev, 3);
137         page->handleMouseEvent(mouseEvent);
138         return;
139     }
140
141     WebMouseEvent mouseEvent = WebEventFactory::createWebMouseEvent(ev, 1);
142     page->handleMouseEvent(mouseEvent);
143 }
144
145 void QWKPagePrivate::mouseReleaseEvent(QGraphicsSceneMouseEvent* ev)
146 {
147     WebMouseEvent mouseEvent = WebEventFactory::createWebMouseEvent(ev, 0);
148     page->handleMouseEvent(mouseEvent);
149 }
150
151 void QWKPagePrivate::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* ev)
152 {
153     WebMouseEvent mouseEvent = WebEventFactory::createWebMouseEvent(ev, 2);
154     page->handleMouseEvent(mouseEvent);
155
156     tripleClickTimer.start(QApplication::doubleClickInterval(), q);
157     tripleClick = ev->pos().toPoint();
158 }
159
160 void QWKPagePrivate::wheelEvent(QGraphicsSceneWheelEvent* ev)
161 {
162     WebWheelEvent wheelEvent = WebEventFactory::createWebWheelEvent(ev);
163     page->handleWheelEvent(wheelEvent);
164 }
165
166 void QWKPagePrivate::setEditCommandState(const WTF::String&, bool, int)
167 {
168 }
169
170 void QWKPagePrivate::updateAction(QWKPage::WebAction action)
171 {
172 #ifdef QT_NO_ACTION
173     Q_UNUSED(action)
174 #else
175     QAction* a = actions[action];
176     if (!a)
177         return;
178
179     RefPtr<WebKit::WebFrameProxy> mainFrame = page->mainFrame();
180     if (!mainFrame)
181         return;
182
183     bool enabled = a->isEnabled();
184     bool checked = a->isChecked();
185
186     switch (action) {
187     case QWKPage::Back:
188         enabled = page->canGoBack();
189         break;
190     case QWKPage::Forward:
191         enabled = page->canGoForward();
192         break;
193     case QWKPage::Stop:
194         enabled = !(WebFrameProxy::LoadStateFinished == mainFrame->loadState());
195         break;
196     case QWKPage::Reload:
197         enabled = (WebFrameProxy::LoadStateFinished == mainFrame->loadState());
198         break;
199     default:
200         break;
201     }
202
203     a->setEnabled(enabled);
204
205     if (a->isCheckable())
206         a->setChecked(checked);
207 #endif // QT_NO_ACTION
208 }
209
210 void QWKPagePrivate::updateNavigationActions()
211 {
212     updateAction(QWKPage::Back);
213     updateAction(QWKPage::Forward);
214     updateAction(QWKPage::Stop);
215     updateAction(QWKPage::Reload);
216 }
217
218 #ifndef QT_NO_ACTION
219 void QWKPagePrivate::_q_webActionTriggered(bool checked)
220 {
221     QAction* a = qobject_cast<QAction*>(q->sender());
222     if (!a)
223         return;
224     QWKPage::WebAction action = static_cast<QWKPage::WebAction>(a->data().toInt());
225     q->triggerAction(action, checked);
226 }
227 #endif // QT_NO_ACTION
228
229 void QWKPagePrivate::touchEvent(QTouchEvent* event)
230 {
231     WebTouchEvent touchEvent = WebEventFactory::createWebTouchEvent(event);
232     page->handleTouchEvent(touchEvent);
233 }
234
235 QWKPage::QWKPage(WKPageNamespaceRef namespaceRef)
236     : d(new QWKPagePrivate(this, namespaceRef))
237 {
238     WKPageLoaderClient loadClient = {
239         0,      /* version */
240         this,   /* clientInfo */
241         qt_wk_didStartProvisionalLoadForFrame,
242         qt_wk_didReceiveServerRedirectForProvisionalLoadForFrame,
243         qt_wk_didFailProvisionalLoadWithErrorForFrame,
244         qt_wk_didCommitLoadForFrame,
245         qt_wk_didFinishDocumentLoadForFrame,
246         qt_wk_didFinishLoadForFrame,
247         qt_wk_didFailLoadWithErrorForFrame,
248         qt_wk_didReceiveTitleForFrame,
249         qt_wk_didFirstLayoutForFrame,
250         qt_wk_didFirstVisuallyNonEmptyLayoutForFrame,
251         qt_wk_didRemoveFrameFromHierarchy,
252         qt_wk_didStartProgress,
253         qt_wk_didChangeProgress,
254         qt_wk_didFinishProgress,
255         qt_wk_didBecomeUnresponsive,
256         qt_wk_didBecomeResponsive,
257         0,  /* processDidExit */
258         0   /* didChangeBackForwardList */
259     };
260     WKPageSetPageLoaderClient(pageRef(), &loadClient);
261
262     WKPageUIClient uiClient = {
263         0,      /* version */
264         this,   /* clientInfo */
265         qt_wk_createNewPage,
266         qt_wk_showPage,
267         qt_wk_close,
268         qt_wk_runJavaScriptAlert,
269         0,  /* runJavaScriptConfirm */
270         0,  /* runJavaScriptPrompt */
271         0,  /* setStatusText */
272         0,  /* mouseDidMoveOverElement */
273         0,  /* contentsSizeChanged */
274         0   /* didNotHandleKeyEvent */
275     };
276     WKPageSetPageUIClient(pageRef(), &uiClient);
277 }
278
279 QWKPage::~QWKPage()
280 {
281     delete d;
282 }
283
284 QWKPage::ViewportConfiguration::ViewportConfiguration()
285     : d(0)
286     , m_initialScaleFactor(-1.0)
287     , m_minimumScaleFactor(-1.0)
288     , m_maximumScaleFactor(-1.0)
289     , m_devicePixelRatio(-1.0)
290     , m_isUserScalable(true)
291     , m_isValid(false)
292 {
293
294 }
295
296 QWKPage::ViewportConfiguration::ViewportConfiguration(const QWKPage::ViewportConfiguration& other)
297     : d(other.d)
298     , m_initialScaleFactor(other.m_initialScaleFactor)
299     , m_minimumScaleFactor(other.m_minimumScaleFactor)
300     , m_maximumScaleFactor(other.m_maximumScaleFactor)
301     , m_devicePixelRatio(other.m_devicePixelRatio)
302     , m_isUserScalable(other.m_isUserScalable)
303     , m_isValid(other.m_isValid)
304     , m_size(other.m_size)
305 {
306
307 }
308
309 QWKPage::ViewportConfiguration::~ViewportConfiguration()
310 {
311
312 }
313
314 QWKPage::ViewportConfiguration& QWKPage::ViewportConfiguration::operator=(const QWKPage::ViewportConfiguration& other)
315 {
316     if (this != &other) {
317         d = other.d;
318         m_initialScaleFactor = other.m_initialScaleFactor;
319         m_minimumScaleFactor = other.m_minimumScaleFactor;
320         m_maximumScaleFactor = other.m_maximumScaleFactor;
321         m_devicePixelRatio = other.m_devicePixelRatio;
322         m_isUserScalable = other.m_isUserScalable;
323         m_isValid = other.m_isValid;
324         m_size = other.m_size;
325     }
326
327     return *this;
328 }
329
330 QWKPage::ViewportConfiguration QWKPage::viewportConfigurationForSize(QSize availableSize) const
331 {
332     static int desktopWidth = 980;
333     static int deviceDPI = 160;
334
335     // FIXME: Add a way to get these data via the platform plugin and fall back
336     // to the size of the view.
337     int deviceWidth = 480;
338     int deviceHeight = 864;
339
340     ViewportArguments args;
341
342     WebCore::ViewportConfiguration conf = WebCore::findConfigurationForViewportData(args, desktopWidth, deviceWidth, deviceHeight, deviceDPI, availableSize);
343
344     ViewportConfiguration result;
345
346     result.m_isValid = true;
347     result.m_size = conf.layoutViewport;
348     result.m_initialScaleFactor = conf.initialScale;
349     result.m_minimumScaleFactor = conf.minimumScale;
350     result.m_maximumScaleFactor = conf.maximumScale;
351     result.m_devicePixelRatio = conf.devicePixelRatio;
352
353     return result;
354 }
355
356 void QWKPage::timerEvent(QTimerEvent* ev)
357 {
358     int timerId = ev->timerId();
359     if (timerId == d->tripleClickTimer.timerId())
360         d->tripleClickTimer.stop();
361     else
362         QObject::timerEvent(ev);
363 }
364
365 WKPageRef QWKPage::pageRef() const
366 {
367     return toRef(d->page.get());
368 }
369
370 QWKPreferences* QWKPage::preferences() const
371 {
372     if (!d->preferences) {
373         WKContextRef contextRef = WKPageNamespaceGetContext(d->pageNamespaceRef);
374         d->preferences = QWKPreferencesPrivate::createPreferences(contextRef);
375     }
376
377     return d->preferences;
378 }
379
380 void QWKPage::setCreateNewPageFunction(CreateNewPageFn function)
381 {
382     d->createNewPageFn = function;
383 }
384
385 void QWKPage::load(const QUrl& url)
386 {
387     WKRetainPtr<WKURLRef> wkurl(WKURLCreateWithQUrl(url));
388     WKPageLoadURL(pageRef(), wkurl.get());
389 }
390
391 void QWKPage::setUrl(const QUrl& url)
392 {
393     load(url);
394 }
395
396 QUrl QWKPage::url() const
397 {
398     WKRetainPtr<WKFrameRef> frame = WKPageGetMainFrame(pageRef());
399     if (!frame)
400         return QUrl();
401     return WKURLCopyQUrl(WKFrameCopyURL(frame.get()));
402 }
403
404 QString QWKPage::title() const
405 {
406     return WKStringCopyQString(WKPageCopyTitle(pageRef()));
407 }
408
409 void QWKPage::setViewportSize(const QSize& size)
410 {
411     if (d->page->drawingArea())
412         d->page->drawingArea()->setSize(IntSize(size));
413 }
414
415 #ifndef QT_NO_ACTION
416 void QWKPage::triggerAction(WebAction action, bool)
417 {
418     switch (action) {
419     case Back:
420         d->page->goBack();
421         break;
422     case Forward:
423         d->page->goForward();
424         break;
425     case Stop:
426         d->page->stopLoading();
427         break;
428     case Reload:
429         d->page->reload(/* reloadFromOrigin */ true);
430         break;
431     default:
432         break;
433     }
434 }
435 #endif // QT_NO_ACTION
436
437 #ifndef QT_NO_ACTION
438 QAction* QWKPage::action(WebAction action) const
439 {
440     if (action == QWKPage::NoWebAction || action >= WebActionCount)
441         return 0;
442
443     if (d->actions[action])
444         return d->actions[action];
445
446     QString text;
447     QIcon icon;
448     QStyle* style = qobject_cast<QApplication*>(QCoreApplication::instance())->style();
449     bool checkable = false;
450
451     switch (action) {
452     case Back:
453         text = contextMenuItemTagGoBack();
454         icon = style->standardIcon(QStyle::SP_ArrowBack);
455         break;
456     case Forward:
457         text = contextMenuItemTagGoForward();
458         icon = style->standardIcon(QStyle::SP_ArrowForward);
459         break;
460     case Stop:
461         text = contextMenuItemTagStop();
462         icon = style->standardIcon(QStyle::SP_BrowserStop);
463         break;
464     case Reload:
465         text = contextMenuItemTagReload();
466         icon = style->standardIcon(QStyle::SP_BrowserReload);
467         break;
468     default:
469         return 0;
470         break;
471     }
472
473     if (text.isEmpty())
474         return 0;
475
476     QAction* a = new QAction(d->q);
477     a->setText(text);
478     a->setData(action);
479     a->setCheckable(checkable);
480     a->setIcon(icon);
481
482     connect(a, SIGNAL(triggered(bool)), this, SLOT(_q_webActionTriggered(bool)));
483
484     d->actions[action] = a;
485     d->updateAction(action);
486     return a;
487 }
488 #endif // QT_NO_ACTION
489
490 #include "moc_qwkpage.cpp"