diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index 187565a7618ed1a15cb80bdee054bbeb8e8fd7e7..fbb7c1f9edd74c0ad10275d680cb844907aa4df8 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -902,7 +902,7 @@ QWebEnginePage::~QWebEnginePage() Q_D(QWebEnginePage); setDevToolsPage(nullptr); d->adapter->stopFinding(); - QWebEngineViewPrivate::bind(nullptr, this, true); + QWebEngineViewPrivate::removePageFromView(this); } QWebEngineHistory *QWebEnginePage::history() const diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp index aa51e5b0ef4c9c1e34945b2ad68974034d5e754e..e6f9fcb49c7f7986ecccd02efec1e9ca7628ccf7 100644 --- a/src/webenginewidgets/api/qwebengineview.cpp +++ b/src/webenginewidgets/api/qwebengineview.cpp @@ -55,33 +55,77 @@ QT_BEGIN_NAMESPACE -void QWebEngineViewPrivate::bind(QWebEngineView *view, QWebEnginePage *page, bool pageBeingDeleted) +void QWebEngineViewPrivate::notify(QWebEngineView *view, QWebEnginePage *oldPage, QWebEnginePage *newPage) +{ + Q_ASSERT(view); + + auto oldUrl = oldPage ? oldPage->url() : QUrl(); + auto newUrl = newPage ? newPage->url() : QUrl(); + if (oldUrl != newUrl) + Q_EMIT view->urlChanged(newUrl); + + auto oldTitle = oldPage ? oldPage->title() : QString(); + auto newTitle = newPage ? newPage->title() : QString(); + if (oldTitle != newTitle) + Q_EMIT view->titleChanged(newTitle); + + auto oldIcon = oldPage ? oldPage->iconUrl() : QUrl(); + auto newIcon = newPage ? newPage->iconUrl() : QUrl(); + if (oldIcon != newIcon) { + Q_EMIT view->iconUrlChanged(newIcon); + Q_EMIT view->iconChanged(newPage ? newPage->icon() : QIcon()); + } + + if ((oldPage && oldPage->hasSelection()) || (newPage && newPage->hasSelection())) + Q_EMIT view->selectionChanged(); +} + +QWebEnginePage* QWebEngineViewPrivate::removeViewFromPage(QWebEngineView *view) +{ + Q_ASSERT(view); + QWebEnginePage *oldPage = view->d_func()->page; + + if (oldPage) { + oldPage->disconnect(view); + oldPage->d_func()->view = nullptr; + if (oldPage->parent() != view) + oldPage->d_func()->adapter->reattachRWHV(); + } + return oldPage; +} + +void QWebEngineViewPrivate::removePageFromView(QWebEnginePage *page) +{ + Q_ASSERT(page); + if (QWebEngineView *oldView = page->d_func()->view) { + page->disconnect(oldView); + page->d_func()->view = nullptr; + oldView->d_func()->page = nullptr; + notify(oldView, page, nullptr); + } +} + +void QWebEngineViewPrivate::bind(QWebEngineView *view, QWebEnginePage *page) { if (view && page == view->d_func()->page) return; if (page) { // Un-bind page from its current view. - if (QWebEngineView *oldView = page->d_func()->view) { - page->disconnect(oldView); - oldView->d_func()->page = nullptr; - } + removePageFromView(page); page->d_func()->view = view; - if (!pageBeingDeleted) - page->d_func()->adapter->reattachRWHV(); + page->d_func()->adapter->reattachRWHV(); } if (view) { // Un-bind view from its current page. - if (QWebEnginePage *oldPage = view->d_func()->page) { - oldPage->disconnect(view); - oldPage->d_func()->view = nullptr; - if (oldPage->parent() == view) - delete oldPage; - else - oldPage->d_func()->adapter->reattachRWHV(); - } + QWebEnginePage *oldPage = removeViewFromPage(view); + view->d_func()->page = page; + notify(view, oldPage, page); + + if (oldPage && oldPage->parent() == view) + delete oldPage; } if (view && page) { @@ -149,7 +193,7 @@ QWebEngineView::QWebEngineView(QWidget *parent) QWebEngineView::~QWebEngineView() { - QWebEngineViewPrivate::bind(this, nullptr); + QWebEngineViewPrivate::removeViewFromPage(this); } QWebEnginePage* QWebEngineView::page() const diff --git a/src/webenginewidgets/api/qwebengineview_p.h b/src/webenginewidgets/api/qwebengineview_p.h index bfb44bec5b29c05cea7702aba08e6f0378e81e16..1845bfb603d3e35977fc8b687a4e6242db977c23 100644 --- a/src/webenginewidgets/api/qwebengineview_p.h +++ b/src/webenginewidgets/api/qwebengineview_p.h @@ -65,7 +65,10 @@ public: Q_DECLARE_PUBLIC(QWebEngineView) QWebEngineView *q_ptr; - static void bind(QWebEngineView *view, QWebEnginePage *page, bool pageBeingDeleted = false); + static void notify(QWebEngineView *view, QWebEnginePage *oldPage, QWebEnginePage *newPage); + static QWebEnginePage* removeViewFromPage(QWebEngineView *view); + static void removePageFromView(QWebEnginePage *page); + static void bind(QWebEngineView *view, QWebEnginePage *page); QWebEngineViewPrivate(); diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index 57f5f6def5acb1f26b3c5946c8313ff1d50ad97d..78677e459157f03939b4ea8d1ef95eb58e2495db 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -134,6 +134,8 @@ private Q_SLOTS: void renderHints(); void getWebKitVersion(); + void changePage_data(); + void changePage(); void reusePage_data(); void reusePage(); void microFocusCoordinates(); @@ -260,6 +262,100 @@ void tst_QWebEngineView::getWebKitVersion() #endif } +void tst_QWebEngineView::changePage_data() +{ + QString html = "<html><head><title>%1</title>" + "<link rel='icon' href='file://" TESTS_SOURCE_DIR "/resources/image2.png'></head></html>"; + QUrl urlFrom("data:text/html," + html.arg("TitleFrom")); + QUrl urlTo("data:text/html," + html.arg("TitleTo")); + QUrl nullPage("data:text/html,<html/>"); + QTest::addColumn<QUrl>("urlFrom"); + QTest::addColumn<QUrl>("urlTo"); + QTest::addColumn<bool>("fromIsNullPage"); + QTest::addColumn<bool>("toIsNullPage"); + QTest::newRow("From empty page to url") << nullPage << urlTo << true << false; + QTest::newRow("From url to empty content page") << urlFrom << nullPage << false << true; + QTest::newRow("From one content to another") << urlFrom << urlTo << false << false; +} + +void tst_QWebEngineView::changePage() +{ + QScopedPointer<QWebEngineView> view(new QWebEngineView); view->resize(640, 480); view->show(); + + QFETCH(QUrl, urlFrom); + QFETCH(QUrl, urlTo); + QFETCH(bool, fromIsNullPage); + QFETCH(bool, toIsNullPage); + + QSignalSpy spyUrl(view.get(), &QWebEngineView::urlChanged); + QSignalSpy spyTitle(view.get(), &QWebEngineView::titleChanged); + QSignalSpy spyIconUrl(view.get(), &QWebEngineView::iconUrlChanged); + QSignalSpy spyIcon(view.get(), &QWebEngineView::iconChanged); + + QScopedPointer<QWebEnginePage> pageFrom(new QWebEnginePage); + QSignalSpy pageFromLoadSpy(pageFrom.get(), &QWebEnginePage::loadFinished); + QSignalSpy pageFromIconLoadSpy(pageFrom.get(), &QWebEnginePage::iconChanged); + pageFrom->load(urlFrom); + QTRY_COMPARE(pageFromLoadSpy.count(), 1); + QCOMPARE(pageFromLoadSpy.last().value(0).toBool(), true); + if (!fromIsNullPage) { + QTRY_COMPARE(pageFromIconLoadSpy.count(), 1); + QVERIFY(!pageFromIconLoadSpy.last().value(0).isNull()); + } + + view->setPage(pageFrom.get()); + + QTRY_COMPARE(spyUrl.count(), 1); + QCOMPARE(spyUrl.last().value(0).toUrl(), pageFrom->url()); + QTRY_COMPARE(spyTitle.count(), 1); + QCOMPARE(spyTitle.last().value(0).toString(), pageFrom->title()); + + QTRY_COMPARE(spyIconUrl.count(), fromIsNullPage ? 0 : 1); + QTRY_COMPARE(spyIcon.count(), fromIsNullPage ? 0 : 1); + if (!fromIsNullPage) { + QVERIFY(!pageFrom->iconUrl().isEmpty()); + QCOMPARE(spyIconUrl.last().value(0).toUrl(), pageFrom->iconUrl()); + QCOMPARE(spyIcon.last().value(0), QVariant::fromValue(pageFrom->icon())); + } + + QScopedPointer<QWebEnginePage> pageTo(new QWebEnginePage); + QSignalSpy pageToLoadSpy(pageTo.get(), &QWebEnginePage::loadFinished); + QSignalSpy pageToIconLoadSpy(pageTo.get(), &QWebEnginePage::iconChanged); + pageTo->load(urlTo); + QTRY_COMPARE(pageToLoadSpy.count(), 1); + QCOMPARE(pageToLoadSpy.last().value(0).toBool(), true); + if (!toIsNullPage) { + QTRY_COMPARE(pageToIconLoadSpy.count(), 1); + QVERIFY(!pageToIconLoadSpy.last().value(0).isNull()); + } + + view->setPage(pageTo.get()); + + QTRY_COMPARE(spyUrl.count(), 2); + QCOMPARE(spyUrl.last().value(0).toUrl(), pageTo->url()); + QTRY_COMPARE(spyTitle.count(), 2); + QCOMPARE(spyTitle.last().value(0).toString(), pageTo->title()); + + bool iconIsSame = fromIsNullPage == toIsNullPage; + int iconChangeNotifyCount = fromIsNullPage ? (iconIsSame ? 0 : 1) : (iconIsSame ? 1 : 2); + + QTRY_COMPARE(spyIconUrl.count(), iconChangeNotifyCount); + QTRY_COMPARE(spyIcon.count(), iconChangeNotifyCount); + QCOMPARE(pageFrom->iconUrl() == pageTo->iconUrl(), iconIsSame); + if (!iconIsSame) { + QCOMPARE(spyIconUrl.last().value(0).toUrl(), pageTo->iconUrl()); + QCOMPARE(spyIcon.last().value(0), QVariant::fromValue(pageTo->icon())); + } + + // verify no emits on destroy with the same number of signals in spy + view.reset(); + qApp->processEvents(); + QTRY_COMPARE(spyUrl.count(), 2); + QTRY_COMPARE(spyTitle.count(), 2); + QTRY_COMPARE(spyIconUrl.count(), iconChangeNotifyCount); + QTRY_COMPARE(spyIcon.count(), iconChangeNotifyCount); +} + void tst_QWebEngineView::reusePage_data() { QTest::addColumn<QString>("html");