tst_qwebview.cpp revision 81bc750723a18f21cd17d1b173cd2a4dda9cea6e
1/* 2 Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) 3 Copyright (C) 2009 Torch Mobile Inc. 4 Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in> 5 6 This library is free software; you can redistribute it and/or 7 modify it under the terms of the GNU Library General Public 8 License as published by the Free Software Foundation; either 9 version 2 of the License, or (at your option) any later version. 10 11 This library is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Library General Public License for more details. 15 16 You should have received a copy of the GNU Library General Public License 17 along with this library; see the file COPYING.LIB. If not, write to 18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 Boston, MA 02110-1301, USA. 20*/ 21 22#include <qtest.h> 23#include "../util.h" 24 25#include <qpainter.h> 26#include <qwebview.h> 27#include <qwebpage.h> 28#include <qnetworkrequest.h> 29#include <qdiriterator.h> 30#include <qwebkitversion.h> 31#include <qwebelement.h> 32#include <qwebframe.h> 33 34class tst_QWebView : public QObject 35{ 36 Q_OBJECT 37 38public slots: 39 void initTestCase(); 40 void cleanupTestCase(); 41 void init(); 42 void cleanup(); 43 44private slots: 45 void renderHints(); 46 void getWebKitVersion(); 47 48 void reusePage_data(); 49 void reusePage(); 50 void microFocusCoordinates(); 51 void focusInputTypes(); 52 53 void crashTests(); 54 55 void setPalette_data(); 56 void setPalette(); 57}; 58 59// This will be called before the first test function is executed. 60// It is only called once. 61void tst_QWebView::initTestCase() 62{ 63} 64 65// This will be called after the last test function is executed. 66// It is only called once. 67void tst_QWebView::cleanupTestCase() 68{ 69} 70 71// This will be called before each test function is executed. 72void tst_QWebView::init() 73{ 74} 75 76// This will be called after every test function. 77void tst_QWebView::cleanup() 78{ 79} 80 81void tst_QWebView::renderHints() 82{ 83 QWebView webView; 84 85 // default is only text antialiasing + smooth pixmap transform 86 QVERIFY(!(webView.renderHints() & QPainter::Antialiasing)); 87 QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); 88 QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform); 89 QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); 90 91 webView.setRenderHint(QPainter::Antialiasing, true); 92 QVERIFY(webView.renderHints() & QPainter::Antialiasing); 93 QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); 94 QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform); 95 QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); 96 97 webView.setRenderHint(QPainter::Antialiasing, false); 98 QVERIFY(!(webView.renderHints() & QPainter::Antialiasing)); 99 QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); 100 QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform); 101 QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); 102 103 webView.setRenderHint(QPainter::SmoothPixmapTransform, true); 104 QVERIFY(!(webView.renderHints() & QPainter::Antialiasing)); 105 QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); 106 QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform); 107 QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); 108 109 webView.setRenderHint(QPainter::SmoothPixmapTransform, false); 110 QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); 111 QVERIFY(!(webView.renderHints() & QPainter::SmoothPixmapTransform)); 112 QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); 113} 114 115void tst_QWebView::getWebKitVersion() 116{ 117 QVERIFY(qWebKitVersion().toDouble() > 0); 118} 119 120void tst_QWebView::reusePage_data() 121{ 122 QTest::addColumn<QString>("html"); 123 QTest::newRow("WithoutPlugin") << "<html><body id='b'>text</body></html>"; 124 QTest::newRow("WindowedPlugin") << QString("<html><body id='b'>text<embed src='resources/test.swf'></embed></body></html>"); 125 QTest::newRow("WindowlessPlugin") << QString("<html><body id='b'>text<embed src='resources/test.swf' wmode=\"transparent\"></embed></body></html>"); 126} 127 128void tst_QWebView::reusePage() 129{ 130 if (!QDir(TESTS_SOURCE_DIR).exists()) 131 QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll); 132 133 QDir::setCurrent(TESTS_SOURCE_DIR); 134 135 QFETCH(QString, html); 136 QWebView* view1 = new QWebView; 137 QPointer<QWebPage> page = new QWebPage; 138 view1->setPage(page); 139 page->settings()->setAttribute(QWebSettings::PluginsEnabled, true); 140 QWebFrame* mainFrame = page->mainFrame(); 141 mainFrame->setHtml(html, QUrl::fromLocalFile(TESTS_SOURCE_DIR)); 142 if (html.contains("</embed>")) { 143 // some reasonable time for the PluginStream to feed test.swf to flash and start painting 144 waitForSignal(view1, SIGNAL(loadFinished(bool)), 2000); 145 } 146 147 view1->show(); 148 QTest::qWaitForWindowShown(view1); 149 delete view1; 150 QVERIFY(page != 0); // deleting view must not have deleted the page, since it's not a child of view 151 152 QWebView *view2 = new QWebView; 153 view2->setPage(page); 154 view2->show(); // in Windowless mode, you should still be able to see the plugin here 155 QTest::qWaitForWindowShown(view2); 156 delete view2; 157 158 delete page; // must not crash 159 160 QDir::setCurrent(QApplication::applicationDirPath()); 161} 162 163// Class used in crashTests 164class WebViewCrashTest : public QObject { 165 Q_OBJECT 166 QWebView* m_view; 167public: 168 bool m_executed; 169 170 171 WebViewCrashTest(QWebView* view) 172 : m_view(view) 173 , m_executed(false) 174 { 175 view->connect(view, SIGNAL(loadProgress(int)), this, SLOT(loading(int))); 176 } 177 178private slots: 179 void loading(int progress) 180 { 181 if (progress >= 20 && progress < 90) { 182 QVERIFY(!m_executed); 183 m_view->stop(); 184 m_executed = true; 185 } 186 } 187}; 188 189 190// Should not crash. 191void tst_QWebView::crashTests() 192{ 193 // Test if loading can be stopped in loadProgress handler without crash. 194 // Test page should have frames. 195 QWebView view; 196 WebViewCrashTest tester(&view); 197 QUrl url("qrc:///resources/index.html"); 198 view.load(url); 199 QTRY_VERIFY(tester.m_executed); // If fail it means that the test wasn't executed. 200} 201 202void tst_QWebView::microFocusCoordinates() 203{ 204 QWebPage* page = new QWebPage; 205 QWebView* webView = new QWebView; 206 webView->setPage( page ); 207 208 page->mainFrame()->setHtml("<html><body>" \ 209 "<input type='text' id='input1' style='font--family: serif' value='' maxlength='20'/><br>" \ 210 "<canvas id='canvas1' width='500' height='500'/>" \ 211 "<input type='password'/><br>" \ 212 "<canvas id='canvas2' width='500' height='500'/>" \ 213 "</body></html>"); 214 215 page->mainFrame()->setFocus(); 216 217 QVariant initialMicroFocus = page->inputMethodQuery(Qt::ImMicroFocus); 218 QVERIFY(initialMicroFocus.isValid()); 219 220 page->mainFrame()->scroll(0,50); 221 222 QVariant currentMicroFocus = page->inputMethodQuery(Qt::ImMicroFocus); 223 QVERIFY(currentMicroFocus.isValid()); 224 225 QCOMPARE(initialMicroFocus.toRect().translated(QPoint(0,-50)), currentMicroFocus.toRect()); 226} 227 228void tst_QWebView::focusInputTypes() 229{ 230 QWebView webView; 231 webView.show(); 232 QTest::qWaitForWindowShown(&webView); 233 234 QUrl url("qrc:///resources/input_types.html"); 235 QWebFrame* const mainFrame = webView.page()->mainFrame(); 236 mainFrame->load(url); 237 mainFrame->setFocus(); 238 239 QVERIFY(waitForSignal(&webView, SIGNAL(loadFinished(bool)))); 240 241 // 'text' type 242 QWebElement inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=text]")); 243 QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); 244#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) || defined(Q_OS_SYMBIAN) 245 QVERIFY(webView.inputMethodHints() & Qt::ImhNoAutoUppercase); 246 QVERIFY(webView.inputMethodHints() & Qt::ImhNoPredictiveText); 247#else 248 QVERIFY(webView.inputMethodHints() == Qt::ImhNone); 249#endif 250 QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); 251 252 // 'password' field 253 inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=password]")); 254 QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); 255 QVERIFY(webView.inputMethodHints() == Qt::ImhHiddenText); 256 QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); 257 258 // 'tel' field 259 inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=tel]")); 260 QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); 261 QVERIFY(webView.inputMethodHints() == Qt::ImhDialableCharactersOnly); 262 QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); 263 264 // 'number' field 265 inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=number]")); 266 QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); 267 QVERIFY(webView.inputMethodHints() == Qt::ImhDigitsOnly); 268 QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); 269 270 // 'email' field 271 inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=email]")); 272 QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); 273 QVERIFY(webView.inputMethodHints() == Qt::ImhEmailCharactersOnly); 274 QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); 275 276 // 'url' field 277 inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=url]")); 278 QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); 279 QVERIFY(webView.inputMethodHints() == Qt::ImhUrlCharactersOnly); 280 QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); 281 282 // 'password' field 283 inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=password]")); 284 QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); 285 QVERIFY(webView.inputMethodHints() == Qt::ImhHiddenText); 286 QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); 287 288 // 'text' type 289 inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=text]")); 290 QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); 291#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) || defined(Q_OS_SYMBIAN) 292 QVERIFY(webView.inputMethodHints() & Qt::ImhNoAutoUppercase); 293 QVERIFY(webView.inputMethodHints() & Qt::ImhNoPredictiveText); 294#else 295 QVERIFY(webView.inputMethodHints() == Qt::ImhNone); 296#endif 297 QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); 298 299 // 'password' field 300 inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=password]")); 301 QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); 302 QVERIFY(webView.inputMethodHints() == Qt::ImhHiddenText); 303 QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); 304 305 // 'text area' field 306 inputElement = mainFrame->documentElement().findFirst(QLatin1String("textarea")); 307 QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); 308 QVERIFY(webView.inputMethodHints() == Qt::ImhNone); 309 QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); 310} 311 312void tst_QWebView::setPalette_data() 313{ 314 QTest::addColumn<bool>("active"); 315 QTest::addColumn<bool>("background"); 316 QTest::newRow("activeBG") << true << true; 317 QTest::newRow("activeFG") << true << false; 318 QTest::newRow("inactiveBG") << false << true; 319 QTest::newRow("inactiveFG") << false << false; 320} 321 322// Render a QWebView to a QImage twice, each time with a different palette set, 323// verify that images rendered are not the same, confirming WebCore usage of 324// custom palette on selections. 325void tst_QWebView::setPalette() 326{ 327 QString html = "<html><head></head>" 328 "<body>" 329 "Some text here" 330 "</body>" 331 "</html>"; 332 333 QFETCH(bool, active); 334 QFETCH(bool, background); 335 336 QWidget* activeView = 0; 337 338 // Use controlView to manage active/inactive state of test views by raising 339 // or lowering their position in the window stack. 340 QWebView controlView; 341 controlView.setHtml(html); 342 343 QWebView view1; 344 345 QPalette palette1; 346 QBrush brush1(Qt::red); 347 brush1.setStyle(Qt::SolidPattern); 348 if (active && background) { 349 // Rendered image must have red background on an active QWebView. 350 palette1.setBrush(QPalette::Active, QPalette::Highlight, brush1); 351 } else if (active && !background) { 352 // Rendered image must have red foreground on an active QWebView. 353 palette1.setBrush(QPalette::Active, QPalette::HighlightedText, brush1); 354 } else if (!active && background) { 355 // Rendered image must have red background on an inactive QWebView. 356 palette1.setBrush(QPalette::Inactive, QPalette::Highlight, brush1); 357 } else if (!active && !background) { 358 // Rendered image must have red foreground on an inactive QWebView. 359 palette1.setBrush(QPalette::Inactive, QPalette::HighlightedText, brush1); 360 } 361 362 view1.setPalette(palette1); 363 view1.setHtml(html); 364 view1.page()->setViewportSize(view1.page()->currentFrame()->contentsSize()); 365 view1.show(); 366 367 QTest::qWaitForWindowShown(&view1); 368 369 if (!active) { 370 controlView.show(); 371 QTest::qWaitForWindowShown(&controlView); 372 activeView = &controlView; 373 controlView.activateWindow(); 374 } else { 375 view1.activateWindow(); 376 activeView = &view1; 377 } 378 379 QTRY_COMPARE(QApplication::activeWindow(), activeView); 380 381 view1.page()->triggerAction(QWebPage::SelectAll); 382 383 QImage img1(view1.page()->viewportSize(), QImage::Format_ARGB32); 384 QPainter painter1(&img1); 385 view1.page()->currentFrame()->render(&painter1); 386 painter1.end(); 387 view1.close(); 388 controlView.close(); 389 390 QWebView view2; 391 392 QPalette palette2; 393 QBrush brush2(Qt::blue); 394 brush2.setStyle(Qt::SolidPattern); 395 if (active && background) { 396 // Rendered image must have blue background on an active QWebView. 397 palette2.setBrush(QPalette::Active, QPalette::Highlight, brush2); 398 } else if (active && !background) { 399 // Rendered image must have blue foreground on an active QWebView. 400 palette2.setBrush(QPalette::Active, QPalette::HighlightedText, brush2); 401 } else if (!active && background) { 402 // Rendered image must have blue background on an inactive QWebView. 403 palette2.setBrush(QPalette::Inactive, QPalette::Highlight, brush2); 404 } else if (!active && !background) { 405 // Rendered image must have blue foreground on an inactive QWebView. 406 palette2.setBrush(QPalette::Inactive, QPalette::HighlightedText, brush2); 407 } 408 409 view2.setPalette(palette2); 410 view2.setHtml(html); 411 view2.page()->setViewportSize(view2.page()->currentFrame()->contentsSize()); 412 view2.show(); 413 414 QTest::qWaitForWindowShown(&view2); 415 416 if (!active) { 417 controlView.show(); 418 QTest::qWaitForWindowShown(&controlView); 419 activeView = &controlView; 420 controlView.activateWindow(); 421 } else { 422 view2.activateWindow(); 423 activeView = &view2; 424 } 425 426 QTRY_COMPARE(QApplication::activeWindow(), activeView); 427 428 view2.page()->triggerAction(QWebPage::SelectAll); 429 430 QImage img2(view2.page()->viewportSize(), QImage::Format_ARGB32); 431 QPainter painter2(&img2); 432 view2.page()->currentFrame()->render(&painter2); 433 painter2.end(); 434 435 view2.close(); 436 controlView.close(); 437 438 QVERIFY(img1 != img2); 439} 440 441QTEST_MAIN(tst_QWebView) 442#include "tst_qwebview.moc" 443 444