1 /*
2 Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
3 Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
4 Copyright (C) 2010 Holger Hans Peter Freyther
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 "../util.h"
23 #include "../WebCoreSupport/DumpRenderTreeSupportQt.h"
24 #include <QClipboard>
25 #include <QDir>
26 #include <QGraphicsWidget>
27 #include <QLineEdit>
28 #include <QMainWindow>
29 #include <QMenu>
30 #include <QPushButton>
31 #include <QStateMachine>
32 #include <QStyle>
33 #include <QtTest/QtTest>
34 #include <QTextCharFormat>
35 #include <qgraphicsscene.h>
36 #include <qgraphicsview.h>
37 #include <qgraphicswebview.h>
38 #include <qnetworkcookiejar.h>
39 #include <qnetworkrequest.h>
40 #include <qwebdatabase.h>
41 #include <qwebelement.h>
42 #include <qwebframe.h>
43 #include <qwebhistory.h>
44 #include <qwebpage.h>
45 #include <qwebsecurityorigin.h>
46 #include <qwebview.h>
47 #include <qimagewriter.h>
48
removeRecursive(const QString & dirname)49 static void removeRecursive(const QString& dirname)
50 {
51 QDir dir(dirname);
52 QFileInfoList entries(dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot));
53 for (int i = 0; i < entries.count(); ++i)
54 if (entries[i].isDir())
55 removeRecursive(entries[i].filePath());
56 else
57 dir.remove(entries[i].fileName());
58 QDir().rmdir(dirname);
59 }
60
61 class EventSpy : public QObject, public QList<QEvent::Type>
62 {
63 Q_OBJECT
64 public:
EventSpy(QObject * objectToSpy)65 EventSpy(QObject* objectToSpy)
66 {
67 objectToSpy->installEventFilter(this);
68 }
69
eventFilter(QObject * receiver,QEvent * event)70 virtual bool eventFilter(QObject* receiver, QEvent* event)
71 {
72 append(event->type());
73 return false;
74 }
75 };
76
77 class tst_QWebPage : public QObject
78 {
79 Q_OBJECT
80
81 public:
82 tst_QWebPage();
83 virtual ~tst_QWebPage();
84
85 public slots:
86 void init();
87 void cleanup();
88 void cleanupFiles();
89
90 private slots:
91 void initTestCase();
92 void cleanupTestCase();
93 void contextMenuCopy();
94 void acceptNavigationRequest();
95 void geolocationRequestJS();
96 void loadFinished();
97 void popupFormSubmission();
98 void acceptNavigationRequestWithNewWindow();
99 void userStyleSheet();
100 void loadHtml5Video();
101 void modified();
102 void contextMenuCrash();
103 void updatePositionDependentActionsCrash();
104 void database();
105 void createPluginWithPluginsEnabled();
106 void createPluginWithPluginsDisabled();
107 void destroyPlugin_data();
108 void destroyPlugin();
109 void createViewlessPlugin_data();
110 void createViewlessPlugin();
111 void graphicsWidgetPlugin();
112 void multiplePageGroupsAndLocalStorage();
113 void cursorMovements();
114 void textSelection();
115 void textEditing();
116 void backActionUpdate();
117 void frameAt();
118 void requestCache();
119 void loadCachedPage();
120 void protectBindingsRuntimeObjectsFromCollector();
121 void localURLSchemes();
122 void testOptionalJSObjects();
123 void testLocalStorageVisibility();
124 void testEnablePersistentStorage();
125 void consoleOutput();
126 void inputMethods_data();
127 void inputMethods();
128 void inputMethodsTextFormat_data();
129 void inputMethodsTextFormat();
130 void defaultTextEncoding();
131 void errorPageExtension();
132 void errorPageExtensionInIFrames();
133 void errorPageExtensionInFrameset();
134 void errorPageExtensionLoadFinished();
135 void userAgentApplicationName();
136
137 void viewModes();
138
139 void crashTests_LazyInitializationOfMainFrame();
140
141 void screenshot_data();
142 void screenshot();
143
144 #if defined(ENABLE_WEBGL) && ENABLE_WEBGL
145 void acceleratedWebGLScreenshotWithoutView();
146 void unacceleratedWebGLScreenshotWithoutView();
147 #endif
148
149 void originatingObjectInNetworkRequests();
150 void testJSPrompt();
151 void showModalDialog();
152 void testStopScheduledPageRefresh();
153 void findText();
154 void supportedContentType();
155 void infiniteLoopJS();
156 void navigatorCookieEnabled();
157 void deleteQWebViewTwice();
158 void renderOnRepaintRequestedShouldNotRecurse();
159 void loadSignalsOrder_data();
160 void loadSignalsOrder();
161
162 #ifdef Q_OS_MAC
163 void macCopyUnicodeToClipboard();
164 #endif
165
166 private:
167 QWebView* m_view;
168 QWebPage* m_page;
tmpDirPath() const169 QString tmpDirPath() const
170 {
171 static QString tmpd = QDir::tempPath() + "/tst_qwebpage-"
172 + QDateTime::currentDateTime().toString(QLatin1String("yyyyMMddhhmmss"));
173 return tmpd;
174 }
175 };
176
tst_QWebPage()177 tst_QWebPage::tst_QWebPage()
178 {
179 }
180
~tst_QWebPage()181 tst_QWebPage::~tst_QWebPage()
182 {
183 }
184
init()185 void tst_QWebPage::init()
186 {
187 m_view = new QWebView();
188 m_page = m_view->page();
189 }
190
cleanup()191 void tst_QWebPage::cleanup()
192 {
193 delete m_view;
194 }
195
cleanupFiles()196 void tst_QWebPage::cleanupFiles()
197 {
198 removeRecursive(tmpDirPath());
199 }
200
initTestCase()201 void tst_QWebPage::initTestCase()
202 {
203 cleanupFiles(); // In case there are old files from previous runs
204 }
205
cleanupTestCase()206 void tst_QWebPage::cleanupTestCase()
207 {
208 cleanupFiles(); // Be nice
209 }
210
211 class NavigationRequestOverride : public QWebPage
212 {
213 public:
NavigationRequestOverride(QWebView * parent,bool initialValue)214 NavigationRequestOverride(QWebView* parent, bool initialValue) : QWebPage(parent), m_acceptNavigationRequest(initialValue) {}
215
216 bool m_acceptNavigationRequest;
217 protected:
acceptNavigationRequest(QWebFrame * frame,const QNetworkRequest & request,QWebPage::NavigationType type)218 virtual bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest &request, QWebPage::NavigationType type) {
219 Q_UNUSED(frame);
220 Q_UNUSED(request);
221 Q_UNUSED(type);
222
223 return m_acceptNavigationRequest;
224 }
225 };
226
acceptNavigationRequest()227 void tst_QWebPage::acceptNavigationRequest()
228 {
229 QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool)));
230
231 NavigationRequestOverride* newPage = new NavigationRequestOverride(m_view, false);
232 m_view->setPage(newPage);
233
234 m_view->setHtml(QString("<html><body><form name='tstform' action='data:text/html,foo'method='get'>"
235 "<input type='text'><input type='submit'></form></body></html>"), QUrl());
236 QTRY_COMPARE(loadSpy.count(), 1);
237
238 m_view->page()->mainFrame()->evaluateJavaScript("tstform.submit();");
239
240 newPage->m_acceptNavigationRequest = true;
241 m_view->page()->mainFrame()->evaluateJavaScript("tstform.submit();");
242 QTRY_COMPARE(loadSpy.count(), 2);
243
244 QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("foo?"));
245
246 // Restore default page
247 m_view->setPage(0);
248 }
249
250 class JSTestPage : public QWebPage
251 {
252 Q_OBJECT
253 public:
JSTestPage(QObject * parent=0)254 JSTestPage(QObject* parent = 0)
255 : QWebPage(parent) {}
256
257 public slots:
shouldInterruptJavaScript()258 bool shouldInterruptJavaScript() {
259 return true;
260 }
requestPermission(QWebFrame * frame,QWebPage::Feature feature)261 void requestPermission(QWebFrame* frame, QWebPage::Feature feature)
262 {
263 if (m_allowGeolocation)
264 setFeaturePermission(frame, feature, PermissionGrantedByUser);
265 else
266 setFeaturePermission(frame, feature, PermissionDeniedByUser);
267 }
268
269 public:
setGeolocationPermission(bool allow)270 void setGeolocationPermission(bool allow)
271 {
272 m_allowGeolocation = allow;
273 }
274
275 private:
276 bool m_allowGeolocation;
277 };
278
infiniteLoopJS()279 void tst_QWebPage::infiniteLoopJS()
280 {
281 JSTestPage* newPage = new JSTestPage(m_view);
282 m_view->setPage(newPage);
283 m_view->setHtml(QString("<html><body>test</body></html>"), QUrl());
284 m_view->page()->mainFrame()->evaluateJavaScript("var run = true;var a = 1;while(run){a++;}");
285 delete newPage;
286 }
287
geolocationRequestJS()288 void tst_QWebPage::geolocationRequestJS()
289 {
290 JSTestPage* newPage = new JSTestPage(m_view);
291
292 if (newPage->mainFrame()->evaluateJavaScript(QLatin1String("!navigator.geolocation")).toBool()) {
293 delete newPage;
294 QSKIP("Geolocation is not supported.", SkipSingle);
295 }
296
297 connect(newPage, SIGNAL(featurePermissionRequested(QWebFrame*, QWebPage::Feature)),
298 newPage, SLOT(requestPermission(QWebFrame*, QWebPage::Feature)));
299
300 newPage->setGeolocationPermission(false);
301 m_view->setPage(newPage);
302 m_view->setHtml(QString("<html><body>test</body></html>"), QUrl());
303 m_view->page()->mainFrame()->evaluateJavaScript("var errorCode = 0; function error(err) { errorCode = err.code; } function success(pos) { } navigator.geolocation.getCurrentPosition(success, error)");
304 QTest::qWait(2000);
305 QVariant empty = m_view->page()->mainFrame()->evaluateJavaScript("errorCode");
306
307 QVERIFY(empty.type() == QVariant::Double && empty.toInt() != 0);
308
309 newPage->setGeolocationPermission(true);
310 m_view->page()->mainFrame()->evaluateJavaScript("errorCode = 0; navigator.geolocation.getCurrentPosition(success, error);");
311 empty = m_view->page()->mainFrame()->evaluateJavaScript("errorCode");
312
313 //http://dev.w3.org/geo/api/spec-source.html#position
314 //PositionError: const unsigned short PERMISSION_DENIED = 1;
315 QVERIFY(empty.type() == QVariant::Double && empty.toInt() != 1);
316 delete newPage;
317 }
318
loadFinished()319 void tst_QWebPage::loadFinished()
320 {
321 qRegisterMetaType<QWebFrame*>("QWebFrame*");
322 qRegisterMetaType<QNetworkRequest*>("QNetworkRequest*");
323 QSignalSpy spyLoadStarted(m_view, SIGNAL(loadStarted()));
324 QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool)));
325
326 m_view->page()->mainFrame()->load(QUrl("data:text/html,<frameset cols=\"25%,75%\"><frame src=\"data:text/html,"
327 "<head><meta http-equiv='refresh' content='1'></head>foo \">"
328 "<frame src=\"data:text/html,bar\"></frameset>"));
329 QTRY_COMPARE(spyLoadFinished.count(), 1);
330
331 QTRY_VERIFY(spyLoadStarted.count() > 1);
332 QTRY_VERIFY(spyLoadFinished.count() > 1);
333
334 spyLoadFinished.clear();
335
336 m_view->page()->mainFrame()->load(QUrl("data:text/html,<frameset cols=\"25%,75%\"><frame src=\"data:text/html,"
337 "foo \"><frame src=\"data:text/html,bar\"></frameset>"));
338 QTRY_COMPARE(spyLoadFinished.count(), 1);
339 QCOMPARE(spyLoadFinished.count(), 1);
340 }
341
342 class ConsolePage : public QWebPage
343 {
344 public:
ConsolePage(QObject * parent=0)345 ConsolePage(QObject* parent = 0) : QWebPage(parent) {}
346
javaScriptConsoleMessage(const QString & message,int lineNumber,const QString & sourceID)347 virtual void javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID)
348 {
349 messages.append(message);
350 lineNumbers.append(lineNumber);
351 sourceIDs.append(sourceID);
352 }
353
354 QStringList messages;
355 QList<int> lineNumbers;
356 QStringList sourceIDs;
357 };
358
consoleOutput()359 void tst_QWebPage::consoleOutput()
360 {
361 ConsolePage page;
362 page.mainFrame()->evaluateJavaScript("this is not valid JavaScript");
363 QCOMPARE(page.messages.count(), 1);
364 QCOMPARE(page.lineNumbers.at(0), 1);
365 }
366
367 class TestPage : public QWebPage
368 {
369 public:
TestPage(QObject * parent=0)370 TestPage(QObject* parent = 0) : QWebPage(parent) {}
371
372 struct Navigation {
373 QPointer<QWebFrame> frame;
374 QNetworkRequest request;
375 NavigationType type;
376 };
377
378 QList<Navigation> navigations;
379 QList<QWebPage*> createdWindows;
380
acceptNavigationRequest(QWebFrame * frame,const QNetworkRequest & request,NavigationType type)381 virtual bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest &request, NavigationType type) {
382 Navigation n;
383 n.frame = frame;
384 n.request = request;
385 n.type = type;
386 navigations.append(n);
387 return true;
388 }
389
createWindow(WebWindowType)390 virtual QWebPage* createWindow(WebWindowType) {
391 QWebPage* page = new TestPage(this);
392 createdWindows.append(page);
393 return page;
394 }
395 };
396
popupFormSubmission()397 void tst_QWebPage::popupFormSubmission()
398 {
399 TestPage page;
400 page.settings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, true);
401 page.mainFrame()->setHtml("<form name=form1 method=get action='' target=myNewWin>"\
402 "<input type=hidden name=foo value='bar'>"\
403 "</form>");
404 page.mainFrame()->evaluateJavaScript("window.open('', 'myNewWin', 'width=500,height=300,toolbar=0')");
405 page.mainFrame()->evaluateJavaScript("document.form1.submit();");
406
407 QTest::qWait(500);
408 // The number of popup created should be one.
409 QVERIFY(page.createdWindows.size() == 1);
410
411 QString url = page.createdWindows.takeFirst()->mainFrame()->url().toString();
412 // Check if the form submission was OK.
413 QVERIFY(url.contains("?foo=bar"));
414 }
415
acceptNavigationRequestWithNewWindow()416 void tst_QWebPage::acceptNavigationRequestWithNewWindow()
417 {
418 TestPage* page = new TestPage(m_view);
419 page->settings()->setAttribute(QWebSettings::LinksIncludedInFocusChain, true);
420 m_page = page;
421 m_view->setPage(m_page);
422
423 m_view->setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me</a>"));
424 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
425
426 QFocusEvent fe(QEvent::FocusIn);
427 m_page->event(&fe);
428
429 QVERIFY(m_page->focusNextPrevChild(/*next*/ true));
430
431 QKeyEvent keyEnter(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier);
432 m_page->event(&keyEnter);
433
434 QCOMPARE(page->navigations.count(), 2);
435
436 TestPage::Navigation n = page->navigations.at(1);
437 QVERIFY(n.frame.isNull());
438 QCOMPARE(n.request.url().toString(), QString("data:text/html,Reached"));
439 QVERIFY(n.type == QWebPage::NavigationTypeLinkClicked);
440
441 QCOMPARE(page->createdWindows.count(), 1);
442 }
443
444 class TestNetworkManager : public QNetworkAccessManager
445 {
446 public:
TestNetworkManager(QObject * parent)447 TestNetworkManager(QObject* parent) : QNetworkAccessManager(parent) {}
448
449 QList<QUrl> requestedUrls;
450 QList<QNetworkRequest> requests;
451
452 protected:
createRequest(Operation op,const QNetworkRequest & request,QIODevice * outgoingData)453 virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest &request, QIODevice* outgoingData) {
454 requests.append(request);
455 requestedUrls.append(request.url());
456 return QNetworkAccessManager::createRequest(op, request, outgoingData);
457 }
458 };
459
userStyleSheet()460 void tst_QWebPage::userStyleSheet()
461 {
462 TestNetworkManager* networkManager = new TestNetworkManager(m_page);
463 m_page->setNetworkAccessManager(networkManager);
464 networkManager->requestedUrls.clear();
465
466 m_page->settings()->setUserStyleSheetUrl(QUrl("data:text/css;charset=utf-8;base64,"
467 + QByteArray("p { background-image: url('http://does.not/exist.png');}").toBase64()));
468 m_view->setHtml("<p>hello world</p>");
469 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
470
471 QVERIFY(networkManager->requestedUrls.count() >= 1);
472 QCOMPARE(networkManager->requestedUrls.at(0), QUrl("http://does.not/exist.png"));
473 }
474
loadHtml5Video()475 void tst_QWebPage::loadHtml5Video()
476 {
477 #if defined(WTF_USE_QT_MULTIMEDIA) && WTF_USE_QT_MULTIMEDIA
478 QByteArray url("http://does.not/exist?a=1%2Cb=2");
479 m_view->setHtml("<p><video id ='video' src='" + url + "' autoplay/></p>");
480 QTest::qWait(2000);
481 QUrl mUrl = DumpRenderTreeSupportQt::mediaContentUrlByElementId(m_page->mainFrame(), "video");
482 QCOMPARE(mUrl.toEncoded(), url);
483 #else
484 QSKIP("This test requires Qt Multimedia", SkipAll);
485 #endif
486 }
487
viewModes()488 void tst_QWebPage::viewModes()
489 {
490 m_view->setHtml("<body></body>");
491 m_page->setProperty("_q_viewMode", "minimized");
492
493 QVariant empty = m_page->mainFrame()->evaluateJavaScript("window.styleMedia.matchMedium(\"(-webkit-view-mode)\")");
494 QVERIFY(empty.type() == QVariant::Bool && empty.toBool());
495
496 QVariant minimized = m_page->mainFrame()->evaluateJavaScript("window.styleMedia.matchMedium(\"(-webkit-view-mode: minimized)\")");
497 QVERIFY(minimized.type() == QVariant::Bool && minimized.toBool());
498
499 QVariant maximized = m_page->mainFrame()->evaluateJavaScript("window.styleMedia.matchMedium(\"(-webkit-view-mode: maximized)\")");
500 QVERIFY(maximized.type() == QVariant::Bool && !maximized.toBool());
501 }
502
modified()503 void tst_QWebPage::modified()
504 {
505 m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>blub"));
506 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
507
508 m_page->mainFrame()->setUrl(QUrl("data:text/html,<body id=foo contenteditable>blah"));
509 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
510
511 QVERIFY(!m_page->isModified());
512
513 // m_page->mainFrame()->evaluateJavaScript("alert(document.getElementById('foo'))");
514 m_page->mainFrame()->evaluateJavaScript("document.getElementById('foo').focus()");
515 m_page->mainFrame()->evaluateJavaScript("document.execCommand('InsertText', true, 'Test');");
516
517 QVERIFY(m_page->isModified());
518
519 m_page->mainFrame()->evaluateJavaScript("document.execCommand('Undo', true);");
520
521 QVERIFY(!m_page->isModified());
522
523 m_page->mainFrame()->evaluateJavaScript("document.execCommand('Redo', true);");
524
525 QVERIFY(m_page->isModified());
526
527 QVERIFY(m_page->history()->canGoBack());
528 QVERIFY(!m_page->history()->canGoForward());
529 QCOMPARE(m_page->history()->count(), 2);
530 QVERIFY(m_page->history()->backItem().isValid());
531 QVERIFY(!m_page->history()->forwardItem().isValid());
532
533 m_page->history()->back();
534 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
535
536 QVERIFY(!m_page->history()->canGoBack());
537 QVERIFY(m_page->history()->canGoForward());
538
539 QVERIFY(!m_page->isModified());
540
541 QVERIFY(m_page->history()->currentItemIndex() == 0);
542
543 m_page->history()->setMaximumItemCount(3);
544 QVERIFY(m_page->history()->maximumItemCount() == 3);
545
546 QVariant variant("string test");
547 m_page->history()->currentItem().setUserData(variant);
548 QVERIFY(m_page->history()->currentItem().userData().toString() == "string test");
549
550 m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>This is second page"));
551 m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>This is third page"));
552 QVERIFY(m_page->history()->count() == 2);
553 m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>This is fourth page"));
554 QVERIFY(m_page->history()->count() == 2);
555 m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>This is fifth page"));
556 QVERIFY(::waitForSignal(m_page, SIGNAL(saveFrameStateRequested(QWebFrame*,QWebHistoryItem*))));
557 }
558
559 // https://bugs.webkit.org/show_bug.cgi?id=51331
updatePositionDependentActionsCrash()560 void tst_QWebPage::updatePositionDependentActionsCrash()
561 {
562 QWebView view;
563 view.setHtml("<p>test");
564 QPoint pos(0, 0);
565 view.page()->updatePositionDependentActions(pos);
566 QMenu* contextMenu = 0;
567 foreach (QObject* child, view.children()) {
568 contextMenu = qobject_cast<QMenu*>(child);
569 if (contextMenu)
570 break;
571 }
572 QVERIFY(!contextMenu);
573 }
574
575 // https://bugs.webkit.org/show_bug.cgi?id=20357
contextMenuCrash()576 void tst_QWebPage::contextMenuCrash()
577 {
578 QWebView view;
579 view.setHtml("<p>test");
580 QPoint pos(0, 0);
581 QContextMenuEvent event(QContextMenuEvent::Mouse, pos);
582 view.page()->swallowContextMenuEvent(&event);
583 view.page()->updatePositionDependentActions(pos);
584 QMenu* contextMenu = 0;
585 foreach (QObject* child, view.children()) {
586 contextMenu = qobject_cast<QMenu*>(child);
587 if (contextMenu)
588 break;
589 }
590 QVERIFY(contextMenu);
591 delete contextMenu;
592 }
593
database()594 void tst_QWebPage::database()
595 {
596 QString path = tmpDirPath();
597 m_page->settings()->setOfflineStoragePath(path);
598 QVERIFY(m_page->settings()->offlineStoragePath() == path);
599
600 QWebSettings::setOfflineStorageDefaultQuota(1024 * 1024);
601 QVERIFY(QWebSettings::offlineStorageDefaultQuota() == 1024 * 1024);
602
603 m_page->settings()->setAttribute(QWebSettings::LocalStorageEnabled, true);
604 m_page->settings()->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, true);
605
606 QString dbFileName = path + "Databases.db";
607
608 if (QFile::exists(dbFileName))
609 QFile::remove(dbFileName);
610
611 qRegisterMetaType<QWebFrame*>("QWebFrame*");
612 QSignalSpy spy(m_page, SIGNAL(databaseQuotaExceeded(QWebFrame*,QString)));
613 m_view->setHtml(QString("<html><head><script>var db; db=openDatabase('testdb', '1.0', 'test database API', 50000); </script></head><body><div></div></body></html>"), QUrl("http://www.myexample.com"));
614 QTRY_COMPARE(spy.count(), 1);
615 m_page->mainFrame()->evaluateJavaScript("var db2; db2=openDatabase('testdb', '1.0', 'test database API', 50000);");
616 QTRY_COMPARE(spy.count(),1);
617
618 m_page->mainFrame()->evaluateJavaScript("localStorage.test='This is a test for local storage';");
619 m_view->setHtml(QString("<html><body id='b'>text</body></html>"), QUrl("http://www.myexample.com"));
620
621 QVariant s1 = m_page->mainFrame()->evaluateJavaScript("localStorage.test");
622 QCOMPARE(s1.toString(), QString("This is a test for local storage"));
623
624 m_page->mainFrame()->evaluateJavaScript("sessionStorage.test='This is a test for session storage';");
625 m_view->setHtml(QString("<html><body id='b'>text</body></html>"), QUrl("http://www.myexample.com"));
626 QVariant s2 = m_page->mainFrame()->evaluateJavaScript("sessionStorage.test");
627 QCOMPARE(s2.toString(), QString("This is a test for session storage"));
628
629 m_view->setHtml(QString("<html><head></head><body><div></div></body></html>"), QUrl("http://www.myexample.com"));
630 m_page->mainFrame()->evaluateJavaScript("var db3; db3=openDatabase('testdb', '1.0', 'test database API', 50000);db3.transaction(function(tx) { tx.executeSql('CREATE TABLE IF NOT EXISTS Test (text TEXT)', []); }, function(tx, result) { }, function(tx, error) { });");
631 QTest::qWait(200);
632
633 // Remove all databases.
634 QWebSecurityOrigin origin = m_page->mainFrame()->securityOrigin();
635 QList<QWebDatabase> dbs = origin.databases();
636 for (int i = 0; i < dbs.count(); i++) {
637 QString fileName = dbs[i].fileName();
638 QVERIFY(QFile::exists(fileName));
639 QWebDatabase::removeDatabase(dbs[i]);
640 QVERIFY(!QFile::exists(fileName));
641 }
642 QVERIFY(!origin.databases().size());
643 // Remove removed test :-)
644 QWebDatabase::removeAllDatabases();
645 QVERIFY(!origin.databases().size());
646 }
647
648 class PluginPage : public QWebPage
649 {
650 public:
PluginPage(QObject * parent=0)651 PluginPage(QObject *parent = 0)
652 : QWebPage(parent) {}
653
654 struct CallInfo
655 {
CallInfoPluginPage::CallInfo656 CallInfo(const QString &c, const QUrl &u,
657 const QStringList &pn, const QStringList &pv,
658 QObject *r)
659 : classid(c), url(u), paramNames(pn),
660 paramValues(pv), returnValue(r)
661 {}
662 QString classid;
663 QUrl url;
664 QStringList paramNames;
665 QStringList paramValues;
666 QObject *returnValue;
667 };
668
669 QList<CallInfo> calls;
670
671 protected:
createPlugin(const QString & classid,const QUrl & url,const QStringList & paramNames,const QStringList & paramValues)672 virtual QObject *createPlugin(const QString &classid, const QUrl &url,
673 const QStringList ¶mNames,
674 const QStringList ¶mValues)
675 {
676 QObject *result = 0;
677 if (classid == "pushbutton")
678 result = new QPushButton();
679 #ifndef QT_NO_INPUTDIALOG
680 else if (classid == "lineedit")
681 result = new QLineEdit();
682 #endif
683 else if (classid == "graphicswidget")
684 result = new QGraphicsWidget();
685 if (result)
686 result->setObjectName(classid);
687 calls.append(CallInfo(classid, url, paramNames, paramValues, result));
688 return result;
689 }
690 };
691
createPlugin(QWebView * view)692 static void createPlugin(QWebView *view)
693 {
694 QSignalSpy loadSpy(view, SIGNAL(loadFinished(bool)));
695
696 PluginPage* newPage = new PluginPage(view);
697 view->setPage(newPage);
698
699 // type has to be application/x-qt-plugin
700 view->setHtml(QString("<html><body><object type='application/x-foobarbaz' classid='pushbutton' id='mybutton'/></body></html>"));
701 QTRY_COMPARE(loadSpy.count(), 1);
702 QCOMPARE(newPage->calls.count(), 0);
703
704 view->setHtml(QString("<html><body><object type='application/x-qt-plugin' classid='pushbutton' id='mybutton'/></body></html>"));
705 QTRY_COMPARE(loadSpy.count(), 2);
706 QCOMPARE(newPage->calls.count(), 1);
707 {
708 PluginPage::CallInfo ci = newPage->calls.takeFirst();
709 QCOMPARE(ci.classid, QString::fromLatin1("pushbutton"));
710 QCOMPARE(ci.url, QUrl());
711 QCOMPARE(ci.paramNames.count(), 3);
712 QCOMPARE(ci.paramValues.count(), 3);
713 QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type"));
714 QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin"));
715 QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid"));
716 QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("pushbutton"));
717 QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id"));
718 QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("mybutton"));
719 QVERIFY(ci.returnValue != 0);
720 QVERIFY(ci.returnValue->inherits("QPushButton"));
721 }
722 // test JS bindings
723 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("document.getElementById('mybutton').toString()").toString(),
724 QString::fromLatin1("[object HTMLObjectElement]"));
725 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("mybutton.toString()").toString(),
726 QString::fromLatin1("[object HTMLObjectElement]"));
727 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("typeof mybutton.objectName").toString(),
728 QString::fromLatin1("string"));
729 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("mybutton.objectName").toString(),
730 QString::fromLatin1("pushbutton"));
731 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("typeof mybutton.clicked").toString(),
732 QString::fromLatin1("function"));
733 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("mybutton.clicked.toString()").toString(),
734 QString::fromLatin1("function clicked() {\n [native code]\n}"));
735
736 view->setHtml(QString("<html><body><table>"
737 "<tr><object type='application/x-qt-plugin' classid='lineedit' id='myedit'/></tr>"
738 "<tr><object type='application/x-qt-plugin' classid='pushbutton' id='mybutton'/></tr>"
739 "</table></body></html>"), QUrl("http://foo.bar.baz"));
740 QTRY_COMPARE(loadSpy.count(), 3);
741 QCOMPARE(newPage->calls.count(), 2);
742 {
743 PluginPage::CallInfo ci = newPage->calls.takeFirst();
744 QCOMPARE(ci.classid, QString::fromLatin1("lineedit"));
745 QCOMPARE(ci.url, QUrl());
746 QCOMPARE(ci.paramNames.count(), 3);
747 QCOMPARE(ci.paramValues.count(), 3);
748 QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type"));
749 QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin"));
750 QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid"));
751 QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("lineedit"));
752 QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id"));
753 QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("myedit"));
754 QVERIFY(ci.returnValue != 0);
755 QVERIFY(ci.returnValue->inherits("QLineEdit"));
756 }
757 {
758 PluginPage::CallInfo ci = newPage->calls.takeFirst();
759 QCOMPARE(ci.classid, QString::fromLatin1("pushbutton"));
760 QCOMPARE(ci.url, QUrl());
761 QCOMPARE(ci.paramNames.count(), 3);
762 QCOMPARE(ci.paramValues.count(), 3);
763 QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type"));
764 QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin"));
765 QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid"));
766 QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("pushbutton"));
767 QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id"));
768 QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("mybutton"));
769 QVERIFY(ci.returnValue != 0);
770 QVERIFY(ci.returnValue->inherits("QPushButton"));
771 }
772 }
773
graphicsWidgetPlugin()774 void tst_QWebPage::graphicsWidgetPlugin()
775 {
776 m_view->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
777 QGraphicsWebView webView;
778
779 QSignalSpy loadSpy(&webView, SIGNAL(loadFinished(bool)));
780
781 PluginPage* newPage = new PluginPage(&webView);
782 webView.setPage(newPage);
783
784 // type has to be application/x-qt-plugin
785 webView.setHtml(QString("<html><body><object type='application/x-foobarbaz' classid='graphicswidget' id='mygraphicswidget'/></body></html>"));
786 QTRY_COMPARE(loadSpy.count(), 1);
787 QCOMPARE(newPage->calls.count(), 0);
788
789 webView.setHtml(QString("<html><body><object type='application/x-qt-plugin' classid='graphicswidget' id='mygraphicswidget'/></body></html>"));
790 QTRY_COMPARE(loadSpy.count(), 2);
791 QCOMPARE(newPage->calls.count(), 1);
792 {
793 PluginPage::CallInfo ci = newPage->calls.takeFirst();
794 QCOMPARE(ci.classid, QString::fromLatin1("graphicswidget"));
795 QCOMPARE(ci.url, QUrl());
796 QCOMPARE(ci.paramNames.count(), 3);
797 QCOMPARE(ci.paramValues.count(), 3);
798 QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type"));
799 QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin"));
800 QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid"));
801 QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("graphicswidget"));
802 QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id"));
803 QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("mygraphicswidget"));
804 QVERIFY(ci.returnValue);
805 QVERIFY(ci.returnValue->inherits("QGraphicsWidget"));
806 }
807 // test JS bindings
808 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("document.getElementById('mygraphicswidget').toString()").toString(),
809 QString::fromLatin1("[object HTMLObjectElement]"));
810 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("mygraphicswidget.toString()").toString(),
811 QString::fromLatin1("[object HTMLObjectElement]"));
812 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("typeof mygraphicswidget.objectName").toString(),
813 QString::fromLatin1("string"));
814 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("mygraphicswidget.objectName").toString(),
815 QString::fromLatin1("graphicswidget"));
816 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("typeof mygraphicswidget.geometryChanged").toString(),
817 QString::fromLatin1("function"));
818 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("mygraphicswidget.geometryChanged.toString()").toString(),
819 QString::fromLatin1("function geometryChanged() {\n [native code]\n}"));
820 }
821
createPluginWithPluginsEnabled()822 void tst_QWebPage::createPluginWithPluginsEnabled()
823 {
824 m_view->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
825 createPlugin(m_view);
826 }
827
createPluginWithPluginsDisabled()828 void tst_QWebPage::createPluginWithPluginsDisabled()
829 {
830 // Qt Plugins should be loaded by QtWebKit even when PluginsEnabled is
831 // false. The client decides whether a Qt plugin is enabled or not when
832 // it decides whether or not to instantiate it.
833 m_view->settings()->setAttribute(QWebSettings::PluginsEnabled, false);
834 createPlugin(m_view);
835 }
836
837 // Standard base class for template PluginTracerPage. In tests it is used as interface.
838 class PluginCounterPage : public QWebPage {
839 public:
840 int m_count;
841 QPointer<QObject> m_widget;
842 QObject* m_pluginParent;
PluginCounterPage(QObject * parent=0)843 PluginCounterPage(QObject* parent = 0)
844 : QWebPage(parent)
845 , m_count(0)
846 , m_widget(0)
847 , m_pluginParent(0)
848 {
849 settings()->setAttribute(QWebSettings::PluginsEnabled, true);
850 }
~PluginCounterPage()851 ~PluginCounterPage()
852 {
853 if (m_pluginParent)
854 m_pluginParent->deleteLater();
855 }
856 };
857
858 template<class T>
859 class PluginTracerPage : public PluginCounterPage {
860 public:
PluginTracerPage(QObject * parent=0)861 PluginTracerPage(QObject* parent = 0)
862 : PluginCounterPage(parent)
863 {
864 // this is a dummy parent object for the created plugin
865 m_pluginParent = new T;
866 }
createPlugin(const QString &,const QUrl &,const QStringList &,const QStringList &)867 virtual QObject* createPlugin(const QString&, const QUrl&, const QStringList&, const QStringList&)
868 {
869 m_count++;
870 m_widget = new T;
871 // need a cast to the specific type, as QObject::setParent cannot be called,
872 // because it is not virtual. Instead it is necesary to call QWidget::setParent,
873 // which also takes a QWidget* instead of a QObject*. Therefore we need to
874 // upcast to T*, which is a QWidget.
875 static_cast<T*>(m_widget.data())->setParent(static_cast<T*>(m_pluginParent));
876 return m_widget;
877 }
878 };
879
880 class PluginFactory {
881 public:
882 enum FactoredType {QWidgetType, QGraphicsWidgetType};
create(FactoredType type,QObject * parent=0)883 static PluginCounterPage* create(FactoredType type, QObject* parent = 0)
884 {
885 PluginCounterPage* result = 0;
886 switch (type) {
887 case QWidgetType:
888 result = new PluginTracerPage<QWidget>(parent);
889 break;
890 case QGraphicsWidgetType:
891 result = new PluginTracerPage<QGraphicsWidget>(parent);
892 break;
893 default: {/*Oops*/};
894 }
895 return result;
896 }
897
prepareTestData()898 static void prepareTestData()
899 {
900 QTest::addColumn<int>("type");
901 QTest::newRow("QWidget") << (int)PluginFactory::QWidgetType;
902 QTest::newRow("QGraphicsWidget") << (int)PluginFactory::QGraphicsWidgetType;
903 }
904 };
905
destroyPlugin_data()906 void tst_QWebPage::destroyPlugin_data()
907 {
908 PluginFactory::prepareTestData();
909 }
910
destroyPlugin()911 void tst_QWebPage::destroyPlugin()
912 {
913 QFETCH(int, type);
914 PluginCounterPage* page = PluginFactory::create((PluginFactory::FactoredType)type, m_view);
915 m_view->setPage(page);
916
917 // we create the plugin, so the widget should be constructed
918 QString content("<html><body><object type=\"application/x-qt-plugin\" classid=\"QProgressBar\"></object></body></html>");
919 m_view->setHtml(content);
920 QVERIFY(page->m_widget);
921 QCOMPARE(page->m_count, 1);
922
923 // navigate away, the plugin widget should be destructed
924 m_view->setHtml("<html><body>Hi</body></html>");
925 QTestEventLoop::instance().enterLoop(1);
926 QVERIFY(!page->m_widget);
927 }
928
createViewlessPlugin_data()929 void tst_QWebPage::createViewlessPlugin_data()
930 {
931 PluginFactory::prepareTestData();
932 }
933
createViewlessPlugin()934 void tst_QWebPage::createViewlessPlugin()
935 {
936 QFETCH(int, type);
937 PluginCounterPage* page = PluginFactory::create((PluginFactory::FactoredType)type);
938 QString content("<html><body><object type=\"application/x-qt-plugin\" classid=\"QProgressBar\"></object></body></html>");
939 page->mainFrame()->setHtml(content);
940 QCOMPARE(page->m_count, 1);
941 QVERIFY(page->m_widget);
942 QVERIFY(page->m_pluginParent);
943 QVERIFY(page->m_widget->parent() == page->m_pluginParent);
944 delete page;
945
946 }
947
multiplePageGroupsAndLocalStorage()948 void tst_QWebPage::multiplePageGroupsAndLocalStorage()
949 {
950 QDir dir(tmpDirPath());
951 dir.mkdir("path1");
952 dir.mkdir("path2");
953
954 QWebView view1;
955 QWebView view2;
956
957 view1.page()->settings()->setAttribute(QWebSettings::LocalStorageEnabled, true);
958 view1.page()->settings()->setLocalStoragePath(QDir::toNativeSeparators(tmpDirPath() + "/path1"));
959 DumpRenderTreeSupportQt::webPageSetGroupName(view1.page(), "group1");
960 view2.page()->settings()->setAttribute(QWebSettings::LocalStorageEnabled, true);
961 view2.page()->settings()->setLocalStoragePath(QDir::toNativeSeparators(tmpDirPath() + "/path2"));
962 DumpRenderTreeSupportQt::webPageSetGroupName(view2.page(), "group2");
963 QCOMPARE(DumpRenderTreeSupportQt::webPageGroupName(view1.page()), QString("group1"));
964 QCOMPARE(DumpRenderTreeSupportQt::webPageGroupName(view2.page()), QString("group2"));
965
966
967 view1.setHtml(QString("<html><body> </body></html>"), QUrl("http://www.myexample.com"));
968 view2.setHtml(QString("<html><body> </body></html>"), QUrl("http://www.myexample.com"));
969
970 view1.page()->mainFrame()->evaluateJavaScript("localStorage.test='value1';");
971 view2.page()->mainFrame()->evaluateJavaScript("localStorage.test='value2';");
972
973 view1.setHtml(QString("<html><body> </body></html>"), QUrl("http://www.myexample.com"));
974 view2.setHtml(QString("<html><body> </body></html>"), QUrl("http://www.myexample.com"));
975
976 QVariant s1 = view1.page()->mainFrame()->evaluateJavaScript("localStorage.test");
977 QCOMPARE(s1.toString(), QString("value1"));
978
979 QVariant s2 = view2.page()->mainFrame()->evaluateJavaScript("localStorage.test");
980 QCOMPARE(s2.toString(), QString("value2"));
981
982 QTest::qWait(1000);
983
984 QFile::remove(QDir::toNativeSeparators(tmpDirPath() + "/path1/http_www.myexample.com_0.localstorage"));
985 QFile::remove(QDir::toNativeSeparators(tmpDirPath() + "/path2/http_www.myexample.com_0.localstorage"));
986 dir.rmdir(QDir::toNativeSeparators("./path1"));
987 dir.rmdir(QDir::toNativeSeparators("./path2"));
988 }
989
990 class CursorTrackedPage : public QWebPage
991 {
992 public:
993
CursorTrackedPage(QWidget * parent=0)994 CursorTrackedPage(QWidget *parent = 0): QWebPage(parent) {
995 setViewportSize(QSize(1024, 768)); // big space
996 }
997
selectedText()998 QString selectedText() {
999 return mainFrame()->evaluateJavaScript("window.getSelection().toString()").toString();
1000 }
1001
selectionStartOffset()1002 int selectionStartOffset() {
1003 return mainFrame()->evaluateJavaScript("window.getSelection().getRangeAt(0).startOffset").toInt();
1004 }
1005
selectionEndOffset()1006 int selectionEndOffset() {
1007 return mainFrame()->evaluateJavaScript("window.getSelection().getRangeAt(0).endOffset").toInt();
1008 }
1009
1010 // true if start offset == end offset, i.e. no selected text
isSelectionCollapsed()1011 int isSelectionCollapsed() {
1012 return mainFrame()->evaluateJavaScript("window.getSelection().getRangeAt(0).collapsed").toBool();
1013 }
1014 };
1015
cursorMovements()1016 void tst_QWebPage::cursorMovements()
1017 {
1018 CursorTrackedPage* page = new CursorTrackedPage;
1019 QString content("<html><body><p id=one>The quick brown fox</p><p id=two>jumps over the lazy dog</p><p>May the source<br/>be with you!</p></body></html>");
1020 page->mainFrame()->setHtml(content);
1021
1022 // this will select the first paragraph
1023 QString script = "var range = document.createRange(); " \
1024 "var node = document.getElementById(\"one\"); " \
1025 "range.selectNode(node); " \
1026 "getSelection().addRange(range);";
1027 page->mainFrame()->evaluateJavaScript(script);
1028 QCOMPARE(page->selectedText().trimmed(), QString::fromLatin1("The quick brown fox"));
1029
1030 QRegExp regExp(" style=\".*\"");
1031 regExp.setMinimal(true);
1032 QCOMPARE(page->selectedHtml().trimmed().replace(regExp, ""), QString::fromLatin1("<span class=\"Apple-style-span\"><p id=\"one\">The quick brown fox</p></span>"));
1033
1034 // these actions must exist
1035 QVERIFY(page->action(QWebPage::MoveToNextChar) != 0);
1036 QVERIFY(page->action(QWebPage::MoveToPreviousChar) != 0);
1037 QVERIFY(page->action(QWebPage::MoveToNextWord) != 0);
1038 QVERIFY(page->action(QWebPage::MoveToPreviousWord) != 0);
1039 QVERIFY(page->action(QWebPage::MoveToNextLine) != 0);
1040 QVERIFY(page->action(QWebPage::MoveToPreviousLine) != 0);
1041 QVERIFY(page->action(QWebPage::MoveToStartOfLine) != 0);
1042 QVERIFY(page->action(QWebPage::MoveToEndOfLine) != 0);
1043 QVERIFY(page->action(QWebPage::MoveToStartOfBlock) != 0);
1044 QVERIFY(page->action(QWebPage::MoveToEndOfBlock) != 0);
1045 QVERIFY(page->action(QWebPage::MoveToStartOfDocument) != 0);
1046 QVERIFY(page->action(QWebPage::MoveToEndOfDocument) != 0);
1047
1048 // right now they are disabled because contentEditable is false
1049 QCOMPARE(page->action(QWebPage::MoveToNextChar)->isEnabled(), false);
1050 QCOMPARE(page->action(QWebPage::MoveToPreviousChar)->isEnabled(), false);
1051 QCOMPARE(page->action(QWebPage::MoveToNextWord)->isEnabled(), false);
1052 QCOMPARE(page->action(QWebPage::MoveToPreviousWord)->isEnabled(), false);
1053 QCOMPARE(page->action(QWebPage::MoveToNextLine)->isEnabled(), false);
1054 QCOMPARE(page->action(QWebPage::MoveToPreviousLine)->isEnabled(), false);
1055 QCOMPARE(page->action(QWebPage::MoveToStartOfLine)->isEnabled(), false);
1056 QCOMPARE(page->action(QWebPage::MoveToEndOfLine)->isEnabled(), false);
1057 QCOMPARE(page->action(QWebPage::MoveToStartOfBlock)->isEnabled(), false);
1058 QCOMPARE(page->action(QWebPage::MoveToEndOfBlock)->isEnabled(), false);
1059 QCOMPARE(page->action(QWebPage::MoveToStartOfDocument)->isEnabled(), false);
1060 QCOMPARE(page->action(QWebPage::MoveToEndOfDocument)->isEnabled(), false);
1061
1062 // make it editable before navigating the cursor
1063 page->setContentEditable(true);
1064
1065 // here the actions are enabled after contentEditable is true
1066 QCOMPARE(page->action(QWebPage::MoveToNextChar)->isEnabled(), true);
1067 QCOMPARE(page->action(QWebPage::MoveToPreviousChar)->isEnabled(), true);
1068 QCOMPARE(page->action(QWebPage::MoveToNextWord)->isEnabled(), true);
1069 QCOMPARE(page->action(QWebPage::MoveToPreviousWord)->isEnabled(), true);
1070 QCOMPARE(page->action(QWebPage::MoveToNextLine)->isEnabled(), true);
1071 QCOMPARE(page->action(QWebPage::MoveToPreviousLine)->isEnabled(), true);
1072 QCOMPARE(page->action(QWebPage::MoveToStartOfLine)->isEnabled(), true);
1073 QCOMPARE(page->action(QWebPage::MoveToEndOfLine)->isEnabled(), true);
1074 QCOMPARE(page->action(QWebPage::MoveToStartOfBlock)->isEnabled(), true);
1075 QCOMPARE(page->action(QWebPage::MoveToEndOfBlock)->isEnabled(), true);
1076 QCOMPARE(page->action(QWebPage::MoveToStartOfDocument)->isEnabled(), true);
1077 QCOMPARE(page->action(QWebPage::MoveToEndOfDocument)->isEnabled(), true);
1078
1079 // cursor will be before the word "jump"
1080 page->triggerAction(QWebPage::MoveToNextChar);
1081 QVERIFY(page->isSelectionCollapsed());
1082 QCOMPARE(page->selectionStartOffset(), 0);
1083
1084 // cursor will be between 'j' and 'u' in the word "jump"
1085 page->triggerAction(QWebPage::MoveToNextChar);
1086 QVERIFY(page->isSelectionCollapsed());
1087 QCOMPARE(page->selectionStartOffset(), 1);
1088
1089 // cursor will be between 'u' and 'm' in the word "jump"
1090 page->triggerAction(QWebPage::MoveToNextChar);
1091 QVERIFY(page->isSelectionCollapsed());
1092 QCOMPARE(page->selectionStartOffset(), 2);
1093
1094 // cursor will be after the word "jump"
1095 page->triggerAction(QWebPage::MoveToNextWord);
1096 QVERIFY(page->isSelectionCollapsed());
1097 QCOMPARE(page->selectionStartOffset(), 5);
1098
1099 // cursor will be after the word "lazy"
1100 page->triggerAction(QWebPage::MoveToNextWord);
1101 page->triggerAction(QWebPage::MoveToNextWord);
1102 page->triggerAction(QWebPage::MoveToNextWord);
1103 QVERIFY(page->isSelectionCollapsed());
1104 QCOMPARE(page->selectionStartOffset(), 19);
1105
1106 // cursor will be between 'z' and 'y' in "lazy"
1107 page->triggerAction(QWebPage::MoveToPreviousChar);
1108 QVERIFY(page->isSelectionCollapsed());
1109 QCOMPARE(page->selectionStartOffset(), 18);
1110
1111 // cursor will be between 'a' and 'z' in "lazy"
1112 page->triggerAction(QWebPage::MoveToPreviousChar);
1113 QVERIFY(page->isSelectionCollapsed());
1114 QCOMPARE(page->selectionStartOffset(), 17);
1115
1116 // cursor will be before the word "lazy"
1117 page->triggerAction(QWebPage::MoveToPreviousWord);
1118 QVERIFY(page->isSelectionCollapsed());
1119 QCOMPARE(page->selectionStartOffset(), 15);
1120
1121 // cursor will be before the word "quick"
1122 page->triggerAction(QWebPage::MoveToPreviousWord);
1123 page->triggerAction(QWebPage::MoveToPreviousWord);
1124 page->triggerAction(QWebPage::MoveToPreviousWord);
1125 page->triggerAction(QWebPage::MoveToPreviousWord);
1126 page->triggerAction(QWebPage::MoveToPreviousWord);
1127 page->triggerAction(QWebPage::MoveToPreviousWord);
1128 QVERIFY(page->isSelectionCollapsed());
1129 QCOMPARE(page->selectionStartOffset(), 4);
1130
1131 // cursor will be between 'p' and 's' in the word "jumps"
1132 page->triggerAction(QWebPage::MoveToNextWord);
1133 page->triggerAction(QWebPage::MoveToNextWord);
1134 page->triggerAction(QWebPage::MoveToNextWord);
1135 page->triggerAction(QWebPage::MoveToNextChar);
1136 page->triggerAction(QWebPage::MoveToNextChar);
1137 page->triggerAction(QWebPage::MoveToNextChar);
1138 page->triggerAction(QWebPage::MoveToNextChar);
1139 page->triggerAction(QWebPage::MoveToNextChar);
1140 QVERIFY(page->isSelectionCollapsed());
1141 QCOMPARE(page->selectionStartOffset(), 4);
1142
1143 // cursor will be before the word "jumps"
1144 page->triggerAction(QWebPage::MoveToStartOfLine);
1145 QVERIFY(page->isSelectionCollapsed());
1146 QCOMPARE(page->selectionStartOffset(), 0);
1147
1148 // cursor will be after the word "dog"
1149 page->triggerAction(QWebPage::MoveToEndOfLine);
1150 QVERIFY(page->isSelectionCollapsed());
1151 QCOMPARE(page->selectionStartOffset(), 23);
1152
1153 // cursor will be between 'w' and 'n' in "brown"
1154 page->triggerAction(QWebPage::MoveToStartOfLine);
1155 page->triggerAction(QWebPage::MoveToPreviousWord);
1156 page->triggerAction(QWebPage::MoveToPreviousWord);
1157 page->triggerAction(QWebPage::MoveToNextChar);
1158 page->triggerAction(QWebPage::MoveToNextChar);
1159 page->triggerAction(QWebPage::MoveToNextChar);
1160 page->triggerAction(QWebPage::MoveToNextChar);
1161 QVERIFY(page->isSelectionCollapsed());
1162 QCOMPARE(page->selectionStartOffset(), 14);
1163
1164 // cursor will be after the word "fox"
1165 page->triggerAction(QWebPage::MoveToEndOfLine);
1166 QVERIFY(page->isSelectionCollapsed());
1167 QCOMPARE(page->selectionStartOffset(), 19);
1168
1169 // cursor will be before the word "The"
1170 page->triggerAction(QWebPage::MoveToStartOfDocument);
1171 QVERIFY(page->isSelectionCollapsed());
1172 QCOMPARE(page->selectionStartOffset(), 0);
1173
1174 // cursor will be after the word "you!"
1175 page->triggerAction(QWebPage::MoveToEndOfDocument);
1176 QVERIFY(page->isSelectionCollapsed());
1177 QCOMPARE(page->selectionStartOffset(), 12);
1178
1179 // cursor will be before the word "be"
1180 page->triggerAction(QWebPage::MoveToStartOfBlock);
1181 QVERIFY(page->isSelectionCollapsed());
1182 QCOMPARE(page->selectionStartOffset(), 0);
1183
1184 // cursor will be after the word "you!"
1185 page->triggerAction(QWebPage::MoveToEndOfBlock);
1186 QVERIFY(page->isSelectionCollapsed());
1187 QCOMPARE(page->selectionStartOffset(), 12);
1188
1189 // try to move before the document start
1190 page->triggerAction(QWebPage::MoveToStartOfDocument);
1191 page->triggerAction(QWebPage::MoveToPreviousChar);
1192 QVERIFY(page->isSelectionCollapsed());
1193 QCOMPARE(page->selectionStartOffset(), 0);
1194 page->triggerAction(QWebPage::MoveToStartOfDocument);
1195 page->triggerAction(QWebPage::MoveToPreviousWord);
1196 QVERIFY(page->isSelectionCollapsed());
1197 QCOMPARE(page->selectionStartOffset(), 0);
1198
1199 // try to move past the document end
1200 page->triggerAction(QWebPage::MoveToEndOfDocument);
1201 page->triggerAction(QWebPage::MoveToNextChar);
1202 QVERIFY(page->isSelectionCollapsed());
1203 QCOMPARE(page->selectionStartOffset(), 12);
1204 page->triggerAction(QWebPage::MoveToEndOfDocument);
1205 page->triggerAction(QWebPage::MoveToNextWord);
1206 QVERIFY(page->isSelectionCollapsed());
1207 QCOMPARE(page->selectionStartOffset(), 12);
1208
1209 delete page;
1210 }
1211
textSelection()1212 void tst_QWebPage::textSelection()
1213 {
1214 CursorTrackedPage* page = new CursorTrackedPage;
1215 QString content("<html><body><p id=one>The quick brown fox</p>" \
1216 "<p id=two>jumps over the lazy dog</p>" \
1217 "<p>May the source<br/>be with you!</p></body></html>");
1218 page->mainFrame()->setHtml(content);
1219
1220 // these actions must exist
1221 QVERIFY(page->action(QWebPage::SelectAll) != 0);
1222 QVERIFY(page->action(QWebPage::SelectNextChar) != 0);
1223 QVERIFY(page->action(QWebPage::SelectPreviousChar) != 0);
1224 QVERIFY(page->action(QWebPage::SelectNextWord) != 0);
1225 QVERIFY(page->action(QWebPage::SelectPreviousWord) != 0);
1226 QVERIFY(page->action(QWebPage::SelectNextLine) != 0);
1227 QVERIFY(page->action(QWebPage::SelectPreviousLine) != 0);
1228 QVERIFY(page->action(QWebPage::SelectStartOfLine) != 0);
1229 QVERIFY(page->action(QWebPage::SelectEndOfLine) != 0);
1230 QVERIFY(page->action(QWebPage::SelectStartOfBlock) != 0);
1231 QVERIFY(page->action(QWebPage::SelectEndOfBlock) != 0);
1232 QVERIFY(page->action(QWebPage::SelectStartOfDocument) != 0);
1233 QVERIFY(page->action(QWebPage::SelectEndOfDocument) != 0);
1234
1235 // right now they are disabled because contentEditable is false and
1236 // there isn't an existing selection to modify
1237 QCOMPARE(page->action(QWebPage::SelectNextChar)->isEnabled(), false);
1238 QCOMPARE(page->action(QWebPage::SelectPreviousChar)->isEnabled(), false);
1239 QCOMPARE(page->action(QWebPage::SelectNextWord)->isEnabled(), false);
1240 QCOMPARE(page->action(QWebPage::SelectPreviousWord)->isEnabled(), false);
1241 QCOMPARE(page->action(QWebPage::SelectNextLine)->isEnabled(), false);
1242 QCOMPARE(page->action(QWebPage::SelectPreviousLine)->isEnabled(), false);
1243 QCOMPARE(page->action(QWebPage::SelectStartOfLine)->isEnabled(), false);
1244 QCOMPARE(page->action(QWebPage::SelectEndOfLine)->isEnabled(), false);
1245 QCOMPARE(page->action(QWebPage::SelectStartOfBlock)->isEnabled(), false);
1246 QCOMPARE(page->action(QWebPage::SelectEndOfBlock)->isEnabled(), false);
1247 QCOMPARE(page->action(QWebPage::SelectStartOfDocument)->isEnabled(), false);
1248 QCOMPARE(page->action(QWebPage::SelectEndOfDocument)->isEnabled(), false);
1249
1250 // ..but SelectAll is awalys enabled
1251 QCOMPARE(page->action(QWebPage::SelectAll)->isEnabled(), true);
1252
1253 // Verify hasSelection returns false since there is no selection yet...
1254 QCOMPARE(page->hasSelection(), false);
1255
1256 // this will select the first paragraph
1257 QString selectScript = "var range = document.createRange(); " \
1258 "var node = document.getElementById(\"one\"); " \
1259 "range.selectNode(node); " \
1260 "getSelection().addRange(range);";
1261 page->mainFrame()->evaluateJavaScript(selectScript);
1262 QCOMPARE(page->selectedText().trimmed(), QString::fromLatin1("The quick brown fox"));
1263 QRegExp regExp(" style=\".*\"");
1264 regExp.setMinimal(true);
1265 QCOMPARE(page->selectedHtml().trimmed().replace(regExp, ""), QString::fromLatin1("<span class=\"Apple-style-span\"><p id=\"one\">The quick brown fox</p></span>"));
1266
1267 // Make sure hasSelection returns true, since there is selected text now...
1268 QCOMPARE(page->hasSelection(), true);
1269
1270 // here the actions are enabled after a selection has been created
1271 QCOMPARE(page->action(QWebPage::SelectNextChar)->isEnabled(), true);
1272 QCOMPARE(page->action(QWebPage::SelectPreviousChar)->isEnabled(), true);
1273 QCOMPARE(page->action(QWebPage::SelectNextWord)->isEnabled(), true);
1274 QCOMPARE(page->action(QWebPage::SelectPreviousWord)->isEnabled(), true);
1275 QCOMPARE(page->action(QWebPage::SelectNextLine)->isEnabled(), true);
1276 QCOMPARE(page->action(QWebPage::SelectPreviousLine)->isEnabled(), true);
1277 QCOMPARE(page->action(QWebPage::SelectStartOfLine)->isEnabled(), true);
1278 QCOMPARE(page->action(QWebPage::SelectEndOfLine)->isEnabled(), true);
1279 QCOMPARE(page->action(QWebPage::SelectStartOfBlock)->isEnabled(), true);
1280 QCOMPARE(page->action(QWebPage::SelectEndOfBlock)->isEnabled(), true);
1281 QCOMPARE(page->action(QWebPage::SelectStartOfDocument)->isEnabled(), true);
1282 QCOMPARE(page->action(QWebPage::SelectEndOfDocument)->isEnabled(), true);
1283
1284 // make it editable before navigating the cursor
1285 page->setContentEditable(true);
1286
1287 // cursor will be before the word "The", this makes sure there is a charet
1288 page->triggerAction(QWebPage::MoveToStartOfDocument);
1289 QVERIFY(page->isSelectionCollapsed());
1290 QCOMPARE(page->selectionStartOffset(), 0);
1291
1292 // here the actions are enabled after contentEditable is true
1293 QCOMPARE(page->action(QWebPage::SelectNextChar)->isEnabled(), true);
1294 QCOMPARE(page->action(QWebPage::SelectPreviousChar)->isEnabled(), true);
1295 QCOMPARE(page->action(QWebPage::SelectNextWord)->isEnabled(), true);
1296 QCOMPARE(page->action(QWebPage::SelectPreviousWord)->isEnabled(), true);
1297 QCOMPARE(page->action(QWebPage::SelectNextLine)->isEnabled(), true);
1298 QCOMPARE(page->action(QWebPage::SelectPreviousLine)->isEnabled(), true);
1299 QCOMPARE(page->action(QWebPage::SelectStartOfLine)->isEnabled(), true);
1300 QCOMPARE(page->action(QWebPage::SelectEndOfLine)->isEnabled(), true);
1301 QCOMPARE(page->action(QWebPage::SelectStartOfBlock)->isEnabled(), true);
1302 QCOMPARE(page->action(QWebPage::SelectEndOfBlock)->isEnabled(), true);
1303 QCOMPARE(page->action(QWebPage::SelectStartOfDocument)->isEnabled(), true);
1304 QCOMPARE(page->action(QWebPage::SelectEndOfDocument)->isEnabled(), true);
1305
1306 delete page;
1307 }
1308
textEditing()1309 void tst_QWebPage::textEditing()
1310 {
1311 CursorTrackedPage* page = new CursorTrackedPage;
1312 QString content("<html><body><p id=one>The quick brown fox</p>" \
1313 "<p id=two>jumps over the lazy dog</p>" \
1314 "<p>May the source<br/>be with you!</p></body></html>");
1315 page->mainFrame()->setHtml(content);
1316
1317 // these actions must exist
1318 QVERIFY(page->action(QWebPage::Cut) != 0);
1319 QVERIFY(page->action(QWebPage::Copy) != 0);
1320 QVERIFY(page->action(QWebPage::Paste) != 0);
1321 QVERIFY(page->action(QWebPage::DeleteStartOfWord) != 0);
1322 QVERIFY(page->action(QWebPage::DeleteEndOfWord) != 0);
1323 QVERIFY(page->action(QWebPage::SetTextDirectionDefault) != 0);
1324 QVERIFY(page->action(QWebPage::SetTextDirectionLeftToRight) != 0);
1325 QVERIFY(page->action(QWebPage::SetTextDirectionRightToLeft) != 0);
1326 QVERIFY(page->action(QWebPage::ToggleBold) != 0);
1327 QVERIFY(page->action(QWebPage::ToggleItalic) != 0);
1328 QVERIFY(page->action(QWebPage::ToggleUnderline) != 0);
1329 QVERIFY(page->action(QWebPage::InsertParagraphSeparator) != 0);
1330 QVERIFY(page->action(QWebPage::InsertLineSeparator) != 0);
1331 QVERIFY(page->action(QWebPage::PasteAndMatchStyle) != 0);
1332 QVERIFY(page->action(QWebPage::RemoveFormat) != 0);
1333 QVERIFY(page->action(QWebPage::ToggleStrikethrough) != 0);
1334 QVERIFY(page->action(QWebPage::ToggleSubscript) != 0);
1335 QVERIFY(page->action(QWebPage::ToggleSuperscript) != 0);
1336 QVERIFY(page->action(QWebPage::InsertUnorderedList) != 0);
1337 QVERIFY(page->action(QWebPage::InsertOrderedList) != 0);
1338 QVERIFY(page->action(QWebPage::Indent) != 0);
1339 QVERIFY(page->action(QWebPage::Outdent) != 0);
1340 QVERIFY(page->action(QWebPage::AlignCenter) != 0);
1341 QVERIFY(page->action(QWebPage::AlignJustified) != 0);
1342 QVERIFY(page->action(QWebPage::AlignLeft) != 0);
1343 QVERIFY(page->action(QWebPage::AlignRight) != 0);
1344
1345 // right now they are disabled because contentEditable is false
1346 QCOMPARE(page->action(QWebPage::Cut)->isEnabled(), false);
1347 QCOMPARE(page->action(QWebPage::Paste)->isEnabled(), false);
1348 QCOMPARE(page->action(QWebPage::DeleteStartOfWord)->isEnabled(), false);
1349 QCOMPARE(page->action(QWebPage::DeleteEndOfWord)->isEnabled(), false);
1350 QCOMPARE(page->action(QWebPage::SetTextDirectionDefault)->isEnabled(), false);
1351 QCOMPARE(page->action(QWebPage::SetTextDirectionLeftToRight)->isEnabled(), false);
1352 QCOMPARE(page->action(QWebPage::SetTextDirectionRightToLeft)->isEnabled(), false);
1353 QCOMPARE(page->action(QWebPage::ToggleBold)->isEnabled(), false);
1354 QCOMPARE(page->action(QWebPage::ToggleItalic)->isEnabled(), false);
1355 QCOMPARE(page->action(QWebPage::ToggleUnderline)->isEnabled(), false);
1356 QCOMPARE(page->action(QWebPage::InsertParagraphSeparator)->isEnabled(), false);
1357 QCOMPARE(page->action(QWebPage::InsertLineSeparator)->isEnabled(), false);
1358 QCOMPARE(page->action(QWebPage::PasteAndMatchStyle)->isEnabled(), false);
1359 QCOMPARE(page->action(QWebPage::RemoveFormat)->isEnabled(), false);
1360 QCOMPARE(page->action(QWebPage::ToggleStrikethrough)->isEnabled(), false);
1361 QCOMPARE(page->action(QWebPage::ToggleSubscript)->isEnabled(), false);
1362 QCOMPARE(page->action(QWebPage::ToggleSuperscript)->isEnabled(), false);
1363 QCOMPARE(page->action(QWebPage::InsertUnorderedList)->isEnabled(), false);
1364 QCOMPARE(page->action(QWebPage::InsertOrderedList)->isEnabled(), false);
1365 QCOMPARE(page->action(QWebPage::Indent)->isEnabled(), false);
1366 QCOMPARE(page->action(QWebPage::Outdent)->isEnabled(), false);
1367 QCOMPARE(page->action(QWebPage::AlignCenter)->isEnabled(), false);
1368 QCOMPARE(page->action(QWebPage::AlignJustified)->isEnabled(), false);
1369 QCOMPARE(page->action(QWebPage::AlignLeft)->isEnabled(), false);
1370 QCOMPARE(page->action(QWebPage::AlignRight)->isEnabled(), false);
1371
1372 // Select everything
1373 page->triggerAction(QWebPage::SelectAll);
1374
1375 // make sure it is enabled since there is a selection
1376 QCOMPARE(page->action(QWebPage::Copy)->isEnabled(), true);
1377
1378 // make it editable before navigating the cursor
1379 page->setContentEditable(true);
1380
1381 // clear the selection
1382 page->triggerAction(QWebPage::MoveToStartOfDocument);
1383 QVERIFY(page->isSelectionCollapsed());
1384 QCOMPARE(page->selectionStartOffset(), 0);
1385
1386 // make sure it is disabled since there isn't a selection
1387 QCOMPARE(page->action(QWebPage::Copy)->isEnabled(), false);
1388
1389 // here the actions are enabled after contentEditable is true
1390 QCOMPARE(page->action(QWebPage::Paste)->isEnabled(), true);
1391 QCOMPARE(page->action(QWebPage::DeleteStartOfWord)->isEnabled(), true);
1392 QCOMPARE(page->action(QWebPage::DeleteEndOfWord)->isEnabled(), true);
1393 QCOMPARE(page->action(QWebPage::SetTextDirectionDefault)->isEnabled(), true);
1394 QCOMPARE(page->action(QWebPage::SetTextDirectionLeftToRight)->isEnabled(), true);
1395 QCOMPARE(page->action(QWebPage::SetTextDirectionRightToLeft)->isEnabled(), true);
1396 QCOMPARE(page->action(QWebPage::ToggleBold)->isEnabled(), true);
1397 QCOMPARE(page->action(QWebPage::ToggleItalic)->isEnabled(), true);
1398 QCOMPARE(page->action(QWebPage::ToggleUnderline)->isEnabled(), true);
1399 QCOMPARE(page->action(QWebPage::InsertParagraphSeparator)->isEnabled(), true);
1400 QCOMPARE(page->action(QWebPage::InsertLineSeparator)->isEnabled(), true);
1401 QCOMPARE(page->action(QWebPage::PasteAndMatchStyle)->isEnabled(), true);
1402 QCOMPARE(page->action(QWebPage::ToggleStrikethrough)->isEnabled(), true);
1403 QCOMPARE(page->action(QWebPage::ToggleSubscript)->isEnabled(), true);
1404 QCOMPARE(page->action(QWebPage::ToggleSuperscript)->isEnabled(), true);
1405 QCOMPARE(page->action(QWebPage::InsertUnorderedList)->isEnabled(), true);
1406 QCOMPARE(page->action(QWebPage::InsertOrderedList)->isEnabled(), true);
1407 QCOMPARE(page->action(QWebPage::Indent)->isEnabled(), true);
1408 QCOMPARE(page->action(QWebPage::Outdent)->isEnabled(), true);
1409 QCOMPARE(page->action(QWebPage::AlignCenter)->isEnabled(), true);
1410 QCOMPARE(page->action(QWebPage::AlignJustified)->isEnabled(), true);
1411 QCOMPARE(page->action(QWebPage::AlignLeft)->isEnabled(), true);
1412 QCOMPARE(page->action(QWebPage::AlignRight)->isEnabled(), true);
1413
1414 // make sure these are disabled since there isn't a selection
1415 QCOMPARE(page->action(QWebPage::Cut)->isEnabled(), false);
1416 QCOMPARE(page->action(QWebPage::RemoveFormat)->isEnabled(), false);
1417
1418 // make sure everything is selected
1419 page->triggerAction(QWebPage::SelectAll);
1420
1421 // this is only true if there is an editable selection
1422 QCOMPARE(page->action(QWebPage::Cut)->isEnabled(), true);
1423 QCOMPARE(page->action(QWebPage::RemoveFormat)->isEnabled(), true);
1424
1425 delete page;
1426 }
1427
requestCache()1428 void tst_QWebPage::requestCache()
1429 {
1430 TestPage page;
1431 QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool)));
1432
1433 page.mainFrame()->setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me</a>"));
1434 QTRY_COMPARE(loadSpy.count(), 1);
1435 QTRY_COMPARE(page.navigations.count(), 1);
1436
1437 page.mainFrame()->setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me2</a>"));
1438 QTRY_COMPARE(loadSpy.count(), 2);
1439 QTRY_COMPARE(page.navigations.count(), 2);
1440
1441 page.triggerAction(QWebPage::Stop);
1442 QVERIFY(page.history()->canGoBack());
1443 page.triggerAction(QWebPage::Back);
1444
1445 QTRY_COMPARE(loadSpy.count(), 3);
1446 QTRY_COMPARE(page.navigations.count(), 3);
1447 QCOMPARE(page.navigations.at(0).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(),
1448 (int)QNetworkRequest::PreferNetwork);
1449 QCOMPARE(page.navigations.at(1).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(),
1450 (int)QNetworkRequest::PreferNetwork);
1451 QCOMPARE(page.navigations.at(2).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(),
1452 (int)QNetworkRequest::PreferCache);
1453 }
1454
loadCachedPage()1455 void tst_QWebPage::loadCachedPage()
1456 {
1457 TestPage page;
1458 QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool)));
1459 page.settings()->setMaximumPagesInCache(3);
1460
1461 page.mainFrame()->load(QUrl("data:text/html,This is first page"));
1462
1463 QTRY_COMPARE(loadSpy.count(), 1);
1464 QTRY_COMPARE(page.navigations.count(), 1);
1465
1466 QUrl firstPageUrl = page.mainFrame()->url();
1467 page.mainFrame()->load(QUrl("data:text/html,This is second page"));
1468
1469 QTRY_COMPARE(loadSpy.count(), 2);
1470 QTRY_COMPARE(page.navigations.count(), 2);
1471
1472 page.triggerAction(QWebPage::Stop);
1473 QVERIFY(page.history()->canGoBack());
1474
1475 QSignalSpy urlSpy(page.mainFrame(), SIGNAL(urlChanged(QUrl)));
1476 QVERIFY(urlSpy.isValid());
1477
1478 page.triggerAction(QWebPage::Back);
1479 ::waitForSignal(page.mainFrame(), SIGNAL(urlChanged(QUrl)));
1480 QCOMPARE(urlSpy.size(), 1);
1481
1482 QList<QVariant> arguments1 = urlSpy.takeFirst();
1483 QCOMPARE(arguments1.at(0).toUrl(), firstPageUrl);
1484
1485 }
backActionUpdate()1486 void tst_QWebPage::backActionUpdate()
1487 {
1488 QWebView view;
1489 QWebPage *page = view.page();
1490 QAction *action = page->action(QWebPage::Back);
1491 QVERIFY(!action->isEnabled());
1492 QSignalSpy loadSpy(page, SIGNAL(loadFinished(bool)));
1493 QUrl url = QUrl("qrc:///resources/framedindex.html");
1494 page->mainFrame()->load(url);
1495 QTRY_COMPARE(loadSpy.count(), 1);
1496 QVERIFY(!action->isEnabled());
1497 QTest::mouseClick(&view, Qt::LeftButton, 0, QPoint(10, 10));
1498 QTRY_COMPARE(loadSpy.count(), 2);
1499
1500 QVERIFY(action->isEnabled());
1501 }
1502
frameAtHelper(QWebPage * webPage,QWebFrame * webFrame,QPoint framePosition)1503 void frameAtHelper(QWebPage* webPage, QWebFrame* webFrame, QPoint framePosition)
1504 {
1505 if (!webFrame)
1506 return;
1507
1508 framePosition += QPoint(webFrame->pos());
1509 QList<QWebFrame*> children = webFrame->childFrames();
1510 for (int i = 0; i < children.size(); ++i) {
1511 if (children.at(i)->childFrames().size() > 0)
1512 frameAtHelper(webPage, children.at(i), framePosition);
1513
1514 QRect frameRect(children.at(i)->pos() + framePosition, children.at(i)->geometry().size());
1515 QVERIFY(children.at(i) == webPage->frameAt(frameRect.topLeft()));
1516 }
1517 }
1518
frameAt()1519 void tst_QWebPage::frameAt()
1520 {
1521 QWebView webView;
1522 QWebPage* webPage = webView.page();
1523 QSignalSpy loadSpy(webPage, SIGNAL(loadFinished(bool)));
1524 QUrl url = QUrl("qrc:///resources/iframe.html");
1525 webPage->mainFrame()->load(url);
1526 QTRY_COMPARE(loadSpy.count(), 1);
1527 frameAtHelper(webPage, webPage->mainFrame(), webPage->mainFrame()->pos());
1528 }
1529
inputMethods_data()1530 void tst_QWebPage::inputMethods_data()
1531 {
1532 QTest::addColumn<QString>("viewType");
1533 QTest::newRow("QWebView") << "QWebView";
1534 QTest::newRow("QGraphicsWebView") << "QGraphicsWebView";
1535 }
1536
inputMethodHints(QObject * object)1537 static Qt::InputMethodHints inputMethodHints(QObject* object)
1538 {
1539 if (QGraphicsObject* o = qobject_cast<QGraphicsObject*>(object))
1540 return o->inputMethodHints();
1541 if (QWidget* w = qobject_cast<QWidget*>(object))
1542 return w->inputMethodHints();
1543 return Qt::InputMethodHints();
1544 }
1545
inputMethodEnabled(QObject * object)1546 static bool inputMethodEnabled(QObject* object)
1547 {
1548 if (QGraphicsObject* o = qobject_cast<QGraphicsObject*>(object))
1549 return o->flags() & QGraphicsItem::ItemAcceptsInputMethod;
1550 if (QWidget* w = qobject_cast<QWidget*>(object))
1551 return w->testAttribute(Qt::WA_InputMethodEnabled);
1552 return false;
1553 }
1554
clickOnPage(QWebPage * page,const QPoint & position)1555 static void clickOnPage(QWebPage* page, const QPoint& position)
1556 {
1557 QMouseEvent evpres(QEvent::MouseButtonPress, position, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1558 page->event(&evpres);
1559 QMouseEvent evrel(QEvent::MouseButtonRelease, position, Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1560 page->event(&evrel);
1561 }
1562
inputMethods()1563 void tst_QWebPage::inputMethods()
1564 {
1565 QFETCH(QString, viewType);
1566 QWebPage* page = new QWebPage;
1567 QObject* view = 0;
1568 QObject* container = 0;
1569 if (viewType == "QWebView") {
1570 QWebView* wv = new QWebView;
1571 wv->setPage(page);
1572 view = wv;
1573 container = view;
1574 } else if (viewType == "QGraphicsWebView") {
1575 QGraphicsWebView* wv = new QGraphicsWebView;
1576 wv->setPage(page);
1577 view = wv;
1578
1579 QGraphicsView* gv = new QGraphicsView;
1580 QGraphicsScene* scene = new QGraphicsScene(gv);
1581 gv->setScene(scene);
1582 scene->addItem(wv);
1583 wv->setGeometry(QRect(0, 0, 500, 500));
1584
1585 container = gv;
1586 } else
1587 QVERIFY2(false, "Unknown view type");
1588
1589 page->settings()->setFontFamily(QWebSettings::SerifFont, "FooSerifFont");
1590 page->mainFrame()->setHtml("<html><body>" \
1591 "<input type='text' id='input1' style='font-family: serif' value='' maxlength='20'/><br>" \
1592 "<input type='password'/>" \
1593 "</body></html>");
1594 page->mainFrame()->setFocus();
1595
1596 EventSpy viewEventSpy(container);
1597
1598 QWebElementCollection inputs = page->mainFrame()->documentElement().findAll("input");
1599 QPoint textInputCenter = inputs.at(0).geometry().center();
1600
1601 clickOnPage(page, textInputCenter);
1602
1603 // This part of the test checks if the SIP (Software Input Panel) is triggered,
1604 // which normally happens on mobile platforms, when a user input form receives
1605 // a mouse click.
1606 int inputPanel = 0;
1607 if (viewType == "QWebView") {
1608 if (QWebView* wv = qobject_cast<QWebView*>(view))
1609 inputPanel = wv->style()->styleHint(QStyle::SH_RequestSoftwareInputPanel);
1610 } else if (viewType == "QGraphicsWebView") {
1611 if (QGraphicsWebView* wv = qobject_cast<QGraphicsWebView*>(view))
1612 inputPanel = wv->style()->styleHint(QStyle::SH_RequestSoftwareInputPanel);
1613 }
1614
1615 // For non-mobile platforms RequestSoftwareInputPanel event is not called
1616 // because there is no SIP (Software Input Panel) triggered. In the case of a
1617 // mobile platform, an input panel, e.g. virtual keyboard, is usually invoked
1618 // and the RequestSoftwareInputPanel event is called. For these two situations
1619 // this part of the test can verified as the checks below.
1620 if (inputPanel)
1621 QVERIFY(viewEventSpy.contains(QEvent::RequestSoftwareInputPanel));
1622 else
1623 QVERIFY(!viewEventSpy.contains(QEvent::RequestSoftwareInputPanel));
1624 viewEventSpy.clear();
1625
1626 clickOnPage(page, textInputCenter);
1627 QVERIFY(viewEventSpy.contains(QEvent::RequestSoftwareInputPanel));
1628
1629 //ImMicroFocus
1630 QVariant variant = page->inputMethodQuery(Qt::ImMicroFocus);
1631 QVERIFY(inputs.at(0).geometry().contains(variant.toRect().topLeft()));
1632
1633 //ImFont
1634 variant = page->inputMethodQuery(Qt::ImFont);
1635 QFont font = variant.value<QFont>();
1636 QCOMPARE(page->settings()->fontFamily(QWebSettings::SerifFont), font.family());
1637
1638 QList<QInputMethodEvent::Attribute> inputAttributes;
1639
1640 //Insert text.
1641 {
1642 QInputMethodEvent eventText("QtWebKit", inputAttributes);
1643 QSignalSpy signalSpy(page, SIGNAL(microFocusChanged()));
1644 page->event(&eventText);
1645 QCOMPARE(signalSpy.count(), 0);
1646 }
1647
1648 {
1649 QInputMethodEvent eventText("", inputAttributes);
1650 eventText.setCommitString(QString("QtWebKit"), 0, 0);
1651 page->event(&eventText);
1652 }
1653
1654 //ImMaximumTextLength
1655 variant = page->inputMethodQuery(Qt::ImMaximumTextLength);
1656 QCOMPARE(20, variant.toInt());
1657
1658 //Set selection
1659 inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 3, 2, QVariant());
1660 QInputMethodEvent eventSelection("",inputAttributes);
1661 page->event(&eventSelection);
1662
1663 //ImAnchorPosition
1664 variant = page->inputMethodQuery(Qt::ImAnchorPosition);
1665 int anchorPosition = variant.toInt();
1666 QCOMPARE(anchorPosition, 3);
1667
1668 //ImCursorPosition
1669 variant = page->inputMethodQuery(Qt::ImCursorPosition);
1670 int cursorPosition = variant.toInt();
1671 QCOMPARE(cursorPosition, 5);
1672
1673 //ImCurrentSelection
1674 variant = page->inputMethodQuery(Qt::ImCurrentSelection);
1675 QString selectionValue = variant.value<QString>();
1676 QCOMPARE(selectionValue, QString("eb"));
1677
1678 //Set selection with negative length
1679 inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 6, -5, QVariant());
1680 QInputMethodEvent eventSelection3("",inputAttributes);
1681 page->event(&eventSelection3);
1682
1683 //ImAnchorPosition
1684 variant = page->inputMethodQuery(Qt::ImAnchorPosition);
1685 anchorPosition = variant.toInt();
1686 QCOMPARE(anchorPosition, 1);
1687
1688 //ImCursorPosition
1689 variant = page->inputMethodQuery(Qt::ImCursorPosition);
1690 cursorPosition = variant.toInt();
1691 QCOMPARE(cursorPosition, 6);
1692
1693 //ImCurrentSelection
1694 variant = page->inputMethodQuery(Qt::ImCurrentSelection);
1695 selectionValue = variant.value<QString>();
1696 QCOMPARE(selectionValue, QString("tWebK"));
1697
1698 //ImSurroundingText
1699 variant = page->inputMethodQuery(Qt::ImSurroundingText);
1700 QString value = variant.value<QString>();
1701 QCOMPARE(value, QString("QtWebKit"));
1702
1703 {
1704 QList<QInputMethodEvent::Attribute> attributes;
1705 // Clear the selection, so the next test does not clear any contents.
1706 QInputMethodEvent::Attribute newSelection(QInputMethodEvent::Selection, 0, 0, QVariant());
1707 attributes.append(newSelection);
1708 QInputMethodEvent event("composition", attributes);
1709 page->event(&event);
1710 }
1711
1712 // A ongoing composition should not change the surrounding text before it is committed.
1713 variant = page->inputMethodQuery(Qt::ImSurroundingText);
1714 value = variant.value<QString>();
1715 QCOMPARE(value, QString("QtWebKit"));
1716
1717 // Cancel current composition first
1718 inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 0, 0, QVariant());
1719 QInputMethodEvent eventSelection4("", inputAttributes);
1720 page->event(&eventSelection4);
1721
1722 // START - Tests for Selection when the Editor is NOT in Composition mode
1723
1724 // LEFT to RIGHT selection
1725 // Deselect the selection by sending MouseButtonPress events
1726 // This moves the current cursor to the end of the text
1727 clickOnPage(page, textInputCenter);
1728
1729 {
1730 QList<QInputMethodEvent::Attribute> attributes;
1731 QInputMethodEvent event(QString(), attributes);
1732 event.setCommitString("XXX", 0, 0);
1733 page->event(&event);
1734 event.setCommitString(QString(), -2, 2); // Erase two characters.
1735 page->event(&event);
1736 event.setCommitString(QString(), -1, 1); // Erase one character.
1737 page->event(&event);
1738 variant = page->inputMethodQuery(Qt::ImSurroundingText);
1739 value = variant.value<QString>();
1740 QCOMPARE(value, QString("QtWebKit"));
1741 }
1742
1743 //Move to the start of the line
1744 page->triggerAction(QWebPage::MoveToStartOfLine);
1745
1746 QKeyEvent keyRightEventPress(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier);
1747 QKeyEvent keyRightEventRelease(QEvent::KeyRelease, Qt::Key_Right, Qt::NoModifier);
1748
1749 //Move 2 characters RIGHT
1750 for (int j = 0; j < 2; ++j) {
1751 page->event(&keyRightEventPress);
1752 page->event(&keyRightEventRelease);
1753 }
1754
1755 //Select to the end of the line
1756 page->triggerAction(QWebPage::SelectEndOfLine);
1757
1758 //ImAnchorPosition QtWebKit
1759 variant = page->inputMethodQuery(Qt::ImAnchorPosition);
1760 anchorPosition = variant.toInt();
1761 QCOMPARE(anchorPosition, 2);
1762
1763 //ImCursorPosition
1764 variant = page->inputMethodQuery(Qt::ImCursorPosition);
1765 cursorPosition = variant.toInt();
1766 QCOMPARE(cursorPosition, 8);
1767
1768 //ImCurrentSelection
1769 variant = page->inputMethodQuery(Qt::ImCurrentSelection);
1770 selectionValue = variant.value<QString>();
1771 QCOMPARE(selectionValue, QString("WebKit"));
1772
1773 //RIGHT to LEFT selection
1774 //Deselect the selection (this moves the current cursor to the end of the text)
1775 clickOnPage(page, textInputCenter);
1776
1777 //ImAnchorPosition
1778 variant = page->inputMethodQuery(Qt::ImAnchorPosition);
1779 anchorPosition = variant.toInt();
1780 QCOMPARE(anchorPosition, 8);
1781
1782 //ImCursorPosition
1783 variant = page->inputMethodQuery(Qt::ImCursorPosition);
1784 cursorPosition = variant.toInt();
1785 QCOMPARE(cursorPosition, 8);
1786
1787 //ImCurrentSelection
1788 variant = page->inputMethodQuery(Qt::ImCurrentSelection);
1789 selectionValue = variant.value<QString>();
1790 QCOMPARE(selectionValue, QString(""));
1791
1792 QKeyEvent keyLeftEventPress(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier);
1793 QKeyEvent keyLeftEventRelease(QEvent::KeyRelease, Qt::Key_Left, Qt::NoModifier);
1794
1795 //Move 2 characters LEFT
1796 for (int i = 0; i < 2; ++i) {
1797 page->event(&keyLeftEventPress);
1798 page->event(&keyLeftEventRelease);
1799 }
1800
1801 //Select to the start of the line
1802 page->triggerAction(QWebPage::SelectStartOfLine);
1803
1804 //ImAnchorPosition
1805 variant = page->inputMethodQuery(Qt::ImAnchorPosition);
1806 anchorPosition = variant.toInt();
1807 QCOMPARE(anchorPosition, 6);
1808
1809 //ImCursorPosition
1810 variant = page->inputMethodQuery(Qt::ImCursorPosition);
1811 cursorPosition = variant.toInt();
1812 QCOMPARE(cursorPosition, 0);
1813
1814 //ImCurrentSelection
1815 variant = page->inputMethodQuery(Qt::ImCurrentSelection);
1816 selectionValue = variant.value<QString>();
1817 QCOMPARE(selectionValue, QString("QtWebK"));
1818
1819 //END - Tests for Selection when the Editor is not in Composition mode
1820
1821 //ImhHiddenText
1822 QPoint passwordInputCenter = inputs.at(1).geometry().center();
1823 clickOnPage(page, passwordInputCenter);
1824
1825 QVERIFY(inputMethodEnabled(view));
1826 QVERIFY(inputMethodHints(view) & Qt::ImhHiddenText);
1827
1828 clickOnPage(page, textInputCenter);
1829 QVERIFY(!(inputMethodHints(view) & Qt::ImhHiddenText));
1830
1831 page->mainFrame()->setHtml("<html><body><p>nothing to input here");
1832 viewEventSpy.clear();
1833
1834 QWebElement para = page->mainFrame()->findFirstElement("p");
1835 clickOnPage(page, para.geometry().center());
1836
1837 QVERIFY(!viewEventSpy.contains(QEvent::RequestSoftwareInputPanel));
1838
1839 //START - Test for sending empty QInputMethodEvent
1840 page->mainFrame()->setHtml("<html><body>" \
1841 "<input type='text' id='input3' value='QtWebKit2'/>" \
1842 "</body></html>");
1843 page->mainFrame()->evaluateJavaScript("var inputEle = document.getElementById('input3'); inputEle.focus(); inputEle.select();");
1844
1845 //Send empty QInputMethodEvent
1846 QInputMethodEvent emptyEvent;
1847 page->event(&emptyEvent);
1848
1849 QString inputValue = page->mainFrame()->evaluateJavaScript("document.getElementById('input3').value").toString();
1850 QCOMPARE(inputValue, QString("QtWebKit2"));
1851 //END - Test for sending empty QInputMethodEvent
1852
1853 page->mainFrame()->setHtml("<html><body>" \
1854 "<input type='text' id='input4' value='QtWebKit inputMethod'/>" \
1855 "</body></html>");
1856 page->mainFrame()->evaluateJavaScript("var inputEle = document.getElementById('input4'); inputEle.focus(); inputEle.select();");
1857
1858 // Clear the selection, also cancel the ongoing composition if there is one.
1859 {
1860 QList<QInputMethodEvent::Attribute> attributes;
1861 QInputMethodEvent::Attribute newSelection(QInputMethodEvent::Selection, 0, 0, QVariant());
1862 attributes.append(newSelection);
1863 QInputMethodEvent event("", attributes);
1864 page->event(&event);
1865 }
1866
1867 // ImCurrentSelection
1868 variant = page->inputMethodQuery(Qt::ImCurrentSelection);
1869 selectionValue = variant.value<QString>();
1870 QCOMPARE(selectionValue, QString(""));
1871
1872 variant = page->inputMethodQuery(Qt::ImSurroundingText);
1873 QString surroundingValue = variant.value<QString>();
1874 QCOMPARE(surroundingValue, QString("QtWebKit inputMethod"));
1875
1876 // ImAnchorPosition
1877 variant = page->inputMethodQuery(Qt::ImAnchorPosition);
1878 anchorPosition = variant.toInt();
1879 QCOMPARE(anchorPosition, 0);
1880
1881 // ImCursorPosition
1882 variant = page->inputMethodQuery(Qt::ImCursorPosition);
1883 cursorPosition = variant.toInt();
1884 QCOMPARE(cursorPosition, 0);
1885
1886 // 1. Insert a character to the begining of the line.
1887 // Send temporary text, which makes the editor has composition 'm'.
1888 {
1889 QList<QInputMethodEvent::Attribute> attributes;
1890 QInputMethodEvent event("m", attributes);
1891 page->event(&event);
1892 }
1893
1894 // ImCurrentSelection
1895 variant = page->inputMethodQuery(Qt::ImCurrentSelection);
1896 selectionValue = variant.value<QString>();
1897 QCOMPARE(selectionValue, QString(""));
1898
1899 // ImSurroundingText
1900 variant = page->inputMethodQuery(Qt::ImSurroundingText);
1901 surroundingValue = variant.value<QString>();
1902 QCOMPARE(surroundingValue, QString("QtWebKit inputMethod"));
1903
1904 // ImCursorPosition
1905 variant = page->inputMethodQuery(Qt::ImCursorPosition);
1906 cursorPosition = variant.toInt();
1907 QCOMPARE(cursorPosition, 0);
1908
1909 // ImAnchorPosition
1910 variant = page->inputMethodQuery(Qt::ImAnchorPosition);
1911 anchorPosition = variant.toInt();
1912 QCOMPARE(anchorPosition, 0);
1913
1914 // Send temporary text, which makes the editor has composition 'n'.
1915 {
1916 QList<QInputMethodEvent::Attribute> attributes;
1917 QInputMethodEvent event("n", attributes);
1918 page->event(&event);
1919 }
1920
1921 // ImCurrentSelection
1922 variant = page->inputMethodQuery(Qt::ImCurrentSelection);
1923 selectionValue = variant.value<QString>();
1924 QCOMPARE(selectionValue, QString(""));
1925
1926 // ImSurroundingText
1927 variant = page->inputMethodQuery(Qt::ImSurroundingText);
1928 surroundingValue = variant.value<QString>();
1929 QCOMPARE(surroundingValue, QString("QtWebKit inputMethod"));
1930
1931 // ImCursorPosition
1932 variant = page->inputMethodQuery(Qt::ImCursorPosition);
1933 cursorPosition = variant.toInt();
1934 QCOMPARE(cursorPosition, 0);
1935
1936 // ImAnchorPosition
1937 variant = page->inputMethodQuery(Qt::ImAnchorPosition);
1938 anchorPosition = variant.toInt();
1939 QCOMPARE(anchorPosition, 0);
1940
1941 // Send commit text, which makes the editor conforms composition.
1942 {
1943 QList<QInputMethodEvent::Attribute> attributes;
1944 QInputMethodEvent event("", attributes);
1945 event.setCommitString("o");
1946 page->event(&event);
1947 }
1948
1949 // ImCurrentSelection
1950 variant = page->inputMethodQuery(Qt::ImCurrentSelection);
1951 selectionValue = variant.value<QString>();
1952 QCOMPARE(selectionValue, QString(""));
1953
1954 // ImSurroundingText
1955 variant = page->inputMethodQuery(Qt::ImSurroundingText);
1956 surroundingValue = variant.value<QString>();
1957 QCOMPARE(surroundingValue, QString("oQtWebKit inputMethod"));
1958
1959 // ImCursorPosition
1960 variant = page->inputMethodQuery(Qt::ImCursorPosition);
1961 cursorPosition = variant.toInt();
1962 QCOMPARE(cursorPosition, 1);
1963
1964 // ImAnchorPosition
1965 variant = page->inputMethodQuery(Qt::ImAnchorPosition);
1966 anchorPosition = variant.toInt();
1967 QCOMPARE(anchorPosition, 1);
1968
1969 // 2. insert a character to the middle of the line.
1970 // Send temporary text, which makes the editor has composition 'd'.
1971 {
1972 QList<QInputMethodEvent::Attribute> attributes;
1973 QInputMethodEvent event("d", attributes);
1974 page->event(&event);
1975 }
1976
1977 // ImCurrentSelection
1978 variant = page->inputMethodQuery(Qt::ImCurrentSelection);
1979 selectionValue = variant.value<QString>();
1980 QCOMPARE(selectionValue, QString(""));
1981
1982 // ImSurroundingText
1983 variant = page->inputMethodQuery(Qt::ImSurroundingText);
1984 surroundingValue = variant.value<QString>();
1985 QCOMPARE(surroundingValue, QString("oQtWebKit inputMethod"));
1986
1987 // ImCursorPosition
1988 variant = page->inputMethodQuery(Qt::ImCursorPosition);
1989 cursorPosition = variant.toInt();
1990 QCOMPARE(cursorPosition, 1);
1991
1992 // ImAnchorPosition
1993 variant = page->inputMethodQuery(Qt::ImAnchorPosition);
1994 anchorPosition = variant.toInt();
1995 QCOMPARE(anchorPosition, 1);
1996
1997 // Send commit text, which makes the editor conforms composition.
1998 {
1999 QList<QInputMethodEvent::Attribute> attributes;
2000 QInputMethodEvent event("", attributes);
2001 event.setCommitString("e");
2002 page->event(&event);
2003 }
2004
2005 // ImCurrentSelection
2006 variant = page->inputMethodQuery(Qt::ImCurrentSelection);
2007 selectionValue = variant.value<QString>();
2008 QCOMPARE(selectionValue, QString(""));
2009
2010 // ImSurroundingText
2011 variant = page->inputMethodQuery(Qt::ImSurroundingText);
2012 surroundingValue = variant.value<QString>();
2013 QCOMPARE(surroundingValue, QString("oeQtWebKit inputMethod"));
2014
2015 // ImCursorPosition
2016 variant = page->inputMethodQuery(Qt::ImCursorPosition);
2017 cursorPosition = variant.toInt();
2018 QCOMPARE(cursorPosition, 2);
2019
2020 // ImAnchorPosition
2021 variant = page->inputMethodQuery(Qt::ImAnchorPosition);
2022 anchorPosition = variant.toInt();
2023 QCOMPARE(anchorPosition, 2);
2024
2025 // 3. Insert a character to the end of the line.
2026 page->triggerAction(QWebPage::MoveToEndOfLine);
2027
2028 // Send temporary text, which makes the editor has composition 't'.
2029 {
2030 QList<QInputMethodEvent::Attribute> attributes;
2031 QInputMethodEvent event("t", attributes);
2032 page->event(&event);
2033 }
2034
2035 // ImCurrentSelection
2036 variant = page->inputMethodQuery(Qt::ImCurrentSelection);
2037 selectionValue = variant.value<QString>();
2038 QCOMPARE(selectionValue, QString(""));
2039
2040 // ImSurroundingText
2041 variant = page->inputMethodQuery(Qt::ImSurroundingText);
2042 surroundingValue = variant.value<QString>();
2043 QCOMPARE(surroundingValue, QString("oeQtWebKit inputMethod"));
2044
2045 // ImCursorPosition
2046 variant = page->inputMethodQuery(Qt::ImCursorPosition);
2047 cursorPosition = variant.toInt();
2048 QCOMPARE(cursorPosition, 22);
2049
2050 // ImAnchorPosition
2051 variant = page->inputMethodQuery(Qt::ImAnchorPosition);
2052 anchorPosition = variant.toInt();
2053 QCOMPARE(anchorPosition, 22);
2054
2055 // Send commit text, which makes the editor conforms composition.
2056 {
2057 QList<QInputMethodEvent::Attribute> attributes;
2058 QInputMethodEvent event("", attributes);
2059 event.setCommitString("t");
2060 page->event(&event);
2061 }
2062
2063 // ImCurrentSelection
2064 variant = page->inputMethodQuery(Qt::ImCurrentSelection);
2065 selectionValue = variant.value<QString>();
2066 QCOMPARE(selectionValue, QString(""));
2067
2068 // ImSurroundingText
2069 variant = page->inputMethodQuery(Qt::ImSurroundingText);
2070 surroundingValue = variant.value<QString>();
2071 QCOMPARE(surroundingValue, QString("oeQtWebKit inputMethodt"));
2072
2073 // ImCursorPosition
2074 variant = page->inputMethodQuery(Qt::ImCursorPosition);
2075 cursorPosition = variant.toInt();
2076 QCOMPARE(cursorPosition, 23);
2077
2078 // ImAnchorPosition
2079 variant = page->inputMethodQuery(Qt::ImAnchorPosition);
2080 anchorPosition = variant.toInt();
2081 QCOMPARE(anchorPosition, 23);
2082
2083 // 4. Replace the selection.
2084 page->triggerAction(QWebPage::SelectPreviousWord);
2085
2086 // ImCurrentSelection
2087 variant = page->inputMethodQuery(Qt::ImCurrentSelection);
2088 selectionValue = variant.value<QString>();
2089 QCOMPARE(selectionValue, QString("inputMethodt"));
2090
2091 // ImSurroundingText
2092 variant = page->inputMethodQuery(Qt::ImSurroundingText);
2093 surroundingValue = variant.value<QString>();
2094 QCOMPARE(surroundingValue, QString("oeQtWebKit inputMethodt"));
2095
2096 // ImCursorPosition
2097 variant = page->inputMethodQuery(Qt::ImCursorPosition);
2098 cursorPosition = variant.toInt();
2099 QCOMPARE(cursorPosition, 11);
2100
2101 // ImAnchorPosition
2102 variant = page->inputMethodQuery(Qt::ImAnchorPosition);
2103 anchorPosition = variant.toInt();
2104 QCOMPARE(anchorPosition, 23);
2105
2106 // Send temporary text, which makes the editor has composition 'w'.
2107 {
2108 QList<QInputMethodEvent::Attribute> attributes;
2109 QInputMethodEvent event("w", attributes);
2110 page->event(&event);
2111 }
2112
2113 // ImCurrentSelection
2114 variant = page->inputMethodQuery(Qt::ImCurrentSelection);
2115 selectionValue = variant.value<QString>();
2116 QCOMPARE(selectionValue, QString(""));
2117
2118 // ImSurroundingText
2119 variant = page->inputMethodQuery(Qt::ImSurroundingText);
2120 surroundingValue = variant.value<QString>();
2121 QCOMPARE(surroundingValue, QString("oeQtWebKit "));
2122
2123 // ImCursorPosition
2124 variant = page->inputMethodQuery(Qt::ImCursorPosition);
2125 cursorPosition = variant.toInt();
2126 QCOMPARE(cursorPosition, 11);
2127
2128 // ImAnchorPosition
2129 variant = page->inputMethodQuery(Qt::ImAnchorPosition);
2130 anchorPosition = variant.toInt();
2131 QCOMPARE(anchorPosition, 11);
2132
2133 // Send commit text, which makes the editor conforms composition.
2134 {
2135 QList<QInputMethodEvent::Attribute> attributes;
2136 QInputMethodEvent event("", attributes);
2137 event.setCommitString("2");
2138 page->event(&event);
2139 }
2140
2141 // ImCurrentSelection
2142 variant = page->inputMethodQuery(Qt::ImCurrentSelection);
2143 selectionValue = variant.value<QString>();
2144 QCOMPARE(selectionValue, QString(""));
2145
2146 // ImSurroundingText
2147 variant = page->inputMethodQuery(Qt::ImSurroundingText);
2148 surroundingValue = variant.value<QString>();
2149 QCOMPARE(surroundingValue, QString("oeQtWebKit 2"));
2150
2151 // ImCursorPosition
2152 variant = page->inputMethodQuery(Qt::ImCursorPosition);
2153 cursorPosition = variant.toInt();
2154 QCOMPARE(cursorPosition, 12);
2155
2156 // ImAnchorPosition
2157 variant = page->inputMethodQuery(Qt::ImAnchorPosition);
2158 anchorPosition = variant.toInt();
2159 QCOMPARE(anchorPosition, 12);
2160
2161 // Check sending RequestSoftwareInputPanel event
2162 page->mainFrame()->setHtml("<html><body>" \
2163 "<input type='text' id='input5' value='QtWebKit inputMethod'/>" \
2164 "<div id='btnDiv' onclick='i=document.getElementById("input5"); i.focus();'>abc</div>"\
2165 "</body></html>");
2166 QWebElement inputElement = page->mainFrame()->findFirstElement("div");
2167 clickOnPage(page, inputElement.geometry().center());
2168
2169 QVERIFY(!viewEventSpy.contains(QEvent::RequestSoftwareInputPanel));
2170
2171 // START - Newline test for textarea
2172 qApp->processEvents();
2173 page->mainFrame()->setHtml("<html><body>" \
2174 "<textarea rows='5' cols='1' id='input5' value=''/>" \
2175 "</body></html>");
2176 page->mainFrame()->evaluateJavaScript("var inputEle = document.getElementById('input5'); inputEle.focus(); inputEle.select();");
2177
2178 // Enter Key without key text
2179 QKeyEvent keyEnter(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier);
2180 page->event(&keyEnter);
2181 QList<QInputMethodEvent::Attribute> attribs;
2182
2183 QInputMethodEvent eventText(QString(), attribs);
2184 eventText.setCommitString("\n");
2185 page->event(&eventText);
2186
2187 QInputMethodEvent eventText2(QString(), attribs);
2188 eventText2.setCommitString("third line");
2189 page->event(&eventText2);
2190 qApp->processEvents();
2191
2192 QString inputValue2 = page->mainFrame()->evaluateJavaScript("document.getElementById('input5').value").toString();
2193 QCOMPARE(inputValue2, QString("\n\nthird line"));
2194
2195 // Enter Key with key text '\r'
2196 page->mainFrame()->evaluateJavaScript("var inputEle = document.getElementById('input5'); inputEle.value = ''; inputEle.focus(); inputEle.select();");
2197 inputValue2 = page->mainFrame()->evaluateJavaScript("document.getElementById('input5').value").toString();
2198 QCOMPARE(inputValue2, QString(""));
2199
2200 QKeyEvent keyEnterWithCarriageReturn(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier, "\r");
2201 page->event(&keyEnterWithCarriageReturn);
2202 page->event(&eventText);
2203 page->event(&eventText2);
2204 qApp->processEvents();
2205
2206 inputValue2 = page->mainFrame()->evaluateJavaScript("document.getElementById('input5').value").toString();
2207 QCOMPARE(inputValue2, QString("\n\nthird line"));
2208
2209 // Enter Key with key text '\n'
2210 page->mainFrame()->evaluateJavaScript("var inputEle = document.getElementById('input5'); inputEle.value = ''; inputEle.focus(); inputEle.select();");
2211 inputValue2 = page->mainFrame()->evaluateJavaScript("document.getElementById('input5').value").toString();
2212 QCOMPARE(inputValue2, QString(""));
2213
2214 QKeyEvent keyEnterWithLineFeed(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier, "\n");
2215 page->event(&keyEnterWithLineFeed);
2216 page->event(&eventText);
2217 page->event(&eventText2);
2218 qApp->processEvents();
2219
2220 inputValue2 = page->mainFrame()->evaluateJavaScript("document.getElementById('input5').value").toString();
2221 QCOMPARE(inputValue2, QString("\n\nthird line"));
2222
2223 // Enter Key with key text "\n\r"
2224 page->mainFrame()->evaluateJavaScript("var inputEle = document.getElementById('input5'); inputEle.value = ''; inputEle.focus(); inputEle.select();");
2225 inputValue2 = page->mainFrame()->evaluateJavaScript("document.getElementById('input5').value").toString();
2226 QCOMPARE(inputValue2, QString(""));
2227
2228 QKeyEvent keyEnterWithLFCR(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier, "\n\r");
2229 page->event(&keyEnterWithLFCR);
2230 page->event(&eventText);
2231 page->event(&eventText2);
2232 qApp->processEvents();
2233
2234 inputValue2 = page->mainFrame()->evaluateJavaScript("document.getElementById('input5').value").toString();
2235 QCOMPARE(inputValue2, QString("\n\nthird line"));
2236
2237 // END - Newline test for textarea
2238
2239 delete container;
2240 }
2241
inputMethodsTextFormat_data()2242 void tst_QWebPage::inputMethodsTextFormat_data()
2243 {
2244 QTest::addColumn<QString>("string");
2245 QTest::addColumn<int>("start");
2246 QTest::addColumn<int>("length");
2247
2248 QTest::newRow("") << QString("") << 0 << 0;
2249 QTest::newRow("Q") << QString("Q") << 0 << 1;
2250 QTest::newRow("Qt") << QString("Qt") << 0 << 1;
2251 QTest::newRow("Qt") << QString("Qt") << 0 << 2;
2252 QTest::newRow("Qt") << QString("Qt") << 1 << 1;
2253 QTest::newRow("Qt ") << QString("Qt ") << 0 << 1;
2254 QTest::newRow("Qt ") << QString("Qt ") << 1 << 1;
2255 QTest::newRow("Qt ") << QString("Qt ") << 2 << 1;
2256 QTest::newRow("Qt ") << QString("Qt ") << 2 << -1;
2257 QTest::newRow("Qt ") << QString("Qt ") << -2 << 3;
2258 QTest::newRow("Qt ") << QString("Qt ") << 0 << 3;
2259 QTest::newRow("Qt by") << QString("Qt by") << 0 << 1;
2260 QTest::newRow("Qt by Nokia") << QString("Qt by Nokia") << 0 << 1;
2261 }
2262
2263
inputMethodsTextFormat()2264 void tst_QWebPage::inputMethodsTextFormat()
2265 {
2266 QWebPage* page = new QWebPage;
2267 QWebView* view = new QWebView;
2268 view->setPage(page);
2269 page->settings()->setFontFamily(QWebSettings::SerifFont, "FooSerifFont");
2270 page->mainFrame()->setHtml("<html><body>" \
2271 "<input type='text' id='input1' style='font-family: serif' value='' maxlength='20'/>");
2272 page->mainFrame()->evaluateJavaScript("document.getElementById('input1').focus()");
2273 page->mainFrame()->setFocus();
2274 view->show();
2275
2276 QFETCH(QString, string);
2277 QFETCH(int, start);
2278 QFETCH(int, length);
2279
2280 QList<QInputMethodEvent::Attribute> attrs;
2281 QTextCharFormat format;
2282 format.setUnderlineStyle(QTextCharFormat::SingleUnderline);
2283 format.setUnderlineColor(Qt::red);
2284 attrs.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, start, length, format));
2285 QInputMethodEvent im(string, attrs);
2286 page->event(&im);
2287
2288 QTest::qWait(1000);
2289
2290 delete view;
2291 }
2292
protectBindingsRuntimeObjectsFromCollector()2293 void tst_QWebPage::protectBindingsRuntimeObjectsFromCollector()
2294 {
2295 QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool)));
2296
2297 PluginPage* newPage = new PluginPage(m_view);
2298 m_view->setPage(newPage);
2299
2300 m_view->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
2301
2302 m_view->setHtml(QString("<html><body><object type='application/x-qt-plugin' classid='lineedit' id='mylineedit'/></body></html>"));
2303 QTRY_COMPARE(loadSpy.count(), 1);
2304
2305 newPage->mainFrame()->evaluateJavaScript("function testme(text) { var lineedit = document.getElementById('mylineedit'); lineedit.setText(text); lineedit.selectAll(); }");
2306
2307 newPage->mainFrame()->evaluateJavaScript("testme('foo')");
2308
2309 DumpRenderTreeSupportQt::garbageCollectorCollect();
2310
2311 // don't crash!
2312 newPage->mainFrame()->evaluateJavaScript("testme('bar')");
2313 }
2314
localURLSchemes()2315 void tst_QWebPage::localURLSchemes()
2316 {
2317 int i = QWebSecurityOrigin::localSchemes().size();
2318
2319 QWebSecurityOrigin::removeLocalScheme("file");
2320 QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i);
2321 QWebSecurityOrigin::addLocalScheme("file");
2322 QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i);
2323
2324 QWebSecurityOrigin::removeLocalScheme("qrc");
2325 QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i - 1);
2326 QWebSecurityOrigin::addLocalScheme("qrc");
2327 QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i);
2328
2329 QString myscheme = "myscheme";
2330 QWebSecurityOrigin::addLocalScheme(myscheme);
2331 QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i + 1);
2332 QVERIFY(QWebSecurityOrigin::localSchemes().contains(myscheme));
2333 QWebSecurityOrigin::removeLocalScheme(myscheme);
2334 QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i);
2335 QWebSecurityOrigin::removeLocalScheme(myscheme);
2336 QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i);
2337 }
2338
testFlag(QWebPage & webPage,QWebSettings::WebAttribute settingAttribute,const QString & jsObjectName,bool settingValue)2339 static inline bool testFlag(QWebPage& webPage, QWebSettings::WebAttribute settingAttribute, const QString& jsObjectName, bool settingValue)
2340 {
2341 webPage.settings()->setAttribute(settingAttribute, settingValue);
2342 return webPage.mainFrame()->evaluateJavaScript(QString("(window.%1 != undefined)").arg(jsObjectName)).toBool();
2343 }
2344
testOptionalJSObjects()2345 void tst_QWebPage::testOptionalJSObjects()
2346 {
2347 // Once a feature is enabled and the JS object is accessed turning off the setting will not turn off
2348 // the visibility of the JS object any more. For this reason this test uses two QWebPage instances.
2349 // Part of the test is to make sure that the QWebPage instances do not interfere with each other so turning on
2350 // a feature for one instance will not turn it on for another.
2351
2352 QWebPage webPage1;
2353 QWebPage webPage2;
2354
2355 webPage1.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("http://www.example.com/"));
2356 webPage2.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("http://www.example.com/"));
2357
2358 QEXPECT_FAIL("","Feature enabled/disabled checking problem. Look at bugs.webkit.org/show_bug.cgi?id=29867", Continue);
2359 QCOMPARE(testFlag(webPage1, QWebSettings::OfflineWebApplicationCacheEnabled, "applicationCache", false), false);
2360 QCOMPARE(testFlag(webPage2, QWebSettings::OfflineWebApplicationCacheEnabled, "applicationCache", true), true);
2361 QEXPECT_FAIL("","Feature enabled/disabled checking problem. Look at bugs.webkit.org/show_bug.cgi?id=29867", Continue);
2362 QCOMPARE(testFlag(webPage1, QWebSettings::OfflineWebApplicationCacheEnabled, "applicationCache", false), false);
2363 QCOMPARE(testFlag(webPage2, QWebSettings::OfflineWebApplicationCacheEnabled, "applicationCache", false), true);
2364
2365 QCOMPARE(testFlag(webPage1, QWebSettings::LocalStorageEnabled, "localStorage", false), false);
2366 QCOMPARE(testFlag(webPage2, QWebSettings::LocalStorageEnabled, "localStorage", true), true);
2367 QCOMPARE(testFlag(webPage1, QWebSettings::LocalStorageEnabled, "localStorage", false), false);
2368 QCOMPARE(testFlag(webPage2, QWebSettings::LocalStorageEnabled, "localStorage", false), true);
2369 }
2370
checkLocalStorageVisibility(QWebPage & webPage,bool localStorageEnabled)2371 static inline bool checkLocalStorageVisibility(QWebPage& webPage, bool localStorageEnabled)
2372 {
2373 webPage.settings()->setAttribute(QWebSettings::LocalStorageEnabled, localStorageEnabled);
2374 return webPage.mainFrame()->evaluateJavaScript(QString("(window.localStorage != undefined)")).toBool();
2375 }
2376
testLocalStorageVisibility()2377 void tst_QWebPage::testLocalStorageVisibility()
2378 {
2379 // Local storage's visibility depends on its security origin, which depends on base url.
2380 // Initially, it will test it with base urls that get a globally unique origin, which may not
2381 // be able to use local storage even if the feature is enabled. Then later the same test is
2382 // done but with urls that would get a valid origin, so local storage could be used.
2383 // Before every test case it checks if local storage is not already visible.
2384
2385 QWebPage webPage;
2386
2387 webPage.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl());
2388
2389 QCOMPARE(checkLocalStorageVisibility(webPage, false), false);
2390 QCOMPARE(checkLocalStorageVisibility(webPage, true), false);
2391
2392 webPage.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("invalid"));
2393
2394 QCOMPARE(checkLocalStorageVisibility(webPage, false), false);
2395 QCOMPARE(checkLocalStorageVisibility(webPage, true), false);
2396
2397 webPage.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("://misparsed.com"));
2398
2399 QCOMPARE(checkLocalStorageVisibility(webPage, false), false);
2400 QCOMPARE(checkLocalStorageVisibility(webPage, true), false);
2401
2402 webPage.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("http://"));
2403
2404 QCOMPARE(checkLocalStorageVisibility(webPage, false), false);
2405 QCOMPARE(checkLocalStorageVisibility(webPage, true), false);
2406
2407 webPage.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("about:blank"));
2408
2409 QCOMPARE(checkLocalStorageVisibility(webPage, false), false);
2410 QCOMPARE(checkLocalStorageVisibility(webPage, true), false);
2411
2412 webPage.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("data:text/html,test"));
2413
2414 QCOMPARE(checkLocalStorageVisibility(webPage, false), false);
2415 QCOMPARE(checkLocalStorageVisibility(webPage, true), false);
2416
2417 webPage.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("file:///"));
2418
2419 QCOMPARE(checkLocalStorageVisibility(webPage, false), false);
2420 QCOMPARE(checkLocalStorageVisibility(webPage, true), false);
2421
2422 webPage.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("http://www.example.com"));
2423
2424 QCOMPARE(checkLocalStorageVisibility(webPage, false), false);
2425 QCOMPARE(checkLocalStorageVisibility(webPage, true), true);
2426
2427 webPage.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("https://www.example.com"));
2428
2429 QCOMPARE(checkLocalStorageVisibility(webPage, false), false);
2430 QCOMPARE(checkLocalStorageVisibility(webPage, true), true);
2431
2432 webPage.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("ftp://files.example.com"));
2433
2434 QCOMPARE(checkLocalStorageVisibility(webPage, false), false);
2435 QCOMPARE(checkLocalStorageVisibility(webPage, true), true);
2436
2437 webPage.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("file:///path/to/index.html"));
2438
2439 QCOMPARE(checkLocalStorageVisibility(webPage, false), false);
2440 QCOMPARE(checkLocalStorageVisibility(webPage, true), true);
2441 }
2442
testEnablePersistentStorage()2443 void tst_QWebPage::testEnablePersistentStorage()
2444 {
2445 QWebPage webPage;
2446
2447 // By default all persistent options should be disabled
2448 QCOMPARE(webPage.settings()->testAttribute(QWebSettings::LocalStorageEnabled), false);
2449 QCOMPARE(webPage.settings()->testAttribute(QWebSettings::OfflineStorageDatabaseEnabled), false);
2450 QCOMPARE(webPage.settings()->testAttribute(QWebSettings::OfflineWebApplicationCacheEnabled), false);
2451 QVERIFY(webPage.settings()->iconDatabasePath().isEmpty());
2452
2453 QWebSettings::enablePersistentStorage();
2454
2455
2456 QTRY_COMPARE(webPage.settings()->testAttribute(QWebSettings::LocalStorageEnabled), true);
2457 QTRY_COMPARE(webPage.settings()->testAttribute(QWebSettings::OfflineStorageDatabaseEnabled), true);
2458 QTRY_COMPARE(webPage.settings()->testAttribute(QWebSettings::OfflineWebApplicationCacheEnabled), true);
2459
2460 QTRY_VERIFY(!webPage.settings()->offlineStoragePath().isEmpty());
2461 QTRY_VERIFY(!webPage.settings()->offlineWebApplicationCachePath().isEmpty());
2462 QTRY_VERIFY(!webPage.settings()->iconDatabasePath().isEmpty());
2463 }
2464
defaultTextEncoding()2465 void tst_QWebPage::defaultTextEncoding()
2466 {
2467 QWebFrame* mainFrame = m_page->mainFrame();
2468
2469 QString defaultCharset = mainFrame->evaluateJavaScript("document.defaultCharset").toString();
2470 QVERIFY(!defaultCharset.isEmpty());
2471 QCOMPARE(QWebSettings::globalSettings()->defaultTextEncoding(), defaultCharset);
2472
2473 m_page->settings()->setDefaultTextEncoding(QString("utf-8"));
2474 QString charset = mainFrame->evaluateJavaScript("document.defaultCharset").toString();
2475 QCOMPARE(charset, QString("utf-8"));
2476 QCOMPARE(m_page->settings()->defaultTextEncoding(), charset);
2477
2478 m_page->settings()->setDefaultTextEncoding(QString());
2479 charset = mainFrame->evaluateJavaScript("document.defaultCharset").toString();
2480 QVERIFY(!charset.isEmpty());
2481 QCOMPARE(charset, defaultCharset);
2482
2483 QWebSettings::globalSettings()->setDefaultTextEncoding(QString("utf-8"));
2484 charset = mainFrame->evaluateJavaScript("document.defaultCharset").toString();
2485 QCOMPARE(charset, QString("utf-8"));
2486 QCOMPARE(QWebSettings::globalSettings()->defaultTextEncoding(), charset);
2487 }
2488
2489 class ErrorPage : public QWebPage
2490 {
2491 public:
2492
ErrorPage(QWidget * parent=0)2493 ErrorPage(QWidget* parent = 0): QWebPage(parent)
2494 {
2495 }
2496
supportsExtension(Extension extension) const2497 virtual bool supportsExtension(Extension extension) const
2498 {
2499 return extension == ErrorPageExtension;
2500 }
2501
extension(Extension,const ExtensionOption * option,ExtensionReturn * output)2502 virtual bool extension(Extension, const ExtensionOption* option, ExtensionReturn* output)
2503 {
2504 ErrorPageExtensionReturn* errorPage = static_cast<ErrorPageExtensionReturn*>(output);
2505
2506 errorPage->contentType = "text/html";
2507 errorPage->content = "error";
2508 return true;
2509 }
2510 };
2511
errorPageExtension()2512 void tst_QWebPage::errorPageExtension()
2513 {
2514 ErrorPage* page = new ErrorPage;
2515 m_view->setPage(page);
2516
2517 QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool)));
2518
2519 m_view->setUrl(QUrl("data:text/html,foo"));
2520 QTRY_COMPARE(spyLoadFinished.count(), 1);
2521
2522 page->mainFrame()->setUrl(QUrl("http://non.existent/url"));
2523 QTRY_COMPARE(spyLoadFinished.count(), 2);
2524 QCOMPARE(page->mainFrame()->toPlainText(), QString("error"));
2525 QCOMPARE(page->history()->count(), 2);
2526 QCOMPARE(page->history()->currentItem().url(), QUrl("http://non.existent/url"));
2527 QCOMPARE(page->history()->canGoBack(), true);
2528 QCOMPARE(page->history()->canGoForward(), false);
2529
2530 page->triggerAction(QWebPage::Back);
2531 QTRY_COMPARE(page->history()->canGoBack(), false);
2532 QTRY_COMPARE(page->history()->canGoForward(), true);
2533
2534 page->triggerAction(QWebPage::Forward);
2535 QTRY_COMPARE(page->history()->canGoBack(), true);
2536 QTRY_COMPARE(page->history()->canGoForward(), false);
2537
2538 page->triggerAction(QWebPage::Back);
2539 QTRY_COMPARE(page->history()->canGoBack(), false);
2540 QTRY_COMPARE(page->history()->canGoForward(), true);
2541 QTRY_COMPARE(page->history()->currentItem().url(), QUrl("data:text/html,foo"));
2542
2543 m_view->setPage(0);
2544 }
2545
errorPageExtensionInIFrames()2546 void tst_QWebPage::errorPageExtensionInIFrames()
2547 {
2548 ErrorPage* page = new ErrorPage;
2549 m_view->setPage(page);
2550
2551 m_view->page()->mainFrame()->load(QUrl(
2552 "data:text/html,"
2553 "<h1>h1</h1>"
2554 "<iframe src='data:text/html,<p/>p'></iframe>"
2555 "<iframe src='http://non.existent/url'></iframe>"));
2556 QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool)));
2557 QTRY_COMPARE(spyLoadFinished.count(), 1);
2558
2559 QCOMPARE(page->mainFrame()->childFrames()[1]->toPlainText(), QString("error"));
2560
2561 m_view->setPage(0);
2562 }
2563
errorPageExtensionInFrameset()2564 void tst_QWebPage::errorPageExtensionInFrameset()
2565 {
2566 ErrorPage* page = new ErrorPage;
2567 m_view->setPage(page);
2568
2569 m_view->load(QUrl("qrc:///resources/index.html"));
2570
2571 QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool)));
2572 QTRY_COMPARE(spyLoadFinished.count(), 1);
2573 QCOMPARE(page->mainFrame()->childFrames().count(), 2);
2574 QCOMPARE(page->mainFrame()->childFrames()[1]->toPlainText(), QString("error"));
2575
2576 m_view->setPage(0);
2577 }
2578
errorPageExtensionLoadFinished()2579 void tst_QWebPage::errorPageExtensionLoadFinished()
2580 {
2581 ErrorPage page;
2582 m_view->setPage(&page);
2583
2584 QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool)));
2585 QSignalSpy spyFrameLoadFinished(m_view->page()->mainFrame(), SIGNAL(loadFinished(bool)));
2586
2587 m_view->setUrl(QUrl("data:text/html,foo"));
2588 QTRY_COMPARE(spyLoadFinished.count(), 1);
2589 QTRY_COMPARE(spyFrameLoadFinished.count(), 1);
2590
2591 const bool loadSucceded = spyLoadFinished.at(0).at(0).toBool();
2592 QVERIFY(loadSucceded);
2593 const bool frameLoadSucceded = spyFrameLoadFinished.at(0).at(0).toBool();
2594 QVERIFY(frameLoadSucceded);
2595
2596 m_view->page()->mainFrame()->setUrl(QUrl("http://non.existent/url"));
2597 QTRY_COMPARE(spyLoadFinished.count(), 2);
2598 QTRY_COMPARE(spyFrameLoadFinished.count(), 2);
2599
2600 const bool nonExistantLoadSucceded = spyLoadFinished.at(1).at(0).toBool();
2601 QVERIFY(nonExistantLoadSucceded);
2602 const bool nonExistantFrameLoadSucceded = spyFrameLoadFinished.at(1).at(0).toBool();
2603 QVERIFY(nonExistantFrameLoadSucceded);
2604
2605 m_view->setPage(0);
2606 }
2607
2608 class FriendlyWebPage : public QWebPage
2609 {
2610 public:
2611 friend class tst_QWebPage;
2612 };
2613
userAgentApplicationName()2614 void tst_QWebPage::userAgentApplicationName()
2615 {
2616 const QString oldApplicationName = QCoreApplication::applicationName();
2617 FriendlyWebPage page;
2618
2619 const QString applicationNameMarker = QString::fromUtf8("StrangeName\342\210\236");
2620 QCoreApplication::setApplicationName(applicationNameMarker);
2621 QVERIFY(page.userAgentForUrl(QUrl()).contains(applicationNameMarker));
2622
2623 QCoreApplication::setApplicationName(oldApplicationName);
2624 }
2625
crashTests_LazyInitializationOfMainFrame()2626 void tst_QWebPage::crashTests_LazyInitializationOfMainFrame()
2627 {
2628 {
2629 QWebPage webPage;
2630 }
2631 {
2632 QWebPage webPage;
2633 webPage.selectedText();
2634 }
2635 {
2636 QWebPage webPage;
2637 webPage.selectedHtml();
2638 }
2639 {
2640 QWebPage webPage;
2641 webPage.triggerAction(QWebPage::Back, true);
2642 }
2643 {
2644 QWebPage webPage;
2645 QPoint pos(10,10);
2646 webPage.updatePositionDependentActions(pos);
2647 }
2648 }
2649
takeScreenshot(QWebPage * page)2650 static void takeScreenshot(QWebPage* page)
2651 {
2652 QWebFrame* mainFrame = page->mainFrame();
2653 page->setViewportSize(mainFrame->contentsSize());
2654 QImage image(page->viewportSize(), QImage::Format_ARGB32);
2655 QPainter painter(&image);
2656 mainFrame->render(&painter);
2657 painter.end();
2658 }
2659
screenshot_data()2660 void tst_QWebPage::screenshot_data()
2661 {
2662 QTest::addColumn<QString>("html");
2663 QTest::newRow("WithoutPlugin") << "<html><body id='b'>text</body></html>";
2664 QTest::newRow("WindowedPlugin") << QString("<html><body id='b'>text<embed src='resources/test.swf'></embed></body></html>");
2665 QTest::newRow("WindowlessPlugin") << QString("<html><body id='b'>text<embed src='resources/test.swf' wmode='transparent'></embed></body></html>");
2666 }
2667
screenshot()2668 void tst_QWebPage::screenshot()
2669 {
2670 if (!QDir(TESTS_SOURCE_DIR).exists())
2671 QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll);
2672
2673 QDir::setCurrent(TESTS_SOURCE_DIR);
2674
2675 QFETCH(QString, html);
2676 QWebPage* page = new QWebPage;
2677 page->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
2678 QWebFrame* mainFrame = page->mainFrame();
2679 mainFrame->setHtml(html, QUrl::fromLocalFile(TESTS_SOURCE_DIR));
2680 ::waitForSignal(mainFrame, SIGNAL(loadFinished(bool)), 2000);
2681
2682 // take screenshot without a view
2683 takeScreenshot(page);
2684
2685 QWebView* view = new QWebView;
2686 view->setPage(page);
2687
2688 // take screenshot when attached to a view
2689 takeScreenshot(page);
2690
2691 delete page;
2692 delete view;
2693
2694 QDir::setCurrent(QApplication::applicationDirPath());
2695 }
2696
2697 #if defined(ENABLE_WEBGL) && ENABLE_WEBGL
2698 // https://bugs.webkit.org/show_bug.cgi?id=54138
webGLScreenshotWithoutView(bool accelerated)2699 static void webGLScreenshotWithoutView(bool accelerated)
2700 {
2701 QWebPage page;
2702 page.settings()->setAttribute(QWebSettings::WebGLEnabled, true);
2703 page.settings()->setAttribute(QWebSettings::AcceleratedCompositingEnabled, accelerated);
2704 QWebFrame* mainFrame = page.mainFrame();
2705 mainFrame->setHtml("<html><body>"
2706 "<canvas id='webgl' width='300' height='300'></canvas>"
2707 "<script>document.getElementById('webgl').getContext('experimental-webgl')</script>"
2708 "</body></html>");
2709
2710 takeScreenshot(&page);
2711 }
2712
acceleratedWebGLScreenshotWithoutView()2713 void tst_QWebPage::acceleratedWebGLScreenshotWithoutView()
2714 {
2715 webGLScreenshotWithoutView(true);
2716 }
2717
unacceleratedWebGLScreenshotWithoutView()2718 void tst_QWebPage::unacceleratedWebGLScreenshotWithoutView()
2719 {
2720 webGLScreenshotWithoutView(false);
2721 }
2722 #endif
2723
originatingObjectInNetworkRequests()2724 void tst_QWebPage::originatingObjectInNetworkRequests()
2725 {
2726 TestNetworkManager* networkManager = new TestNetworkManager(m_page);
2727 m_page->setNetworkAccessManager(networkManager);
2728 networkManager->requests.clear();
2729
2730 m_view->setHtml(QString("<frameset cols=\"25%,75%\"><frame src=\"data:text/html,"
2731 "<head><meta http-equiv='refresh' content='1'></head>foo \">"
2732 "<frame src=\"data:text/html,bar\"></frameset>"), QUrl());
2733 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
2734
2735 QCOMPARE(networkManager->requests.count(), 2);
2736
2737 QList<QWebFrame*> childFrames = m_page->mainFrame()->childFrames();
2738 QCOMPARE(childFrames.count(), 2);
2739
2740 for (int i = 0; i < 2; ++i)
2741 QVERIFY(qobject_cast<QWebFrame*>(networkManager->requests.at(i).originatingObject()) == childFrames.at(i));
2742 }
2743
2744 /**
2745 * Test fixups for https://bugs.webkit.org/show_bug.cgi?id=30914
2746 *
2747 * From JS we test the following conditions.
2748 *
2749 * OK + QString() => SUCCESS, empty string (but not null)
2750 * OK + "text" => SUCCESS, "text"
2751 * CANCEL + QString() => CANCEL, null string
2752 * CANCEL + "text" => CANCEL, null string
2753 */
2754 class JSPromptPage : public QWebPage {
2755 Q_OBJECT
2756 public:
JSPromptPage()2757 JSPromptPage()
2758 {}
2759
javaScriptPrompt(QWebFrame * frame,const QString & msg,const QString & defaultValue,QString * result)2760 bool javaScriptPrompt(QWebFrame* frame, const QString& msg, const QString& defaultValue, QString* result)
2761 {
2762 if (msg == QLatin1String("test1")) {
2763 *result = QString();
2764 return true;
2765 } else if (msg == QLatin1String("test2")) {
2766 *result = QLatin1String("text");
2767 return true;
2768 } else if (msg == QLatin1String("test3")) {
2769 *result = QString();
2770 return false;
2771 } else if (msg == QLatin1String("test4")) {
2772 *result = QLatin1String("text");
2773 return false;
2774 }
2775
2776 qFatal("Unknown msg.");
2777 return QWebPage::javaScriptPrompt(frame, msg, defaultValue, result);
2778 }
2779 };
2780
testJSPrompt()2781 void tst_QWebPage::testJSPrompt()
2782 {
2783 JSPromptPage page;
2784 bool res;
2785
2786 // OK + QString()
2787 res = page.mainFrame()->evaluateJavaScript(
2788 "var retval = prompt('test1');"
2789 "retval=='' && retval.length == 0;").toBool();
2790 QVERIFY(res);
2791
2792 // OK + "text"
2793 res = page.mainFrame()->evaluateJavaScript(
2794 "var retval = prompt('test2');"
2795 "retval=='text' && retval.length == 4;").toBool();
2796 QVERIFY(res);
2797
2798 // Cancel + QString()
2799 res = page.mainFrame()->evaluateJavaScript(
2800 "var retval = prompt('test3');"
2801 "retval===null;").toBool();
2802 QVERIFY(res);
2803
2804 // Cancel + "text"
2805 res = page.mainFrame()->evaluateJavaScript(
2806 "var retval = prompt('test4');"
2807 "retval===null;").toBool();
2808 QVERIFY(res);
2809 }
2810
2811 class TestModalPage : public QWebPage
2812 {
2813 Q_OBJECT
2814 public:
TestModalPage(QObject * parent=0)2815 TestModalPage(QObject* parent = 0) : QWebPage(parent) {
2816 }
createWindow(WebWindowType)2817 virtual QWebPage* createWindow(WebWindowType) {
2818 QWebPage* page = new TestModalPage();
2819 connect(page, SIGNAL(windowCloseRequested()), page, SLOT(deleteLater()));
2820 return page;
2821 }
2822 };
2823
showModalDialog()2824 void tst_QWebPage::showModalDialog()
2825 {
2826 TestModalPage page;
2827 page.mainFrame()->setHtml(QString("<html></html>"));
2828 QString res = page.mainFrame()->evaluateJavaScript("window.showModalDialog('javascript:window.returnValue=dialogArguments; window.close();', 'This is a test');").toString();
2829 QEXPECT_FAIL("", "https://bugs.webkit.org/show_bug.cgi?id=63244", Continue);
2830 QCOMPARE(res, QString("This is a test"));
2831 }
2832
testStopScheduledPageRefresh()2833 void tst_QWebPage::testStopScheduledPageRefresh()
2834 {
2835 // Without QWebPage::StopScheduledPageRefresh
2836 QWebPage page1;
2837 page1.setNetworkAccessManager(new TestNetworkManager(&page1));
2838 page1.mainFrame()->setHtml("<html><head>"
2839 "<meta http-equiv=\"refresh\"content=\"0;URL=qrc:///resources/index.html\">"
2840 "</head><body><h1>Page redirects immediately...</h1>"
2841 "</body></html>");
2842 QEXPECT_FAIL("", "https://bugs.webkit.org/show_bug.cgi?id=63245", Continue);
2843 QVERIFY(::waitForSignal(&page1, SIGNAL(loadFinished(bool))));
2844 QTest::qWait(500);
2845 QEXPECT_FAIL("", "https://bugs.webkit.org/show_bug.cgi?id=63245", Continue);
2846 QCOMPARE(page1.mainFrame()->url(), QUrl(QLatin1String("qrc:///resources/index.html")));
2847
2848 // With QWebPage::StopScheduledPageRefresh
2849 QWebPage page2;
2850 page2.setNetworkAccessManager(new TestNetworkManager(&page2));
2851 page2.mainFrame()->setHtml("<html><head>"
2852 "<meta http-equiv=\"refresh\"content=\"1;URL=qrc:///resources/index.html\">"
2853 "</head><body><h1>Page redirect test with 1 sec timeout...</h1>"
2854 "</body></html>");
2855 page2.triggerAction(QWebPage::StopScheduledPageRefresh);
2856 QTest::qWait(1500);
2857 QCOMPARE(page2.mainFrame()->url().toString(), QLatin1String("about:blank"));
2858 }
2859
findText()2860 void tst_QWebPage::findText()
2861 {
2862 m_view->setHtml(QString("<html><head></head><body><div>foo bar</div></body></html>"));
2863 m_page->triggerAction(QWebPage::SelectAll);
2864 QVERIFY(!m_page->selectedText().isEmpty());
2865 QVERIFY(!m_page->selectedHtml().isEmpty());
2866 m_page->findText("");
2867 QVERIFY(m_page->selectedText().isEmpty());
2868 QVERIFY(m_page->selectedHtml().isEmpty());
2869 QStringList words = (QStringList() << "foo" << "bar");
2870 QRegExp regExp(" style=\".*\"");
2871 regExp.setMinimal(true);
2872 foreach (QString subString, words) {
2873 m_page->findText(subString, QWebPage::FindWrapsAroundDocument);
2874 QCOMPARE(m_page->selectedText(), subString);
2875 QCOMPARE(m_page->selectedHtml().trimmed().replace(regExp, ""), QString("<span class=\"Apple-style-span\">%1</span>").arg(subString));
2876 m_page->findText("");
2877 QVERIFY(m_page->selectedText().isEmpty());
2878 QVERIFY(m_page->selectedHtml().isEmpty());
2879 }
2880 }
2881
2882 struct ImageExtensionMap {
2883 const char* extension;
2884 const char* mimeType;
2885 };
2886
2887 static const ImageExtensionMap extensionMap[] = {
2888 { "bmp", "image/bmp" },
2889 { "css", "text/css" },
2890 { "gif", "image/gif" },
2891 { "html", "text/html" },
2892 { "htm", "text/html" },
2893 { "ico", "image/x-icon" },
2894 { "jpeg", "image/jpeg" },
2895 { "jpg", "image/jpeg" },
2896 { "js", "application/x-javascript" },
2897 { "mng", "video/x-mng" },
2898 { "pbm", "image/x-portable-bitmap" },
2899 { "pgm", "image/x-portable-graymap" },
2900 { "pdf", "application/pdf" },
2901 { "png", "image/png" },
2902 { "ppm", "image/x-portable-pixmap" },
2903 { "rss", "application/rss+xml" },
2904 { "svg", "image/svg+xml" },
2905 { "text", "text/plain" },
2906 { "tif", "image/tiff" },
2907 { "tiff", "image/tiff" },
2908 { "txt", "text/plain" },
2909 { "xbm", "image/x-xbitmap" },
2910 { "xml", "text/xml" },
2911 { "xpm", "image/x-xpm" },
2912 { "xsl", "text/xsl" },
2913 { "xhtml", "application/xhtml+xml" },
2914 { "wml", "text/vnd.wap.wml" },
2915 { "wmlc", "application/vnd.wap.wmlc" },
2916 { 0, 0 }
2917 };
2918
getMimeTypeForExtension(const QString & ext)2919 static QString getMimeTypeForExtension(const QString &ext)
2920 {
2921 const ImageExtensionMap *e = extensionMap;
2922 while (e->extension) {
2923 if (ext.compare(QLatin1String(e->extension), Qt::CaseInsensitive) == 0)
2924 return QLatin1String(e->mimeType);
2925 ++e;
2926 }
2927
2928 return QString();
2929 }
2930
supportedContentType()2931 void tst_QWebPage::supportedContentType()
2932 {
2933 QStringList contentTypes;
2934
2935 // Add supported non image types...
2936 contentTypes << "text/html" << "text/xml" << "text/xsl" << "text/plain" << "text/"
2937 << "application/xml" << "application/xhtml+xml" << "application/vnd.wap.xhtml+xml"
2938 << "application/rss+xml" << "application/atom+xml" << "application/json";
2939
2940 // Add supported image types...
2941 Q_FOREACH(const QByteArray& imageType, QImageWriter::supportedImageFormats()) {
2942 const QString mimeType = getMimeTypeForExtension(imageType);
2943 if (!mimeType.isEmpty())
2944 contentTypes << mimeType;
2945 }
2946
2947 // Get the mime types supported by webkit...
2948 const QStringList supportedContentTypes = m_page->supportedContentTypes();
2949
2950 Q_FOREACH(const QString& mimeType, contentTypes)
2951 QVERIFY2(supportedContentTypes.contains(mimeType), QString("'%1' is not a supported content type!").arg(mimeType).toLatin1());
2952
2953 Q_FOREACH(const QString& mimeType, contentTypes)
2954 QVERIFY2(m_page->supportsContentType(mimeType), QString("Cannot handle content types '%1'!").arg(mimeType).toLatin1());
2955 }
2956
2957
navigatorCookieEnabled()2958 void tst_QWebPage::navigatorCookieEnabled()
2959 {
2960 m_page->networkAccessManager()->setCookieJar(0);
2961 QVERIFY(!m_page->networkAccessManager()->cookieJar());
2962 QVERIFY(!m_page->mainFrame()->evaluateJavaScript("navigator.cookieEnabled").toBool());
2963
2964 m_page->networkAccessManager()->setCookieJar(new QNetworkCookieJar());
2965 QVERIFY(m_page->networkAccessManager()->cookieJar());
2966 QVERIFY(m_page->mainFrame()->evaluateJavaScript("navigator.cookieEnabled").toBool());
2967 }
2968
2969 #ifdef Q_OS_MAC
macCopyUnicodeToClipboard()2970 void tst_QWebPage::macCopyUnicodeToClipboard()
2971 {
2972 QString unicodeText = QString::fromUtf8("αβγδεζηθικλμπ");
2973 m_page->mainFrame()->setHtml(QString("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /></head><body>%1</body></html>").arg(unicodeText));
2974 m_page->triggerAction(QWebPage::SelectAll);
2975 m_page->triggerAction(QWebPage::Copy);
2976
2977 QString clipboardData = QString::fromUtf8(QApplication::clipboard()->mimeData()->data(QLatin1String("text/html")));
2978
2979 QVERIFY(clipboardData.contains(QLatin1String("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />")));
2980 QVERIFY(clipboardData.contains(unicodeText));
2981 }
2982 #endif
2983
contextMenuCopy()2984 void tst_QWebPage::contextMenuCopy()
2985 {
2986 QWebView view;
2987
2988 view.setHtml("<a href=\"http://www.google.com\">You cant miss this</a>");
2989
2990 view.page()->triggerAction(QWebPage::SelectAll);
2991 QVERIFY(!view.page()->selectedText().isEmpty());
2992
2993 QWebElement link = view.page()->mainFrame()->findFirstElement("a");
2994 QPoint pos(link.geometry().center());
2995 QContextMenuEvent event(QContextMenuEvent::Mouse, pos);
2996 view.page()->swallowContextMenuEvent(&event);
2997 view.page()->updatePositionDependentActions(pos);
2998
2999 QList<QMenu*> contextMenus = view.findChildren<QMenu*>();
3000 QVERIFY(!contextMenus.isEmpty());
3001 QMenu* contextMenu = contextMenus.first();
3002 QVERIFY(contextMenu);
3003
3004 QList<QAction *> list = contextMenu->actions();
3005 int index = list.indexOf(view.page()->action(QWebPage::Copy));
3006 QVERIFY(index != -1);
3007 }
3008
deleteQWebViewTwice()3009 void tst_QWebPage::deleteQWebViewTwice()
3010 {
3011 for (int i = 0; i < 2; ++i) {
3012 QMainWindow mainWindow;
3013 QWebView* webView = new QWebView(&mainWindow);
3014 mainWindow.setCentralWidget(webView);
3015 webView->load(QUrl("qrc:///resources/frame_a.html"));
3016 mainWindow.show();
3017 connect(webView, SIGNAL(loadFinished(bool)), &mainWindow, SLOT(close()));
3018 QApplication::instance()->exec();
3019 }
3020 }
3021
3022 class RepaintRequestedRenderer : public QObject {
3023 Q_OBJECT
3024 public:
RepaintRequestedRenderer(QWebPage * page,QPainter * painter)3025 RepaintRequestedRenderer(QWebPage* page, QPainter* painter)
3026 : m_page(page)
3027 , m_painter(painter)
3028 , m_recursionCount(0)
3029 {
3030 connect(m_page, SIGNAL(repaintRequested(QRect)), this, SLOT(onRepaintRequested(QRect)));
3031 }
3032
3033 signals:
3034 void finished();
3035
3036 private slots:
onRepaintRequested(const QRect & rect)3037 void onRepaintRequested(const QRect& rect)
3038 {
3039 QCOMPARE(m_recursionCount, 0);
3040
3041 m_recursionCount++;
3042 m_page->mainFrame()->render(m_painter, rect);
3043 m_recursionCount--;
3044
3045 QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
3046 }
3047
3048 private:
3049 QWebPage* m_page;
3050 QPainter* m_painter;
3051 int m_recursionCount;
3052 };
3053
renderOnRepaintRequestedShouldNotRecurse()3054 void tst_QWebPage::renderOnRepaintRequestedShouldNotRecurse()
3055 {
3056 QSize viewportSize(720, 576);
3057 QWebPage page;
3058
3059 QImage image(viewportSize, QImage::Format_ARGB32);
3060 QPainter painter(&image);
3061
3062 page.setPreferredContentsSize(viewportSize);
3063 page.setViewportSize(viewportSize);
3064 RepaintRequestedRenderer r(&page, &painter);
3065
3066 page.mainFrame()->setHtml("zalan loves trunk", QUrl());
3067
3068 QVERIFY(::waitForSignal(&r, SIGNAL(finished())));
3069 }
3070
3071 class SpyForLoadSignalsOrder : public QStateMachine {
3072 Q_OBJECT
3073 public:
SpyForLoadSignalsOrder(QWebPage * page,QObject * parent=0)3074 SpyForLoadSignalsOrder(QWebPage* page, QObject* parent = 0)
3075 : QStateMachine(parent)
3076 {
3077 connect(page, SIGNAL(loadProgress(int)), SLOT(onLoadProgress(int)));
3078
3079 QState* waitingForLoadStarted = new QState(this);
3080 QState* waitingForLastLoadProgress = new QState(this);
3081 QState* waitingForLoadFinished = new QState(this);
3082 QFinalState* final = new QFinalState(this);
3083
3084 waitingForLoadStarted->addTransition(page, SIGNAL(loadStarted()), waitingForLastLoadProgress);
3085 waitingForLastLoadProgress->addTransition(this, SIGNAL(lastLoadProgress()), waitingForLoadFinished);
3086 waitingForLoadFinished->addTransition(page, SIGNAL(loadFinished(bool)), final);
3087
3088 setInitialState(waitingForLoadStarted);
3089 start();
3090 }
isFinished() const3091 bool isFinished() const
3092 {
3093 return !isRunning();
3094 }
3095 public Q_SLOTS:
onLoadProgress(int progress)3096 void onLoadProgress(int progress)
3097 {
3098 if (progress == 100)
3099 emit lastLoadProgress();
3100 }
3101 signals:
3102 void lastLoadProgress();
3103 };
3104
loadSignalsOrder_data()3105 void tst_QWebPage::loadSignalsOrder_data()
3106 {
3107 QTest::addColumn<QUrl>("url");
3108 QTest::newRow("inline data") << QUrl("data:text/html,This is first page");
3109 QTest::newRow("simple page") << QUrl("qrc:///resources/content.html");
3110 QTest::newRow("frameset page") << QUrl("qrc:///resources/index.html");
3111 }
3112
loadSignalsOrder()3113 void tst_QWebPage::loadSignalsOrder()
3114 {
3115 QFETCH(QUrl, url);
3116 QWebPage page;
3117 SpyForLoadSignalsOrder loadSpy(&page);
3118 waitForSignal(&loadSpy, SIGNAL(started()));
3119 page.mainFrame()->load(url);
3120 QTRY_VERIFY(loadSpy.isFinished());
3121 }
3122
3123 QTEST_MAIN(tst_QWebPage)
3124 #include "tst_qwebpage.moc"
3125