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