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