blob: f557dc15ce85349abe9318a42b1aee8b5d921c1e [file] [log] [blame]
/*
Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
Copyright (C) 2009 Torch Mobile Inc.
Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
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 <qtest.h>
#include "../util.h"
#include <qpainter.h>
#include <qwebview.h>
#include <qwebpage.h>
#include <qnetworkrequest.h>
#include <qdiriterator.h>
#include <qwebkitversion.h>
#include <qwebelement.h>
#include <qwebframe.h>
#ifdef Q_OS_SYMBIAN
#define VERIFY_INPUTMETHOD_HINTS(actual, expect) \
QVERIFY(actual & Qt::ImhNoAutoUppercase); \
QVERIFY(actual & Qt::ImhNoPredictiveText); \
QVERIFY(actual & expect);
#else
#define VERIFY_INPUTMETHOD_HINTS(actual, expect) \
QVERIFY(actual == expect);
#endif
class tst_QWebView : public QObject
{
Q_OBJECT
public slots:
void initTestCase();
void cleanupTestCase();
void init();
void cleanup();
private slots:
void renderingAfterMaxAndBack();
void renderHints();
void getWebKitVersion();
void reusePage_data();
void reusePage();
void microFocusCoordinates();
void focusInputTypes();
void crashTests();
void setPalette_data();
void setPalette();
};
// This will be called before the first test function is executed.
// It is only called once.
void tst_QWebView::initTestCase()
{
}
// This will be called after the last test function is executed.
// It is only called once.
void tst_QWebView::cleanupTestCase()
{
}
// This will be called before each test function is executed.
void tst_QWebView::init()
{
}
// This will be called after every test function.
void tst_QWebView::cleanup()
{
}
void tst_QWebView::renderHints()
{
QWebView 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));
}
void tst_QWebView::getWebKitVersion()
{
QVERIFY(qWebKitVersion().toDouble() > 0);
}
void tst_QWebView::reusePage_data()
{
QTest::addColumn<QString>("html");
QTest::newRow("WithoutPlugin") << "<html><body id='b'>text</body></html>";
QTest::newRow("WindowedPlugin") << QString("<html><body id='b'>text<embed src='resources/test.swf'></embed></body></html>");
QTest::newRow("WindowlessPlugin") << QString("<html><body id='b'>text<embed src='resources/test.swf' wmode=\"transparent\"></embed></body></html>");
}
void tst_QWebView::reusePage()
{
if (!QDir(TESTS_SOURCE_DIR).exists())
QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll);
QDir::setCurrent(TESTS_SOURCE_DIR);
QFETCH(QString, html);
QWebView* view1 = new QWebView;
QPointer<QWebPage> page = new QWebPage;
view1->setPage(page);
page->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
QWebFrame* mainFrame = page->mainFrame();
mainFrame->setHtml(html, QUrl::fromLocalFile(TESTS_SOURCE_DIR));
if (html.contains("</embed>")) {
// some reasonable time for the PluginStream to feed test.swf to flash and start painting
waitForSignal(view1, SIGNAL(loadFinished(bool)), 2000);
}
view1->show();
QTest::qWaitForWindowShown(view1);
delete view1;
QVERIFY(page != 0); // deleting view must not have deleted the page, since it's not a child of view
QWebView *view2 = new QWebView;
view2->setPage(page);
view2->show(); // in Windowless mode, you should still be able to see the plugin here
QTest::qWaitForWindowShown(view2);
delete view2;
delete page; // must not crash
QDir::setCurrent(QApplication::applicationDirPath());
}
// Class used in crashTests
class WebViewCrashTest : public QObject {
Q_OBJECT
QWebView* m_view;
public:
bool m_executed;
WebViewCrashTest(QWebView* view)
: m_view(view)
, m_executed(false)
{
view->connect(view, SIGNAL(loadProgress(int)), this, SLOT(loading(int)));
}
private slots:
void loading(int progress)
{
if (progress >= 20 && progress < 90) {
QVERIFY(!m_executed);
m_view->stop();
m_executed = true;
}
}
};
// Should not crash.
void tst_QWebView::crashTests()
{
// Test if loading can be stopped in loadProgress handler without crash.
// Test page should have frames.
QWebView view;
WebViewCrashTest tester(&view);
QUrl url("qrc:///resources/index.html");
view.load(url);
QTRY_VERIFY(tester.m_executed); // If fail it means that the test wasn't executed.
}
void tst_QWebView::microFocusCoordinates()
{
QWebPage* page = new QWebPage;
QWebView* webView = new QWebView;
webView->setPage( page );
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,50);
QVariant currentMicroFocus = page->inputMethodQuery(Qt::ImMicroFocus);
QVERIFY(currentMicroFocus.isValid());
QCOMPARE(initialMicroFocus.toRect().translated(QPoint(0,-50)), currentMicroFocus.toRect());
}
void tst_QWebView::focusInputTypes()
{
QWebView webView;
webView.show();
QTest::qWaitForWindowShown(&webView);
QUrl url("qrc:///resources/input_types.html");
QWebFrame* const mainFrame = webView.page()->mainFrame();
mainFrame->load(url);
mainFrame->setFocus();
QVERIFY(waitForSignal(&webView, SIGNAL(loadFinished(bool))));
// 'text' type
QWebElement inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=text]"));
QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center());
#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
QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled));
// 'password' field
inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=password]"));
QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center());
VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhHiddenText);
QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled));
// 'tel' field
inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=tel]"));
QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center());
VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhDialableCharactersOnly);
QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled));
// 'number' field
inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=number]"));
QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center());
VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhDigitsOnly);
QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled));
// 'email' field
inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=email]"));
QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center());
VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhEmailCharactersOnly);
QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled));
// 'url' field
inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=url]"));
QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center());
VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhUrlCharactersOnly);
QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled));
// 'password' field
inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=password]"));
QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center());
VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhHiddenText);
QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled));
// 'text' type
inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=text]"));
QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center());
#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
QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled));
// 'password' field
inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=password]"));
QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center());
VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhHiddenText);
QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled));
// 'text area' field
inputElement = mainFrame->documentElement().findFirst(QLatin1String("textarea"));
QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center());
#if defined(Q_OS_SYMBIAN)
QVERIFY(webView.inputMethodHints() & Qt::ImhNoAutoUppercase);
QVERIFY(webView.inputMethodHints() & Qt::ImhNoPredictiveText);
#else
QVERIFY(webView.inputMethodHints() == Qt::ImhNone);
#endif
QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled));
}
void tst_QWebView::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 QWebView 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_QWebView::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.
QWebView controlView;
controlView.setHtml(html);
QWebView view1;
QPalette palette1;
QBrush brush1(Qt::red);
brush1.setStyle(Qt::SolidPattern);
if (active && background) {
// Rendered image must have red background on an active QWebView.
palette1.setBrush(QPalette::Active, QPalette::Highlight, brush1);
} else if (active && !background) {
// Rendered image must have red foreground on an active QWebView.
palette1.setBrush(QPalette::Active, QPalette::HighlightedText, brush1);
} else if (!active && background) {
// Rendered image must have red background on an inactive QWebView.
palette1.setBrush(QPalette::Inactive, QPalette::Highlight, brush1);
} else if (!active && !background) {
// Rendered image must have red foreground on an inactive QWebView.
palette1.setBrush(QPalette::Inactive, QPalette::HighlightedText, brush1);
}
view1.setPalette(palette1);
view1.setHtml(html);
view1.page()->setViewportSize(view1.page()->currentFrame()->contentsSize());
view1.show();
QTest::qWaitForWindowShown(&view1);
if (!active) {
controlView.show();
QTest::qWaitForWindowShown(&controlView);
activeView = &controlView;
controlView.activateWindow();
} else {
view1.activateWindow();
activeView = &view1;
}
QTRY_COMPARE(QApplication::activeWindow(), activeView);
view1.page()->triggerAction(QWebPage::SelectAll);
QImage img1(view1.page()->viewportSize(), QImage::Format_ARGB32);
QPainter painter1(&img1);
view1.page()->currentFrame()->render(&painter1);
painter1.end();
view1.close();
controlView.close();
QWebView view2;
QPalette palette2;
QBrush brush2(Qt::blue);
brush2.setStyle(Qt::SolidPattern);
if (active && background) {
// Rendered image must have blue background on an active QWebView.
palette2.setBrush(QPalette::Active, QPalette::Highlight, brush2);
} else if (active && !background) {
// Rendered image must have blue foreground on an active QWebView.
palette2.setBrush(QPalette::Active, QPalette::HighlightedText, brush2);
} else if (!active && background) {
// Rendered image must have blue background on an inactive QWebView.
palette2.setBrush(QPalette::Inactive, QPalette::Highlight, brush2);
} else if (!active && !background) {
// Rendered image must have blue foreground on an inactive QWebView.
palette2.setBrush(QPalette::Inactive, QPalette::HighlightedText, brush2);
}
view2.setPalette(palette2);
view2.setHtml(html);
view2.page()->setViewportSize(view2.page()->currentFrame()->contentsSize());
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);
view2.page()->triggerAction(QWebPage::SelectAll);
QImage img2(view2.page()->viewportSize(), QImage::Format_ARGB32);
QPainter painter2(&img2);
view2.page()->currentFrame()->render(&painter2);
painter2.end();
view2.close();
controlView.close();
QVERIFY(img1 != img2);
}
void tst_QWebView::renderingAfterMaxAndBack()
{
QUrl url = QUrl("data:text/html,<html><head></head>"
"<body width=1024 height=768 bgcolor=red>"
"</body>"
"</html>");
QWebView view;
view.page()->mainFrame()->load(url);
QVERIFY(waitForSignal(&view, SIGNAL(loadFinished(bool))));
view.show();
view.page()->settings()->setMaximumPagesInCache(3);
QTest::qWaitForWindowShown(&view);
QPixmap reference(view.page()->viewportSize());
reference.fill(Qt::red);
QPixmap image(view.page()->viewportSize());
QPainter painter(&image);
view.page()->currentFrame()->render(&painter);
QCOMPARE(image, reference);
QUrl url2 = QUrl("data:text/html,<html><head></head>"
"<body width=1024 height=768 bgcolor=blue>"
"</body>"
"</html>");
view.page()->mainFrame()->load(url2);
QVERIFY(waitForSignal(&view, SIGNAL(loadFinished(bool))));
view.showMaximized();
QTest::qWaitForWindowShown(&view);
QPixmap reference2(view.page()->viewportSize());
reference2.fill(Qt::blue);
QPixmap image2(view.page()->viewportSize());
QPainter painter2(&image2);
view.page()->currentFrame()->render(&painter2);
QCOMPARE(image2, reference2);
view.back();
QPixmap reference3(view.page()->viewportSize());
reference3.fill(Qt::red);
QPixmap image3(view.page()->viewportSize());
QPainter painter3(&image3);
view.page()->currentFrame()->render(&painter3);
QCOMPARE(image3, reference3);
}
QTEST_MAIN(tst_QWebView)
#include "tst_qwebview.moc"