• Jocelyn Turcotte's avatar
    Implement QWebEnginePage::findText · 324706a5
    Jocelyn Turcotte authored
    
    A few changes to the API:
    - Return the success result asynchronously.
    - FindWrapsAroundDocument and HighlightAllOccurrences are enabled by
      defaults and cannot be disabled.
    - Found text isn't updating the selection on the page like QtWebKit
      did, but triggers a separate state not available. A find count and
      current index could be exposed, but isn't in this case to keep the
      API delta lower.
    
    This also adds the possibility to pass bool results through the
    CallbackDirectory and add a new tst_QWebEnginePage::findTextResult
    test since the old test relied on the selection to be updated when
    the searched text is found.
    
    Change-Id: I8189b5aea8d832df183c6c1ae03e3f08198a9c45
    Reviewed-by: default avatarSimon Hausmann <simon.hausmann@digia.com>
    324706a5
tst_qwebenginepage.cpp 139.61 KiB
/*
    Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
    Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
    Copyright (C) 2010 Holger Hans Peter Freyther
    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.
    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.
    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
#include "../util.h"
#include <QClipboard>
#include <QDir>
#include <QGraphicsWidget>
#include <QLineEdit>
#include <QMainWindow>
#include <QMenu>
#include <QMimeDatabase>
#include <QPushButton>
#include <QStateMachine>
#include <QStyle>
#include <QtTest/QtTest>
#include <QTextCharFormat>
#include <private/qinputmethod_p.h>
#include <qnetworkcookiejar.h>
#include <qnetworkreply.h>
#include <qnetworkrequest.h>
#include <qpa/qplatforminputcontext.h>
#include <qwebenginehistory.h>
#include <qwebenginepage.h>
#include <qwebengineview.h>
#include <qimagewriter.h>
static void removeRecursive(const QString& dirname)
    QDir dir(dirname);
    QFileInfoList entries(dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot));
    for (int i = 0; i < entries.count(); ++i)
        if (entries[i].isDir())
            removeRecursive(entries[i].filePath());
        else
            dir.remove(entries[i].fileName());
    QDir().rmdir(dirname);
class TestInputContext : public QPlatformInputContext
public:
    TestInputContext()
    : m_visible(false)
        QInputMethodPrivate* inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod());
        inputMethodPrivate->testContext = this;
    ~TestInputContext()
        QInputMethodPrivate* inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod());
        inputMethodPrivate->testContext = 0;
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
} virtual void showInputPanel() { m_visible = true; } virtual void hideInputPanel() { m_visible = false; } virtual bool isInputPanelVisible() const { return m_visible; } bool m_visible; }; class tst_QWebEnginePage : public QObject { Q_OBJECT public: tst_QWebEnginePage(); virtual ~tst_QWebEnginePage(); public Q_SLOTS: void init(); void cleanup(); void cleanupFiles(); private Q_SLOTS: void initTestCase(); void cleanupTestCase(); void thirdPartyCookiePolicy(); void contextMenuCopy(); void contextMenuPopulatedOnce(); void acceptNavigationRequest(); void geolocationRequestJS(); void loadFinished(); void actionStates(); void popupFormSubmission(); void acceptNavigationRequestWithNewWindow(); void userStyleSheet(); void userStyleSheetFromLocalFileUrl(); void userStyleSheetFromQrcUrl(); void loadHtml5Video(); void modified(); void contextMenuCrash(); void updatePositionDependentActionsCrash(); void database(); void createPluginWithPluginsEnabled(); void createPluginWithPluginsDisabled(); void destroyPlugin_data(); void destroyPlugin(); void createViewlessPlugin_data(); void createViewlessPlugin(); void graphicsWidgetPlugin(); void multiplePageGroupsAndLocalStorage(); void cursorMovements(); void textSelection(); void textEditing(); void backActionUpdate(); void frameAt(); void requestCache(); void loadCachedPage(); void protectBindingsRuntimeObjectsFromCollector(); void localURLSchemes(); void testOptionalJSObjects(); void testLocalStorageVisibility();
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
void testEnablePersistentStorage(); void consoleOutput(); void inputMethods_data(); void inputMethods(); void inputMethodsTextFormat_data(); void inputMethodsTextFormat(); void defaultTextEncoding(); void errorPageExtension(); void errorPageExtensionInIFrames(); void errorPageExtensionInFrameset(); void errorPageExtensionLoadFinished(); void userAgentApplicationName(); void userAgentNewlineStripping(); void undoActionHaveCustomText(); void renderWidgetHostViewNotShowTopLevel(); void viewModes(); void crashTests_LazyInitializationOfMainFrame(); void screenshot_data(); void screenshot(); #if defined(ENABLE_WEBGL) && ENABLE_WEBGL void acceleratedWebGLScreenshotWithoutView(); void unacceleratedWebGLScreenshotWithoutView(); #endif void originatingObjectInNetworkRequests(); void networkReplyParentDidntChange(); void destroyQNAMBeforeAbortDoesntCrash(); void testJSPrompt(); void showModalDialog(); void testStopScheduledPageRefresh(); void findText(); void findTextResult(); void supportedContentType(); // [Qt] tst_QWebEnginePage::infiniteLoopJS() timeouts with DFG JIT // https://bugs.webkit.org/show_bug.cgi?id=79040 // void infiniteLoopJS(); void navigatorCookieEnabled(); void deleteQWebEngineViewTwice(); void renderOnRepaintRequestedShouldNotRecurse(); void loadSignalsOrder_data(); void loadSignalsOrder(); void openWindowDefaultSize(); void cssMediaTypeGlobalSetting(); void cssMediaTypePageSetting(); #ifdef Q_OS_MAC void macCopyUnicodeToClipboard(); #endif private: QWebEngineView* m_view; QWebEnginePage* m_page; QString tmpDirPath() const { static QString tmpd = QDir::tempPath() + "/tst_qwebenginepage-" + QDateTime::currentDateTime().toString(QLatin1String("yyyyMMddhhmmss")); return tmpd; } }; tst_QWebEnginePage::tst_QWebEnginePage() { } tst_QWebEnginePage::~tst_QWebEnginePage() {
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
} void tst_QWebEnginePage::init() { m_view = new QWebEngineView(); m_page = m_view->page(); } void tst_QWebEnginePage::cleanup() { delete m_view; } void tst_QWebEnginePage::cleanupFiles() { removeRecursive(tmpDirPath()); } void tst_QWebEnginePage::initTestCase() { cleanupFiles(); // In case there are old files from previous runs } void tst_QWebEnginePage::cleanupTestCase() { cleanupFiles(); // Be nice } class NavigationRequestOverride : public QWebEnginePage { public: NavigationRequestOverride(QWebEngineView* parent, bool initialValue) : QWebEnginePage(parent), m_acceptNavigationRequest(initialValue) {} bool m_acceptNavigationRequest; protected: virtual bool acceptNavigationRequest(QWebEngineFrame* frame, const QNetworkRequest &request, QWebEnginePage::NavigationType type) { Q_UNUSED(frame); Q_UNUSED(request); Q_UNUSED(type); return m_acceptNavigationRequest; } }; void tst_QWebEnginePage::acceptNavigationRequest() { #if !defined(QWEBENGINEPAGE_ACCEPTNAVIGATIONREQUEST) QSKIP("QWEBENGINEPAGE_ACCEPTNAVIGATIONREQUEST"); #else QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool))); NavigationRequestOverride* newPage = new NavigationRequestOverride(m_view, false); m_view->setPage(newPage); m_view->setHtml(QString("<html><body><form name='tstform' action='data:text/html,foo'method='get'>" "<input type='text'><input type='submit'></form></body></html>"), QUrl()); QTRY_COMPARE(loadSpy.count(), 1); evaluateJavaScriptSync(m_view->page(), "tstform.submit();"); newPage->m_acceptNavigationRequest = true; evaluateJavaScriptSync(m_view->page(), "tstform.submit();"); QTRY_COMPARE(loadSpy.count(), 2); QCOMPARE(m_view->page()->toPlainText(), QString("foo?")); // Restore default page m_view->setPage(0); #endif }
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
#if defined(QWEBENGINEPAGE_SETFEATUREPERMISSION) class JSTestPage : public QWebEnginePage { Q_OBJECT public: JSTestPage(QObject* parent = 0) : QWebEnginePage(parent) {} virtual bool shouldInterruptJavaScript() { return true; } public Q_SLOTS: void requestPermission(QWebEngineFrame* frame, QWebEnginePage::Feature feature) { if (m_allowGeolocation) setFeaturePermission(frame, feature, PermissionGrantedByUser); else setFeaturePermission(frame, feature, PermissionDeniedByUser); } public: void setGeolocationPermission(bool allow) { m_allowGeolocation = allow; } private: bool m_allowGeolocation; }; #endif // [Qt] tst_QWebEnginePage::infiniteLoopJS() timeouts with DFG JIT // https://bugs.webkit.org/show_bug.cgi?id=79040 /* void tst_QWebEnginePage::infiniteLoopJS() { JSTestPage* newPage = new JSTestPage(m_view); m_view->setPage(newPage); m_view->setHtml(QString("<html><body>test</body></html>"), QUrl()); m_view->page()->evaluateJavaScript("var run = true; var a = 1; while (run) { a++; }"); delete newPage; } */ void tst_QWebEnginePage::geolocationRequestJS() { #if !defined(QWEBENGINEPAGE_SETFEATUREPERMISSION) QSKIP("QWEBENGINEPAGE_SETFEATUREPERMISSION"); #else JSTestPage* newPage = new JSTestPage(m_view); if (evaluateJavaScriptSync(newPage, QLatin1String("!navigator.geolocation")).toBool()) { delete newPage; W_QSKIP("Geolocation is not supported.", SkipSingle); } connect(newPage, SIGNAL(featurePermissionRequested(QWebEngineFrame*, QWebEnginePage::Feature)), newPage, SLOT(requestPermission(QWebEngineFrame*, QWebEnginePage::Feature))); newPage->setGeolocationPermission(false); m_view->setPage(newPage); m_view->setHtml(QString("<html><body>test</body></html>"), QUrl()); evaluateJavaScriptSync(m_view->page(), "var errorCode = 0; function error(err) { errorCode = err.code; } function success(pos) { } navigator.geolocation.getCurrentPosition(success, error)"); QTest::qWait(2000); QVariant empty = evaluateJavaScriptSync(m_view->page(), "errorCode"); QEXPECT_FAIL("", "https://bugs.webkit.org/show_bug.cgi?id=102235", Continue); QVERIFY(empty.type() == QVariant::Double && empty.toInt() != 0);
351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
newPage->setGeolocationPermission(true); evaluateJavaScriptSync(m_view->page(), "errorCode = 0; navigator.geolocation.getCurrentPosition(success, error);"); empty = evaluateJavaScriptSync(m_view->page(), "errorCode"); //http://dev.w3.org/geo/api/spec-source.html#position //PositionError: const unsigned short PERMISSION_DENIED = 1; QVERIFY(empty.type() == QVariant::Double && empty.toInt() != 1); delete newPage; #endif } void tst_QWebEnginePage::loadFinished() { qRegisterMetaType<QNetworkRequest*>("QNetworkRequest*"); QSignalSpy spyLoadStarted(m_view, SIGNAL(loadStarted())); QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool))); m_view->page()->load(QUrl("data:text/html,<frameset cols=\"25%,75%\"><frame src=\"data:text/html," "<head><meta http-equiv='refresh' content='1'></head>foo \">" "<frame src=\"data:text/html,bar\"></frameset>")); QTRY_COMPARE(spyLoadFinished.count(), 1); QTRY_VERIFY(spyLoadStarted.count() > 1); QTRY_VERIFY(spyLoadFinished.count() > 1); spyLoadFinished.clear(); m_view->page()->load(QUrl("data:text/html,<frameset cols=\"25%,75%\"><frame src=\"data:text/html," "foo \"><frame src=\"data:text/html,bar\"></frameset>")); QTRY_COMPARE(spyLoadFinished.count(), 1); QCOMPARE(spyLoadFinished.count(), 1); } void tst_QWebEnginePage::actionStates() { QWebEnginePage* page = m_view->page(); page->load(QUrl("qrc:///resources/script.html")); QAction* reloadAction = page->action(QWebEnginePage::Reload); QAction* stopAction = page->action(QWebEnginePage::Stop); QTRY_VERIFY(reloadAction->isEnabled()); QTRY_VERIFY(!stopAction->isEnabled()); } class ConsolePage : public QWebEnginePage { public: ConsolePage(QObject* parent = 0) : QWebEnginePage(parent) {} virtual void javaScriptConsoleMessage(int level, const QString& message, int lineNumber, const QString& sourceID) { levels.append(level); messages.append(message); lineNumbers.append(lineNumber); sourceIDs.append(sourceID); } QList<int> levels; QStringList messages; QList<int> lineNumbers; QStringList sourceIDs; }; void tst_QWebEnginePage::consoleOutput() { ConsolePage page; // We don't care about the result but want this to be synchronous
421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
evaluateJavaScriptSync(&page, "this is not valid JavaScript"); QCOMPARE(page.messages.count(), 1); QCOMPARE(page.lineNumbers.at(0), 1); } class TestPage : public QWebEnginePage { Q_OBJECT public: TestPage(QObject* parent = 0) : QWebEnginePage(parent) { connect(this, SIGNAL(geometryChangeRequested(QRect)), this, SLOT(slotGeometryChangeRequested(QRect))); } struct Navigation { QWebEngineFrame *frame; QNetworkRequest request; NavigationType type; }; QList<Navigation> navigations; QList<TestPage*> createdWindows; QRect requestedGeometry; virtual bool acceptNavigationRequest(QWebEngineFrame* frame, const QNetworkRequest &request, NavigationType type) { Navigation n; n.frame = frame; n.request = request; n.type = type; navigations.append(n); return true; } virtual QWebEnginePage* createWindow(WebWindowType) { TestPage* page = new TestPage(this); createdWindows.append(page); return page; } private Q_SLOTS: void slotGeometryChangeRequested(const QRect& geom) { requestedGeometry = geom; } }; void tst_QWebEnginePage::popupFormSubmission() { #if !defined(QWEBENGINEPAGE_SETTINGS) QSKIP("QWEBENGINEPAGE_SETTINGS"); #else TestPage page; page.settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true); page.setHtml("<form name=form1 method=get action='' target=myNewWin>"\ "<input type=hidden name=foo value='bar'>"\ "</form>"); page.runJavaScript("window.open('', 'myNewWin', 'width=500,height=300,toolbar=0')"); evaluateJavaScriptSync(&page, "document.form1.submit();"); QTest::qWait(500); // The number of popup created should be one. QVERIFY(page.createdWindows.size() == 1); QString url = page.createdWindows.takeFirst()->url().toString(); // Check if the form submission was OK. QEXPECT_FAIL("", "https://bugs.webkit.org/show_bug.cgi?id=118597", Continue); QVERIFY(url.contains("?foo=bar")); #endif } void tst_QWebEnginePage::acceptNavigationRequestWithNewWindow() {
491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
#if !defined(QWEBENGINESETTINGS) QSKIP("QWEBENGINESETTINGS"); #else TestPage* page = new TestPage(m_view); page->settings()->setAttribute(QWebEngineSettings::LinksIncludedInFocusChain, true); m_page = page; m_view->setPage(m_page); m_view->setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me</a>")); QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); QFocusEvent fe(QEvent::FocusIn); m_page->event(&fe); QVERIFY(m_page->focusNextPrevChild(/*next*/ true)); QKeyEvent keyEnter(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier); m_page->event(&keyEnter); QCOMPARE(page->navigations.count(), 2); TestPage::Navigation n = page->navigations.at(1); QVERIFY(!n.frame); QCOMPARE(n.request.url().toString(), QString("data:text/html,Reached")); QVERIFY(n.type == QWebEnginePage::NavigationTypeLinkClicked); QCOMPARE(page->createdWindows.count(), 1); #endif } class TestNetworkManager : public QNetworkAccessManager { public: TestNetworkManager(QObject* parent) : QNetworkAccessManager(parent) {} QList<QUrl> requestedUrls; QList<QNetworkRequest> requests; protected: virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest &request, QIODevice* outgoingData) { requests.append(request); requestedUrls.append(request.url()); return QNetworkAccessManager::createRequest(op, request, outgoingData); } }; void tst_QWebEnginePage::userStyleSheet() { #if !defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) QSKIP("QWEBENGINEPAGE_SETNETWORKACCESSMANAGER"); #else TestNetworkManager* networkManager = new TestNetworkManager(m_page); m_page->setNetworkAccessManager(networkManager); m_page->settings()->setUserStyleSheetUrl(QUrl("data:text/css;charset=utf-8;base64," + QByteArray("p { background-image: url('http://does.not/exist.png');}").toBase64())); m_view->setHtml("<p>hello world</p>"); QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); QVERIFY(networkManager->requestedUrls.count() >= 1); QCOMPARE(networkManager->requestedUrls.at(0), QUrl("http://does.not/exist.png")); #endif } void tst_QWebEnginePage::userStyleSheetFromLocalFileUrl() { #if !defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) QSKIP("QWEBENGINEPAGE_SETNETWORKACCESSMANAGER"); #else TestNetworkManager* networkManager = new TestNetworkManager(m_page);
561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
m_page->setNetworkAccessManager(networkManager); QUrl styleSheetUrl = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebenginepage/resources/user.css")); m_page->settings()->setUserStyleSheetUrl(styleSheetUrl); m_view->setHtml("<p>hello world</p>"); QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); QVERIFY(networkManager->requestedUrls.count() >= 1); QCOMPARE(networkManager->requestedUrls.at(0), QUrl("http://does.not/exist.png")); #endif } void tst_QWebEnginePage::userStyleSheetFromQrcUrl() { #if !defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) QSKIP("QWEBENGINEPAGE_SETNETWORKACCESSMANAGER"); #else TestNetworkManager* networkManager = new TestNetworkManager(m_page); m_page->setNetworkAccessManager(networkManager); m_page->settings()->setUserStyleSheetUrl(QUrl("qrc:///resources/user.css")); m_view->setHtml("<p>hello world</p>"); QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); QVERIFY(networkManager->requestedUrls.count() >= 1); QCOMPARE(networkManager->requestedUrls.at(0), QUrl("http://does.not/exist.png")); #endif } void tst_QWebEnginePage::loadHtml5Video() { #if defined(WTF_USE_QT_MULTIMEDIA) && WTF_USE_QT_MULTIMEDIA QByteArray url("http://does.not/exist?a=1%2Cb=2"); m_view->setHtml("<p><video id ='video' src='" + url + "' autoplay/></p>"); QTest::qWait(2000); QUrl mUrl = DumpRenderTreeSupportQt::mediaContentUrlByElementId(m_page->mainFrame()->handle(), "video"); QEXPECT_FAIL("", "https://bugs.webkit.org/show_bug.cgi?id=65452", Continue); QCOMPARE(mUrl.toEncoded(), url); #else W_QSKIP("This test requires Qt Multimedia", SkipAll); #endif } void tst_QWebEnginePage::viewModes() { #if !defined(QWEBENGINEPAGE_VIEW_MODES) QSKIP("QWEBENGINEPAGE_VIEW_MODES"); #else m_view->setHtml("<body></body>"); m_page->setProperty("_q_viewMode", "minimized"); QVariant empty = evaluateJavaScriptSync(m_page, "window.styleMedia.matchMedium(\"(-webengine-view-mode)\")"); QVERIFY(empty.type() == QVariant::Bool && empty.toBool()); QVariant minimized = evaluateJavaScriptSync(m_page, "window.styleMedia.matchMedium(\"(-webengine-view-mode: minimized)\")"); QVERIFY(minimized.type() == QVariant::Bool && minimized.toBool()); QVariant maximized = evaluateJavaScriptSync(m_page, "window.styleMedia.matchMedium(\"(-webengine-view-mode: maximized)\")"); QVERIFY(maximized.type() == QVariant::Bool && !maximized.toBool()); #endif } void tst_QWebEnginePage::modified() { #if !defined(QWEBENGINEPAGE_ISMODIFIED) QSKIP("QWEBENGINEPAGE_ISMODIFIED"); #else m_page->setUrl(QUrl("data:text/html,<body>blub")); QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
m_page->setUrl(QUrl("data:text/html,<body id=foo contenteditable>blah")); QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); QVERIFY(!m_page->isModified()); m_page->runJavaScript("document.getElementById('foo').focus()"); evaluateJavaScriptSync(m_page, "document.execCommand('InsertText', true, 'Test');"); QVERIFY(m_page->isModified()); evaluateJavaScriptSync(m_page, "document.execCommand('Undo', true);"); QVERIFY(!m_page->isModified()); evaluateJavaScriptSync(m_page, "document.execCommand('Redo', true);"); QVERIFY(m_page->isModified()); QVERIFY(m_page->history()->canGoBack()); QVERIFY(!m_page->history()->canGoForward()); QCOMPARE(m_page->history()->count(), 2); QVERIFY(m_page->history()->backItem().isValid()); QVERIFY(!m_page->history()->forwardItem().isValid()); m_page->history()->back(); QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); QVERIFY(!m_page->history()->canGoBack()); QVERIFY(m_page->history()->canGoForward()); QVERIFY(!m_page->isModified()); QCOMPARE(m_page->history()->currentItemIndex(), 0); m_page->history()->setMaximumItemCount(3); QCOMPARE(m_page->history()->maximumItemCount(), 3); QVariant variant("string test"); m_page->history()->currentItem().setUserData(variant); QVERIFY(m_page->history()->currentItem().userData().toString() == "string test"); m_page->setUrl(QUrl("data:text/html,<body>This is second page")); m_page->setUrl(QUrl("data:text/html,<body>This is third page")); QCOMPARE(m_page->history()->count(), 2); m_page->setUrl(QUrl("data:text/html,<body>This is fourth page")); QCOMPARE(m_page->history()->count(), 2); m_page->setUrl(QUrl("data:text/html,<body>This is fifth page")); QVERIFY(::waitForSignal(m_page, SIGNAL(saveFrameStateRequested(QWebEngineFrame*,QWebEngineHistoryItem*)))); #endif } // https://bugs.webkit.org/show_bug.cgi?id=51331 void tst_QWebEnginePage::updatePositionDependentActionsCrash() { #if !defined(QWEBENGINEPAGE_UPDATEPOSITIONDEPENDENTACTIONS) QSKIP("QWEBENGINEPAGE_UPDATEPOSITIONDEPENDENTACTIONS"); #else QWebEngineView view; view.setHtml("<p>test"); QPoint pos(0, 0); view.page()->updatePositionDependentActions(pos); QMenu* contextMenu = 0; foreach (QObject* child, view.children()) { contextMenu = qobject_cast<QMenu*>(child); if (contextMenu) break; } QVERIFY(!contextMenu); #endif }
701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
// https://bugs.webkit.org/show_bug.cgi?id=20357 void tst_QWebEnginePage::contextMenuCrash() { #if !defined(QWEBENGINEPAGE_SWALLOWCONTEXTMENUEVENT) QSKIP("QWEBENGINEPAGE_SWALLOWCONTEXTMENUEVENT"); #else QWebEngineView view; view.setHtml("<p>test"); QPoint pos(0, 0); QContextMenuEvent event(QContextMenuEvent::Mouse, pos); view.page()->swallowContextMenuEvent(&event); view.page()->updatePositionDependentActions(pos); QMenu* contextMenu = 0; foreach (QObject* child, view.children()) { contextMenu = qobject_cast<QMenu*>(child); if (contextMenu) break; } QVERIFY(contextMenu); delete contextMenu; #endif } void tst_QWebEnginePage::database() { #if !defined(QWEBENGINEDATABASE) QSKIP("QWEBENGINEDATABASE"); #else QString path = tmpDirPath(); m_page->settings()->setOfflineStoragePath(path); QVERIFY(m_page->settings()->offlineStoragePath() == path); QWebEngineSettings::setOfflineStorageDefaultQuota(1024 * 1024); QVERIFY(QWebEngineSettings::offlineStorageDefaultQuota() == 1024 * 1024); m_page->settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true); m_page->settings()->setAttribute(QWebEngineSettings::OfflineStorageDatabaseEnabled, true); QString dbFileName = path + "Databases.db"; if (QFile::exists(dbFileName)) QFile::remove(dbFileName); qRegisterMetaType<QWebEngineFrame*>("QWebEngineFrame*"); QSignalSpy spy(m_page, SIGNAL(databaseQuotaExceeded(QWebEngineFrame*,QString))); 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")); QTRY_COMPARE(spy.count(), 1); evaluateJavaScriptSync(m_page, "var db2; db2=openDatabase('testdb', '1.0', 'test database API', 50000);"); QTRY_COMPARE(spy.count(),1); evaluateJavaScriptSync(m_page, "localStorage.test='This is a test for local storage';"); m_view->setHtml(QString("<html><body id='b'>text</body></html>"), QUrl("http://www.myexample.com")); QVariant s1 = evaluateJavaScriptSync(m_page, "localStorage.test"); QCOMPARE(s1.toString(), QString("This is a test for local storage")); evaluateJavaScriptSync(m_page, "sessionStorage.test='This is a test for session storage';"); m_view->setHtml(QString("<html><body id='b'>text</body></html>"), QUrl("http://www.myexample.com")); QVariant s2 = evaluateJavaScriptSync(m_page, "sessionStorage.test"); QCOMPARE(s2.toString(), QString("This is a test for session storage")); m_view->setHtml(QString("<html><head></head><body><div></div></body></html>"), QUrl("http://www.myexample.com")); evaluateJavaScriptSync(m_page, "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) { });"); QTest::qWait(200); // Remove all databases. QWebEngineSecurityOrigin origin = m_page->mainFrame()->securityOrigin(); QList<QWebEngineDatabase> dbs = origin.databases(); for (int i = 0; i < dbs.count(); i++) {
771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
QString fileName = dbs[i].fileName(); QVERIFY(QFile::exists(fileName)); QWebEngineDatabase::removeDatabase(dbs[i]); QVERIFY(!QFile::exists(fileName)); } QVERIFY(!origin.databases().size()); // Remove removed test :-) QWebEngineDatabase::removeAllDatabases(); QVERIFY(!origin.databases().size()); #endif } #if defined(QWEBENGINEPAGE_CREATEPLUGIN) class PluginPage : public QWebEnginePage { public: PluginPage(QObject *parent = 0) : QWebEnginePage(parent) {} struct CallInfo { CallInfo(const QString &c, const QUrl &u, const QStringList &pn, const QStringList &pv, QObject *r) : classid(c), url(u), paramNames(pn), paramValues(pv), returnValue(r) {} QString classid; QUrl url; QStringList paramNames; QStringList paramValues; QObject *returnValue; }; QList<CallInfo> calls; protected: virtual QObject *createPlugin(const QString &classid, const QUrl &url, const QStringList &paramNames, const QStringList &paramValues) { QObject *result = 0; if (classid == "pushbutton") result = new QPushButton(); #ifndef QT_NO_INPUTDIALOG else if (classid == "lineedit") result = new QLineEdit(); #endif else if (classid == "graphicswidget") result = new QGraphicsWidget(); if (result) result->setObjectName(classid); calls.append(CallInfo(classid, url, paramNames, paramValues, result)); return result; } }; static void createPlugin(QWebEngineView *view) { QSignalSpy loadSpy(view, SIGNAL(loadFinished(bool))); PluginPage* newPage = new PluginPage(view); view->setPage(newPage); // type has to be application/x-qt-plugin view->setHtml(QString("<html><body><object type='application/x-foobarbaz' classid='pushbutton' id='mybutton'/></body></html>")); QTRY_COMPARE(loadSpy.count(), 1); QCOMPARE(newPage->calls.count(), 0); view->setHtml(QString("<html><body><object type='application/x-qt-plugin' classid='pushbutton' id='mybutton'/></body></html>"));
841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910
QTRY_COMPARE(loadSpy.count(), 2); QCOMPARE(newPage->calls.count(), 1); { PluginPage::CallInfo ci = newPage->calls.takeFirst(); QCOMPARE(ci.classid, QString::fromLatin1("pushbutton")); QCOMPARE(ci.url, QUrl()); QCOMPARE(ci.paramNames.count(), 3); QCOMPARE(ci.paramValues.count(), 3); QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type")); QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin")); QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid")); QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("pushbutton")); QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id")); QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("mybutton")); QVERIFY(ci.returnValue != 0); QVERIFY(ci.returnValue->inherits("QPushButton")); } // test JS bindings QCOMPARE(evaluateJavaScriptSync(newPage, "document.getElementById('mybutton').toString()").toString(), QString::fromLatin1("[object HTMLObjectElement]")); QCOMPARE(evaluateJavaScriptSync(newPage, "mybutton.toString()").toString(), QString::fromLatin1("[object HTMLObjectElement]")); QCOMPARE(evaluateJavaScriptSync(newPage, "typeof mybutton.objectName").toString(), QString::fromLatin1("string")); QCOMPARE(evaluateJavaScriptSync(newPage, "mybutton.objectName").toString(), QString::fromLatin1("pushbutton")); QCOMPARE(evaluateJavaScriptSync(newPage, "typeof mybutton.clicked").toString(), QString::fromLatin1("function")); QCOMPARE(evaluateJavaScriptSync(newPage, "mybutton.clicked.toString()").toString(), QString::fromLatin1("function clicked() {\n [native code]\n}")); view->setHtml(QString("<html><body><table>" "<tr><object type='application/x-qt-plugin' classid='lineedit' id='myedit'/></tr>" "<tr><object type='application/x-qt-plugin' classid='pushbutton' id='mybutton'/></tr>" "</table></body></html>"), QUrl("http://foo.bar.baz")); QTRY_COMPARE(loadSpy.count(), 3); QCOMPARE(newPage->calls.count(), 2); { PluginPage::CallInfo ci = newPage->calls.takeFirst(); QCOMPARE(ci.classid, QString::fromLatin1("lineedit")); QCOMPARE(ci.url, QUrl()); QCOMPARE(ci.paramNames.count(), 3); QCOMPARE(ci.paramValues.count(), 3); QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type")); QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin")); QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid")); QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("lineedit")); QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id")); QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("myedit")); QVERIFY(ci.returnValue != 0); QVERIFY(ci.returnValue->inherits("QLineEdit")); } { PluginPage::CallInfo ci = newPage->calls.takeFirst(); QCOMPARE(ci.classid, QString::fromLatin1("pushbutton")); QCOMPARE(ci.url, QUrl()); QCOMPARE(ci.paramNames.count(), 3); QCOMPARE(ci.paramValues.count(), 3); QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type")); QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin")); QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid")); QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("pushbutton")); QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id")); QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("mybutton")); QVERIFY(ci.returnValue != 0); QVERIFY(ci.returnValue->inherits("QPushButton")); } } #endif
911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980
void tst_QWebEnginePage::graphicsWidgetPlugin() { #if !defined(QWEBENGINEPAGE_CREATEPLUGIN) QSKIP("QWEBENGINEPAGE_CREATEPLUGIN"); #else m_view->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true); QGraphicsWebView webView; QSignalSpy loadSpy(&webView, SIGNAL(loadFinished(bool))); PluginPage* newPage = new PluginPage(&webView); webView.setPage(newPage); // type has to be application/x-qt-plugin webView.setHtml(QString("<html><body><object type='application/x-foobarbaz' classid='graphicswidget' id='mygraphicswidget'/></body></html>")); QTRY_COMPARE(loadSpy.count(), 1); QCOMPARE(newPage->calls.count(), 0); webView.setHtml(QString("<html><body><object type='application/x-qt-plugin' classid='graphicswidget' id='mygraphicswidget'/></body></html>")); QTRY_COMPARE(loadSpy.count(), 2); QCOMPARE(newPage->calls.count(), 1); { PluginPage::CallInfo ci = newPage->calls.takeFirst(); QCOMPARE(ci.classid, QString::fromLatin1("graphicswidget")); QCOMPARE(ci.url, QUrl()); QCOMPARE(ci.paramNames.count(), 3); QCOMPARE(ci.paramValues.count(), 3); QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type")); QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin")); QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid")); QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("graphicswidget")); QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id")); QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("mygraphicswidget")); QVERIFY(ci.returnValue); QVERIFY(ci.returnValue->inherits("QGraphicsWidget")); } // test JS bindings QCOMPARE(evaluateJavaScriptSync(newPage, "document.getElementById('mygraphicswidget').toString()").toString(), QString::fromLatin1("[object HTMLObjectElement]")); QCOMPARE(evaluateJavaScriptSync(newPage, "mygraphicswidget.toString()").toString(), QString::fromLatin1("[object HTMLObjectElement]")); QCOMPARE(evaluateJavaScriptSync(newPage, "typeof mygraphicswidget.objectName").toString(), QString::fromLatin1("string")); QCOMPARE(evaluateJavaScriptSync(newPage, "mygraphicswidget.objectName").toString(), QString::fromLatin1("graphicswidget")); QCOMPARE(evaluateJavaScriptSync(newPage, "typeof mygraphicswidget.geometryChanged").toString(), QString::fromLatin1("function")); QCOMPARE(evaluateJavaScriptSync(newPage, "mygraphicswidget.geometryChanged.toString()").toString(), QString::fromLatin1("function geometryChanged() {\n [native code]\n}")); #endif } void tst_QWebEnginePage::createPluginWithPluginsEnabled() { #if !defined(QWEBENGINEPAGE_CREATEPLUGIN) QSKIP("QWEBENGINEPAGE_CREATEPLUGIN"); #else m_view->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true); createPlugin(m_view); #endif } void tst_QWebEnginePage::createPluginWithPluginsDisabled() { #if !defined(QWEBENGINEPAGE_CREATEPLUGIN) QSKIP("QWEBENGINEPAGE_CREATEPLUGIN"); #else // Qt Plugins should be loaded by QtWebEngine even when PluginsEnabled is // false. The client decides whether a Qt plugin is enabled or not when // it decides whether or not to instantiate it.
981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050
m_view->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, false); createPlugin(m_view); #endif } #if defined(QWEBENGINEPAGE_CREATEPLUGIN) // Standard base class for template PluginTracerPage. In tests it is used as interface. class PluginCounterPage : public QWebEnginePage { public: int m_count; QPointer<QObject> m_widget; QObject* m_pluginParent; PluginCounterPage(QObject* parent = 0) : QWebEnginePage(parent) , m_count(0) , m_pluginParent(0) { settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true); } ~PluginCounterPage() { if (m_pluginParent) m_pluginParent->deleteLater(); } }; template<class T> class PluginTracerPage : public PluginCounterPage { public: PluginTracerPage(QObject* parent = 0) : PluginCounterPage(parent) { // this is a dummy parent object for the created plugin m_pluginParent = new T; } virtual QObject* createPlugin(const QString&, const QUrl&, const QStringList&, const QStringList&) { m_count++; m_widget = new T; // need a cast to the specific type, as QObject::setParent cannot be called, // because it is not virtual. Instead it is necessary to call QWidget::setParent, // which also takes a QWidget* instead of a QObject*. Therefore we need to // upcast to T*, which is a QWidget. static_cast<T*>(m_widget.data())->setParent(static_cast<T*>(m_pluginParent)); return m_widget.data(); } }; class PluginFactory { public: enum FactoredType {QWidgetType, QGraphicsWidgetType}; static PluginCounterPage* create(FactoredType type, QObject* parent = 0) { PluginCounterPage* result = 0; switch (type) { case QWidgetType: result = new PluginTracerPage<QWidget>(parent); break; case QGraphicsWidgetType: result = new PluginTracerPage<QGraphicsWidget>(parent); break; default: {/*Oops*/}; } return result; } static void prepareTestData() { QTest::addColumn<int>("type"); QTest::newRow("QWidget") << (int)PluginFactory::QWidgetType;
1051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120
QTest::newRow("QGraphicsWidget") << (int)PluginFactory::QGraphicsWidgetType; } }; #endif void tst_QWebEnginePage::destroyPlugin_data() { #if defined(QWEBENGINEPAGE_CREATEPLUGIN) PluginFactory::prepareTestData(); #endif } void tst_QWebEnginePage::destroyPlugin() { #if !defined(QWEBENGINEPAGE_CREATEPLUGIN) QSKIP("QWEBENGINEPAGE_CREATEPLUGIN"); #else QFETCH(int, type); PluginCounterPage* page = PluginFactory::create((PluginFactory::FactoredType)type, m_view); m_view->setPage(page); // we create the plugin, so the widget should be constructed QString content("<html><body><object type=\"application/x-qt-plugin\" classid=\"QProgressBar\"></object></body></html>"); m_view->setHtml(content); QVERIFY(page->m_widget); QCOMPARE(page->m_count, 1); // navigate away, the plugin widget should be destructed m_view->setHtml("<html><body>Hi</body></html>"); QTestEventLoop::instance().enterLoop(1); QVERIFY(!page->m_widget); #endif } void tst_QWebEnginePage::createViewlessPlugin_data() { #if defined(QWEBENGINEPAGE_CREATEPLUGIN) PluginFactory::prepareTestData(); #endif } void tst_QWebEnginePage::createViewlessPlugin() { #if !defined(QWEBENGINEPAGE_CREATEPLUGIN) QSKIP("QWEBENGINEPAGE_CREATEPLUGIN"); #else QFETCH(int, type); PluginCounterPage* page = PluginFactory::create((PluginFactory::FactoredType)type); QString content("<html><body><object type=\"application/x-qt-plugin\" classid=\"QProgressBar\"></object></body></html>"); page->setHtml(content); QCOMPARE(page->m_count, 1); QVERIFY(page->m_widget); QVERIFY(page->m_pluginParent); QVERIFY(page->m_widget.data()->parent() == page->m_pluginParent); delete page; #endif } void tst_QWebEnginePage::multiplePageGroupsAndLocalStorage() { #if !defined(QWEBENGINESETTINGS_SETLOCALSTORAGEPATH) QSKIP("QWEBENGINESETTINGS_SETLOCALSTORAGEPATH"); #else QDir dir(tmpDirPath()); dir.mkdir("path1"); dir.mkdir("path2"); QWebEngineView view1; QWebEngineView view2;
1121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190
view1.page()->settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true); view1.page()->settings()->setLocalStoragePath(QDir::toNativeSeparators(tmpDirPath() + "/path1")); DumpRenderTreeSupportQt::webPageSetGroupName(view1.page()->handle(), "group1"); view2.page()->settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true); view2.page()->settings()->setLocalStoragePath(QDir::toNativeSeparators(tmpDirPath() + "/path2")); DumpRenderTreeSupportQt::webPageSetGroupName(view2.page()->handle(), "group2"); QCOMPARE(DumpRenderTreeSupportQt::webPageGroupName(view1.page()->handle()), QString("group1")); QCOMPARE(DumpRenderTreeSupportQt::webPageGroupName(view2.page()->handle()), QString("group2")); view1.setHtml(QString("<html><body> </body></html>"), QUrl("http://www.myexample.com")); view2.setHtml(QString("<html><body> </body></html>"), QUrl("http://www.myexample.com")); evaluateJavaScriptSync(view1.page(), "localStorage.test='value1';"); evaluateJavaScriptSync(view2.page(), "localStorage.test='value2';"); view1.setHtml(QString("<html><body> </body></html>"), QUrl("http://www.myexample.com")); view2.setHtml(QString("<html><body> </body></html>"), QUrl("http://www.myexample.com")); QVariant s1 = evaluateJavaScriptSync(view1.page(), "localStorage.test"); QCOMPARE(s1.toString(), QString("value1")); QVariant s2 = evaluateJavaScriptSync(view2.page(), "localStorage.test"); QCOMPARE(s2.toString(), QString("value2")); QTest::qWait(1000); QFile::remove(QDir::toNativeSeparators(tmpDirPath() + "/path1/http_www.myexample.com_0.localstorage")); QFile::remove(QDir::toNativeSeparators(tmpDirPath() + "/path2/http_www.myexample.com_0.localstorage")); dir.rmdir(QDir::toNativeSeparators("./path1")); dir.rmdir(QDir::toNativeSeparators("./path2")); #endif } class CursorTrackedPage : public QWebEnginePage { public: CursorTrackedPage(QWidget *parent = 0): QWebEnginePage(parent) { setViewportSize(QSize(1024, 768)); // big space } QString selectedText() { return evaluateJavaScriptSync(this, "window.getSelection().toString()").toString(); } int selectionStartOffset() { return evaluateJavaScriptSync(this, "window.getSelection().getRangeAt(0).startOffset").toInt(); } int selectionEndOffset() { return evaluateJavaScriptSync(this, "window.getSelection().getRangeAt(0).endOffset").toInt(); } // true if start offset == end offset, i.e. no selected text int isSelectionCollapsed() { return evaluateJavaScriptSync(this, "window.getSelection().getRangeAt(0).collapsed").toBool(); } }; void tst_QWebEnginePage::cursorMovements() { #if !defined(QWEBENGINEPAGE_SELECTEDTEXT) QSKIP("QWEBENGINEPAGE_SELECTEDTEXT"); #else CursorTrackedPage* page = new CursorTrackedPage; 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>"); page->setHtml(content); // this will select the first paragraph
1191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260
QString script = "var range = document.createRange(); " \ "var node = document.getElementById(\"one\"); " \ "range.selectNode(node); " \ "getSelection().addRange(range);"; evaluateJavaScriptSync(page, script); QCOMPARE(page->selectedText().trimmed(), QString::fromLatin1("The quick brown fox")); QRegExp regExp(" style=\".*\""); regExp.setMinimal(true); QCOMPARE(page->selectedHtml().trimmed().replace(regExp, ""), QString::fromLatin1("<p id=\"one\">The quick brown fox</p>")); // these actions must exist QVERIFY(page->action(QWebEnginePage::MoveToNextChar) != 0); QVERIFY(page->action(QWebEnginePage::MoveToPreviousChar) != 0); QVERIFY(page->action(QWebEnginePage::MoveToNextWord) != 0); QVERIFY(page->action(QWebEnginePage::MoveToPreviousWord) != 0); QVERIFY(page->action(QWebEnginePage::MoveToNextLine) != 0); QVERIFY(page->action(QWebEnginePage::MoveToPreviousLine) != 0); QVERIFY(page->action(QWebEnginePage::MoveToStartOfLine) != 0); QVERIFY(page->action(QWebEnginePage::MoveToEndOfLine) != 0); QVERIFY(page->action(QWebEnginePage::MoveToStartOfBlock) != 0); QVERIFY(page->action(QWebEnginePage::MoveToEndOfBlock) != 0); QVERIFY(page->action(QWebEnginePage::MoveToStartOfDocument) != 0); QVERIFY(page->action(QWebEnginePage::MoveToEndOfDocument) != 0); // right now they are disabled because contentEditable is false QCOMPARE(page->action(QWebEnginePage::MoveToNextChar)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::MoveToPreviousChar)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::MoveToNextWord)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::MoveToPreviousWord)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::MoveToNextLine)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::MoveToPreviousLine)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::MoveToStartOfLine)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::MoveToEndOfLine)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::MoveToStartOfBlock)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::MoveToEndOfBlock)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::MoveToStartOfDocument)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::MoveToEndOfDocument)->isEnabled(), false); // make it editable before navigating the cursor page->setContentEditable(true); // here the actions are enabled after contentEditable is true QCOMPARE(page->action(QWebEnginePage::MoveToNextChar)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::MoveToPreviousChar)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::MoveToNextWord)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::MoveToPreviousWord)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::MoveToNextLine)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::MoveToPreviousLine)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::MoveToStartOfLine)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::MoveToEndOfLine)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::MoveToStartOfBlock)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::MoveToEndOfBlock)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::MoveToStartOfDocument)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::MoveToEndOfDocument)->isEnabled(), true); // cursor will be before the word "jump" page->triggerAction(QWebEnginePage::MoveToNextChar); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 0); // cursor will be between 'j' and 'u' in the word "jump" page->triggerAction(QWebEnginePage::MoveToNextChar); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 1); // cursor will be between 'u' and 'm' in the word "jump" page->triggerAction(QWebEnginePage::MoveToNextChar); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 2);
1261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330
// cursor will be after the word "jump" page->triggerAction(QWebEnginePage::MoveToNextWord); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 5); // cursor will be after the word "lazy" page->triggerAction(QWebEnginePage::MoveToNextWord); page->triggerAction(QWebEnginePage::MoveToNextWord); page->triggerAction(QWebEnginePage::MoveToNextWord); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 19); // cursor will be between 'z' and 'y' in "lazy" page->triggerAction(QWebEnginePage::MoveToPreviousChar); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 18); // cursor will be between 'a' and 'z' in "lazy" page->triggerAction(QWebEnginePage::MoveToPreviousChar); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 17); // cursor will be before the word "lazy" page->triggerAction(QWebEnginePage::MoveToPreviousWord); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 15); // cursor will be before the word "quick" page->triggerAction(QWebEnginePage::MoveToPreviousWord); page->triggerAction(QWebEnginePage::MoveToPreviousWord); page->triggerAction(QWebEnginePage::MoveToPreviousWord); page->triggerAction(QWebEnginePage::MoveToPreviousWord); page->triggerAction(QWebEnginePage::MoveToPreviousWord); page->triggerAction(QWebEnginePage::MoveToPreviousWord); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 4); // cursor will be between 'p' and 's' in the word "jumps" page->triggerAction(QWebEnginePage::MoveToNextWord); page->triggerAction(QWebEnginePage::MoveToNextWord); page->triggerAction(QWebEnginePage::MoveToNextWord); page->triggerAction(QWebEnginePage::MoveToNextChar); page->triggerAction(QWebEnginePage::MoveToNextChar); page->triggerAction(QWebEnginePage::MoveToNextChar); page->triggerAction(QWebEnginePage::MoveToNextChar); page->triggerAction(QWebEnginePage::MoveToNextChar); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 4); // cursor will be before the word "jumps" page->triggerAction(QWebEnginePage::MoveToStartOfLine); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 0); // cursor will be after the word "dog" page->triggerAction(QWebEnginePage::MoveToEndOfLine); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 23); // cursor will be between 'w' and 'n' in "brown" page->triggerAction(QWebEnginePage::MoveToStartOfLine); page->triggerAction(QWebEnginePage::MoveToPreviousWord); page->triggerAction(QWebEnginePage::MoveToPreviousWord); page->triggerAction(QWebEnginePage::MoveToNextChar); page->triggerAction(QWebEnginePage::MoveToNextChar); page->triggerAction(QWebEnginePage::MoveToNextChar); page->triggerAction(QWebEnginePage::MoveToNextChar); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 14);
1331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400
// cursor will be after the word "fox" page->triggerAction(QWebEnginePage::MoveToEndOfLine); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 19); // cursor will be before the word "The" page->triggerAction(QWebEnginePage::MoveToStartOfDocument); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 0); // cursor will be after the word "you!" page->triggerAction(QWebEnginePage::MoveToEndOfDocument); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 12); // cursor will be before the word "be" page->triggerAction(QWebEnginePage::MoveToStartOfBlock); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 0); // cursor will be after the word "you!" page->triggerAction(QWebEnginePage::MoveToEndOfBlock); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 12); // try to move before the document start page->triggerAction(QWebEnginePage::MoveToStartOfDocument); page->triggerAction(QWebEnginePage::MoveToPreviousChar); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 0); page->triggerAction(QWebEnginePage::MoveToStartOfDocument); page->triggerAction(QWebEnginePage::MoveToPreviousWord); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 0); // try to move past the document end page->triggerAction(QWebEnginePage::MoveToEndOfDocument); page->triggerAction(QWebEnginePage::MoveToNextChar); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 12); page->triggerAction(QWebEnginePage::MoveToEndOfDocument); page->triggerAction(QWebEnginePage::MoveToNextWord); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 12); delete page; #endif } void tst_QWebEnginePage::textSelection() { #if !defined(QWEBENGINEPAGE_EVALUATEJAVASCRIPT) QSKIP("QWEBENGINEPAGE_EVALUATEJAVASCRIPT"); #else CursorTrackedPage* page = new CursorTrackedPage; 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>"); page->setHtml(content); // these actions must exist QVERIFY(page->action(QWebEnginePage::SelectAll) != 0); QVERIFY(page->action(QWebEnginePage::SelectNextChar) != 0); QVERIFY(page->action(QWebEnginePage::SelectPreviousChar) != 0); QVERIFY(page->action(QWebEnginePage::SelectNextWord) != 0); QVERIFY(page->action(QWebEnginePage::SelectPreviousWord) != 0); QVERIFY(page->action(QWebEnginePage::SelectNextLine) != 0); QVERIFY(page->action(QWebEnginePage::SelectPreviousLine) != 0); QVERIFY(page->action(QWebEnginePage::SelectStartOfLine) != 0);
1401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470
QVERIFY(page->action(QWebEnginePage::SelectEndOfLine) != 0); QVERIFY(page->action(QWebEnginePage::SelectStartOfBlock) != 0); QVERIFY(page->action(QWebEnginePage::SelectEndOfBlock) != 0); QVERIFY(page->action(QWebEnginePage::SelectStartOfDocument) != 0); QVERIFY(page->action(QWebEnginePage::SelectEndOfDocument) != 0); // right now they are disabled because contentEditable is false and // there isn't an existing selection to modify QCOMPARE(page->action(QWebEnginePage::SelectNextChar)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::SelectPreviousChar)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::SelectNextWord)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::SelectPreviousWord)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::SelectNextLine)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::SelectPreviousLine)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::SelectStartOfLine)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::SelectEndOfLine)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::SelectStartOfBlock)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::SelectEndOfBlock)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::SelectStartOfDocument)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::SelectEndOfDocument)->isEnabled(), false); // ..but SelectAll is awalys enabled QCOMPARE(page->action(QWebEnginePage::SelectAll)->isEnabled(), true); // Verify hasSelection returns false since there is no selection yet... QCOMPARE(page->hasSelection(), false); // this will select the first paragraph QString selectScript = "var range = document.createRange(); " \ "var node = document.getElementById(\"one\"); " \ "range.selectNode(node); " \ "getSelection().addRange(range);"; evaluateJavaScriptSync(page, selectScript); QCOMPARE(page->selectedText().trimmed(), QString::fromLatin1("The quick brown fox")); QRegExp regExp(" style=\".*\""); regExp.setMinimal(true); QCOMPARE(page->selectedHtml().trimmed().replace(regExp, ""), QString::fromLatin1("<p id=\"one\">The quick brown fox</p>")); // Make sure hasSelection returns true, since there is selected text now... QCOMPARE(page->hasSelection(), true); // here the actions are enabled after a selection has been created QCOMPARE(page->action(QWebEnginePage::SelectNextChar)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SelectPreviousChar)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SelectNextWord)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SelectPreviousWord)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SelectNextLine)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SelectPreviousLine)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SelectStartOfLine)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SelectEndOfLine)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SelectStartOfBlock)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SelectEndOfBlock)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SelectStartOfDocument)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SelectEndOfDocument)->isEnabled(), true); // make it editable before navigating the cursor page->setContentEditable(true); // cursor will be before the word "The", this makes sure there is a charet page->triggerAction(QWebEnginePage::MoveToStartOfDocument); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 0); // here the actions are enabled after contentEditable is true QCOMPARE(page->action(QWebEnginePage::SelectNextChar)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SelectPreviousChar)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SelectNextWord)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SelectPreviousWord)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SelectNextLine)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SelectPreviousLine)->isEnabled(), true);
1471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540
QCOMPARE(page->action(QWebEnginePage::SelectStartOfLine)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SelectEndOfLine)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SelectStartOfBlock)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SelectEndOfBlock)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SelectStartOfDocument)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SelectEndOfDocument)->isEnabled(), true); delete page; #endif } void tst_QWebEnginePage::textEditing() { #if !defined(QWEBENGINEPAGE_EVALUATEJAVASCRIPT) QSKIP("QWEBENGINEPAGE_EVALUATEJAVASCRIPT"); #else CursorTrackedPage* page = new CursorTrackedPage; 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>"); page->setHtml(content); // these actions must exist QVERIFY(page->action(QWebEnginePage::Cut) != 0); QVERIFY(page->action(QWebEnginePage::Copy) != 0); QVERIFY(page->action(QWebEnginePage::Paste) != 0); QVERIFY(page->action(QWebEnginePage::DeleteStartOfWord) != 0); QVERIFY(page->action(QWebEnginePage::DeleteEndOfWord) != 0); QVERIFY(page->action(QWebEnginePage::SetTextDirectionDefault) != 0); QVERIFY(page->action(QWebEnginePage::SetTextDirectionLeftToRight) != 0); QVERIFY(page->action(QWebEnginePage::SetTextDirectionRightToLeft) != 0); QVERIFY(page->action(QWebEnginePage::ToggleBold) != 0); QVERIFY(page->action(QWebEnginePage::ToggleItalic) != 0); QVERIFY(page->action(QWebEnginePage::ToggleUnderline) != 0); QVERIFY(page->action(QWebEnginePage::InsertParagraphSeparator) != 0); QVERIFY(page->action(QWebEnginePage::InsertLineSeparator) != 0); QVERIFY(page->action(QWebEnginePage::PasteAndMatchStyle) != 0); QVERIFY(page->action(QWebEnginePage::RemoveFormat) != 0); QVERIFY(page->action(QWebEnginePage::ToggleStrikethrough) != 0); QVERIFY(page->action(QWebEnginePage::ToggleSubscript) != 0); QVERIFY(page->action(QWebEnginePage::ToggleSuperscript) != 0); QVERIFY(page->action(QWebEnginePage::InsertUnorderedList) != 0); QVERIFY(page->action(QWebEnginePage::InsertOrderedList) != 0); QVERIFY(page->action(QWebEnginePage::Indent) != 0); QVERIFY(page->action(QWebEnginePage::Outdent) != 0); QVERIFY(page->action(QWebEnginePage::AlignCenter) != 0); QVERIFY(page->action(QWebEnginePage::AlignJustified) != 0); QVERIFY(page->action(QWebEnginePage::AlignLeft) != 0); QVERIFY(page->action(QWebEnginePage::AlignRight) != 0); // right now they are disabled because contentEditable is false QCOMPARE(page->action(QWebEnginePage::Cut)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::Paste)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::DeleteStartOfWord)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::DeleteEndOfWord)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::SetTextDirectionDefault)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::SetTextDirectionLeftToRight)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::SetTextDirectionRightToLeft)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::ToggleBold)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::ToggleItalic)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::ToggleUnderline)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::InsertParagraphSeparator)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::InsertLineSeparator)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::PasteAndMatchStyle)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::RemoveFormat)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::ToggleStrikethrough)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::ToggleSubscript)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::ToggleSuperscript)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::InsertUnorderedList)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::InsertOrderedList)->isEnabled(), false);
1541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610
QCOMPARE(page->action(QWebEnginePage::Indent)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::Outdent)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::AlignCenter)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::AlignJustified)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::AlignLeft)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::AlignRight)->isEnabled(), false); // Select everything page->triggerAction(QWebEnginePage::SelectAll); // make sure it is enabled since there is a selection QCOMPARE(page->action(QWebEnginePage::Copy)->isEnabled(), true); // make it editable before navigating the cursor page->setContentEditable(true); // clear the selection page->triggerAction(QWebEnginePage::MoveToStartOfDocument); QVERIFY(page->isSelectionCollapsed()); QCOMPARE(page->selectionStartOffset(), 0); // make sure it is disabled since there isn't a selection QCOMPARE(page->action(QWebEnginePage::Copy)->isEnabled(), false); // here the actions are enabled after contentEditable is true QCOMPARE(page->action(QWebEnginePage::Paste)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::DeleteStartOfWord)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::DeleteEndOfWord)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SetTextDirectionDefault)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SetTextDirectionLeftToRight)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::SetTextDirectionRightToLeft)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::ToggleBold)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::ToggleItalic)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::ToggleUnderline)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::InsertParagraphSeparator)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::InsertLineSeparator)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::PasteAndMatchStyle)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::ToggleStrikethrough)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::ToggleSubscript)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::ToggleSuperscript)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::InsertUnorderedList)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::InsertOrderedList)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::Indent)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::Outdent)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::AlignCenter)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::AlignJustified)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::AlignLeft)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::AlignRight)->isEnabled(), true); // make sure these are disabled since there isn't a selection QCOMPARE(page->action(QWebEnginePage::Cut)->isEnabled(), false); QCOMPARE(page->action(QWebEnginePage::RemoveFormat)->isEnabled(), false); // make sure everything is selected page->triggerAction(QWebEnginePage::SelectAll); // this is only true if there is an editable selection QCOMPARE(page->action(QWebEnginePage::Cut)->isEnabled(), true); QCOMPARE(page->action(QWebEnginePage::RemoveFormat)->isEnabled(), true); delete page; #endif } void tst_QWebEnginePage::requestCache() { TestPage page; QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); page.setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me</a>"));
1611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680
QTRY_COMPARE(loadSpy.count(), 1); QTRY_COMPARE(page.navigations.count(), 1); page.setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me2</a>")); QTRY_COMPARE(loadSpy.count(), 2); QTRY_COMPARE(page.navigations.count(), 2); page.triggerAction(QWebEnginePage::Stop); QVERIFY(page.history()->canGoBack()); page.triggerAction(QWebEnginePage::Back); QTRY_COMPARE(loadSpy.count(), 3); QTRY_COMPARE(page.navigations.count(), 3); QCOMPARE(page.navigations.at(0).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(), (int)QNetworkRequest::PreferNetwork); QCOMPARE(page.navigations.at(1).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(), (int)QNetworkRequest::PreferNetwork); QCOMPARE(page.navigations.at(2).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(), (int)QNetworkRequest::PreferCache); } void tst_QWebEnginePage::loadCachedPage() { #if !defined(QWEBENGINESETTINGS) QSKIP("QWEBENGINESETTINGS"); #else TestPage page; QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); page.settings()->setMaximumPagesInCache(3); page.load(QUrl("data:text/html,This is first page")); QTRY_COMPARE(loadSpy.count(), 1); QTRY_COMPARE(page.navigations.count(), 1); QUrl firstPageUrl = page.url(); page.load(QUrl("data:text/html,This is second page")); QTRY_COMPARE(loadSpy.count(), 2); QTRY_COMPARE(page.navigations.count(), 2); page.triggerAction(QWebEnginePage::Stop); QVERIFY(page.history()->canGoBack()); QSignalSpy urlSpy(&page, SIGNAL(urlChanged(QUrl))); QVERIFY(urlSpy.isValid()); page.triggerAction(QWebEnginePage::Back); ::waitForSignal(&page, SIGNAL(urlChanged(QUrl))); QCOMPARE(urlSpy.size(), 1); QList<QVariant> arguments1 = urlSpy.takeFirst(); QCOMPARE(arguments1.at(0).toUrl(), firstPageUrl); #endif } void tst_QWebEnginePage::backActionUpdate() { QWebEngineView view; QWebEnginePage *page = view.page(); QAction *action = page->action(QWebEnginePage::Back); QVERIFY(!action->isEnabled()); QSignalSpy loadSpy(page, SIGNAL(loadFinished(bool))); QUrl url = QUrl("qrc:///resources/framedindex.html"); page->load(url); QTRY_COMPARE(loadSpy.count(), 1); QVERIFY(!action->isEnabled()); QTest::mouseClick(&view, Qt::LeftButton, 0, QPoint(10, 10)); QTRY_COMPARE(loadSpy.count(), 2);
1681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750
QVERIFY(action->isEnabled()); } #if defined(QWEBENGINEFRAME) void frameAtHelper(QWebEnginePage* webPage, QWebEngineFrame* webFrame, QPoint framePosition) { if (!webFrame) return; framePosition += QPoint(webFrame->pos()); QList<QWebEngineFrame*> children = webFrame->childFrames(); for (int i = 0; i < children.size(); ++i) { if (children.at(i)->childFrames().size() > 0) frameAtHelper(webPage, children.at(i), framePosition); QRect frameRect(children.at(i)->pos() + framePosition, children.at(i)->geometry().size()); QVERIFY(children.at(i) == webPage->frameAt(frameRect.topLeft())); } } #endif void tst_QWebEnginePage::frameAt() { #if !defined(QWEBENGINEFRAME) QSKIP("QWEBENGINEFRAME"); #else QWebEngineView webView; QWebEnginePage* webPage = webView.page(); QSignalSpy loadSpy(webPage, SIGNAL(loadFinished(bool))); QUrl url = QUrl("qrc:///resources/iframe.html"); webPage->load(url); QTRY_COMPARE(loadSpy.count(), 1); frameAtHelper(webPage, webPage->mainFrame(), webPage->mainFrame()->pos()); #endif } void tst_QWebEnginePage::inputMethods_data() { QTest::addColumn<QString>("viewType"); QTest::newRow("QWebEngineView") << "QWebEngineView"; QTest::newRow("QGraphicsWebView") << "QGraphicsWebView"; } static Qt::InputMethodHints inputMethodHints(QObject* object) { if (QGraphicsObject* o = qobject_cast<QGraphicsObject*>(object)) return o->inputMethodHints(); if (QWidget* w = qobject_cast<QWidget*>(object)) return w->inputMethodHints(); return Qt::InputMethodHints(); } static bool inputMethodEnabled(QObject* object) { if (QGraphicsObject* o = qobject_cast<QGraphicsObject*>(object)) return o->flags() & QGraphicsItem::ItemAcceptsInputMethod; if (QWidget* w = qobject_cast<QWidget*>(object)) return w->testAttribute(Qt::WA_InputMethodEnabled); return false; } static void clickOnPage(QWebEnginePage* page, const QPoint& position) { QMouseEvent evpres(QEvent::MouseButtonPress, position, Qt::LeftButton, Qt::NoButton, Qt::NoModifier); page->event(&evpres); QMouseEvent evrel(QEvent::MouseButtonRelease, position, Qt::LeftButton, Qt::NoButton, Qt::NoModifier); page->event(&evrel); } void tst_QWebEnginePage::inputMethods()
1751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820
{ #if !defined(QWEBENGINEPAGE_INPUTMETHODQUERY) QSKIP("QWEBENGINEPAGE_INPUTMETHODQUERY"); #else QFETCH(QString, viewType); QWebEnginePage* page = new QWebEnginePage; QObject* view = 0; QObject* container = 0; if (viewType == "QWebEngineView") { QWebEngineView* wv = new QWebEngineView; wv->setPage(page); view = wv; container = view; } else if (viewType == "QGraphicsWebView") { QGraphicsWebView* wv = new QGraphicsWebView; wv->setPage(page); view = wv; QGraphicsView* gv = new QGraphicsView; QGraphicsScene* scene = new QGraphicsScene(gv); gv->setScene(scene); scene->addItem(wv); wv->setGeometry(QRect(0, 0, 500, 500)); container = gv; } else QVERIFY2(false, "Unknown view type"); page->settings()->setFontFamily(QWebEngineSettings::SerifFont, page->settings()->fontFamily(QWebEngineSettings::FixedFont)); page->setHtml("<html><body>" \ "<input type='text' id='input1' style='font-family: serif' value='' maxlength='20'/><br>" \ "<input type='password'/>" \ "</body></html>"); page->mainFrame()->setFocus(); TestInputContext testContext; QWebEngineElementCollection inputs = page->mainFrame()->documentElement().findAll("input"); QPoint textInputCenter = inputs.at(0).geometry().center(); clickOnPage(page, textInputCenter); // This part of the test checks if the SIP (Software Input Panel) is triggered, // which normally happens on mobile platforms, when a user input form receives // a mouse click. int inputPanel = 0; if (viewType == "QWebEngineView") { if (QWebEngineView* wv = qobject_cast<QWebEngineView*>(view)) inputPanel = wv->style()->styleHint(QStyle::SH_RequestSoftwareInputPanel); } else if (viewType == "QGraphicsWebView") { if (QGraphicsWebView* wv = qobject_cast<QGraphicsWebView*>(view)) inputPanel = wv->style()->styleHint(QStyle::SH_RequestSoftwareInputPanel); } // For non-mobile platforms RequestSoftwareInputPanel event is not called // because there is no SIP (Software Input Panel) triggered. In the case of a // mobile platform, an input panel, e.g. virtual keyboard, is usually invoked // and the RequestSoftwareInputPanel event is called. For these two situations // this part of the test can verified as the checks below. if (inputPanel) QVERIFY(testContext.isInputPanelVisible()); else QVERIFY(!testContext.isInputPanelVisible()); testContext.hideInputPanel(); clickOnPage(page, textInputCenter); QVERIFY(testContext.isInputPanelVisible()); //ImMicroFocus QVariant variant = page->inputMethodQuery(Qt::ImMicroFocus);
1821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890
QVERIFY(inputs.at(0).geometry().contains(variant.toRect().topLeft())); // We assigned the serif font famility to be the same as the fixef font family. // Then test ImFont on a serif styled element, we should get our fixef font family. variant = page->inputMethodQuery(Qt::ImFont); QFont font = variant.value<QFont>(); QCOMPARE(page->settings()->fontFamily(QWebEngineSettings::FixedFont), font.family()); QList<QInputMethodEvent::Attribute> inputAttributes; //Insert text. { QInputMethodEvent eventText("QtWebEngine", inputAttributes); QSignalSpy signalSpy(page, SIGNAL(microFocusChanged())); page->event(&eventText); QCOMPARE(signalSpy.count(), 0); } { QInputMethodEvent eventText("", inputAttributes); eventText.setCommitString(QString("QtWebEngine"), 0, 0); page->event(&eventText); } //ImMaximumTextLength variant = page->inputMethodQuery(Qt::ImMaximumTextLength); QCOMPARE(20, variant.toInt()); //Set selection inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 3, 2, QVariant()); QInputMethodEvent eventSelection("",inputAttributes); page->event(&eventSelection); //ImAnchorPosition variant = page->inputMethodQuery(Qt::ImAnchorPosition); int anchorPosition = variant.toInt(); QCOMPARE(anchorPosition, 3); //ImCursorPosition variant = page->inputMethodQuery(Qt::ImCursorPosition); int cursorPosition = variant.toInt(); QCOMPARE(cursorPosition, 5); //ImCurrentSelection variant = page->inputMethodQuery(Qt::ImCurrentSelection); QString selectionValue = variant.value<QString>(); QCOMPARE(selectionValue, QString("eb")); //Set selection with negative length inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 6, -5, QVariant()); QInputMethodEvent eventSelection3("",inputAttributes); page->event(&eventSelection3); //ImAnchorPosition variant = page->inputMethodQuery(Qt::ImAnchorPosition); anchorPosition = variant.toInt(); QCOMPARE(anchorPosition, 1); //ImCursorPosition variant = page->inputMethodQuery(Qt::ImCursorPosition); cursorPosition = variant.toInt(); QCOMPARE(cursorPosition, 6); //ImCurrentSelection variant = page->inputMethodQuery(Qt::ImCurrentSelection); selectionValue = variant.value<QString>(); QCOMPARE(selectionValue, QString("tWebK")); //ImSurroundingText variant = page->inputMethodQuery(Qt::ImSurroundingText);
1891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960
QString value = variant.value<QString>(); QCOMPARE(value, QString("QtWebEngine")); { QList<QInputMethodEvent::Attribute> attributes; // Clear the selection, so the next test does not clear any contents. QInputMethodEvent::Attribute newSelection(QInputMethodEvent::Selection, 0, 0, QVariant()); attributes.append(newSelection); QInputMethodEvent event("composition", attributes); page->event(&event); } // A ongoing composition should not change the surrounding text before it is committed. variant = page->inputMethodQuery(Qt::ImSurroundingText); value = variant.value<QString>(); QCOMPARE(value, QString("QtWebEngine")); // Cancel current composition first inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 0, 0, QVariant()); QInputMethodEvent eventSelection4("", inputAttributes); page->event(&eventSelection4); // START - Tests for Selection when the Editor is NOT in Composition mode // LEFT to RIGHT selection // Deselect the selection by sending MouseButtonPress events // This moves the current cursor to the end of the text clickOnPage(page, textInputCenter); { QList<QInputMethodEvent::Attribute> attributes; QInputMethodEvent event(QString(), attributes); event.setCommitString("XXX", 0, 0); page->event(&event); event.setCommitString(QString(), -2, 2); // Erase two characters. page->event(&event); event.setCommitString(QString(), -1, 1); // Erase one character. page->event(&event); variant = page->inputMethodQuery(Qt::ImSurroundingText); value = variant.value<QString>(); QCOMPARE(value, QString("QtWebEngine")); } //Move to the start of the line page->triggerAction(QWebEnginePage::MoveToStartOfLine); QKeyEvent keyRightEventPress(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier); QKeyEvent keyRightEventRelease(QEvent::KeyRelease, Qt::Key_Right, Qt::NoModifier); //Move 2 characters RIGHT for (int j = 0; j < 2; ++j) { page->event(&keyRightEventPress); page->event(&keyRightEventRelease); } //Select to the end of the line page->triggerAction(QWebEnginePage::SelectEndOfLine); //ImAnchorPosition QtWebEngine variant = page->inputMethodQuery(Qt::ImAnchorPosition); anchorPosition = variant.toInt(); QCOMPARE(anchorPosition, 2); //ImCursorPosition variant = page->inputMethodQuery(Qt::ImCursorPosition); cursorPosition = variant.toInt(); QCOMPARE(cursorPosition, 8); //ImCurrentSelection variant = page->inputMethodQuery(Qt::ImCurrentSelection);
1961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030
selectionValue = variant.value<QString>(); QCOMPARE(selectionValue, QString("WebKit")); //RIGHT to LEFT selection //Deselect the selection (this moves the current cursor to the end of the text) clickOnPage(page, textInputCenter); //ImAnchorPosition variant = page->inputMethodQuery(Qt::ImAnchorPosition); anchorPosition = variant.toInt(); QCOMPARE(anchorPosition, 8); //ImCursorPosition variant = page->inputMethodQuery(Qt::ImCursorPosition); cursorPosition = variant.toInt(); QCOMPARE(cursorPosition, 8); //ImCurrentSelection variant = page->inputMethodQuery(Qt::ImCurrentSelection); selectionValue = variant.value<QString>(); QCOMPARE(selectionValue, QString("")); QKeyEvent keyLeftEventPress(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier); QKeyEvent keyLeftEventRelease(QEvent::KeyRelease, Qt::Key_Left, Qt::NoModifier); //Move 2 characters LEFT for (int i = 0; i < 2; ++i) { page->event(&keyLeftEventPress); page->event(&keyLeftEventRelease); } //Select to the start of the line page->triggerAction(QWebEnginePage::SelectStartOfLine); //ImAnchorPosition variant = page->inputMethodQuery(Qt::ImAnchorPosition); anchorPosition = variant.toInt(); QCOMPARE(anchorPosition, 6); //ImCursorPosition variant = page->inputMethodQuery(Qt::ImCursorPosition); cursorPosition = variant.toInt(); QCOMPARE(cursorPosition, 0); //ImCurrentSelection variant = page->inputMethodQuery(Qt::ImCurrentSelection); selectionValue = variant.value<QString>(); QCOMPARE(selectionValue, QString("QtWebK")); //END - Tests for Selection when the Editor is not in Composition mode //ImhHiddenText QPoint passwordInputCenter = inputs.at(1).geometry().center(); clickOnPage(page, passwordInputCenter); QVERIFY(inputMethodEnabled(view)); QVERIFY(inputMethodHints(view) & Qt::ImhHiddenText); clickOnPage(page, textInputCenter); QVERIFY(!(inputMethodHints(view) & Qt::ImhHiddenText)); page->setHtml("<html><body><p>nothing to input here"); testContext.hideInputPanel(); QWebEngineElement para = page->mainFrame()->findFirstElement("p"); clickOnPage(page, para.geometry().center()); QVERIFY(!testContext.isInputPanelVisible()); //START - Test for sending empty QInputMethodEvent
2031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100
page->setHtml("<html><body>" \ "<input type='text' id='input3' value='QtWebEngine2'/>" \ "</body></html>"); evaluateJavaScriptSync(page, "var inputEle = document.getElementById('input3'); inputEle.focus(); inputEle.select();"); //Send empty QInputMethodEvent QInputMethodEvent emptyEvent; page->event(&emptyEvent); QString inputValue = evaluateJavaScriptSync(page, "document.getElementById('input3').value").toString(); QCOMPARE(inputValue, QString("QtWebEngine2")); //END - Test for sending empty QInputMethodEvent page->setHtml("<html><body>" \ "<input type='text' id='input4' value='QtWebEngine inputMethod'/>" \ "</body></html>"); evaluateJavaScriptSync(page, "var inputEle = document.getElementById('input4'); inputEle.focus(); inputEle.select();"); // Clear the selection, also cancel the ongoing composition if there is one. { QList<QInputMethodEvent::Attribute> attributes; QInputMethodEvent::Attribute newSelection(QInputMethodEvent::Selection, 0, 0, QVariant()); attributes.append(newSelection); QInputMethodEvent event("", attributes); page->event(&event); } // ImCurrentSelection variant = page->inputMethodQuery(Qt::ImCurrentSelection); selectionValue = variant.value<QString>(); QCOMPARE(selectionValue, QString("")); variant = page->inputMethodQuery(Qt::ImSurroundingText); QString surroundingValue = variant.value<QString>(); QCOMPARE(surroundingValue, QString("QtWebEngine inputMethod")); // ImAnchorPosition variant = page->inputMethodQuery(Qt::ImAnchorPosition); anchorPosition = variant.toInt(); QCOMPARE(anchorPosition, 0); // ImCursorPosition variant = page->inputMethodQuery(Qt::ImCursorPosition); cursorPosition = variant.toInt(); QCOMPARE(cursorPosition, 0); // 1. Insert a character to the beginning of the line. // Send temporary text, which makes the editor has composition 'm'. { QList<QInputMethodEvent::Attribute> attributes; QInputMethodEvent event("m", attributes); page->event(&event); } // ImCurrentSelection variant = page->inputMethodQuery(Qt::ImCurrentSelection); selectionValue = variant.value<QString>(); QCOMPARE(selectionValue, QString("")); // ImSurroundingText variant = page->inputMethodQuery(Qt::ImSurroundingText); surroundingValue = variant.value<QString>(); QCOMPARE(surroundingValue, QString("QtWebEngine inputMethod")); // ImCursorPosition variant = page->inputMethodQuery(Qt::ImCursorPosition); cursorPosition = variant.toInt(); QCOMPARE(cursorPosition, 0); // ImAnchorPosition
2101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170
variant = page->inputMethodQuery(Qt::ImAnchorPosition); anchorPosition = variant.toInt(); QCOMPARE(anchorPosition, 0); // Send temporary text, which makes the editor has composition 'n'. { QList<QInputMethodEvent::Attribute> attributes; QInputMethodEvent event("n", attributes); page->event(&event); } // ImCurrentSelection variant = page->inputMethodQuery(Qt::ImCurrentSelection); selectionValue = variant.value<QString>(); QCOMPARE(selectionValue, QString("")); // ImSurroundingText variant = page->inputMethodQuery(Qt::ImSurroundingText); surroundingValue = variant.value<QString>(); QCOMPARE(surroundingValue, QString("QtWebEngine inputMethod")); // ImCursorPosition variant = page->inputMethodQuery(Qt::ImCursorPosition); cursorPosition = variant.toInt(); QCOMPARE(cursorPosition, 0); // ImAnchorPosition variant = page->inputMethodQuery(Qt::ImAnchorPosition); anchorPosition = variant.toInt(); QCOMPARE(anchorPosition, 0); // Send commit text, which makes the editor conforms composition. { QList<QInputMethodEvent::Attribute> attributes; QInputMethodEvent event("", attributes); event.setCommitString("o"); page->event(&event); } // ImCurrentSelection variant = page->inputMethodQuery(Qt::ImCurrentSelection); selectionValue = variant.value<QString>(); QCOMPARE(selectionValue, QString("")); // ImSurroundingText variant = page->inputMethodQuery(Qt::ImSurroundingText); surroundingValue = variant.value<QString>(); QCOMPARE(surroundingValue, QString("oQtWebEngine inputMethod")); // ImCursorPosition variant = page->inputMethodQuery(Qt::ImCursorPosition); cursorPosition = variant.toInt(); QCOMPARE(cursorPosition, 1); // ImAnchorPosition variant = page->inputMethodQuery(Qt::ImAnchorPosition); anchorPosition = variant.toInt(); QCOMPARE(anchorPosition, 1); // 2. insert a character to the middle of the line. // Send temporary text, which makes the editor has composition 'd'. { QList<QInputMethodEvent::Attribute> attributes; QInputMethodEvent event("d", attributes); page->event(&event); } // ImCurrentSelection variant = page->inputMethodQuery(Qt::ImCurrentSelection); selectionValue = variant.value<QString>();
2171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240
QCOMPARE(selectionValue, QString("")); // ImSurroundingText variant = page->inputMethodQuery(Qt::ImSurroundingText); surroundingValue = variant.value<QString>(); QCOMPARE(surroundingValue, QString("oQtWebEngine inputMethod")); // ImCursorPosition variant = page->inputMethodQuery(Qt::ImCursorPosition); cursorPosition = variant.toInt(); QCOMPARE(cursorPosition, 1); // ImAnchorPosition variant = page->inputMethodQuery(Qt::ImAnchorPosition); anchorPosition = variant.toInt(); QCOMPARE(anchorPosition, 1); // Send commit text, which makes the editor conforms composition. { QList<QInputMethodEvent::Attribute> attributes; QInputMethodEvent event("", attributes); event.setCommitString("e"); page->event(&event); } // ImCurrentSelection variant = page->inputMethodQuery(Qt::ImCurrentSelection); selectionValue = variant.value<QString>(); QCOMPARE(selectionValue, QString("")); // ImSurroundingText variant = page->inputMethodQuery(Qt::ImSurroundingText); surroundingValue = variant.value<QString>(); QCOMPARE(surroundingValue, QString("oeQtWebEngine inputMethod")); // ImCursorPosition variant = page->inputMethodQuery(Qt::ImCursorPosition); cursorPosition = variant.toInt(); QCOMPARE(cursorPosition, 2); // ImAnchorPosition variant = page->inputMethodQuery(Qt::ImAnchorPosition); anchorPosition = variant.toInt(); QCOMPARE(anchorPosition, 2); // 3. Insert a character to the end of the line. page->triggerAction(QWebEnginePage::MoveToEndOfLine); // Send temporary text, which makes the editor has composition 't'. { QList<QInputMethodEvent::Attribute> attributes; QInputMethodEvent event("t", attributes); page->event(&event); } // ImCurrentSelection variant = page->inputMethodQuery(Qt::ImCurrentSelection); selectionValue = variant.value<QString>(); QCOMPARE(selectionValue, QString("")); // ImSurroundingText variant = page->inputMethodQuery(Qt::ImSurroundingText); surroundingValue = variant.value<QString>(); QCOMPARE(surroundingValue, QString("oeQtWebEngine inputMethod")); // ImCursorPosition variant = page->inputMethodQuery(Qt::ImCursorPosition); cursorPosition = variant.toInt(); QCOMPARE(cursorPosition, 22);
2241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310
// ImAnchorPosition variant = page->inputMethodQuery(Qt::ImAnchorPosition); anchorPosition = variant.toInt(); QCOMPARE(anchorPosition, 22); // Send commit text, which makes the editor conforms composition. { QList<QInputMethodEvent::Attribute> attributes; QInputMethodEvent event("", attributes); event.setCommitString("t"); page->event(&event); } // ImCurrentSelection variant = page->inputMethodQuery(Qt::ImCurrentSelection); selectionValue = variant.value<QString>(); QCOMPARE(selectionValue, QString("")); // ImSurroundingText variant = page->inputMethodQuery(Qt::ImSurroundingText); surroundingValue = variant.value<QString>(); QCOMPARE(surroundingValue, QString("oeQtWebEngine inputMethodt")); // ImCursorPosition variant = page->inputMethodQuery(Qt::ImCursorPosition); cursorPosition = variant.toInt(); QCOMPARE(cursorPosition, 23); // ImAnchorPosition variant = page->inputMethodQuery(Qt::ImAnchorPosition); anchorPosition = variant.toInt(); QCOMPARE(anchorPosition, 23); // 4. Replace the selection. page->triggerAction(QWebEnginePage::SelectPreviousWord); // ImCurrentSelection variant = page->inputMethodQuery(Qt::ImCurrentSelection); selectionValue = variant.value<QString>(); QCOMPARE(selectionValue, QString("inputMethodt")); // ImSurroundingText variant = page->inputMethodQuery(Qt::ImSurroundingText); surroundingValue = variant.value<QString>(); QCOMPARE(surroundingValue, QString("oeQtWebEngine inputMethodt")); // ImCursorPosition variant = page->inputMethodQuery(Qt::ImCursorPosition); cursorPosition = variant.toInt(); QCOMPARE(cursorPosition, 11); // ImAnchorPosition variant = page->inputMethodQuery(Qt::ImAnchorPosition); anchorPosition = variant.toInt(); QCOMPARE(anchorPosition, 23); // Send temporary text, which makes the editor has composition 'w'. { QList<QInputMethodEvent::Attribute> attributes; QInputMethodEvent event("w", attributes); page->event(&event); } // ImCurrentSelection variant = page->inputMethodQuery(Qt::ImCurrentSelection); selectionValue = variant.value<QString>(); QCOMPARE(selectionValue, QString("")); // ImSurroundingText variant = page->inputMethodQuery(Qt::ImSurroundingText);
2311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380
surroundingValue = variant.value<QString>(); QCOMPARE(surroundingValue, QString("oeQtWebEngine ")); // ImCursorPosition variant = page->inputMethodQuery(Qt::ImCursorPosition); cursorPosition = variant.toInt(); QCOMPARE(cursorPosition, 11); // ImAnchorPosition variant = page->inputMethodQuery(Qt::ImAnchorPosition); anchorPosition = variant.toInt(); QCOMPARE(anchorPosition, 11); // Send commit text, which makes the editor conforms composition. { QList<QInputMethodEvent::Attribute> attributes; QInputMethodEvent event("", attributes); event.setCommitString("2"); page->event(&event); } // ImCurrentSelection variant = page->inputMethodQuery(Qt::ImCurrentSelection); selectionValue = variant.value<QString>(); QCOMPARE(selectionValue, QString("")); // ImSurroundingText variant = page->inputMethodQuery(Qt::ImSurroundingText); surroundingValue = variant.value<QString>(); QCOMPARE(surroundingValue, QString("oeQtWebEngine 2")); // ImCursorPosition variant = page->inputMethodQuery(Qt::ImCursorPosition); cursorPosition = variant.toInt(); QCOMPARE(cursorPosition, 12); // ImAnchorPosition variant = page->inputMethodQuery(Qt::ImAnchorPosition); anchorPosition = variant.toInt(); QCOMPARE(anchorPosition, 12); // Check sending RequestSoftwareInputPanel event page->setHtml("<html><body>" \ "<input type='text' id='input5' value='QtWebEngine inputMethod'/>" \ "<div id='btnDiv' onclick='i=document.getElementById(&quot;input5&quot;); i.focus();'>abc</div>"\ "</body></html>"); QWebEngineElement inputElement = page->mainFrame()->findFirstElement("div"); clickOnPage(page, inputElement.geometry().center()); QVERIFY(!testContext.isInputPanelVisible()); // START - Newline test for textarea qApp->processEvents(); page->setHtml("<html><body>" \ "<textarea rows='5' cols='1' id='input5' value=''/>" \ "</body></html>"); evaluateJavaScriptSync(page, "var inputEle = document.getElementById('input5'); inputEle.focus(); inputEle.select();"); // Enter Key without key text QKeyEvent keyEnter(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier); page->event(&keyEnter); QList<QInputMethodEvent::Attribute> attribs; QInputMethodEvent eventText(QString(), attribs); eventText.setCommitString("\n"); page->event(&eventText); QInputMethodEvent eventText2(QString(), attribs); eventText2.setCommitString("third line"); page->event(&eventText2);
2381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450
qApp->processEvents(); QString inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); QCOMPARE(inputValue2, QString("\n\nthird line")); // Enter Key with key text '\r' evaluateJavaScriptSync(page, "var inputEle = document.getElementById('input5'); inputEle.value = ''; inputEle.focus(); inputEle.select();"); inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); QCOMPARE(inputValue2, QString("")); QKeyEvent keyEnterWithCarriageReturn(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier, "\r"); page->event(&keyEnterWithCarriageReturn); page->event(&eventText); page->event(&eventText2); qApp->processEvents(); inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); QCOMPARE(inputValue2, QString("\n\nthird line")); // Enter Key with key text '\n' page->runJavaScript("var inputEle = document.getElementById('input5'); inputEle.value = ''; inputEle.focus(); inputEle.select();"); inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); QCOMPARE(inputValue2, QString("")); QKeyEvent keyEnterWithLineFeed(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier, "\n"); page->event(&keyEnterWithLineFeed); page->event(&eventText); page->event(&eventText2); qApp->processEvents(); inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); QCOMPARE(inputValue2, QString("\n\nthird line")); // Enter Key with key text "\n\r" page->runJavaScript("var inputEle = document.getElementById('input5'); inputEle.value = ''; inputEle.focus(); inputEle.select();"); inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); QCOMPARE(inputValue2, QString("")); QKeyEvent keyEnterWithLFCR(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier, "\n\r"); page->event(&keyEnterWithLFCR); page->event(&eventText); page->event(&eventText2); qApp->processEvents(); inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); QCOMPARE(inputValue2, QString("\n\nthird line")); // Return Key without key text page->runJavaScript("var inputEle = document.getElementById('input5'); inputEle.value = ''; inputEle.focus(); inputEle.select();"); inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); QCOMPARE(inputValue2, QString("")); QKeyEvent keyReturn(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier); page->event(&keyReturn); page->event(&eventText); page->event(&eventText2); qApp->processEvents(); inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); QCOMPARE(inputValue2, QString("\n\nthird line")); // END - Newline test for textarea delete container; #endif } void tst_QWebEnginePage::inputMethodsTextFormat_data() { QTest::addColumn<QString>("string");
2451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520
QTest::addColumn<int>("start"); QTest::addColumn<int>("length"); QTest::newRow("") << QString("") << 0 << 0; QTest::newRow("Q") << QString("Q") << 0 << 1; QTest::newRow("Qt") << QString("Qt") << 0 << 1; QTest::newRow("Qt") << QString("Qt") << 0 << 2; QTest::newRow("Qt") << QString("Qt") << 1 << 1; QTest::newRow("Qt ") << QString("Qt ") << 0 << 1; QTest::newRow("Qt ") << QString("Qt ") << 1 << 1; QTest::newRow("Qt ") << QString("Qt ") << 2 << 1; QTest::newRow("Qt ") << QString("Qt ") << 2 << -1; QTest::newRow("Qt ") << QString("Qt ") << -2 << 3; QTest::newRow("Qt ") << QString("Qt ") << 0 << 3; QTest::newRow("Qt by") << QString("Qt by") << 0 << 1; QTest::newRow("Qt by Nokia") << QString("Qt by Nokia") << 0 << 1; } void tst_QWebEnginePage::inputMethodsTextFormat() { #if !defined(QINPUTMETHODEVENT_TEXTFORMAT) QSKIP("QINPUTMETHODEVENT_TEXTFORMAT"); #else QWebEnginePage* page = new QWebEnginePage; QWebEngineView* view = new QWebEngineView; view->setPage(page); page->settings()->setFontFamily(QWebEngineSettings::SerifFont, "FooSerifFont"); page->setHtml("<html><body>" \ "<input type='text' id='input1' style='font-family: serif' value='' maxlength='20'/>"); evaluateJavaScriptSync(page, "document.getElementById('input1').focus()"); page->mainFrame()->setFocus(); view->show(); QFETCH(QString, string); QFETCH(int, start); QFETCH(int, length); QList<QInputMethodEvent::Attribute> attrs; QTextCharFormat format; format.setUnderlineStyle(QTextCharFormat::SingleUnderline); format.setUnderlineColor(Qt::red); attrs.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, start, length, format)); QInputMethodEvent im(string, attrs); page->event(&im); QTest::qWait(1000); delete view; #endif } void tst_QWebEnginePage::protectBindingsRuntimeObjectsFromCollector() { #if !defined(QWEBENGINEPAGE_CREATEPLUGIN) QSKIP("QWEBENGINEPAGE_CREATEPLUGIN"); #else QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool))); PluginPage* newPage = new PluginPage(m_view); m_view->setPage(newPage); m_view->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true); m_view->setHtml(QString("<html><body><object type='application/x-qt-plugin' classid='lineedit' id='mylineedit'/></body></html>")); QTRY_COMPARE(loadSpy.count(), 1); newPage->runJavaScript("function testme(text) { var lineedit = document.getElementById('mylineedit'); lineedit.setText(text); lineedit.selectAll(); }"); evaluateJavaScriptSync(newPage, "testme('foo')");
2521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590
DumpRenderTreeSupportQt::garbageCollectorCollect(); // don't crash! evaluateJavaScriptSync(newPage, "testme('bar')"); #endif } void tst_QWebEnginePage::localURLSchemes() { #if !defined(QWEBENGINESECURITYORIGIN) QSKIP("QWEBENGINESECURITYORIGIN"); #else int i = QWebEngineSecurityOrigin::localSchemes().size(); QWebEngineSecurityOrigin::removeLocalScheme("file"); QTRY_COMPARE(QWebEngineSecurityOrigin::localSchemes().size(), i); QWebEngineSecurityOrigin::addLocalScheme("file"); QTRY_COMPARE(QWebEngineSecurityOrigin::localSchemes().size(), i); QWebEngineSecurityOrigin::removeLocalScheme("qrc"); QTRY_COMPARE(QWebEngineSecurityOrigin::localSchemes().size(), i - 1); QWebEngineSecurityOrigin::addLocalScheme("qrc"); QTRY_COMPARE(QWebEngineSecurityOrigin::localSchemes().size(), i); QString myscheme = "myscheme"; QWebEngineSecurityOrigin::addLocalScheme(myscheme); QTRY_COMPARE(QWebEngineSecurityOrigin::localSchemes().size(), i + 1); QVERIFY(QWebEngineSecurityOrigin::localSchemes().contains(myscheme)); QWebEngineSecurityOrigin::removeLocalScheme(myscheme); QTRY_COMPARE(QWebEngineSecurityOrigin::localSchemes().size(), i); QWebEngineSecurityOrigin::removeLocalScheme(myscheme); QTRY_COMPARE(QWebEngineSecurityOrigin::localSchemes().size(), i); #endif } #if defined(QWEBENGINEPAGE_SETTINGS) static inline bool testFlag(QWebEnginePage& webPage, QWebEngineSettings::WebAttribute settingAttribute, const QString& jsObjectName, bool settingValue) { webPage.settings()->setAttribute(settingAttribute, settingValue); return evaluateJavaScriptSync(&webPage, QString("(window.%1 != undefined)").arg(jsObjectName)).toBool(); } #endif void tst_QWebEnginePage::testOptionalJSObjects() { #if !defined(QWEBENGINESETTINGS) QSKIP("QWEBENGINSETTINGS"); #else // Once a feature is enabled and the JS object is accessed turning off the setting will not turn off // the visibility of the JS object any more. For this reason this test uses two QWebEnginePage instances. // Part of the test is to make sure that the QWebEnginePage instances do not interfere with each other so turning on // a feature for one instance will not turn it on for another. QWebEnginePage webPage1; QWebEnginePage webPage2; webPage1.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("http://www.example.com/")); webPage2.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("http://www.example.com/")); QEXPECT_FAIL("","Feature enabled/disabled checking problem. Look at bugs.webkit.org/show_bug.cgi?id=29867", Continue); QCOMPARE(testFlag(webPage1, QWebEngineSettings::OfflineWebApplicationCacheEnabled, "applicationCache", false), false); QCOMPARE(testFlag(webPage2, QWebEngineSettings::OfflineWebApplicationCacheEnabled, "applicationCache", true), true); QEXPECT_FAIL("","Feature enabled/disabled checking problem. Look at bugs.webkit.org/show_bug.cgi?id=29867", Continue); QCOMPARE(testFlag(webPage1, QWebEngineSettings::OfflineWebApplicationCacheEnabled, "applicationCache", false), false); QCOMPARE(testFlag(webPage2, QWebEngineSettings::OfflineWebApplicationCacheEnabled, "applicationCache", false), true); QCOMPARE(testFlag(webPage1, QWebEngineSettings::LocalStorageEnabled, "localStorage", false), false); QCOMPARE(testFlag(webPage2, QWebEngineSettings::LocalStorageEnabled, "localStorage", true), true); QCOMPARE(testFlag(webPage1, QWebEngineSettings::LocalStorageEnabled, "localStorage", false), false);
2591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660
QCOMPARE(testFlag(webPage2, QWebEngineSettings::LocalStorageEnabled, "localStorage", false), true); #endif } #if defined(QWEBENGINEPAGE_SETTINGS) static inline bool checkLocalStorageVisibility(QWebEnginePage& webPage, bool localStorageEnabled) { webPage.settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, localStorageEnabled); return evaluateJavaScriptSync(&webPage, QString("(window.localStorage != undefined)")).toBool(); } #endif void tst_QWebEnginePage::testLocalStorageVisibility() { #if !defined(QWEBENGINEPAGE_SETTINGS) QSKIP("QWEBENGINEPAGE_SETTINGS"); #else // Local storage's visibility depends on its security origin, which depends on base url. // Initially, it will test it with base urls that get a globally unique origin, which may not // be able to use local storage even if the feature is enabled. Then later the same test is // done but with urls that would get a valid origin, so local storage could be used. // Before every test case it checks if local storage is not already visible. QWebEnginePage webPage; webPage.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl()); QCOMPARE(checkLocalStorageVisibility(webPage, false), false); QCOMPARE(checkLocalStorageVisibility(webPage, true), false); webPage.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("invalid")); QCOMPARE(checkLocalStorageVisibility(webPage, false), false); QCOMPARE(checkLocalStorageVisibility(webPage, true), false); webPage.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("://misparsed.com")); QCOMPARE(checkLocalStorageVisibility(webPage, false), false); QCOMPARE(checkLocalStorageVisibility(webPage, true), false); webPage.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("http://")); QCOMPARE(checkLocalStorageVisibility(webPage, false), false); QCOMPARE(checkLocalStorageVisibility(webPage, true), false); webPage.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("about:blank")); QCOMPARE(checkLocalStorageVisibility(webPage, false), false); QCOMPARE(checkLocalStorageVisibility(webPage, true), false); webPage.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("data:text/html,test")); QCOMPARE(checkLocalStorageVisibility(webPage, false), false); QCOMPARE(checkLocalStorageVisibility(webPage, true), false); webPage.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("file:///")); QCOMPARE(checkLocalStorageVisibility(webPage, false), false); QCOMPARE(checkLocalStorageVisibility(webPage, true), true); webPage.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("http://www.example.com")); QCOMPARE(checkLocalStorageVisibility(webPage, false), false); QCOMPARE(checkLocalStorageVisibility(webPage, true), true); webPage.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("https://www.example.com")); QCOMPARE(checkLocalStorageVisibility(webPage, false), false); QCOMPARE(checkLocalStorageVisibility(webPage, true), true);
2661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730
webPage.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("ftp://files.example.com")); QCOMPARE(checkLocalStorageVisibility(webPage, false), false); QCOMPARE(checkLocalStorageVisibility(webPage, true), true); webPage.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl("file:///path/to/index.html")); QCOMPARE(checkLocalStorageVisibility(webPage, false), false); QCOMPARE(checkLocalStorageVisibility(webPage, true), true); #endif } void tst_QWebEnginePage::testEnablePersistentStorage() { #if !defined(QWEBENGINESETTINGS) QSKIP("QWEBENGINESETTINGS"); #else QWebEnginePage webPage; // By default all persistent options should be disabled QCOMPARE(webPage.settings()->testAttribute(QWebEngineSettings::LocalStorageEnabled), false); QCOMPARE(webPage.settings()->testAttribute(QWebEngineSettings::OfflineStorageDatabaseEnabled), false); QCOMPARE(webPage.settings()->testAttribute(QWebEngineSettings::OfflineWebApplicationCacheEnabled), false); QVERIFY(webPage.settings()->iconDatabasePath().isEmpty()); QWebEngineSettings::enablePersistentStorage(); QTRY_COMPARE(webPage.settings()->testAttribute(QWebEngineSettings::LocalStorageEnabled), true); QTRY_COMPARE(webPage.settings()->testAttribute(QWebEngineSettings::OfflineStorageDatabaseEnabled), true); QTRY_COMPARE(webPage.settings()->testAttribute(QWebEngineSettings::OfflineWebApplicationCacheEnabled), true); QTRY_VERIFY(!webPage.settings()->offlineStoragePath().isEmpty()); QTRY_VERIFY(!webPage.settings()->offlineWebApplicationCachePath().isEmpty()); QTRY_VERIFY(!webPage.settings()->iconDatabasePath().isEmpty()); #endif } void tst_QWebEnginePage::defaultTextEncoding() { #if !defined(QWEBENGINESETTINGS_SETDEFAULTTEXTENCODING) QSKIP("QWEBENGINESETTINGS_SETDEFAULTTEXTENCODING"); #else QString defaultCharset = evaluateJavaScriptSync(m_page, "document.defaultCharset").toString(); QVERIFY(!defaultCharset.isEmpty()); QCOMPARE(QWebEngineSettings::globalSettings()->defaultTextEncoding(), defaultCharset); m_page->settings()->setDefaultTextEncoding(QString("utf-8")); QString charset = evaluateJavaScriptSync(m_page, "document.defaultCharset").toString(); QCOMPARE(charset, QString("utf-8")); QCOMPARE(m_page->settings()->defaultTextEncoding(), charset); m_page->settings()->setDefaultTextEncoding(QString()); charset = evaluateJavaScriptSync(m_page, "document.defaultCharset").toString(); QVERIFY(!charset.isEmpty()); QCOMPARE(charset, defaultCharset); QWebEngineSettings::globalSettings()->setDefaultTextEncoding(QString("utf-8")); charset = evaluateJavaScriptSync(m_page, "document.defaultCharset").toString(); QCOMPARE(charset, QString("utf-8")); QCOMPARE(QWebEngineSettings::globalSettings()->defaultTextEncoding(), charset); #endif } class ErrorPage : public QWebEnginePage { public: ErrorPage(QWidget* parent = 0): QWebEnginePage(parent)
2731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800
{ } virtual bool supportsExtension(Extension extension) const { return extension == ErrorPageExtension; } virtual bool extension(Extension, const ExtensionOption* option, ExtensionReturn* output) { ErrorPageExtensionReturn* errorPage = static_cast<ErrorPageExtensionReturn*>(output); errorPage->contentType = "text/html"; errorPage->content = "error"; return true; } }; void tst_QWebEnginePage::errorPageExtension() { #if !defined(QWEBENGINEPAGE_ERRORPAGEEXTENSION) QSKIP("QWEBENGINEPAGE_ERRORPAGEEXTENSION"); #else ErrorPage page; m_view->setPage(&page); QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool))); m_view->setUrl(QUrl("data:text/html,foo")); QTRY_COMPARE(spyLoadFinished.count(), 1); page.setUrl(QUrl("http://non.existent/url")); QTRY_COMPARE(spyLoadFinished.count(), 2); QCOMPARE(toPlainTextSync(&page), QString("error")); QCOMPARE(page.history()->count(), 2); QCOMPARE(page.history()->currentItem().url(), QUrl("http://non.existent/url")); QCOMPARE(page.history()->canGoBack(), true); QCOMPARE(page.history()->canGoForward(), false); page.triggerAction(QWebEnginePage::Back); QTRY_COMPARE(page.history()->canGoBack(), false); QTRY_COMPARE(page.history()->canGoForward(), true); page.triggerAction(QWebEnginePage::Forward); QTRY_COMPARE(page.history()->canGoBack(), true); QTRY_COMPARE(page.history()->canGoForward(), false); page.triggerAction(QWebEnginePage::Back); QTRY_COMPARE(page.history()->canGoBack(), false); QTRY_COMPARE(page.history()->canGoForward(), true); QTRY_COMPARE(page.history()->currentItem().url(), QUrl("data:text/html,foo")); m_view->setPage(0); #endif } void tst_QWebEnginePage::errorPageExtensionInIFrames() { #if !defined(QWEBENGINEFRAME) QSKIP("QWEBENGINEFRAME"); #else ErrorPage page; m_view->setPage(&page); m_view->page()->load(QUrl( "data:text/html," "<h1>h1</h1>" "<iframe src='data:text/html,<p/>p'></iframe>" "<iframe src='http://non.existent/url'></iframe>")); QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool)));
2801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870
QTRY_COMPARE(spyLoadFinished.count(), 1); QCOMPARE(page.mainFrame()->childFrames()[1]->toPlainText(), QString("error")); m_view->setPage(0); #endif } void tst_QWebEnginePage::errorPageExtensionInFrameset() { #if !defined(QWEBENGINEFRAME) QSKIP("QWEBENGINEFRAME"); #else ErrorPage page; m_view->setPage(&page); m_view->load(QUrl("qrc:///resources/index.html")); QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool))); QTRY_COMPARE(spyLoadFinished.count(), 1); QCOMPARE(page.mainFrame()->childFrames().count(), 2); QCOMPARE(page.mainFrame()->childFrames()[1]->toPlainText(), QString("error")); m_view->setPage(0); #endif } void tst_QWebEnginePage::errorPageExtensionLoadFinished() { ErrorPage page; m_view->setPage(&page); QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool))); QSignalSpy spyFrameLoadFinished(m_view->page(), SIGNAL(loadFinished(bool))); m_view->setUrl(QUrl("data:text/html,foo")); QTRY_COMPARE(spyLoadFinished.count(), 1); QTRY_COMPARE(spyFrameLoadFinished.count(), 1); const bool loadSucceded = spyLoadFinished.at(0).at(0).toBool(); QVERIFY(loadSucceded); const bool frameLoadSucceded = spyFrameLoadFinished.at(0).at(0).toBool(); QVERIFY(frameLoadSucceded); m_view->page()->setUrl(QUrl("http://non.existent/url")); QTRY_COMPARE(spyLoadFinished.count(), 2); QTRY_COMPARE(spyFrameLoadFinished.count(), 2); const bool nonExistantLoadSucceded = spyLoadFinished.at(1).at(0).toBool(); QVERIFY(nonExistantLoadSucceded); const bool nonExistantFrameLoadSucceded = spyFrameLoadFinished.at(1).at(0).toBool(); QVERIFY(nonExistantFrameLoadSucceded); m_view->setPage(0); } class FriendlyWebPage : public QWebEnginePage { public: friend class tst_QWebEnginePage; }; void tst_QWebEnginePage::userAgentApplicationName() { #if !defined(QWEBENGINEPAGE_USERAGENTFORURL) QSKIP("QWEBENGINEPAGE_USERAGENTFORURL"); #else const QString oldApplicationName = QCoreApplication::applicationName(); FriendlyWebPage page;
2871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940
const QString applicationNameMarker = QString::fromUtf8("StrangeName\342\210\236"); QCoreApplication::setApplicationName(applicationNameMarker); QVERIFY(page.userAgentForUrl(QUrl()).contains(applicationNameMarker)); QCoreApplication::setApplicationName(oldApplicationName); #endif } class CustomUserAgentWebPage : public QWebEnginePage { public: static const QLatin1String filteredUserAgent; protected: virtual QString userAgentForUrl(const QUrl& url) const { return QString("My User Agent\nX-New-Http-Header: Oh Noes!"); } }; const QLatin1String CustomUserAgentWebPage::filteredUserAgent("My User AgentX-New-Http-Header: Oh Noes!"); void tst_QWebEnginePage::userAgentNewlineStripping() { #if !defined(QWEBENGINEPAGE_USERAGENTFORURL) QSKIP("QWEBENGINEPAGE_USERAGENTFORURL"); #else CustomUserAgentWebPage page; page.setHtml("<html><body></body></html>"); QCOMPARE(evaluateJavaScriptSync(&page, "navigator.userAgent").toString(), CustomUserAgentWebPage::filteredUserAgent); #endif } void tst_QWebEnginePage::crashTests_LazyInitializationOfMainFrame() { { QWebEnginePage webPage; } { QWebEnginePage webPage; webPage.selectedText(); } { #if defined(QWEBENGINEPAGE_SELECTEDHTML) QWebEnginePage webPage; webPage.selectedHtml(); #endif } { QWebEnginePage webPage; webPage.triggerAction(QWebEnginePage::Back, true); } { #if defined(QWEBENGINEPAGE_UPDATEPOSITIONDEPENDENTACTIONS) QWebEnginePage webPage; QPoint pos(10,10); webPage.updatePositionDependentActions(pos); #endif } } #if defined(QWEBENGINEPAGE_RENDER) static void takeScreenshot(QWebEnginePage* page) { page->setViewportSize(page->contentsSize()); QImage image(page->viewportSize(), QImage::Format_ARGB32); QPainter painter(&image); page->render(&painter); painter.end(); } #endif
2941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010
void tst_QWebEnginePage::screenshot_data() { QTest::addColumn<QString>("html"); QTest::newRow("WithoutPlugin") << "<html><body id='b'>text</body></html>"; QTest::newRow("WindowedPlugin") << QString("<html><body id='b'>text<embed src='resources/test.swf'></embed></body></html>"); QTest::newRow("WindowlessPlugin") << QString("<html><body id='b'>text<embed src='resources/test.swf' wmode='transparent'></embed></body></html>"); } void tst_QWebEnginePage::screenshot() { #if !defined(QWEBENGINESETTINGS) QSKIP("QWEBENGINESETTINGS"); #else if (!QDir(TESTS_SOURCE_DIR).exists()) W_QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll); QDir::setCurrent(TESTS_SOURCE_DIR); QFETCH(QString, html); QWebEnginePage* page = new QWebEnginePage; page->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true); page->setHtml(html, QUrl::fromLocalFile(TESTS_SOURCE_DIR)); ::waitForSignal(page, SIGNAL(loadFinished(bool)), 2000); // take screenshot without a view takeScreenshot(page); QWebEngineView* view = new QWebEngineView; view->setPage(page); // take screenshot when attached to a view takeScreenshot(page); delete page; delete view; QDir::setCurrent(QApplication::applicationDirPath()); #endif } #if defined(ENABLE_WEBGL) && ENABLE_WEBGL // https://bugs.webkit.org/show_bug.cgi?id=54138 static void webGLScreenshotWithoutView(bool accelerated) { QWebEnginePage page; page.settings()->setAttribute(QWebEngineSettings::WebGLEnabled, true); page.settings()->setAttribute(QWebEngineSettings::AcceleratedCompositingEnabled, accelerated); page.setHtml("<html><body>" "<canvas id='webgl' width='300' height='300'></canvas>" "<script>document.getElementById('webgl').getContext('experimental-webgl')</script>" "</body></html>"); takeScreenshot(&page); } void tst_QWebEnginePage::acceleratedWebGLScreenshotWithoutView() { webGLScreenshotWithoutView(true); } void tst_QWebEnginePage::unacceleratedWebGLScreenshotWithoutView() { webGLScreenshotWithoutView(false); } #endif void tst_QWebEnginePage::originatingObjectInNetworkRequests() { #if !defined(QWEBENGINEFRAME) QSKIP("QWEBENGINEFRAME");
3011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080
#else TestNetworkManager* networkManager = new TestNetworkManager(m_page); m_page->setNetworkAccessManager(networkManager); networkManager->requests.clear(); m_view->setHtml(QString("<frameset cols=\"25%,75%\"><frame src=\"data:text/html," "<head><meta http-equiv='refresh' content='1'></head>foo \">" "<frame src=\"data:text/html,bar\"></frameset>"), QUrl()); QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); QCOMPARE(networkManager->requests.count(), 2); QList<QWebEngineFrame*> childFrames = m_page->mainFrame()->childFrames(); QEXPECT_FAIL("", "https://bugs.webkit.org/show_bug.cgi?id=118660", Continue); QCOMPARE(childFrames.count(), 2); for (int i = 0; i < 2; ++i) QVERIFY(qobject_cast<QWebEngineFrame*>(networkManager->requests.at(i).originatingObject()) == childFrames.at(i)); #endif } void tst_QWebEnginePage::networkReplyParentDidntChange() { #if !defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) QSKIP("QWEBENGINEPAGE_SETNETWORKACCESSMANAGER"); #else TestNetworkManager* networkManager = new TestNetworkManager(m_page); m_page->setNetworkAccessManager(networkManager); networkManager->requests.clear(); // Trigger a load and check that pending QNetworkReplies haven't been reparented before returning to the event loop. m_view->load(QUrl("qrc:///resources/content.html")); QVERIFY(networkManager->requests.count() > 0); QVERIFY(networkManager->findChildren<QNetworkReply*>().size() > 0); #endif } void tst_QWebEnginePage::destroyQNAMBeforeAbortDoesntCrash() { #if !defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) QSKIP("QWEBENGINEPAGE_SETNETWORKACCESSMANAGER"); #else QNetworkAccessManager* networkManager = new QNetworkAccessManager; m_page->setNetworkAccessManager(networkManager); m_view->load(QUrl("qrc:///resources/content.html")); delete networkManager; // This simulates what PingLoader does with its QNetworkReply when it times out. // PingLoader isn't attached to a QWebEnginePage and can be kept alive // for 60000 seconds (~16.7 hours) to then cancel its ResourceHandle. m_view->stop(); #endif } /** * Test fixups for https://bugs.webkit.org/show_bug.cgi?id=30914 * * From JS we test the following conditions. * * OK + QString() => SUCCESS, empty string (but not null) * OK + "text" => SUCCESS, "text" * CANCEL + QString() => CANCEL, null string * CANCEL + "text" => CANCEL, null string */ class JSPromptPage : public QWebEnginePage { Q_OBJECT public: JSPromptPage() {}
3081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150
bool javaScriptPrompt(QWebEngineFrame* frame, const QString& msg, const QString& defaultValue, QString* result) { if (msg == QLatin1String("test1")) { *result = QString(); return true; } else if (msg == QLatin1String("test2")) { *result = QLatin1String("text"); return true; } else if (msg == QLatin1String("test3")) { *result = QString(); return false; } else if (msg == QLatin1String("test4")) { *result = QLatin1String("text"); return false; } qFatal("Unknown msg."); return QWebEnginePage::javaScriptPrompt(frame, msg, defaultValue, result); } }; void tst_QWebEnginePage::testJSPrompt() { JSPromptPage page; bool res; // OK + QString() res = evaluateJavaScriptSync(&page, "var retval = prompt('test1');" "retval=='' && retval.length == 0;").toBool(); QVERIFY(res); // OK + "text" res = evaluateJavaScriptSync(&page, "var retval = prompt('test2');" "retval=='text' && retval.length == 4;").toBool(); QVERIFY(res); // Cancel + QString() res = evaluateJavaScriptSync(&page, "var retval = prompt('test3');" "retval===null;").toBool(); QVERIFY(res); // Cancel + "text" res = evaluateJavaScriptSync(&page, "var retval = prompt('test4');" "retval===null;").toBool(); QVERIFY(res); } class TestModalPage : public QWebEnginePage { Q_OBJECT public: TestModalPage(QObject* parent = 0) : QWebEnginePage(parent) { } virtual QWebEnginePage* createWindow(WebWindowType) { QWebEnginePage* page = new TestModalPage(); connect(page, SIGNAL(windowCloseRequested()), page, SLOT(deleteLater())); return page; } }; void tst_QWebEnginePage::showModalDialog() { #if !defined(QWEBENGINESETTINGS) QSKIP("QWEBENGINESETTINGS"); #else
3151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220
TestModalPage page; page.settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true); page.setHtml(QString("<html></html>")); QString res = evaluateJavaScriptSync(&page, "window.showModalDialog('javascript:window.returnValue=dialogArguments; window.close();', 'This is a test');").toString(); QCOMPARE(res, QString("This is a test")); #endif } void tst_QWebEnginePage::testStopScheduledPageRefresh() { #if !defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) QSKIP("QWEBENGINEPAGE_SETNETWORKACCESSMANAGER"); #else // Without QWebEnginePage::StopScheduledPageRefresh QWebEnginePage page1; page1.setNetworkAccessManager(new TestNetworkManager(&page1)); page1.setHtml("<html><head>" "<meta http-equiv=\"refresh\"content=\"0;URL=qrc:///resources/index.html\">" "</head><body><h1>Page redirects immediately...</h1>" "</body></html>"); QVERIFY(::waitForSignal(&page1, SIGNAL(loadFinished(bool)))); QTest::qWait(500); QCOMPARE(page1.url(), QUrl(QLatin1String("qrc:///resources/index.html"))); // With QWebEnginePage::StopScheduledPageRefresh QWebEnginePage page2; page2.setNetworkAccessManager(new TestNetworkManager(&page2)); page2.setHtml("<html><head>" "<meta http-equiv=\"refresh\"content=\"1;URL=qrc:///resources/index.html\">" "</head><body><h1>Page redirect test with 1 sec timeout...</h1>" "</body></html>"); page2.triggerAction(QWebEnginePage::StopScheduledPageRefresh); QTest::qWait(1500); QEXPECT_FAIL("", "https://bugs.webkit.org/show_bug.cgi?id=118673", Continue); QCOMPARE(page2.url().toString(), QLatin1String("about:blank")); #endif } void tst_QWebEnginePage::findText() { m_view->setHtml(QString("<html><head></head><body><div>foo bar</div></body></html>")); #if defined(QWEBENGINEPAGE_TRIGGERACTION_SELECTALL) m_page->triggerAction(QWebEnginePage::SelectAll); QVERIFY(!m_page->selectedText().isEmpty()); QVERIFY(!m_page->selectedHtml().isEmpty()); #endif m_page->findText(""); QVERIFY(m_page->selectedText().isEmpty()); #if defined(QWEBENGINEPAGE_SELECTEDHTML) QVERIFY(m_page->selectedHtml().isEmpty()); #endif QStringList words = (QStringList() << "foo" << "bar"); foreach (QString subString, words) { m_page->findText(subString); QEXPECT_FAIL("", "Unsupported: findText only highlights and doesn't update the selection.", Continue); QCOMPARE(m_page->selectedText(), subString); #if defined(QWEBENGINEPAGE_SELECTEDHTML) QVERIFY(m_page->selectedHtml().contains(subString)); #endif m_page->findText(""); QVERIFY(m_page->selectedText().isEmpty()); #if defined(QWEBENGINEPAGE_SELECTEDHTML) QVERIFY(m_page->selectedHtml().isEmpty()); #endif } } void tst_QWebEnginePage::findTextResult() { // findText will abort in blink if the view has an empty size.
3221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290
m_view->resize(800, 600); m_view->show(); QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool))); m_view->setHtml(QString("<html><head></head><body><div>foo bar</div></body></html>")); QTRY_COMPARE(loadSpy.count(), 1); QCOMPARE(findTextSync(m_page, ""), false); QStringList words = (QStringList() << "foo" << "bar"); foreach (QString subString, words) { QCOMPARE(findTextSync(m_page, subString), true); QCOMPARE(findTextSync(m_page, ""), false); } QCOMPARE(findTextSync(m_page, "blahhh"), false); QCOMPARE(findTextSync(m_page, ""), false); } static QString getMimeTypeForExtension(const QString &ext) { QMimeType mimeType = QMimeDatabase().mimeTypeForFile(QStringLiteral("filename.") + ext.toLower(), QMimeDatabase::MatchExtension); if (mimeType.isValid() && !mimeType.isDefault()) return mimeType.name(); return QString(); } void tst_QWebEnginePage::supportedContentType() { #if !defined(QWEBENGINEPAGE_SUPPORTEDCONTENTTYPES) QSKIP("QWEBENGINEPAGE_SUPPORTEDCONTENTTYPES"); #else QStringList contentTypes; // Add supported non image types... contentTypes << "text/html" << "text/xml" << "text/xsl" << "text/plain" << "text/" << "application/xml" << "application/xhtml+xml" << "application/vnd.wap.xhtml+xml" << "application/rss+xml" << "application/atom+xml" << "application/json"; #if ENABLE_MHTML contentTypes << "application/x-mimearchive"; #endif // Add supported image types... Q_FOREACH (const QByteArray& imageType, QImageWriter::supportedImageFormats()) { const QString mimeType = getMimeTypeForExtension(imageType); if (!mimeType.isEmpty()) contentTypes << mimeType; } // Get the mime types supported by webengine... const QStringList supportedContentTypes = m_page->supportedContentTypes(); Q_FOREACH (const QString& mimeType, contentTypes) QVERIFY2(supportedContentTypes.contains(mimeType), QString("'%1' is not a supported content type!").arg(mimeType).toLatin1()); Q_FOREACH (const QString& mimeType, contentTypes) QVERIFY2(m_page->supportsContentType(mimeType), QString("Cannot handle content types '%1'!").arg(mimeType).toLatin1()); #endif } void tst_QWebEnginePage::navigatorCookieEnabled() { #if !defined(QWEBENGINEPAGE_NETWORKACCESSMANAGER) QSKIP("QWEBENGINEPAGE_NETWORKACCESSMANAGER"); #else m_page->networkAccessManager()->setCookieJar(0); QVERIFY(!m_page->networkAccessManager()->cookieJar());
3291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360
QVERIFY(!evaluateJavaScriptSync(m_page, "navigator.cookieEnabled").toBool()); m_page->networkAccessManager()->setCookieJar(new QNetworkCookieJar()); QVERIFY(m_page->networkAccessManager()->cookieJar()); QVERIFY(evaluateJavaScriptSync(m_page, "navigator.cookieEnabled").toBool()); #endif } void tst_QWebEnginePage::thirdPartyCookiePolicy() { #if !defined(DUMPRENDERTREESUPPORTQT) QSKIP("DUMPRENDERTREESUPPORTQT"); #else QWebEngineSettings::globalSettings()->setThirdPartyCookiePolicy(QWebEngineSettings::AlwaysBlockThirdPartyCookies); m_page->networkAccessManager()->setCookieJar(new QNetworkCookieJar()); QVERIFY(m_page->networkAccessManager()->cookieJar()); // These are all first-party cookies, so should pass. QVERIFY(DumpRenderTreeSupportQt::thirdPartyCookiePolicyAllows(m_page->handle(), QUrl("http://www.example.com"), QUrl("http://example.com"))); QVERIFY(DumpRenderTreeSupportQt::thirdPartyCookiePolicyAllows(m_page->handle(), QUrl("http://www.example.com"), QUrl("http://doc.example.com"))); QVERIFY(DumpRenderTreeSupportQt::thirdPartyCookiePolicyAllows(m_page->handle(), QUrl("http://aaa.www.example.com"), QUrl("http://doc.example.com"))); QVERIFY(DumpRenderTreeSupportQt::thirdPartyCookiePolicyAllows(m_page->handle(), QUrl("http://example.com"), QUrl("http://www.example.com"))); QVERIFY(DumpRenderTreeSupportQt::thirdPartyCookiePolicyAllows(m_page->handle(), QUrl("http://www.example.co.uk"), QUrl("http://example.co.uk"))); QVERIFY(DumpRenderTreeSupportQt::thirdPartyCookiePolicyAllows(m_page->handle(), QUrl("http://www.example.co.uk"), QUrl("http://doc.example.co.uk"))); QVERIFY(DumpRenderTreeSupportQt::thirdPartyCookiePolicyAllows(m_page->handle(), QUrl("http://aaa.www.example.co.uk"), QUrl("http://doc.example.co.uk"))); QVERIFY(DumpRenderTreeSupportQt::thirdPartyCookiePolicyAllows(m_page->handle(), QUrl("http://example.co.uk"), QUrl("http://www.example.co.uk"))); // These are all third-party cookies, so should fail. QVERIFY(!DumpRenderTreeSupportQt::thirdPartyCookiePolicyAllows(m_page->handle(), QUrl("http://www.example.com"), QUrl("http://slashdot.org"))); QVERIFY(!DumpRenderTreeSupportQt::thirdPartyCookiePolicyAllows(m_page->handle(), QUrl("http://example.com"), QUrl("http://anotherexample.com"))); QVERIFY(!DumpRenderTreeSupportQt::thirdPartyCookiePolicyAllows(m_page->handle(), QUrl("http://anotherexample.com"), QUrl("http://example.com"))); QVERIFY(!DumpRenderTreeSupportQt::thirdPartyCookiePolicyAllows(m_page->handle(), QUrl("http://www.example.co.uk"), QUrl("http://slashdot.co.uk"))); QVERIFY(!DumpRenderTreeSupportQt::thirdPartyCookiePolicyAllows(m_page->handle(), QUrl("http://example.co.uk"), QUrl("http://anotherexample.co.uk"))); QVERIFY(!DumpRenderTreeSupportQt::thirdPartyCookiePolicyAllows(m_page->handle(), QUrl("http://anotherexample.co.uk"), QUrl("http://example.co.uk"))); #endif } #ifdef Q_OS_MAC void tst_QWebEnginePage::macCopyUnicodeToClipboard() { QString unicodeText = QString::fromUtf8("αβγδεζηθικλμπ"); m_page->setHtml(QString("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /></head><body>%1</body></html>").arg(unicodeText)); m_page->triggerAction(QWebEnginePage::SelectAll); m_page->triggerAction(QWebEnginePage::Copy); QString clipboardData = QString::fromUtf8(QApplication::clipboard()->mimeData()->data(QLatin1String("text/html"))); QVERIFY(clipboardData.contains(QLatin1String("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />"))); QVERIFY(clipboardData.contains(unicodeText)); } #endif void tst_QWebEnginePage::contextMenuCopy() { #if !defined(QWEBENGINEELEMENT) QSKIP("QWEBENGINEELEMENT");
3361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430
#else QWebEngineView view; view.setHtml("<a href=\"http://www.google.com\">You cant miss this</a>"); view.page()->triggerAction(QWebEnginePage::SelectAll); QVERIFY(!view.page()->selectedText().isEmpty()); QWebEngineElement link = view.page()->mainFrame()->findFirstElement("a"); QPoint pos(link.geometry().center()); QContextMenuEvent event(QContextMenuEvent::Mouse, pos); view.page()->swallowContextMenuEvent(&event); view.page()->updatePositionDependentActions(pos); QList<QMenu*> contextMenus = view.findChildren<QMenu*>(); QVERIFY(!contextMenus.isEmpty()); QMenu* contextMenu = contextMenus.first(); QVERIFY(contextMenu); QList<QAction *> list = contextMenu->actions(); int index = list.indexOf(view.page()->action(QWebEnginePage::Copy)); QVERIFY(index != -1); #endif } // https://bugs.webkit.org/show_bug.cgi?id=62139 void tst_QWebEnginePage::contextMenuPopulatedOnce() { #if !defined(QWEBENGINEELEMENT) QSKIP("QWEBENGINEELEMENT"); #else QWebEngineView view; view.setHtml("<input type=\"text\">"); QWebEngineElement link = view.page()->mainFrame()->findFirstElement("input"); QPoint pos(link.geometry().center()); QContextMenuEvent event(QContextMenuEvent::Mouse, pos); view.page()->swallowContextMenuEvent(&event); view.page()->updatePositionDependentActions(pos); QList<QMenu*> contextMenus = view.findChildren<QMenu*>(); QVERIFY(!contextMenus.isEmpty()); QMenu* contextMenu = contextMenus.first(); QVERIFY(contextMenu); QList<QAction *> list = contextMenu->actions(); QStringList entries; while (!list.isEmpty()) { QString entry = list.takeFirst()->text(); QVERIFY(!entries.contains(entry)); entries << entry; } #endif } void tst_QWebEnginePage::deleteQWebEngineViewTwice() { for (int i = 0; i < 2; ++i) { QMainWindow mainWindow; QWebEngineView* webView = new QWebEngineView(&mainWindow); mainWindow.setCentralWidget(webView); webView->load(QUrl("qrc:///resources/frame_a.html")); mainWindow.show(); QVERIFY(::waitForSignal(webView, SIGNAL(loadFinished(bool)))); } } #if defined(QWEBENGINEPAGE_RENDER) class RepaintRequestedRenderer : public QObject {
3431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500
Q_OBJECT public: RepaintRequestedRenderer(QWebEnginePage* page, QPainter* painter) : m_page(page) , m_painter(painter) , m_recursionCount(0) { connect(m_page, SIGNAL(repaintRequested(QRect)), this, SLOT(onRepaintRequested(QRect))); } Q_SIGNALS: void finished(); private Q_SLOTS: void onRepaintRequested(const QRect& rect) { QCOMPARE(m_recursionCount, 0); m_recursionCount++; m_page->render(m_painter, rect); m_recursionCount--; QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); } private: QWebEnginePage* m_page; QPainter* m_painter; int m_recursionCount; }; #endif void tst_QWebEnginePage::renderOnRepaintRequestedShouldNotRecurse() { #if !defined(QWEBENGINEPAGE_RENDER) QSKIP("QWEBENGINEPAGE_RENDER"); #else QSize viewportSize(720, 576); QWebEnginePage page; QImage image(viewportSize, QImage::Format_ARGB32); QPainter painter(&image); page.setPreferredContentsSize(viewportSize); page.setViewportSize(viewportSize); RepaintRequestedRenderer r(&page, &painter); page.setHtml("zalan loves trunk", QUrl()); QVERIFY(::waitForSignal(&r, SIGNAL(finished()))); #endif } class SpyForLoadSignalsOrder : public QStateMachine { Q_OBJECT public: SpyForLoadSignalsOrder(QWebEnginePage* page, QObject* parent = 0) : QStateMachine(parent) { connect(page, SIGNAL(loadProgress(int)), SLOT(onLoadProgress(int))); QState* waitingForLoadStarted = new QState(this); QState* waitingForLastLoadProgress = new QState(this); QState* waitingForLoadFinished = new QState(this); QFinalState* final = new QFinalState(this); waitingForLoadStarted->addTransition(page, SIGNAL(loadStarted()), waitingForLastLoadProgress); waitingForLastLoadProgress->addTransition(this, SIGNAL(lastLoadProgress()), waitingForLoadFinished); waitingForLoadFinished->addTransition(page, SIGNAL(loadFinished(bool)), final);
3501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570
setInitialState(waitingForLoadStarted); start(); } bool isFinished() const { return !isRunning(); } public Q_SLOTS: void onLoadProgress(int progress) { if (progress == 100) emit lastLoadProgress(); } Q_SIGNALS: void lastLoadProgress(); }; void tst_QWebEnginePage::loadSignalsOrder_data() { QTest::addColumn<QUrl>("url"); QTest::newRow("inline data") << QUrl("data:text/html,This is first page"); QTest::newRow("simple page") << QUrl("qrc:///resources/content.html"); QTest::newRow("frameset page") << QUrl("qrc:///resources/index.html"); } void tst_QWebEnginePage::loadSignalsOrder() { QFETCH(QUrl, url); QWebEnginePage page; SpyForLoadSignalsOrder loadSpy(&page); waitForSignal(&loadSpy, SIGNAL(started())); page.load(url); QTRY_VERIFY(loadSpy.isFinished()); } void tst_QWebEnginePage::undoActionHaveCustomText() { #if !defined(QWEBENGINEPAGE_UNDOACTION) QSKIP("QWEBENGINEPAGE_UNDOACTION"); #else m_page->setHtml("<div id=test contenteditable></div>"); evaluateJavaScriptSync(m_page, "document.getElementById('test').focus()"); evaluateJavaScriptSync(m_page, "document.execCommand('insertText', true, 'Test');"); QString typingActionText = m_page->action(QWebEnginePage::Undo)->text(); evaluateJavaScriptSync(m_page, "document.execCommand('indent', true);"); QString alignActionText = m_page->action(QWebEnginePage::Undo)->text(); QVERIFY(typingActionText != alignActionText); #endif } void tst_QWebEnginePage::renderWidgetHostViewNotShowTopLevel() { QWebEnginePage page; QSignalSpy spyLoadFinished(&page, SIGNAL(loadFinished(bool))); page.load(QUrl("http://qt-project.org")); if (!spyLoadFinished.wait(10000) || !spyLoadFinished.at(0).at(0).toBool()) QSKIP("Couldn't load page from network, skipping test."); spyLoadFinished.clear(); // Loading a different domain will force the creation of a separate render // process and should therefore create a new RenderWidgetHostViewQtDelegateWidget. page.load(QUrl("http://www.wikipedia.org/")); if (!spyLoadFinished.wait(10000) || !spyLoadFinished.at(0).at(0).toBool()) QSKIP("Couldn't load page from network, skipping test."); // Make sure that RenderWidgetHostViewQtDelegateWidgets are not shown as top-level.
3571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640
// They should only be made visible when parented to a QWebEngineView. foreach (QWidget *widget, QApplication::topLevelWidgets()) QCOMPARE(widget->isVisible(), false); } void tst_QWebEnginePage::openWindowDefaultSize() { #if !defined(QWEBENGINEPAGE_SETTINGS) QSKIP("QWEBENGINEPAGE_SETTINGS"); #else TestPage page; page.settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true); // Open a default window. page.runJavaScript("window.open()"); // Open a too small window. evaluateJavaScriptSync(&page, "window.open('', '', 'width=10,height=10')"); QTest::qWait(500); // The number of popups created should be two. QVERIFY(page.createdWindows.size() == 2); QRect requestedGeometry = page.createdWindows[0]->requestedGeometry; // Check default size has been requested. QVERIFY(requestedGeometry.width() == 0); QVERIFY(requestedGeometry.height() == 0); requestedGeometry = page.createdWindows[1]->requestedGeometry; // Check minimum size has been requested. QVERIFY(requestedGeometry.width() == 100); QVERIFY(requestedGeometry.height() == 100); #endif } void tst_QWebEnginePage::cssMediaTypeGlobalSetting() { #if !defined(QWEBENGINESETTINGS_SETCSSMEDIATYPE) QSKIP("QWEBENGINESETTINGS_SETCSSMEDIATYPE"); #else QString testHtml("<style>@media tv {body{background-color:red;}}@media handheld {body{background-color:green;}}@media screen {body{background-color:blue;}}</style>"); QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool))); QWebEngineSettings::globalSettings()->setCSSMediaType("tv"); // Clear page specific setting to read from global setting m_view->page()->settings()->setCSSMediaType(QString()); m_view->setHtml(testHtml); QTRY_COMPARE(loadSpy.count(), 1); QVERIFY(evaluateJavaScriptSync(m_view->page(), "window.matchMedia('tv').matches == true").toBool()); QVERIFY(QWebEngineSettings::globalSettings()->cssMediaType() == "tv"); QWebEngineSettings::globalSettings()->setCSSMediaType("handheld"); // Clear page specific setting to read from global setting m_view->page()->settings()->setCSSMediaType(QString()); m_view->setHtml(testHtml); QTRY_COMPARE(loadSpy.count(), 2); QVERIFY(evaluateJavaScriptSync(m_view->page(), "window.matchMedia('handheld').matches == true").toBool()); QVERIFY(QWebEngineSettings::globalSettings()->cssMediaType() == "handheld"); QWebEngineSettings::globalSettings()->setCSSMediaType("screen"); // Clear page specific setting to read from global setting m_view->page()->settings()->setCSSMediaType(QString()); m_view->setHtml(testHtml); QTRY_COMPARE(loadSpy.count(), 3); QVERIFY(evaluateJavaScriptSync(m_view->page(), "window.matchMedia('screen').matches == true").toBool()); QVERIFY(QWebEngineSettings::globalSettings()->cssMediaType() == "screen"); #endif } void tst_QWebEnginePage::cssMediaTypePageSetting() { #if !defined(QWEBENGINESETTINGS_SETCSSMEDIATYPE)
3641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668
QSKIP("QWEBENGINESETTINGS_SETCSSMEDIATYPE"); #else QString testHtml("<style>@media tv {body{background-color:red;}}@media handheld {body{background-color:green;}}@media screen {body{background-color:blue;}}</style>"); QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool))); m_view->page()->settings()->setCSSMediaType("tv"); m_view->setHtml(testHtml); QTRY_COMPARE(loadSpy.count(), 1); QVERIFY(evaluateJavaScriptSync(m_view->page(), "window.matchMedia('tv').matches == true").toBool()); QVERIFY(m_view->page()->settings()->cssMediaType() == "tv"); m_view->page()->settings()->setCSSMediaType("handheld"); m_view->setHtml(testHtml); QTRY_COMPARE(loadSpy.count(), 2); QVERIFY(evaluateJavaScriptSync(m_view->page(), "window.matchMedia('handheld').matches == true").toBool()); QVERIFY(m_view->page()->settings()->cssMediaType() == "handheld"); m_view->page()->settings()->setCSSMediaType("screen"); m_view->setHtml(testHtml); QTRY_COMPARE(loadSpy.count(), 3); QVERIFY(evaluateJavaScriptSync(m_view->page(), "window.matchMedia('screen').matches == true").toBool()); QVERIFY(m_view->page()->settings()->cssMediaType() == "screen"); #endif } QTEST_MAIN(tst_QWebEnginePage) #include "tst_qwebenginepage.moc"