1/* 2 * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) 3 * Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in> 4 * Copyright (C) 2006 George Staikos <staikos@kde.org> 5 * Copyright (C) 2006 Dirk Mueller <mueller@kde.org> 6 * Copyright (C) 2006 Zack Rusin <zack@kde.org> 7 * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org> 8 * 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 21 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 28 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#include "webview.h" 34 35#include <QtGui> 36#include <QGraphicsScene> 37 38WebViewGraphicsBased::WebViewGraphicsBased(QWidget* parent) 39 : QGraphicsView(parent) 40 , m_item(new GraphicsWebView) 41 , m_numPaintsTotal(0) 42 , m_numPaintsSinceLastMeasure(0) 43 , m_measureFps(false) 44 , m_resizesToContents(false) 45 , m_machine(0) 46{ 47 setScene(new QGraphicsScene(this)); 48 scene()->addItem(m_item); 49 scene()->setFocusItem(m_item); 50 51 setFrameShape(QFrame::NoFrame); 52 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 53 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 54 55 m_updateTimer = new QTimer(this); 56 m_updateTimer->setInterval(1000); 57 connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(updateFrameRate())); 58} 59 60void WebViewGraphicsBased::setPage(QWebPage* page) 61{ 62 connect(page->mainFrame(), SIGNAL(contentsSizeChanged(const QSize&)), SLOT(contentsSizeChanged(const QSize&))); 63 connect(page, SIGNAL(scrollRequested(int, int, const QRect&)), SLOT(scrollRequested(int, int))); 64 graphicsWebView()->setPage(page); 65} 66 67void WebViewGraphicsBased::scrollRequested(int x, int y) 68{ 69 if (!m_resizesToContents) 70 return; 71 72 // Turn off interactive mode while scrolling, or QGraphicsView will replay the 73 // last mouse event which may cause WebKit to initiate a drag operation. 74 bool interactive = isInteractive(); 75 setInteractive(false); 76 77 verticalScrollBar()->setValue(-y); 78 horizontalScrollBar()->setValue(-x); 79 80 setInteractive(interactive); 81} 82 83void WebViewGraphicsBased::contentsSizeChanged(const QSize& size) 84{ 85 if (m_resizesToContents) 86 scene()->setSceneRect(0, 0, size.width(), size.height()); 87} 88 89void WebViewGraphicsBased::setResizesToContents(bool b) 90{ 91 if (b == m_resizesToContents) 92 return; 93 94 m_resizesToContents = b; 95 graphicsWebView()->setResizesToContents(m_resizesToContents); 96 97 // When setting resizesToContents ON, our web view widget will always size as big as the 98 // web content being displayed, and so will the QWebPage's viewport. It implies that internally 99 // WebCore will work as if there was no content rendered offscreen, and then no scrollbars need 100 // drawing. In order to keep scrolling working, we: 101 // 102 // 1) Set QGraphicsView's scrollbars policy back to 'auto'. 103 // 2) Set scene's boundaries rect to an invalid size, which automatically makes it to be as big 104 // as it needs to enclose all items onto it. We do that because QGraphicsView also calculates 105 // the size of its scrollable area according to the amount of content in scene that is rendered 106 // offscreen. 107 // 3) Set QWebPage's preferredContentsSize according to the size of QGraphicsView's viewport, 108 // so WebCore properly lays pages out. 109 // 110 // On the other hand, when toggling resizesToContents OFF, we set back the default values, as 111 // opposite as described above. 112 if (m_resizesToContents) { 113 setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); 114 setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); 115 graphicsWebView()->page()->setPreferredContentsSize(size()); 116 QRectF itemRect(graphicsWebView()->geometry().topLeft(), graphicsWebView()->page()->mainFrame()->contentsSize()); 117 graphicsWebView()->setGeometry(itemRect); 118 scene()->setSceneRect(itemRect); 119 } else { 120 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 121 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 122 graphicsWebView()->page()->setPreferredContentsSize(QSize()); 123 QRect viewportRect(QPoint(0, 0), size()); 124 graphicsWebView()->setGeometry(viewportRect); 125 scene()->setSceneRect(viewportRect); 126 } 127} 128 129void WebViewGraphicsBased::resizeEvent(QResizeEvent* event) 130{ 131 QGraphicsView::resizeEvent(event); 132 133 QSize size(event->size()); 134 135 if (m_resizesToContents) { 136 graphicsWebView()->page()->setPreferredContentsSize(size); 137 return; 138 } 139 140 QRectF rect(QPoint(0, 0), size); 141 graphicsWebView()->setGeometry(rect); 142 scene()->setSceneRect(rect); 143} 144 145void WebViewGraphicsBased::setFrameRateMeasurementEnabled(bool enabled) 146{ 147 m_measureFps = enabled; 148 if (m_measureFps) { 149 m_lastConsultTime = m_startTime = QTime::currentTime(); 150 m_fpsTimer.start(); 151 m_updateTimer->start(); 152 } else { 153 m_fpsTimer.stop(); 154 m_updateTimer->stop(); 155 } 156} 157 158void WebViewGraphicsBased::updateFrameRate() 159{ 160 const QTime now = QTime::currentTime(); 161 int interval = m_lastConsultTime.msecsTo(now); 162 int frames = m_fpsTimer.numFrames(interval); 163 int current = interval ? frames * 1000 / interval : 0; 164 165 emit currentFPSUpdated(current); 166 167 m_lastConsultTime = now; 168} 169 170void WebViewGraphicsBased::animatedFlip() 171{ 172#ifndef QT_NO_ANIMATION 173 QSizeF center = graphicsWebView()->boundingRect().size() / 2; 174 QPointF centerPoint = QPointF(center.width(), center.height()); 175 graphicsWebView()->setTransformOriginPoint(centerPoint); 176 177 QPropertyAnimation* animation = new QPropertyAnimation(graphicsWebView(), "rotation", this); 178 animation->setDuration(1000); 179 180 int rotation = int(graphicsWebView()->rotation()); 181 182 animation->setStartValue(rotation); 183 animation->setEndValue(rotation + 180 - (rotation % 180)); 184 185 animation->start(QAbstractAnimation::DeleteWhenStopped); 186#endif 187} 188 189void WebViewGraphicsBased::animatedYFlip() 190{ 191#ifndef QT_NO_ANIMATION 192 if (!m_machine) { 193 m_machine = new QStateMachine(this); 194 195 QState* s0 = new QState(m_machine); 196 s0->assignProperty(this, "yRotation", 0); 197 198 QState* s1 = new QState(m_machine); 199 s1->assignProperty(this, "yRotation", 90); 200 201 QAbstractTransition* t1 = s0->addTransition(s1); 202 QPropertyAnimation* yRotationAnim = new QPropertyAnimation(this, "yRotation", this); 203 t1->addAnimation(yRotationAnim); 204 205 QState* s2 = new QState(m_machine); 206 s2->assignProperty(this, "yRotation", -90); 207 s1->addTransition(s1, SIGNAL(propertiesAssigned()), s2); 208 209 QState* s3 = new QState(m_machine); 210 s3->assignProperty(this, "yRotation", 0); 211 212 QAbstractTransition* t2 = s2->addTransition(s3); 213 t2->addAnimation(yRotationAnim); 214 215 QFinalState* final = new QFinalState(m_machine); 216 s3->addTransition(s3, SIGNAL(propertiesAssigned()), final); 217 218 m_machine->setInitialState(s0); 219 yRotationAnim->setDuration(1000); 220 } 221 222 m_machine->start(); 223#endif 224} 225 226void WebViewGraphicsBased::paintEvent(QPaintEvent* event) 227{ 228 QGraphicsView::paintEvent(event); 229 if (!m_measureFps) 230 return; 231} 232 233static QMenu* createContextMenu(QWebPage* page, QPoint position) 234{ 235 QMenu* menu = page->createStandardContextMenu(); 236 237 QWebHitTestResult r = page->mainFrame()->hitTestContent(position); 238 239 if (!r.linkUrl().isEmpty()) { 240 WebPage* webPage = qobject_cast<WebPage*>(page); 241 QAction* newTabAction = menu->addAction("Open in Default &Browser", webPage, SLOT(openUrlInDefaultBrowser())); 242 newTabAction->setData(r.linkUrl()); 243 menu->insertAction(menu->actions().at(2), newTabAction); 244 } 245 return menu; 246} 247 248void GraphicsWebView::mousePressEvent(QGraphicsSceneMouseEvent* event) 249{ 250 setProperty("mouseButtons", QVariant::fromValue(int(event->buttons()))); 251 setProperty("keyboardModifiers", QVariant::fromValue(int(event->modifiers()))); 252 253 QGraphicsWebView::mousePressEvent(event); 254} 255 256void WebViewTraditional::mousePressEvent(QMouseEvent* event) 257{ 258 setProperty("mouseButtons", QVariant::fromValue(int(event->buttons()))); 259 setProperty("keyboardModifiers", QVariant::fromValue(int(event->modifiers()))); 260 261 QWebView::mousePressEvent(event); 262} 263 264void GraphicsWebView::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) 265{ 266 QMenu* menu = createContextMenu(page(), event->pos().toPoint()); 267 menu->exec(event->screenPos()); 268 delete menu; 269} 270 271void WebViewTraditional::contextMenuEvent(QContextMenuEvent* event) 272{ 273 QMenu* menu = createContextMenu(page(), event->pos()); 274 menu->exec(event->globalPos()); 275 delete menu; 276} 277 278