qgraphicswebview.cpp [plain text]
#include "config.h"
#include "qgraphicswebview.h"
#if !defined(QT_NO_GRAPHICSVIEW)
#include "qwebframe.h"
#include "qwebframe_p.h"
#include "qwebpage.h"
#include "qwebpage_p.h"
#include "Page.h"
#include "PageClientQt.h"
#include "Frame.h"
#include "FrameView.h"
#include "GraphicsContext.h"
#include "IntRect.h"
#include "TiledBackingStore.h"
#include <QtCore/qmetaobject.h>
#include <QtCore/qsharedpointer.h>
#include <QtCore/qtimer.h>
#include <QtGui/qapplication.h>
#include <QtGui/qgraphicsscene.h>
#include <QtGui/qgraphicssceneevent.h>
#include <QtGui/qgraphicsview.h>
#include <QtGui/qpixmapcache.h>
#include <QtGui/qscrollbar.h>
#include <QtGui/qstyleoption.h>
#include <QtGui/qinputcontext.h>
#if defined(Q_WS_X11)
#include <QX11Info>
#endif
#include <Settings.h>
using namespace WebCore;
class QGraphicsWebViewPrivate {
public:
QGraphicsWebViewPrivate(QGraphicsWebView* parent)
: q(parent)
, page(0)
, resizesToContents(false)
, renderHints(QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform) {}
virtual ~QGraphicsWebViewPrivate();
void syncLayers();
void updateResizesToContentsForPage();
void detachCurrentPage();
void _q_doLoadFinished(bool success);
void _q_contentsSizeChanged(const QSize&);
void _q_scaleChanged();
void _q_pageDestroyed();
QGraphicsWebView* q;
QWebPage* page;
bool resizesToContents;
QPainter::RenderHints renderHints;
QGraphicsItemOverlay* overlay() const
{
if (!page || !page->d->client)
return 0;
return pageClient()->overlay;
}
PageClientQGraphicsWidget* pageClient() const
{
return static_cast<WebCore::PageClientQGraphicsWidget*> (page->d->client.get());
}
};
QGraphicsWebViewPrivate::~QGraphicsWebViewPrivate()
{
detachCurrentPage();
}
void QGraphicsWebViewPrivate::syncLayers()
{
#if USE(ACCELERATED_COMPOSITING)
pageClient()->syncLayers();
#endif
}
void QGraphicsWebViewPrivate::_q_doLoadFinished(bool success)
{
if (q->title().isEmpty())
emit q->urlChanged(q->url());
emit q->loadFinished(success);
}
void QGraphicsWebViewPrivate::_q_pageDestroyed()
{
page = 0;
q->setPage(0);
}
void QGraphicsWebViewPrivate::updateResizesToContentsForPage()
{
ASSERT(page);
pageClient()->viewResizesToContents = resizesToContents;
if (resizesToContents) {
if (!page->preferredContentsSize().isValid())
page->setPreferredContentsSize(QSize(960, 800));
QObject::connect(page->mainFrame(), SIGNAL(contentsSizeChanged(QSize)),
q, SLOT(_q_contentsSizeChanged(const QSize&)), Qt::UniqueConnection);
} else {
QObject::disconnect(page->mainFrame(), SIGNAL(contentsSizeChanged(QSize)),
q, SLOT(_q_contentsSizeChanged(const QSize&)));
}
page->d->page->mainFrame()->view()->setPaintsEntireContents(resizesToContents);
page->d->page->mainFrame()->view()->setDelegatesScrolling(resizesToContents);
}
void QGraphicsWebViewPrivate::_q_contentsSizeChanged(const QSize& size)
{
if (!resizesToContents)
return;
q->setGeometry(QRectF(q->geometry().topLeft(), size));
}
void QGraphicsWebViewPrivate::_q_scaleChanged()
{
#if ENABLE(TILED_BACKING_STORE)
if (!page)
return;
pageClient()->updateTiledBackingStoreScale();
#endif
}
QGraphicsWebView::QGraphicsWebView(QGraphicsItem* parent)
: QGraphicsWidget(parent)
, d(new QGraphicsWebViewPrivate(this))
{
setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
setAcceptDrops(true);
setAcceptHoverEvents(true);
setAcceptTouchEvents(true);
setFocusPolicy(Qt::StrongFocus);
setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
#if ENABLE(TILED_BACKING_STORE)
QObject::connect(this, SIGNAL(scaleChanged()), this, SLOT(_q_scaleChanged()));
#endif
}
QGraphicsWebView::~QGraphicsWebView()
{
delete d;
}
QWebPage* QGraphicsWebView::page() const
{
if (!d->page) {
QGraphicsWebView* that = const_cast<QGraphicsWebView*>(this);
QWebPage* page = new QWebPage(that);
QPalette palette = QApplication::palette();
palette.setBrush(QPalette::Base, QColor::fromRgbF(0, 0, 0, 0));
page->setPalette(palette);
that->setPage(page);
}
return d->page;
}
void QGraphicsWebView::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget*)
{
QPainter::RenderHints oldHints = painter->renderHints();
painter->setRenderHints(oldHints | d->renderHints);
#if ENABLE(TILED_BACKING_STORE)
if (WebCore::TiledBackingStore* backingStore = QWebFramePrivate::core(page()->mainFrame())->tiledBackingStore()) {
backingStore->adjustVisibleRect();
WebCore::GraphicsContext context(painter);
page()->mainFrame()->d->renderFromTiledBackingStore(&context, option->exposedRect.toAlignedRect());
painter->setRenderHints(oldHints);
return;
}
#endif
#if USE(ACCELERATED_COMPOSITING) && !USE(TEXTURE_MAPPER)
page()->mainFrame()->render(painter, d->overlay() ? QWebFrame::ContentsLayer : QWebFrame::AllLayers, option->exposedRect.toAlignedRect());
#else
page()->mainFrame()->render(painter, QWebFrame::AllLayers, option->exposedRect.toRect());
#endif
painter->setRenderHints(oldHints);
}
bool QGraphicsWebView::sceneEvent(QEvent* event)
{
if (d->page && (event->type() == QEvent::TouchBegin
|| event->type() == QEvent::TouchEnd
|| event->type() == QEvent::TouchUpdate)) {
d->page->event(event);
return true;
}
return QGraphicsWidget::sceneEvent(event);
}
QVariant QGraphicsWebView::itemChange(GraphicsItemChange change, const QVariant& value)
{
switch (change) {
case ItemCursorChange:
return value;
case ItemCursorHasChanged: {
QEvent event(QEvent::CursorChange);
QApplication::sendEvent(this, &event);
return value;
}
default:
break;
}
return QGraphicsWidget::itemChange(change, value);
}
QSizeF QGraphicsWebView::sizeHint(Qt::SizeHint which, const QSizeF& constraint) const
{
if (which == Qt::PreferredSize)
return QSizeF(800, 600); return QGraphicsWidget::sizeHint(which, constraint);
}
QVariant QGraphicsWebView::inputMethodQuery(Qt::InputMethodQuery query) const
{
if (d->page)
return d->page->inputMethodQuery(query);
return QVariant();
}
QPainter::RenderHints QGraphicsWebView::renderHints() const
{
return d->renderHints;
}
void QGraphicsWebView::setRenderHints(QPainter::RenderHints hints)
{
if (hints == d->renderHints)
return;
d->renderHints = hints;
update();
}
void QGraphicsWebView::setRenderHint(QPainter::RenderHint hint, bool enabled)
{
QPainter::RenderHints oldHints = d->renderHints;
if (enabled)
d->renderHints |= hint;
else
d->renderHints &= ~hint;
if (oldHints != d->renderHints)
update();
}
bool QGraphicsWebView::event(QEvent* event)
{
if (d->page) {
if (event->type() == QEvent::PaletteChange)
d->page->setPalette(palette());
#ifndef QT_NO_CONTEXTMENU
if (event->type() == QEvent::GraphicsSceneContextMenu) {
if (!isEnabled())
return false;
QGraphicsSceneContextMenuEvent* ev = static_cast<QGraphicsSceneContextMenuEvent*>(event);
QContextMenuEvent fakeEvent(QContextMenuEvent::Reason(ev->reason()), ev->pos().toPoint());
if (d->page->swallowContextMenuEvent(&fakeEvent)) {
event->accept();
return true;
}
d->page->updatePositionDependentActions(fakeEvent.pos());
} else
#endif // QT_NO_CONTEXTMENU
{
#ifndef QT_NO_CURSOR
if (event->type() == QEvent::CursorChange) {
if (cursor().shape() == Qt::ArrowCursor)
d->page->d->client->resetCursor();
}
#endif
}
}
return QGraphicsWidget::event(event);
}
void QGraphicsWebViewPrivate::detachCurrentPage()
{
if (!page)
return;
page->d->view.clear();
page->d->client = nullptr;
if (page->parent() == q)
delete page;
else
page->disconnect(q);
page = 0;
}
void QGraphicsWebView::setPage(QWebPage* page)
{
if (d->page == page)
return;
d->detachCurrentPage();
d->page = page;
if (!d->page)
return;
d->page->d->client = adoptPtr(new PageClientQGraphicsWidget(this, page));
if (d->overlay())
d->overlay()->prepareGraphicsItemGeometryChange();
QSize size = geometry().size().toSize();
page->setViewportSize(size);
if (d->resizesToContents)
d->updateResizesToContentsForPage();
QWebFrame* mainFrame = d->page->mainFrame();
connect(mainFrame, SIGNAL(titleChanged(QString)),
this, SIGNAL(titleChanged(QString)));
connect(mainFrame, SIGNAL(iconChanged()),
this, SIGNAL(iconChanged()));
connect(mainFrame, SIGNAL(urlChanged(QUrl)),
this, SIGNAL(urlChanged(QUrl)));
connect(d->page, SIGNAL(loadStarted()),
this, SIGNAL(loadStarted()));
connect(d->page, SIGNAL(loadProgress(int)),
this, SIGNAL(loadProgress(int)));
connect(d->page, SIGNAL(loadFinished(bool)),
this, SLOT(_q_doLoadFinished(bool)));
connect(d->page, SIGNAL(statusBarMessage(QString)),
this, SIGNAL(statusBarMessage(QString)));
connect(d->page, SIGNAL(linkClicked(QUrl)),
this, SIGNAL(linkClicked(QUrl)));
connect(d->page, SIGNAL(destroyed()),
this, SLOT(_q_pageDestroyed()));
#if !defined(QT_NO_IM) && (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN))
connect(d->page, SIGNAL(microFocusChanged()),
this, SLOT(updateMicroFocus()));
#endif
}
void QGraphicsWebView::setUrl(const QUrl &url)
{
page()->mainFrame()->setUrl(url);
}
QUrl QGraphicsWebView::url() const
{
if (d->page)
return d->page->mainFrame()->url();
return QUrl();
}
QString QGraphicsWebView::title() const
{
if (d->page)
return d->page->mainFrame()->title();
return QString();
}
QIcon QGraphicsWebView::icon() const
{
if (d->page)
return d->page->mainFrame()->icon();
return QIcon();
}
void QGraphicsWebView::setZoomFactor(qreal factor)
{
if (factor == page()->mainFrame()->zoomFactor())
return;
page()->mainFrame()->setZoomFactor(factor);
}
qreal QGraphicsWebView::zoomFactor() const
{
return page()->mainFrame()->zoomFactor();
}
void QGraphicsWebView::updateGeometry()
{
if (d->overlay())
d->overlay()->prepareGraphicsItemGeometryChange();
QGraphicsWidget::updateGeometry();
if (!d->page)
return;
QSize size = geometry().size().toSize();
d->page->setViewportSize(size);
}
void QGraphicsWebView::setGeometry(const QRectF& rect)
{
QGraphicsWidget::setGeometry(rect);
if (d->overlay())
d->overlay()->prepareGraphicsItemGeometryChange();
if (!d->page)
return;
QSize size = geometry().size().toSize();
d->page->setViewportSize(size);
}
void QGraphicsWebView::stop()
{
if (d->page)
d->page->triggerAction(QWebPage::Stop);
}
void QGraphicsWebView::back()
{
if (d->page)
d->page->triggerAction(QWebPage::Back);
}
void QGraphicsWebView::forward()
{
if (d->page)
d->page->triggerAction(QWebPage::Forward);
}
void QGraphicsWebView::reload()
{
if (d->page)
d->page->triggerAction(QWebPage::Reload);
}
void QGraphicsWebView::load(const QUrl& url)
{
page()->mainFrame()->load(url);
}
void QGraphicsWebView::load(const QNetworkRequest& request,
QNetworkAccessManager::Operation operation,
const QByteArray& body)
{
page()->mainFrame()->load(request, operation, body);
}
void QGraphicsWebView::setHtml(const QString& html, const QUrl& baseUrl)
{
page()->mainFrame()->setHtml(html, baseUrl);
}
void QGraphicsWebView::setContent(const QByteArray& data, const QString& mimeType, const QUrl& baseUrl)
{
page()->mainFrame()->setContent(data, mimeType, baseUrl);
}
QWebHistory* QGraphicsWebView::history() const
{
return page()->history();
}
bool QGraphicsWebView::isModified() const
{
if (d->page)
return d->page->isModified();
return false;
}
QWebSettings* QGraphicsWebView::settings() const
{
return page()->settings();
}
QAction *QGraphicsWebView::pageAction(QWebPage::WebAction action) const
{
#ifdef QT_NO_ACTION
Q_UNUSED(action)
return 0;
#else
return page()->action(action);
#endif
}
void QGraphicsWebView::triggerPageAction(QWebPage::WebAction action, bool checked)
{
page()->triggerAction(action, checked);
}
bool QGraphicsWebView::findText(const QString &subString, QWebPage::FindFlags options)
{
if (d->page)
return d->page->findText(subString, options);
return false;
}
void QGraphicsWebView::setResizesToContents(bool enabled)
{
if (d->resizesToContents == enabled)
return;
d->resizesToContents = enabled;
if (d->page)
d->updateResizesToContentsForPage();
}
bool QGraphicsWebView::resizesToContents() const
{
return d->resizesToContents;
}
bool QGraphicsWebView::isTiledBackingStoreFrozen() const
{
#if ENABLE(TILED_BACKING_STORE)
WebCore::TiledBackingStore* backingStore = QWebFramePrivate::core(page()->mainFrame())->tiledBackingStore();
if (!backingStore)
return false;
return backingStore->contentsFrozen();
#else
return false;
#endif
}
void QGraphicsWebView::setTiledBackingStoreFrozen(bool frozen)
{
#if ENABLE(TILED_BACKING_STORE)
WebCore::TiledBackingStore* backingStore = QWebFramePrivate::core(page()->mainFrame())->tiledBackingStore();
if (!backingStore)
return;
backingStore->setContentsFrozen(frozen);
#else
UNUSED_PARAM(frozen);
#endif
}
void QGraphicsWebView::hoverMoveEvent(QGraphicsSceneHoverEvent* ev)
{
if (d->page) {
const bool accepted = ev->isAccepted();
QMouseEvent me = QMouseEvent(QEvent::MouseMove,
ev->pos().toPoint(), Qt::NoButton,
Qt::NoButton, Qt::NoModifier);
d->page->event(&me);
ev->setAccepted(accepted);
}
if (!ev->isAccepted())
QGraphicsItem::hoverMoveEvent(ev);
}
void QGraphicsWebView::hoverLeaveEvent(QGraphicsSceneHoverEvent* ev)
{
Q_UNUSED(ev);
}
void QGraphicsWebView::mouseMoveEvent(QGraphicsSceneMouseEvent* ev)
{
if (d->page) {
const bool accepted = ev->isAccepted();
d->page->event(ev);
ev->setAccepted(accepted);
}
if (!ev->isAccepted())
QGraphicsItem::mouseMoveEvent(ev);
}
void QGraphicsWebView::mousePressEvent(QGraphicsSceneMouseEvent* ev)
{
if (d->page) {
const bool accepted = ev->isAccepted();
d->page->event(ev);
ev->setAccepted(accepted);
}
if (!ev->isAccepted())
QGraphicsItem::mousePressEvent(ev);
}
void QGraphicsWebView::mouseReleaseEvent(QGraphicsSceneMouseEvent* ev)
{
if (d->page) {
const bool accepted = ev->isAccepted();
d->page->event(ev);
ev->setAccepted(accepted);
}
if (!ev->isAccepted())
QGraphicsItem::mouseReleaseEvent(ev);
}
void QGraphicsWebView::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* ev)
{
if (d->page) {
const bool accepted = ev->isAccepted();
d->page->event(ev);
ev->setAccepted(accepted);
}
if (!ev->isAccepted())
QGraphicsItem::mouseDoubleClickEvent(ev);
}
void QGraphicsWebView::keyPressEvent(QKeyEvent* ev)
{
if (d->page)
d->page->event(ev);
if (!ev->isAccepted())
QGraphicsItem::keyPressEvent(ev);
}
void QGraphicsWebView::keyReleaseEvent(QKeyEvent* ev)
{
if (d->page)
d->page->event(ev);
if (!ev->isAccepted())
QGraphicsItem::keyReleaseEvent(ev);
}
void QGraphicsWebView::focusInEvent(QFocusEvent* ev)
{
if (d->page)
d->page->event(ev);
else
QGraphicsItem::focusInEvent(ev);
}
void QGraphicsWebView::focusOutEvent(QFocusEvent* ev)
{
if (d->page)
d->page->event(ev);
else
QGraphicsItem::focusOutEvent(ev);
}
bool QGraphicsWebView::focusNextPrevChild(bool next)
{
if (d->page)
return d->page->focusNextPrevChild(next);
return QGraphicsWidget::focusNextPrevChild(next);
}
void QGraphicsWebView::dragEnterEvent(QGraphicsSceneDragDropEvent* ev)
{
#ifndef QT_NO_DRAGANDDROP
if (d->page)
d->page->event(ev);
#else
Q_UNUSED(ev);
#endif
}
void QGraphicsWebView::dragLeaveEvent(QGraphicsSceneDragDropEvent* ev)
{
#ifndef QT_NO_DRAGANDDROP
if (d->page) {
const bool accepted = ev->isAccepted();
d->page->event(ev);
ev->setAccepted(accepted);
}
if (!ev->isAccepted())
QGraphicsWidget::dragLeaveEvent(ev);
#else
Q_UNUSED(ev);
#endif
}
void QGraphicsWebView::dragMoveEvent(QGraphicsSceneDragDropEvent* ev)
{
#ifndef QT_NO_DRAGANDDROP
if (d->page) {
const bool accepted = ev->isAccepted();
d->page->event(ev);
ev->setAccepted(accepted);
}
if (!ev->isAccepted())
QGraphicsWidget::dragMoveEvent(ev);
#else
Q_UNUSED(ev);
#endif
}
void QGraphicsWebView::dropEvent(QGraphicsSceneDragDropEvent* ev)
{
#ifndef QT_NO_DRAGANDDROP
if (d->page) {
const bool accepted = ev->isAccepted();
d->page->event(ev);
ev->setAccepted(accepted);
}
if (!ev->isAccepted())
QGraphicsWidget::dropEvent(ev);
#else
Q_UNUSED(ev);
#endif
}
#ifndef QT_NO_CONTEXTMENU
void QGraphicsWebView::contextMenuEvent(QGraphicsSceneContextMenuEvent* ev)
{
if (d->page) {
const bool accepted = ev->isAccepted();
d->page->event(ev);
ev->setAccepted(accepted);
}
}
#endif // QT_NO_CONTEXTMENU
#ifndef QT_NO_WHEELEVENT
void QGraphicsWebView::wheelEvent(QGraphicsSceneWheelEvent* ev)
{
if (d->page) {
const bool accepted = ev->isAccepted();
d->page->event(ev);
ev->setAccepted(accepted);
}
if (!ev->isAccepted())
QGraphicsItem::wheelEvent(ev);
}
#endif // QT_NO_WHEELEVENT
void QGraphicsWebView::inputMethodEvent(QInputMethodEvent* ev)
{
if (d->page)
d->page->event(ev);
if (!ev->isAccepted())
QGraphicsItem::inputMethodEvent(ev);
}
#endif // QT_NO_GRAPHICSVIEW
#include "moc_qgraphicswebview.cpp"