tst_qwebview.cpp revision 2bde8e466a4451c7319e3a072d118917957d6554
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 renderingAfterMaxAndBack(); 46 void renderHints(); 47 void getWebKitVersion(); 48 49 void reusePage_data(); 50 void reusePage(); 51 void microFocusCoordinates(); 52 void focusInputTypes(); 53 54 void crashTests(); 55 56 void setPalette_data(); 57 void setPalette(); 58}; 59 60// This will be called before the first test function is executed. 61// It is only called once. 62void tst_QWebView::initTestCase() 63{ 64} 65 66// This will be called after the last test function is executed. 67// It is only called once. 68void tst_QWebView::cleanupTestCase() 69{ 70} 71 72// This will be called before each test function is executed. 73void tst_QWebView::init() 74{ 75} 76 77// This will be called after every test function. 78void tst_QWebView::cleanup() 79{ 80} 81 82void tst_QWebView::renderHints() 83{ 84 QWebView webView; 85 86 // default is only text antialiasing + smooth pixmap transform 87 QVERIFY(!(webView.renderHints() & QPainter::Antialiasing)); 88 QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); 89 QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform); 90 QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); 91 92 webView.setRenderHint(QPainter::Antialiasing, true); 93 QVERIFY(webView.renderHints() & QPainter::Antialiasing); 94 QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); 95 QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform); 96 QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); 97 98 webView.setRenderHint(QPainter::Antialiasing, false); 99 QVERIFY(!(webView.renderHints() & QPainter::Antialiasing)); 100 QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); 101 QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform); 102 QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); 103 104 webView.setRenderHint(QPainter::SmoothPixmapTransform, true); 105 QVERIFY(!(webView.renderHints() & QPainter::Antialiasing)); 106 QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); 107 QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform); 108 QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); 109 110 webView.setRenderHint(QPainter::SmoothPixmapTransform, false); 111 QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); 112 QVERIFY(!(webView.renderHints() & QPainter::SmoothPixmapTransform)); 113 QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); 114} 115 116void tst_QWebView::getWebKitVersion() 117{ 118 QVERIFY(qWebKitVersion().toDouble() > 0); 119} 120 121void tst_QWebView::reusePage_data() 122{ 123 QTest::addColumn<QString>("html"); 124 QTest::newRow("WithoutPlugin") << "<html><body id='b'>text</body></html>"; 125 QTest::newRow("WindowedPlugin") << QString("<html><body id='b'>text<embed src='resources/test.swf'></embed></body></html>"); 126 QTest::newRow("WindowlessPlugin") << QString("<html><body id='b'>text<embed src='resources/test.swf' wmode=\"transparent\"></embed></body></html>"); 127} 128 129void tst_QWebView::reusePage() 130{ 131 if (!QDir(TESTS_SOURCE_DIR).exists()) 132 QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll); 133 134 QDir::setCurrent(TESTS_SOURCE_DIR); 135 136 QFETCH(QString, html); 137 QWebView* view1 = new QWebView; 138 QPointer<QWebPage> page = new QWebPage; 139 view1->setPage(page); 140 page->settings()->setAttribute(QWebSettings::PluginsEnabled, true); 141 QWebFrame* mainFrame = page->mainFrame(); 142 mainFrame->setHtml(html, QUrl::fromLocalFile(TESTS_SOURCE_DIR)); 143 if (html.contains("</embed>")) { 144 // some reasonable time for the PluginStream to feed test.swf to flash and start painting 145 waitForSignal(view1, SIGNAL(loadFinished(bool)), 2000); 146 } 147 148 view1->show(); 149 QTest::qWaitForWindowShown(view1); 150 delete view1; 151 QVERIFY(page != 0); // deleting view must not have deleted the page, since it's not a child of view 152 153 QWebView *view2 = new QWebView; 154 view2->setPage(page); 155 view2->show(); // in Windowless mode, you should still be able to see the plugin here 156 QTest::qWaitForWindowShown(view2); 157 delete view2; 158 159 delete page; // must not crash 160 161 QDir::setCurrent(QApplication::applicationDirPath()); 162} 163 164// Class used in crashTests 165class WebViewCrashTest : public QObject { 166 Q_OBJECT 167 QWebView* m_view; 168public: 169 bool m_executed; 170 171 172 WebViewCrashTest(QWebView* view) 173 : m_view(view) 174 , m_executed(false) 175 { 176 view->connect(view, SIGNAL(loadProgress(int)), this, SLOT(loading(int))); 177 } 178 179private slots: 180 void loading(int progress) 181 { 182 if (progress >= 20 && progress < 90) { 183 QVERIFY(!m_executed); 184 m_view->stop(); 185 m_executed = true; 186 } 187 } 188}; 189 190 191// Should not crash. 192void tst_QWebView::crashTests() 193{ 194 // Test if loading can be stopped in loadProgress handler without crash. 195 // Test page should have frames. 196 QWebView view; 197 WebViewCrashTest tester(&view); 198 QUrl url("qrc:///resources/index.html"); 199 view.load(url); 200 QTRY_VERIFY(tester.m_executed); // If fail it means that the test wasn't executed. 201} 202 203void tst_QWebView::microFocusCoordinates() 204{ 205 QWebPage* page = new QWebPage; 206 QWebView* webView = new QWebView; 207 webView->setPage( page ); 208 209 page->mainFrame()->setHtml("<html><body>" \ 210 "<input type='text' id='input1' style='font--family: serif' value='' maxlength='20'/><br>" \ 211 "<canvas id='canvas1' width='500' height='500'></canvas>" \ 212 "<input type='password'/><br>" \ 213 "<canvas id='canvas2' width='500' height='500'></canvas>" \ 214 "</body></html>"); 215 216 page->mainFrame()->setFocus(); 217 218 QVariant initialMicroFocus = page->inputMethodQuery(Qt::ImMicroFocus); 219 QVERIFY(initialMicroFocus.isValid()); 220 221 page->mainFrame()->scroll(0,50); 222 223 QVariant currentMicroFocus = page->inputMethodQuery(Qt::ImMicroFocus); 224 QVERIFY(currentMicroFocus.isValid()); 225 226 QCOMPARE(initialMicroFocus.toRect().translated(QPoint(0,-50)), currentMicroFocus.toRect()); 227} 228 229void tst_QWebView::focusInputTypes() 230{ 231 QWebView webView; 232 webView.show(); 233 QTest::qWaitForWindowShown(&webView); 234 235 QUrl url("qrc:///resources/input_types.html"); 236 QWebFrame* const mainFrame = webView.page()->mainFrame(); 237 mainFrame->load(url); 238 mainFrame->setFocus(); 239 240 QVERIFY(waitForSignal(&webView, SIGNAL(loadFinished(bool)))); 241 242 // 'text' type 243 QWebElement inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=text]")); 244 QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); 245#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) || defined(Q_OS_SYMBIAN) 246 QVERIFY(webView.inputMethodHints() & Qt::ImhNoAutoUppercase); 247 QVERIFY(webView.inputMethodHints() & Qt::ImhNoPredictiveText); 248#else 249 QVERIFY(webView.inputMethodHints() == Qt::ImhNone); 250#endif 251 QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); 252 253 // 'password' field 254 inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=password]")); 255 QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); 256 QVERIFY(webView.inputMethodHints() == Qt::ImhHiddenText); 257 QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); 258 259 // 'tel' field 260 inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=tel]")); 261 QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); 262 QVERIFY(webView.inputMethodHints() == Qt::ImhDialableCharactersOnly); 263 QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); 264 265 // 'number' field 266 inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=number]")); 267 QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); 268 QVERIFY(webView.inputMethodHints() == Qt::ImhDigitsOnly); 269 QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); 270 271 // 'email' field 272 inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=email]")); 273 QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); 274 QVERIFY(webView.inputMethodHints() == Qt::ImhEmailCharactersOnly); 275 QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); 276 277 // 'url' field 278 inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=url]")); 279 QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); 280 QVERIFY(webView.inputMethodHints() == Qt::ImhUrlCharactersOnly); 281 QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); 282 283 // 'password' field 284 inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=password]")); 285 QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); 286 QVERIFY(webView.inputMethodHints() == Qt::ImhHiddenText); 287 QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); 288 289 // 'text' type 290 inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=text]")); 291 QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); 292#if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6) || defined(Q_OS_SYMBIAN) 293 QVERIFY(webView.inputMethodHints() & Qt::ImhNoAutoUppercase); 294 QVERIFY(webView.inputMethodHints() & Qt::ImhNoPredictiveText); 295#else 296 QVERIFY(webView.inputMethodHints() == Qt::ImhNone); 297#endif 298 QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); 299 300 // 'password' field 301 inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=password]")); 302 QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); 303 QVERIFY(webView.inputMethodHints() == Qt::ImhHiddenText); 304 QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); 305 306 // 'text area' field 307 inputElement = mainFrame->documentElement().findFirst(QLatin1String("textarea")); 308 QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); 309 QVERIFY(webView.inputMethodHints() == Qt::ImhNone); 310 QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); 311} 312 313void tst_QWebView::setPalette_data() 314{ 315 QTest::addColumn<bool>("active"); 316 QTest::addColumn<bool>("background"); 317 QTest::newRow("activeBG") << true << true; 318 QTest::newRow("activeFG") << true << false; 319 QTest::newRow("inactiveBG") << false << true; 320 QTest::newRow("inactiveFG") << false << false; 321} 322 323// Render a QWebView to a QImage twice, each time with a different palette set, 324// verify that images rendered are not the same, confirming WebCore usage of 325// custom palette on selections. 326void tst_QWebView::setPalette() 327{ 328 QString html = "<html><head></head>" 329 "<body>" 330 "Some text here" 331 "</body>" 332 "</html>"; 333 334 QFETCH(bool, active); 335 QFETCH(bool, background); 336 337 QWidget* activeView = 0; 338 339 // Use controlView to manage active/inactive state of test views by raising 340 // or lowering their position in the window stack. 341 QWebView controlView; 342 controlView.setHtml(html); 343 344 QWebView view1; 345 346 QPalette palette1; 347 QBrush brush1(Qt::red); 348 brush1.setStyle(Qt::SolidPattern); 349 if (active && background) { 350 // Rendered image must have red background on an active QWebView. 351 palette1.setBrush(QPalette::Active, QPalette::Highlight, brush1); 352 } else if (active && !background) { 353 // Rendered image must have red foreground on an active QWebView. 354 palette1.setBrush(QPalette::Active, QPalette::HighlightedText, brush1); 355 } else if (!active && background) { 356 // Rendered image must have red background on an inactive QWebView. 357 palette1.setBrush(QPalette::Inactive, QPalette::Highlight, brush1); 358 } else if (!active && !background) { 359 // Rendered image must have red foreground on an inactive QWebView. 360 palette1.setBrush(QPalette::Inactive, QPalette::HighlightedText, brush1); 361 } 362 363 view1.setPalette(palette1); 364 view1.setHtml(html); 365 view1.page()->setViewportSize(view1.page()->currentFrame()->contentsSize()); 366 view1.show(); 367 368 QTest::qWaitForWindowShown(&view1); 369 370 if (!active) { 371 controlView.show(); 372 QTest::qWaitForWindowShown(&controlView); 373 activeView = &controlView; 374 controlView.activateWindow(); 375 } else { 376 view1.activateWindow(); 377 activeView = &view1; 378 } 379 380 QTRY_COMPARE(QApplication::activeWindow(), activeView); 381 382 view1.page()->triggerAction(QWebPage::SelectAll); 383 384 QImage img1(view1.page()->viewportSize(), QImage::Format_ARGB32); 385 QPainter painter1(&img1); 386 view1.page()->currentFrame()->render(&painter1); 387 painter1.end(); 388 view1.close(); 389 controlView.close(); 390 391 QWebView view2; 392 393 QPalette palette2; 394 QBrush brush2(Qt::blue); 395 brush2.setStyle(Qt::SolidPattern); 396 if (active && background) { 397 // Rendered image must have blue background on an active QWebView. 398 palette2.setBrush(QPalette::Active, QPalette::Highlight, brush2); 399 } else if (active && !background) { 400 // Rendered image must have blue foreground on an active QWebView. 401 palette2.setBrush(QPalette::Active, QPalette::HighlightedText, brush2); 402 } else if (!active && background) { 403 // Rendered image must have blue background on an inactive QWebView. 404 palette2.setBrush(QPalette::Inactive, QPalette::Highlight, brush2); 405 } else if (!active && !background) { 406 // Rendered image must have blue foreground on an inactive QWebView. 407 palette2.setBrush(QPalette::Inactive, QPalette::HighlightedText, brush2); 408 } 409 410 view2.setPalette(palette2); 411 view2.setHtml(html); 412 view2.page()->setViewportSize(view2.page()->currentFrame()->contentsSize()); 413 view2.show(); 414 415 QTest::qWaitForWindowShown(&view2); 416 417 if (!active) { 418 controlView.show(); 419 QTest::qWaitForWindowShown(&controlView); 420 activeView = &controlView; 421 controlView.activateWindow(); 422 } else { 423 view2.activateWindow(); 424 activeView = &view2; 425 } 426 427 QTRY_COMPARE(QApplication::activeWindow(), activeView); 428 429 view2.page()->triggerAction(QWebPage::SelectAll); 430 431 QImage img2(view2.page()->viewportSize(), QImage::Format_ARGB32); 432 QPainter painter2(&img2); 433 view2.page()->currentFrame()->render(&painter2); 434 painter2.end(); 435 436 view2.close(); 437 controlView.close(); 438 439 QVERIFY(img1 != img2); 440} 441 442void tst_QWebView::renderingAfterMaxAndBack() 443{ 444 QUrl url = QUrl("data:text/html,<html><head></head>" 445 "<body width=1024 height=768 bgcolor=red>" 446 "</body>" 447 "</html>"); 448 449 QWebView view; 450 view.page()->mainFrame()->load(url); 451 QVERIFY(waitForSignal(&view, SIGNAL(loadFinished(bool)))); 452 view.show(); 453 454 view.page()->settings()->setMaximumPagesInCache(3); 455 456 QTest::qWaitForWindowShown(&view); 457 458 QPixmap reference(view.page()->viewportSize()); 459 reference.fill(Qt::red); 460 461 QPixmap image(view.page()->viewportSize()); 462 QPainter painter(&image); 463 view.page()->currentFrame()->render(&painter); 464 465 QCOMPARE(image, reference); 466 467 QUrl url2 = QUrl("data:text/html,<html><head></head>" 468 "<body width=1024 height=768 bgcolor=blue>" 469 "</body>" 470 "</html>"); 471 view.page()->mainFrame()->load(url2); 472 473 QVERIFY(waitForSignal(&view, SIGNAL(loadFinished(bool)))); 474 475 view.showMaximized(); 476 477 QTest::qWaitForWindowShown(&view); 478 479 QPixmap reference2(view.page()->viewportSize()); 480 reference2.fill(Qt::blue); 481 482 QPixmap image2(view.page()->viewportSize()); 483 QPainter painter2(&image2); 484 view.page()->currentFrame()->render(&painter2); 485 486 QCOMPARE(image2, reference2); 487 488 view.back(); 489 490 QPixmap reference3(view.page()->viewportSize()); 491 reference3.fill(Qt::red); 492 QPixmap image3(view.page()->viewportSize()); 493 QPainter painter3(&image3); 494 view.page()->currentFrame()->render(&painter3); 495 496 QCOMPARE(image3, reference3); 497} 498 499QTEST_MAIN(tst_QWebView) 500#include "tst_qwebview.moc" 501 502