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