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