| /* |
| Copyright (C) 2009 Jakub Wieczorek <faw217@gmail.com> |
| |
| This library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Library General Public |
| License as published by the Free Software Foundation; either |
| version 2 of the License, or (at your option) any later version. |
| |
| This library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Library General Public License for more details. |
| |
| You should have received a copy of the GNU Library General Public License |
| along with this library; see the file COPYING.LIB. If not, write to |
| the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| Boston, MA 02110-1301, USA. |
| */ |
| |
| #include "../util.h" |
| #include <QtTest/QtTest> |
| #include <QGraphicsSceneMouseEvent> |
| #include <QGraphicsView> |
| #include <QStyleOptionGraphicsItem> |
| #include <qgraphicswebview.h> |
| #include <qwebpage.h> |
| #include <qwebframe.h> |
| |
| #if defined(ENABLE_WEBGL) && ENABLE_WEBGL |
| #include <QGLWidget> |
| #endif |
| |
| class tst_QGraphicsWebView : public QObject |
| { |
| Q_OBJECT |
| |
| private slots: |
| void qgraphicswebview(); |
| void crashOnViewlessWebPages(); |
| void microFocusCoordinates(); |
| void focusInputTypes(); |
| void crashOnSetScaleBeforeSetUrl(); |
| void widgetsRenderingThroughCache(); |
| void setPalette_data(); |
| void setPalette(); |
| void renderHints(); |
| #if defined(ENABLE_TILED_BACKING_STORE) && ENABLE_TILED_BACKING_STORE |
| void bug56929(); |
| #endif |
| #if defined(ENABLE_WEBGL) && ENABLE_WEBGL |
| void webglSoftwareFallbackVerticalOrientation(); |
| void webglSoftwareFallbackHorizontalOrientation(); |
| |
| private: |
| void compareCanvasToImage(const QUrl&, const QImage&); |
| #endif |
| }; |
| |
| void tst_QGraphicsWebView::qgraphicswebview() |
| { |
| QGraphicsWebView item; |
| item.url(); |
| item.title(); |
| item.icon(); |
| item.zoomFactor(); |
| item.history(); |
| item.settings(); |
| item.page(); |
| item.setPage(0); |
| item.page(); |
| item.setUrl(QUrl()); |
| item.setZoomFactor(0); |
| item.load(QUrl()); |
| item.setHtml(QString()); |
| item.setContent(QByteArray()); |
| item.isModified(); |
| } |
| |
| class WebPage : public QWebPage |
| { |
| Q_OBJECT |
| |
| public: |
| WebPage(QObject* parent = 0): QWebPage(parent) |
| { |
| } |
| |
| QGraphicsWebView* webView; |
| |
| private slots: |
| // Force a webview deletion during the load. |
| // It should not cause WebPage to crash due to |
| // it accessing invalid pageClient pointer. |
| void aborting() |
| { |
| delete webView; |
| } |
| }; |
| |
| class GraphicsWebView : public QGraphicsWebView |
| { |
| Q_OBJECT |
| |
| public: |
| GraphicsWebView(QGraphicsItem* parent = 0): QGraphicsWebView(parent) |
| { |
| } |
| |
| void fireMouseClick(QPointF point) { |
| QGraphicsSceneMouseEvent presEv(QEvent::GraphicsSceneMousePress); |
| presEv.setPos(point); |
| presEv.setButton(Qt::LeftButton); |
| presEv.setButtons(Qt::LeftButton); |
| QGraphicsSceneMouseEvent relEv(QEvent::GraphicsSceneMouseRelease); |
| relEv.setPos(point); |
| relEv.setButton(Qt::LeftButton); |
| relEv.setButtons(Qt::LeftButton); |
| QGraphicsWebView::sceneEvent(&presEv); |
| QGraphicsWebView::sceneEvent(&relEv); |
| } |
| }; |
| |
| void tst_QGraphicsWebView::crashOnViewlessWebPages() |
| { |
| QGraphicsScene scene; |
| QGraphicsView view(&scene); |
| |
| QGraphicsWebView* webView = new QGraphicsWebView; |
| WebPage* page = new WebPage; |
| webView->setPage(page); |
| page->webView = webView; |
| scene.addItem(webView); |
| |
| view.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); |
| view.resize(600, 480); |
| webView->resize(view.geometry().size()); |
| |
| QCoreApplication::processEvents(); |
| view.show(); |
| |
| // Resizing the page will resize and layout the empty "about:blank" |
| // page, so we first connect the signal afterward. |
| connect(page->mainFrame(), SIGNAL(initialLayoutCompleted()), page, SLOT(aborting())); |
| |
| page->mainFrame()->load(QUrl("data:text/html," |
| "<frameset cols=\"25%,75%\">" |
| "<frame src=\"data:text/html,foo \">" |
| "<frame src=\"data:text/html,bar\">" |
| "</frameset>")); |
| |
| QVERIFY(waitForSignal(page, SIGNAL(loadFinished(bool)))); |
| delete page; |
| } |
| |
| void tst_QGraphicsWebView::crashOnSetScaleBeforeSetUrl() |
| { |
| QGraphicsWebView* webView = new QGraphicsWebView; |
| webView->setScale(2.0); |
| delete webView; |
| } |
| |
| void tst_QGraphicsWebView::widgetsRenderingThroughCache() |
| { |
| // Widgets should be rendered the same way with and without |
| // intermediate cache (tiling for example). |
| // See bug https://bugs.webkit.org/show_bug.cgi?id=47767 where |
| // widget are rendered as disabled when caching is using. |
| |
| QGraphicsWebView* webView = new QGraphicsWebView; |
| webView->setHtml(QLatin1String("<body style=\"background-color: white\"><input type=range></input><input type=checkbox></input><input type=radio></input><input type=file></input></body>")); |
| |
| QGraphicsView view; |
| view.show(); |
| QGraphicsScene* scene = new QGraphicsScene(&view); |
| view.setScene(scene); |
| scene->addItem(webView); |
| view.setGeometry(QRect(0, 0, 500, 500)); |
| QWidget *const widget = &view; |
| QTest::qWaitForWindowShown(widget); |
| |
| // 1. Reference without tiling. |
| webView->settings()->setAttribute(QWebSettings::TiledBackingStoreEnabled, false); |
| QPixmap referencePixmap(view.size()); |
| widget->render(&referencePixmap); |
| |
| // 2. With tiling. |
| webView->settings()->setAttribute(QWebSettings::TiledBackingStoreEnabled, true); |
| QPixmap viewWithTiling(view.size()); |
| widget->render(&viewWithTiling); |
| QApplication::processEvents(); |
| viewWithTiling.fill(); |
| widget->render(&viewWithTiling); |
| |
| QCOMPARE(referencePixmap.toImage(), viewWithTiling.toImage()); |
| } |
| |
| #if defined(ENABLE_TILED_BACKING_STORE) && ENABLE_TILED_BACKING_STORE |
| void tst_QGraphicsWebView::bug56929() |
| { |
| // When rendering from tiles sychronous layout should not be triggered |
| // and scrollbars should be in sync with the size of the document in the displayed state. |
| |
| QGraphicsWebView* webView = new QGraphicsWebView(); |
| webView->setGeometry(QRectF(0.0, 0.0, 100.0, 100.0)); |
| QGraphicsView view(new QGraphicsScene()); |
| view.scene()->setParent(&view); |
| view.scene()->addItem(webView); |
| webView->settings()->setAttribute(QWebSettings::TiledBackingStoreEnabled, true); |
| QUrl url("qrc:///resources/56929.html"); |
| webView->load(url); |
| QVERIFY(waitForSignal(webView, SIGNAL(loadFinished(bool)))); |
| QStyleOptionGraphicsItem option; |
| option.exposedRect = webView->geometry(); |
| QImage img(option.exposedRect.width(), option.exposedRect.height(), QImage::Format_ARGB32_Premultiplied); |
| QPainter painter(&img); |
| // This will not paint anything as the tiles are not ready, yet. |
| webView->paint(&painter, &option); |
| QApplication::processEvents(); |
| webView->paint(&painter, &option); |
| QCOMPARE(img.pixel(option.exposedRect.width() - 2, option.exposedRect.height() / 2), qRgba(255, 255, 255, 255)); |
| painter.fillRect(option.exposedRect, Qt::black); |
| QCOMPARE(img.pixel(option.exposedRect.width() - 2, option.exposedRect.height() / 2), qRgba(0, 0, 0, 255)); |
| webView->page()->mainFrame()->evaluateJavaScript(QString("resizeDiv();")); |
| webView->paint(&painter, &option); |
| QCOMPARE(img.pixel(option.exposedRect.width() - 2, option.exposedRect.height() / 2), qRgba(255, 255, 255, 255)); |
| } |
| #endif |
| |
| void tst_QGraphicsWebView::microFocusCoordinates() |
| { |
| QWebPage* page = new QWebPage; |
| QGraphicsWebView* webView = new QGraphicsWebView; |
| webView->setPage( page ); |
| QGraphicsView* view = new QGraphicsView; |
| QGraphicsScene* scene = new QGraphicsScene(view); |
| view->setScene(scene); |
| scene->addItem(webView); |
| view->setGeometry(QRect(0,0,500,500)); |
| |
| page->mainFrame()->setHtml("<html><body>" \ |
| "<input type='text' id='input1' style='font--family: serif' value='' maxlength='20'/><br>" \ |
| "<canvas id='canvas1' width='500' height='500'></canvas>" \ |
| "<input type='password'/><br>" \ |
| "<canvas id='canvas2' width='500' height='500'></canvas>" \ |
| "</body></html>"); |
| |
| page->mainFrame()->setFocus(); |
| |
| QVariant initialMicroFocus = page->inputMethodQuery(Qt::ImMicroFocus); |
| QVERIFY(initialMicroFocus.isValid()); |
| |
| page->mainFrame()->scroll(0,300); |
| |
| QVariant currentMicroFocus = page->inputMethodQuery(Qt::ImMicroFocus); |
| QVERIFY(currentMicroFocus.isValid()); |
| |
| QCOMPARE(initialMicroFocus.toRect().translated(QPoint(0,-300)), currentMicroFocus.toRect()); |
| |
| delete view; |
| } |
| |
| void tst_QGraphicsWebView::focusInputTypes() |
| { |
| QWebPage* page = new QWebPage; |
| GraphicsWebView* webView = new GraphicsWebView; |
| webView->setPage( page ); |
| QGraphicsView* view = new QGraphicsView; |
| QGraphicsScene* scene = new QGraphicsScene(view); |
| view->setScene(scene); |
| scene->addItem(webView); |
| view->setGeometry(QRect(0,0,500,500)); |
| QCoreApplication::processEvents(); |
| QUrl url("qrc:///resources/input_types.html"); |
| page->mainFrame()->load(url); |
| page->mainFrame()->setFocus(); |
| |
| QVERIFY(waitForSignal(page, SIGNAL(loadFinished(bool)))); |
| |
| // 'text' type |
| webView->fireMouseClick(QPointF(20.0, 10.0)); |
| #if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) || defined(Q_OS_SYMBIAN) |
| QVERIFY(webView->inputMethodHints() & Qt::ImhNoAutoUppercase); |
| QVERIFY(webView->inputMethodHints() & Qt::ImhNoPredictiveText); |
| #else |
| QVERIFY(webView->inputMethodHints() == Qt::ImhNone); |
| #endif |
| |
| // 'password' field |
| webView->fireMouseClick(QPointF(20.0, 60.0)); |
| QVERIFY(webView->inputMethodHints() & Qt::ImhHiddenText); |
| |
| // 'tel' field |
| webView->fireMouseClick(QPointF(20.0, 110.0)); |
| QVERIFY(webView->inputMethodHints() & Qt::ImhDialableCharactersOnly); |
| |
| // 'number' field |
| webView->fireMouseClick(QPointF(20.0, 160.0)); |
| QVERIFY(webView->inputMethodHints() & Qt::ImhDigitsOnly); |
| |
| // 'email' field |
| webView->fireMouseClick(QPointF(20.0, 210.0)); |
| QVERIFY(webView->inputMethodHints() & Qt::ImhEmailCharactersOnly); |
| |
| // 'url' field |
| webView->fireMouseClick(QPointF(20.0, 260.0)); |
| QVERIFY(webView->inputMethodHints() & Qt::ImhUrlCharactersOnly); |
| |
| delete webView; |
| delete view; |
| } |
| |
| void tst_QGraphicsWebView::setPalette_data() |
| { |
| QTest::addColumn<bool>("active"); |
| QTest::addColumn<bool>("background"); |
| QTest::newRow("activeBG") << true << true; |
| QTest::newRow("activeFG") << true << false; |
| QTest::newRow("inactiveBG") << false << true; |
| QTest::newRow("inactiveFG") << false << false; |
| } |
| |
| // Render a QGraphicsWebView to a QImage twice, each time with a different palette set, |
| // verify that images rendered are not the same, confirming WebCore usage of |
| // custom palette on selections. |
| void tst_QGraphicsWebView::setPalette() |
| { |
| QString html = "<html><head></head>" |
| "<body>" |
| "Some text here" |
| "</body>" |
| "</html>"; |
| |
| QFETCH(bool, active); |
| QFETCH(bool, background); |
| |
| QWidget* activeView = 0; |
| |
| // Use controlView to manage active/inactive state of test views by raising |
| // or lowering their position in the window stack. |
| QGraphicsScene controlScene; |
| QGraphicsView controlView(&controlScene); |
| QGraphicsWebView controlWebView; |
| controlScene.addItem(&controlWebView); |
| controlWebView.setHtml(html); |
| controlWebView.setGeometry(QRectF(0, 0, 200, 200)); |
| |
| QGraphicsScene scene1; |
| QGraphicsView view1(&scene1); |
| view1.setSceneRect(0, 0, 300, 300); |
| QGraphicsWebView webView1; |
| webView1.setResizesToContents(true); |
| scene1.addItem(&webView1); |
| webView1.setFocus(); |
| |
| QPalette palette1; |
| QBrush brush1(Qt::red); |
| brush1.setStyle(Qt::SolidPattern); |
| if (active && background) { |
| // Rendered image must have red background on an active QGraphicsWebView. |
| palette1.setBrush(QPalette::Active, QPalette::Highlight, brush1); |
| } else if (active && !background) { |
| // Rendered image must have red foreground on an active QGraphicsWebView. |
| palette1.setBrush(QPalette::Active, QPalette::HighlightedText, brush1); |
| } else if (!active && background) { |
| // Rendered image must have red background on an inactive QGraphicsWebView. |
| palette1.setBrush(QPalette::Inactive, QPalette::Highlight, brush1); |
| } else if (!active && !background) { |
| // Rendered image must have red foreground on an inactive QGraphicsWebView. |
| palette1.setBrush(QPalette::Inactive, QPalette::HighlightedText, brush1); |
| } |
| |
| webView1.setHtml(html); |
| view1.resize(webView1.page()->viewportSize()); |
| webView1.setPalette(palette1); |
| view1.show(); |
| |
| QVERIFY(webView1.palette() == palette1); |
| QVERIFY(webView1.page()->palette() == palette1); |
| |
| QTest::qWaitForWindowShown(&view1); |
| |
| if (!active) { |
| controlView.show(); |
| QTest::qWaitForWindowShown(&controlView); |
| activeView = &controlView; |
| controlView.activateWindow(); |
| } else { |
| view1.activateWindow(); |
| activeView = &view1; |
| } |
| |
| QTRY_COMPARE(QApplication::activeWindow(), activeView); |
| |
| webView1.page()->triggerAction(QWebPage::SelectAll); |
| |
| QImage img1(webView1.page()->viewportSize(), QImage::Format_ARGB32); |
| QPainter painter1(&img1); |
| webView1.page()->currentFrame()->render(&painter1); |
| painter1.end(); |
| view1.close(); |
| controlView.close(); |
| |
| QGraphicsScene scene2; |
| QGraphicsView view2(&scene2); |
| view2.setSceneRect(0, 0, 300, 300); |
| QGraphicsWebView webView2; |
| webView2.setResizesToContents(true); |
| scene2.addItem(&webView2); |
| webView2.setFocus(); |
| |
| QPalette palette2; |
| QBrush brush2(Qt::blue); |
| brush2.setStyle(Qt::SolidPattern); |
| if (active && background) { |
| // Rendered image must have blue background on an active QGraphicsWebView. |
| palette2.setBrush(QPalette::Active, QPalette::Highlight, brush2); |
| } else if (active && !background) { |
| // Rendered image must have blue foreground on an active QGraphicsWebView. |
| palette2.setBrush(QPalette::Active, QPalette::HighlightedText, brush2); |
| } else if (!active && background) { |
| // Rendered image must have blue background on an inactive QGraphicsWebView. |
| palette2.setBrush(QPalette::Inactive, QPalette::Highlight, brush2); |
| } else if (!active && !background) { |
| // Rendered image must have blue foreground on an inactive QGraphicsWebView. |
| palette2.setBrush(QPalette::Inactive, QPalette::HighlightedText, brush2); |
| } |
| |
| webView2.setHtml(html); |
| view2.resize(webView2.page()->viewportSize()); |
| webView2.setPalette(palette2); |
| view2.show(); |
| |
| QTest::qWaitForWindowShown(&view2); |
| |
| if (!active) { |
| controlView.show(); |
| QTest::qWaitForWindowShown(&controlView); |
| activeView = &controlView; |
| controlView.activateWindow(); |
| } else { |
| view2.activateWindow(); |
| activeView = &view2; |
| } |
| |
| QTRY_COMPARE(QApplication::activeWindow(), activeView); |
| |
| webView2.page()->triggerAction(QWebPage::SelectAll); |
| |
| QImage img2(webView2.page()->viewportSize(), QImage::Format_ARGB32); |
| QPainter painter2(&img2); |
| webView2.page()->currentFrame()->render(&painter2); |
| painter2.end(); |
| |
| view2.close(); |
| controlView.close(); |
| |
| QVERIFY(img1 != img2); |
| } |
| |
| void tst_QGraphicsWebView::renderHints() |
| { |
| QGraphicsWebView webView; |
| |
| // default is only text antialiasing + smooth pixmap transform |
| QVERIFY(!(webView.renderHints() & QPainter::Antialiasing)); |
| QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); |
| QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform); |
| QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); |
| |
| webView.setRenderHint(QPainter::Antialiasing, true); |
| QVERIFY(webView.renderHints() & QPainter::Antialiasing); |
| QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); |
| QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform); |
| QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); |
| |
| webView.setRenderHint(QPainter::Antialiasing, false); |
| QVERIFY(!(webView.renderHints() & QPainter::Antialiasing)); |
| QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); |
| QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform); |
| QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); |
| |
| webView.setRenderHint(QPainter::SmoothPixmapTransform, true); |
| QVERIFY(!(webView.renderHints() & QPainter::Antialiasing)); |
| QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); |
| QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform); |
| QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); |
| |
| webView.setRenderHint(QPainter::SmoothPixmapTransform, false); |
| QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); |
| QVERIFY(!(webView.renderHints() & QPainter::SmoothPixmapTransform)); |
| QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); |
| } |
| |
| class GraphicsView : public QGraphicsView { |
| public: |
| GraphicsView(); |
| QGraphicsWebView* m_webView; |
| }; |
| |
| #if defined(ENABLE_WEBGL) && ENABLE_WEBGL |
| bool compareImagesFuzzyPixelCount(const QImage& image1, const QImage& image2, qreal tolerance = 0.05) |
| { |
| if (image1.size() != image2.size()) |
| return false; |
| |
| unsigned diffPixelCount = 0; |
| for (int row = 0; row < image1.size().width(); ++row) { |
| for (int column = 0; column < image1.size().height(); ++column) |
| if (image1.pixel(row, column) != image2.pixel(row, column)) |
| ++diffPixelCount; |
| } |
| |
| if (diffPixelCount > (image1.size().width() * image1.size().height()) * tolerance) |
| return false; |
| |
| return true; |
| } |
| |
| GraphicsView::GraphicsView() |
| { |
| QGraphicsScene* const scene = new QGraphicsScene(this); |
| setScene(scene); |
| |
| m_webView = new QGraphicsWebView; |
| scene->addItem(m_webView); |
| |
| m_webView->page()->settings()->setAttribute(QWebSettings::WebGLEnabled, true); |
| m_webView->setResizesToContents(true); |
| |
| setFrameShape(QFrame::NoFrame); |
| setViewport(new QGLWidget); |
| } |
| |
| void tst_QGraphicsWebView::webglSoftwareFallbackVerticalOrientation() |
| { |
| QSize canvasSize(100, 100); |
| QImage reference(canvasSize, QImage::Format_ARGB32); |
| reference.fill(0xFF00FF00); |
| { // Reference. |
| QPainter painter(&reference); |
| QPolygonF triangleUp; |
| triangleUp << QPointF(0, canvasSize.height()) |
| << QPointF(canvasSize.width(), canvasSize.height()) |
| << QPointF(canvasSize.width() / 2.0, canvasSize.height() / 2.0); |
| painter.setPen(Qt::NoPen); |
| painter.setBrush(Qt::red); |
| painter.drawPolygon(triangleUp); |
| } |
| |
| compareCanvasToImage(QUrl(QLatin1String("qrc:///resources/pointing_up.html")), reference); |
| } |
| |
| void tst_QGraphicsWebView::webglSoftwareFallbackHorizontalOrientation() |
| { |
| QSize canvasSize(100, 100); |
| QImage reference(canvasSize, QImage::Format_ARGB32); |
| reference.fill(0xFF00FF00); |
| { // Reference. |
| QPainter painter(&reference); |
| QPolygonF triangleUp; |
| triangleUp << QPointF(0, 0) |
| << QPointF(0, canvasSize.height()) |
| << QPointF(canvasSize.width() / 2.0, canvasSize.height() / 2.0); |
| painter.setPen(Qt::NoPen); |
| painter.setBrush(Qt::red); |
| painter.drawPolygon(triangleUp); |
| } |
| |
| compareCanvasToImage(QUrl(QLatin1String("qrc:///resources/pointing_right.html")), reference); |
| } |
| |
| void tst_QGraphicsWebView::compareCanvasToImage(const QUrl& url, const QImage& reference) |
| { |
| GraphicsView view; |
| view.show(); |
| QTest::qWaitForWindowShown(&view); |
| |
| QGraphicsWebView* const graphicsWebView = view.m_webView; |
| graphicsWebView->load(url); |
| QVERIFY(waitForSignal(graphicsWebView, SIGNAL(loadFinished(bool)))); |
| { // Force a render, to create the accelerated compositing tree. |
| QPixmap pixmap(view.size()); |
| QPainter painter(&pixmap); |
| view.render(&painter); |
| } |
| QApplication::syncX(); |
| |
| const QSize imageSize = reference.size(); |
| |
| QImage target(imageSize, QImage::Format_ARGB32); |
| { // Web page content. |
| QPainter painter(&target); |
| QRectF renderRect(0, 0, imageSize.width(), imageSize.height()); |
| view.scene()->render(&painter, renderRect, renderRect); |
| } |
| QVERIFY(compareImagesFuzzyPixelCount(target, reference, 0.01)); |
| } |
| #endif |
| |
| QTEST_MAIN(tst_QGraphicsWebView) |
| |
| #include "tst_qgraphicswebview.moc" |