• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "config.h"
22 #include "qgraphicswkview.h"
23 
24 #include "ChunkedUpdateDrawingAreaProxy.h"
25 #include "IntSize.h"
26 #include "RunLoop.h"
27 #include "TiledDrawingAreaProxy.h"
28 #include "UpdateChunk.h"
29 #include "WKAPICast.h"
30 #include "qwkpage.h"
31 #include "qwkpage_p.h"
32 #include <QApplication>
33 #include <QCursor>
34 #include <QGraphicsSceneMouseEvent>
35 #include <QGraphicsView>
36 #include <QMenu>
37 #include <QPainter>
38 #include <QScrollBar>
39 #include <QStyleOptionGraphicsItem>
40 #include <QUrl>
41 #include <QtDebug>
42 #include <WebKit2/WKRetainPtr.h>
43 #include <wtf/RefPtr.h>
44 #include <wtf/text/WTFString.h>
45 
46 using namespace WebKit;
47 using namespace WebCore;
48 
49 struct QGraphicsWKViewPrivate {
50     QGraphicsWKViewPrivate(QGraphicsWKView* view);
pageRefQGraphicsWKViewPrivate51     WKPageRef pageRef() const { return page->pageRef(); }
52 
53     void onToolTipChanged(const QString&);
54     void onScaleChanged();
55     void commitScale();
56 
57     QGraphicsWKView* q;
58     QWKPage* page;
59     QSharedPointer<QMenu> activeMenu;
60     RunLoop::Timer<QGraphicsWKViewPrivate> m_scaleCommitTimer;
61     bool m_isChangingScale;
62 };
63 
QGraphicsWKView(QWKContext * context,BackingStoreType backingStoreType,QGraphicsItem * parent)64 QGraphicsWKView::QGraphicsWKView(QWKContext* context, BackingStoreType backingStoreType, QGraphicsItem* parent)
65     : QGraphicsWidget(parent)
66     , d(new QGraphicsWKViewPrivate(this))
67 {
68     setFocusPolicy(Qt::StrongFocus);
69     setAcceptHoverEvents(true);
70 
71 
72 #if ENABLE(TILED_BACKING_STORE)
73     if (backingStoreType == Tiled)
74         connect(this, SIGNAL(scaleChanged()), this, SLOT(onScaleChanged()));
75 #endif
76 
77     d->page = new QWKPage(context);
78     d->page->d->init(this, backingStoreType);
79     connect(d->page, SIGNAL(titleChanged(QString)), this, SIGNAL(titleChanged(QString)));
80     connect(d->page, SIGNAL(loadStarted()), this, SIGNAL(loadStarted()));
81     connect(d->page, SIGNAL(loadFinished(bool)), this, SIGNAL(loadFinished(bool)));
82     connect(d->page, SIGNAL(loadProgress(int)), this, SIGNAL(loadProgress(int)));
83     connect(d->page, SIGNAL(initialLayoutCompleted()), this, SIGNAL(initialLayoutCompleted()));
84     connect(d->page, SIGNAL(urlChanged(const QUrl&)), this, SIGNAL(urlChanged(const QUrl&)));
85     connect(d->page, SIGNAL(cursorChanged(const QCursor&)), this, SLOT(updateCursor(const QCursor&)));
86     connect(d->page, SIGNAL(focusNextPrevChild(bool)), this, SLOT(focusNextPrevChildCallback(bool)));
87     connect(d->page, SIGNAL(showContextMenu(QSharedPointer<QMenu>)), this, SLOT(showContextMenu(QSharedPointer<QMenu>)));
88     connect(d->page, SIGNAL(toolTipChanged(QString)), this, SLOT(onToolTipChanged(QString)));
89 }
90 
~QGraphicsWKView()91 QGraphicsWKView::~QGraphicsWKView()
92 {
93     delete d->page;
94     delete d;
95 }
96 
page() const97 QWKPage* QGraphicsWKView::page() const
98 {
99     return d->page;
100 }
101 
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget *)102 void QGraphicsWKView::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget*)
103 {
104     page()->d->paint(painter, option->exposedRect.toAlignedRect());
105 }
106 
setGeometry(const QRectF & rect)107 void QGraphicsWKView::setGeometry(const QRectF& rect)
108 {
109     QSizeF oldSize = geometry().size();
110     QGraphicsWidget::setGeometry(rect);
111     if (geometry().size() == oldSize)
112         return;
113 
114     // NOTE: call geometry() as setGeometry ensures that
115     // the geometry is within legal bounds (minimumSize, maximumSize)
116     page()->setViewportSize(geometry().size().toSize());
117 }
118 
load(const QUrl & url)119 void QGraphicsWKView::load(const QUrl& url)
120 {
121     page()->load(url);
122 }
123 
setUrl(const QUrl & url)124 void QGraphicsWKView::setUrl(const QUrl& url)
125 {
126     page()->setUrl(url);
127 }
128 
url() const129 QUrl QGraphicsWKView::url() const
130 {
131     return page()->url();
132 }
133 
title() const134 QString QGraphicsWKView::title() const
135 {
136     return page()->title();
137 }
138 
triggerPageAction(QWKPage::WebAction action,bool checked)139 void QGraphicsWKView::triggerPageAction(QWKPage::WebAction action, bool checked)
140 {
141     page()->triggerAction(action, checked);
142 }
143 
back()144 void QGraphicsWKView::back()
145 {
146     page()->triggerAction(QWKPage::Back);
147 }
148 
forward()149 void QGraphicsWKView::forward()
150 {
151     page()->triggerAction(QWKPage::Forward);
152 }
153 
reload()154 void QGraphicsWKView::reload()
155 {
156     page()->triggerAction(QWKPage::Reload);
157 }
158 
stop()159 void QGraphicsWKView::stop()
160 {
161     page()->triggerAction(QWKPage::Stop);
162 }
163 
updateCursor(const QCursor & cursor)164 void QGraphicsWKView::updateCursor(const QCursor& cursor)
165 {
166     setCursor(cursor);
167 }
168 
169 class FriendlyWidget : public QWidget
170 {
171 public:
172     bool focusNextPrevChild(bool next);
173 };
174 
focusNextPrevChildCallback(bool next)175 void QGraphicsWKView::focusNextPrevChildCallback(bool next)
176 {
177     if (hasFocus()) {
178         // find the view which has the focus:
179         QList<QGraphicsView*> views = scene()->views();
180         const int viewCount = views.count();
181         QGraphicsView* focusedView = 0;
182         for (int i = 0; i < viewCount; ++i) {
183             if (views[i]->hasFocus()) {
184                 focusedView = views[i];
185                 break;
186             }
187         }
188 
189         if (focusedView) {
190             QWidget* window = focusedView->window();
191             FriendlyWidget* friendlyWindow = static_cast<FriendlyWidget*>(window);
192             friendlyWindow->focusNextPrevChild(next);
193         }
194     }
195 }
196 
197 /*! \reimp
198 */
focusNextPrevChild(bool next)199 bool QGraphicsWKView::focusNextPrevChild(bool next)
200 {
201     QKeyEvent ev(QEvent::KeyPress, Qt::Key_Tab, Qt::KeyboardModifiers(next ? Qt::NoModifier : Qt::ShiftModifier));
202     page()->d->keyPressEvent(&ev);
203     return true;
204 }
205 
206 /*! \reimp
207 */
itemChange(GraphicsItemChange change,const QVariant & value)208 QVariant QGraphicsWKView::itemChange(GraphicsItemChange change, const QVariant& value)
209 {
210     // Here so that it can be reimplemented without breaking ABI.
211     return QGraphicsWidget::itemChange(change, value);
212 }
213 
214 /*! \reimp
215 */
event(QEvent * event)216 bool QGraphicsWKView::event(QEvent* event)
217 {
218     QEvent::Type eventType = event->type();
219     switch (eventType) {
220     case QEvent::TouchBegin:
221     case QEvent::TouchEnd:
222     case QEvent::TouchUpdate:
223         touchEvent(static_cast<QTouchEvent*>(event));
224         return true;
225     case QEvent::Show:
226         page()->d->page->drawingArea()->setPageIsVisible(true);
227         break;
228     case QEvent::Hide:
229         page()->d->page->drawingArea()->setPageIsVisible(false);
230         break;
231     default:
232         break;
233     }
234 
235     // Here so that it can be reimplemented without breaking ABI.
236     return QGraphicsWidget::event(event);
237 }
238 
239 /*! \reimp
240 */
sizeHint(Qt::SizeHint which,const QSizeF & constraint) const241 QSizeF QGraphicsWKView::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const
242 {
243     if (which == Qt::PreferredSize)
244         return QSizeF(800, 600);
245     return QGraphicsWidget::sizeHint(which, constraint);
246 }
247 
248 /*! \reimp
249 */
inputMethodQuery(Qt::InputMethodQuery query) const250 QVariant QGraphicsWKView::inputMethodQuery(Qt::InputMethodQuery query) const
251 {
252     // implement
253     return QVariant();
254 }
255 
256 /*! \reimp
257 */
keyPressEvent(QKeyEvent * ev)258 void QGraphicsWKView::keyPressEvent(QKeyEvent* ev)
259 {
260     page()->d->keyPressEvent(ev);
261 }
262 
263 /*! \reimp
264 */
keyReleaseEvent(QKeyEvent * ev)265 void QGraphicsWKView::keyReleaseEvent(QKeyEvent* ev)
266 {
267     page()->d->keyReleaseEvent(ev);
268 }
269 
hoverMoveEvent(QGraphicsSceneHoverEvent * ev)270 void QGraphicsWKView::hoverMoveEvent(QGraphicsSceneHoverEvent* ev)
271 {
272     QGraphicsSceneMouseEvent me(QEvent::GraphicsSceneMouseMove);
273     me.setPos(ev->pos());
274     me.setScreenPos(ev->screenPos());
275 
276     page()->d->mouseMoveEvent(&me);
277 
278     if (!ev->isAccepted())
279         QGraphicsItem::hoverMoveEvent(ev);
280 }
281 
mouseMoveEvent(QGraphicsSceneMouseEvent * ev)282 void QGraphicsWKView::mouseMoveEvent(QGraphicsSceneMouseEvent* ev)
283 {
284     page()->d->mouseMoveEvent(ev);
285     if (!ev->isAccepted())
286         QGraphicsItem::mouseMoveEvent(ev);
287 }
288 
mousePressEvent(QGraphicsSceneMouseEvent * ev)289 void QGraphicsWKView::mousePressEvent(QGraphicsSceneMouseEvent* ev)
290 {
291     page()->d->mousePressEvent(ev);
292     if (!ev->isAccepted())
293         QGraphicsItem::mousePressEvent(ev);
294 }
295 
mouseReleaseEvent(QGraphicsSceneMouseEvent * ev)296 void QGraphicsWKView::mouseReleaseEvent(QGraphicsSceneMouseEvent* ev)
297 {
298     page()->d->mouseReleaseEvent(ev);
299     if (!ev->isAccepted())
300         QGraphicsItem::mouseReleaseEvent(ev);
301 }
302 
mouseDoubleClickEvent(QGraphicsSceneMouseEvent * ev)303 void QGraphicsWKView::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* ev)
304 {
305     page()->d->mouseDoubleClickEvent(ev);
306     if (!ev->isAccepted())
307         QGraphicsItem::mouseReleaseEvent(ev);
308 }
309 
wheelEvent(QGraphicsSceneWheelEvent * ev)310 void QGraphicsWKView::wheelEvent(QGraphicsSceneWheelEvent* ev)
311 {
312     page()->d->wheelEvent(ev);
313     if (!ev->isAccepted())
314         QGraphicsItem::wheelEvent(ev);
315 }
316 
touchEvent(QTouchEvent * ev)317 void QGraphicsWKView::touchEvent(QTouchEvent* ev)
318 {
319     page()->d->touchEvent(ev);
320 }
321 
focusInEvent(QFocusEvent *)322 void QGraphicsWKView::focusInEvent(QFocusEvent*)
323 {
324     page()->d->page->viewStateDidChange(WebPageProxy::ViewIsFocused | WebPageProxy::ViewWindowIsActive);
325 }
326 
focusOutEvent(QFocusEvent *)327 void QGraphicsWKView::focusOutEvent(QFocusEvent*)
328 {
329     page()->d->page->viewStateDidChange(WebPageProxy::ViewIsFocused | WebPageProxy::ViewWindowIsActive);
330 }
331 
332 
333 /*!
334     This slot is called when the engine require a context sensitive menu to be displayed.
335 
336     The \a menu passed as a parameter is the menu to be displayed. It is populated with the
337     actions possible for its current position. The menu is empty if there is no action for the position.
338 */
showContextMenu(QSharedPointer<QMenu> menu)339 void QGraphicsWKView::showContextMenu(QSharedPointer<QMenu> menu)
340 {
341     // Remove the active menu in case this function is called twice.
342     if (d->activeMenu)
343         d->activeMenu->hide();
344 
345     if (menu->isEmpty())
346         return;
347 
348     d->activeMenu = menu;
349 
350     QWidget* view = 0;
351     if (QGraphicsScene* myScene = scene()) {
352         const QList<QGraphicsView*> views = myScene->views();
353         for (unsigned i = 0; i < views.size(); ++i) {
354             if (views.at(i) == QApplication::focusWidget()) {
355                 view = views.at(i);
356                 break;
357             }
358         }
359         if (!view)
360             view = views.value(0, 0);
361     }
362     if (view)
363         menu->setParent(view, menu->windowFlags());
364     menu->exec(view->mapToGlobal(menu->pos()));
365     if (d->activeMenu == menu)
366         d->activeMenu.clear();
367 }
368 
takeSnapshot(const QSize & size,const QRect & contentsRect)369 void QGraphicsWKView::takeSnapshot(const QSize& size, const QRect& contentsRect)
370 {
371 #if ENABLE(TILED_BACKING_STORE)
372     DrawingAreaProxy* drawingArea = page()->d->page->drawingArea();
373     if (drawingArea->type() != DrawingAreaTypeTiled)
374         return;
375     TiledDrawingAreaProxy* tiledDrawingArea = static_cast<TiledDrawingAreaProxy*>(drawingArea);
376     tiledDrawingArea->takeSnapshot(size, contentsRect);
377 #endif
378 }
379 
QGraphicsWKViewPrivate(QGraphicsWKView * view)380 QGraphicsWKViewPrivate::QGraphicsWKViewPrivate(QGraphicsWKView* view)
381     : q(view)
382     , activeMenu(0)
383     , m_scaleCommitTimer(RunLoop::current(), this, &QGraphicsWKViewPrivate::commitScale)
384     , m_isChangingScale(false)
385 {
386 }
387 
visibleRect() const388 QRectF QGraphicsWKView::visibleRect() const
389 {
390     if (!scene())
391         return QRectF();
392 
393     QList<QGraphicsView*> views = scene()->views();
394     if (views.isEmpty())
395         return QRectF();
396 
397     QGraphicsView* graphicsView = views.at(0);
398     int xOffset = graphicsView->horizontalScrollBar()->value();
399     int yOffset = graphicsView->verticalScrollBar()->value();
400     return mapRectFromScene(QRectF(QPointF(xOffset, yOffset), graphicsView->viewport()->size()));
401 }
402 
prepareScaleChange()403 void QGraphicsWKView::prepareScaleChange()
404 {
405 #if ENABLE(TILED_BACKING_STORE)
406     ASSERT(!d->m_isChangingScale);
407     d->m_isChangingScale = true;
408     d->m_scaleCommitTimer.stop();
409 #endif
410 }
411 
commitScaleChange()412 void QGraphicsWKView::commitScaleChange()
413 {
414 #if ENABLE(TILED_BACKING_STORE)
415     ASSERT(d->m_isChangingScale);
416     d->m_isChangingScale = false;
417     d->commitScale();
418 #endif
419 }
420 
onScaleChanged()421 void QGraphicsWKViewPrivate::onScaleChanged()
422 {
423 #if ENABLE(TILED_BACKING_STORE)
424     if (!m_isChangingScale)
425         m_scaleCommitTimer.startOneShot(0.1);
426 #endif
427 }
428 
onToolTipChanged(const QString & toolTip)429 void QGraphicsWKViewPrivate::onToolTipChanged(const QString& toolTip)
430 {
431     q->setToolTip(toolTip);
432 }
433 
commitScale()434 void QGraphicsWKViewPrivate::commitScale()
435 {
436 #if ENABLE(TILED_BACKING_STORE)
437     DrawingAreaProxy* drawingArea = page->d->page->drawingArea();
438     float newScale = q->scale();
439     if (drawingArea->type() == DrawingAreaTypeTiled) {
440         TiledDrawingAreaProxy* tiledDrawingArea = static_cast<TiledDrawingAreaProxy*>(drawingArea);
441         if (tiledDrawingArea->contentsScale() == newScale)
442             return;
443         tiledDrawingArea->setContentsScale(newScale);
444         // For now we block until complete.
445         tiledDrawingArea->waitUntilUpdatesComplete();
446     }
447 #endif
448 }
449 
450 #include "moc_qgraphicswkview.cpp"
451