diff options
57 files changed, 1484 insertions, 1883 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 2a545f5b2..b32415028 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -91,7 +91,8 @@ foreach(config ${configs}) devtools_frontend_qt.cpp devtools_frontend_qt.h devtools_manager_delegate_qt.cpp devtools_manager_delegate_qt.h download_manager_delegate_qt.cpp download_manager_delegate_qt.h - favicon_manager.cpp favicon_manager.h + favicon_driver_qt.cpp favicon_driver_qt.h + favicon_service_factory_qt.cpp favicon_service_factory_qt.h file_picker_controller.cpp file_picker_controller.h find_text_helper.cpp find_text_helper.h global_descriptors_qt.h diff --git a/src/core/api/qwebenginepage.cpp b/src/core/api/qwebenginepage.cpp index 6e2b37514..64b4f4d99 100644 --- a/src/core/api/qwebenginepage.cpp +++ b/src/core/api/qwebenginepage.cpp @@ -44,7 +44,6 @@ #include "authentication_dialog_controller.h" #include "profile_adapter.h" #include "color_chooser_controller.h" -#include "favicon_manager.h" #include "find_text_helper.h" #include "file_picker_controller.h" #include "javascript_dialog_controller.h" @@ -255,7 +254,7 @@ void QWebEnginePagePrivate::iconChanged(const QUrl &url) return; iconUrl = url; Q_EMIT q->iconUrlChanged(iconUrl); - Q_EMIT q->iconChanged(adapter->faviconManager()->getIcon()); + Q_EMIT q->iconChanged(iconUrl.isEmpty() ? QIcon() : adapter->icon()); } void QWebEnginePagePrivate::loadProgressChanged(int progress) @@ -1980,7 +1979,7 @@ QIcon QWebEnginePage::icon() const if (d->iconUrl.isEmpty() || !d->adapter->isInitialized()) return QIcon(); - return d->adapter->faviconManager()->getIcon(); + return d->adapter->icon(); } qreal QWebEnginePage::zoomFactor() const diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp index d68cad2b0..fdcd98024 100644 --- a/src/core/content_browser_client_qt.cpp +++ b/src/core/content_browser_client_qt.cpp @@ -113,6 +113,7 @@ #include "web_contents_view_qt.h" #include "web_engine_context.h" #include "web_engine_library_info.h" +#include "web_engine_settings.h" #include "api/qwebenginecookiestore.h" #include "api/qwebenginecookiestore_p.h" diff --git a/src/core/extensions/plugin_service_filter_qt.cpp b/src/core/extensions/plugin_service_filter_qt.cpp index 94cf5cb27..778f803c3 100644 --- a/src/core/extensions/plugin_service_filter_qt.cpp +++ b/src/core/extensions/plugin_service_filter_qt.cpp @@ -43,6 +43,7 @@ #include "content/public/browser/web_contents.h" #include "web_contents_delegate_qt.h" +#include "web_engine_settings.h" using namespace QtWebEngineCore; diff --git a/src/core/favicon_driver_qt.cpp b/src/core/favicon_driver_qt.cpp new file mode 100644 index 000000000..a3bbd5939 --- /dev/null +++ b/src/core/favicon_driver_qt.cpp @@ -0,0 +1,407 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "favicon_driver_qt.h" +#include "type_conversion.h" +#include "web_contents_adapter_client.h" +#include "web_engine_settings.h" + +#include "components/favicon/content/favicon_url_util.h" +#include "components/favicon/core/favicon_service.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/favicon_status.h" +#include "content/public/browser/navigation_entry.h" +#include "content/public/browser/navigation_handle.h" +#include "third_party/blink/public/common/manifest/manifest.h" + +namespace QtWebEngineCore { + +namespace { + +void ExtractManifestIcons(FaviconDriverQt::ManifestDownloadCallback callback, + const GURL &manifest_url, const blink::Manifest &manifest) +{ + std::vector<favicon::FaviconURL> candidates; + for (const auto &icon : manifest.icons) { + candidates.emplace_back(icon.src, favicon_base::IconType::kWebManifestIcon, icon.sizes); + } + std::move(callback).Run(candidates); +} + +int activeHandlersCount(QWebEngineSettings *settings) +{ + bool touchIconsEnabled = settings->testAttribute(QWebEngineSettings::TouchIconsEnabled); + return touchIconsEnabled ? 2 : 1; +} + +} // namespace + +FaviconStatusQt::FaviconStatusQt() + : FaviconStatus(), source(favicon::FaviconDriverObserver::NON_TOUCH_16_DIP) +{ +} + +// static +void FaviconDriverQt::CreateForWebContents(content::WebContents *webContents, + favicon::FaviconService *faviconService, + WebContentsAdapterClient *viewClient) +{ + if (FromWebContents(webContents)) + return; + + webContents->SetUserData( + UserDataKey(), + base::WrapUnique(new FaviconDriverQt(webContents, faviconService, viewClient))); +} + +FaviconDriverQt::FaviconDriverQt(content::WebContents *webContents, + favicon::FaviconService *faviconService, + WebContentsAdapterClient *viewClient) + : content::WebContentsObserver(webContents) + , m_faviconService(faviconService) + , m_viewClient(viewClient) +{ + if (!m_faviconService) + return; + + m_handlers.push_back(std::make_unique<favicon::FaviconHandler>( + m_faviconService, this, favicon::FaviconDriverObserver::NON_TOUCH_16_DIP)); + m_handlers.push_back(std::make_unique<favicon::FaviconHandler>( + m_faviconService, this, favicon::FaviconDriverObserver::NON_TOUCH_LARGEST)); + m_handlers.push_back(std::make_unique<favicon::FaviconHandler>( + m_faviconService, this, favicon::FaviconDriverObserver::TOUCH_LARGEST)); +} + +void FaviconDriverQt::FetchFavicon(const GURL &page_url, bool is_same_document) +{ + QWebEngineSettings *settings = m_viewClient->webEngineSettings(); + bool iconsEnabled = settings->testAttribute(QWebEngineSettings::AutoLoadIconsForPage); + bool touchIconsEnabled = settings->testAttribute(QWebEngineSettings::TouchIconsEnabled); + + if (!iconsEnabled) + return; + + for (const std::unique_ptr<favicon::FaviconHandler> &handler : m_handlers) { + switch (handler->Type()) { + case favicon::FaviconDriverObserver::NON_TOUCH_16_DIP: + if (touchIconsEnabled) + continue; + break; + case favicon::FaviconDriverObserver::NON_TOUCH_LARGEST: + case favicon::FaviconDriverObserver::TOUCH_LARGEST: + if (!touchIconsEnabled) + continue; + break; + } + + handler->FetchFavicon(page_url, is_same_document); + } +} + +gfx::Image FaviconDriverQt::GetFavicon() const +{ + // Like GetTitle(), we also want to use the favicon for the last committed + // entry rather than a pending navigation entry. + content::NavigationController &controller = web_contents()->GetController(); + + content::NavigationEntry *entry = controller.GetLastCommittedEntry(); + if (entry) + return entry->GetFavicon().image; + return gfx::Image(); +} + +bool FaviconDriverQt::FaviconIsValid() const +{ + content::NavigationController &controller = web_contents()->GetController(); + + content::NavigationEntry *entry = controller.GetLastCommittedEntry(); + if (entry) + return entry->GetFavicon().valid; + + return false; +} + +GURL FaviconDriverQt::GetActiveURL() +{ + content::NavigationEntry *entry = web_contents()->GetController().GetLastCommittedEntry(); + return entry ? entry->GetURL() : GURL(); +} + +GURL FaviconDriverQt::GetFaviconURL() const +{ + content::NavigationController &controller = web_contents()->GetController(); + + content::NavigationEntry *entry = controller.GetLastCommittedEntry(); + if (entry) + return entry->GetFavicon().url; + return GURL(); +} + +int FaviconDriverQt::DownloadImage(const GURL &url, int max_image_size, + ImageDownloadCallback callback) +{ + bool bypass_cache = (m_bypassCachePageURL == GetActiveURL()); + m_bypassCachePageURL = GURL(); + + return web_contents()->DownloadImage(url, true, /*preferred_size=*/max_image_size, + /*max_bitmap_size=*/max_image_size, bypass_cache, + std::move(callback)); +} + +void FaviconDriverQt::DownloadManifest(const GURL &url, ManifestDownloadCallback callback) +{ + web_contents()->GetManifest(base::BindOnce(&ExtractManifestIcons, std::move(callback))); +} + +bool FaviconDriverQt::IsOffTheRecord() +{ + DCHECK(web_contents()); + return web_contents()->GetBrowserContext()->IsOffTheRecord(); +} + +void FaviconDriverQt::OnFaviconUpdated( + const GURL &page_url, + favicon::FaviconDriverObserver::NotificationIconType notification_icon_type, + const GURL &icon_url, bool icon_url_changed, const gfx::Image &image) +{ + Q_UNUSED(page_url); + + QWebEngineSettings *settings = m_viewClient->webEngineSettings(); + bool touchIconsEnabled = settings->testAttribute(QWebEngineSettings::TouchIconsEnabled); + + // Prefer touch icons over favicons if touch icons are enabled. + if (!touchIconsEnabled + || m_latestFavicon.source != favicon::FaviconDriverObserver::TOUCH_LARGEST + || notification_icon_type == favicon::FaviconDriverObserver::TOUCH_LARGEST) { + m_latestFavicon.valid = true; + m_latestFavicon.url = icon_url; + m_latestFavicon.image = image; + m_latestFavicon.source = notification_icon_type; + } + + NotifyFaviconUpdatedObservers(notification_icon_type, icon_url, icon_url_changed, image); + emitIconChangedIfNeeded(); +} + +void FaviconDriverQt::OnFaviconDeleted( + const GURL &page_url, + favicon::FaviconDriverObserver::NotificationIconType notification_icon_type) +{ + content::NavigationEntry *entry = web_contents()->GetController().GetLastCommittedEntry(); + DCHECK(entry && entry->GetURL() == page_url); + + entry->GetFavicon() = FaviconStatusQt(); + web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB); + + NotifyFaviconUpdatedObservers(notification_icon_type, /*icon_url=*/GURL(), + /*icon_url_changed=*/true, FaviconStatusQt().image); +} + +void FaviconDriverQt::OnHandlerCompleted(favicon::FaviconHandler *handler) +{ + Q_UNUSED(handler); + + if (activeHandlersCount(m_viewClient->webEngineSettings()) > m_completedHandlersCount) + ++m_completedHandlersCount; + emitIconChangedIfNeeded(); +} + +void FaviconDriverQt::DidUpdateFaviconURL( + content::RenderFrameHost *render_frame_host, + const std::vector<blink::mojom::FaviconURLPtr> &candidates) +{ + Q_UNUSED(render_frame_host); + + // Ignore the update if there is no last committed navigation entry. This can + // occur when loading an initially blank page. + content::NavigationEntry *entry = web_contents()->GetController().GetLastCommittedEntry(); + if (!entry) + return; + + // We update |m_faviconUrls| even if the list is believed to be partial + // (checked below), because callers of our getter favicon_urls() expect so. + std::vector<blink::mojom::FaviconURL> faviconUrls; + for (const auto &candidate : candidates) + faviconUrls.push_back(*candidate); + m_faviconUrls = faviconUrls; + + if (!m_documentOnLoadCompleted) + return; + + OnUpdateCandidates(entry->GetURL(), + favicon::FaviconURLsFromContentFaviconURLs( + m_faviconUrls.value_or(std::vector<blink::mojom::FaviconURL>())), + m_manifestUrl); +} + +void FaviconDriverQt::DidUpdateWebManifestURL(content::RenderFrameHost *target_frame, + const base::Optional<GURL> &manifest_url) +{ + Q_UNUSED(target_frame); + + // Ignore the update if there is no last committed navigation entry. This can + // occur when loading an initially blank page. + content::NavigationEntry *entry = web_contents()->GetController().GetLastCommittedEntry(); + if (!entry || !m_documentOnLoadCompleted) + return; + + m_manifestUrl = manifest_url.value_or(GURL()); + + // On regular page loads, DidUpdateManifestURL() is guaranteed to be called + // before DidUpdateFaviconURL(). However, a page can update the favicons via + // javascript. + if (m_faviconUrls.has_value()) { + OnUpdateCandidates(entry->GetURL(), + favicon::FaviconURLsFromContentFaviconURLs(*m_faviconUrls), + m_manifestUrl); + } +} + +void FaviconDriverQt::DidStartNavigation(content::NavigationHandle *navigation_handle) +{ + if (!navigation_handle->IsInMainFrame()) + return; + + m_faviconUrls.reset(); + m_completedHandlersCount = 0; + m_latestFavicon = FaviconStatusQt(); + + if (!navigation_handle->IsSameDocument()) { + m_documentOnLoadCompleted = false; + m_manifestUrl = GURL(); + } + + m_viewClient->iconChanged(QUrl()); + + content::ReloadType reload_type = navigation_handle->GetReloadType(); + if (reload_type == content::ReloadType::NONE || IsOffTheRecord()) + return; + + m_bypassCachePageURL = navigation_handle->GetURL(); + SetFaviconOutOfDateForPage(navigation_handle->GetURL(), + reload_type == content::ReloadType::BYPASSING_CACHE); +} + +void FaviconDriverQt::DidFinishNavigation(content::NavigationHandle *navigation_handle) +{ + if (!navigation_handle->IsInMainFrame() || !navigation_handle->HasCommitted() + || navigation_handle->IsErrorPage()) { + return; + } + + // Wait till the user navigates to a new URL to start checking the cache + // again. The cache may be ignored for non-reload navigations (e.g. + // history.replace() in-page navigation). This is allowed to increase the + // likelihood that "reloading a page ignoring the cache" redownloads the + // favicon. In particular, a page may do an in-page navigation before + // FaviconHandler has the time to determine that the favicon needs to be + // redownloaded. + GURL url = navigation_handle->GetURL(); + if (url != m_bypassCachePageURL) + m_bypassCachePageURL = GURL(); + + // Get the favicon, either from history or request it from the net. + FetchFavicon(url, navigation_handle->IsSameDocument()); +} + +void FaviconDriverQt::DocumentOnLoadCompletedInMainFrame() +{ + m_documentOnLoadCompleted = true; +} + +void FaviconDriverQt::SetFaviconOutOfDateForPage(const GURL &url, bool force_reload) +{ + if (m_faviconService) { + m_faviconService->SetFaviconOutOfDateForPage(url); + if (force_reload) + m_faviconService->ClearUnableToDownloadFavicons(); + } +} + +void FaviconDriverQt::OnUpdateCandidates(const GURL &page_url, + const std::vector<favicon::FaviconURL> &candidates, + const GURL &manifest_url) +{ + QWebEngineSettings *settings = m_viewClient->webEngineSettings(); + bool touchIconsEnabled = settings->testAttribute(QWebEngineSettings::TouchIconsEnabled); + for (const std::unique_ptr<favicon::FaviconHandler> &handler : m_handlers) { + switch (handler->Type()) { + case favicon::FaviconDriverObserver::NON_TOUCH_16_DIP: + if (touchIconsEnabled) + continue; + break; + case favicon::FaviconDriverObserver::NON_TOUCH_LARGEST: + case favicon::FaviconDriverObserver::TOUCH_LARGEST: + if (!touchIconsEnabled) + continue; + break; + } + + // We feed in the Web Manifest URL (if any) to the instance handling type + // kWebManifestIcon, because those compete which each other (i.e. manifest + // icons override inline touch icons). + handler->OnUpdateCandidates( + page_url, candidates, + (handler->icon_types().count(favicon_base::IconType::kWebManifestIcon) != 0) + ? manifest_url + : GURL::EmptyGURL()); + } +} + +void FaviconDriverQt::emitIconChangedIfNeeded() +{ + if (activeHandlersCount(m_viewClient->webEngineSettings()) != m_completedHandlersCount) + return; + + content::NavigationEntry *entry = web_contents()->GetController().GetLastCommittedEntry(); + DCHECK(entry); + + if (entry->GetFavicon().url != m_latestFavicon.url) { + entry->GetFavicon().valid = m_latestFavicon.valid; + entry->GetFavicon().url = m_latestFavicon.url; + entry->GetFavicon().image = m_latestFavicon.image; + web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB); + } + + m_viewClient->iconChanged(toQt(m_latestFavicon.url)); +} + +WEB_CONTENTS_USER_DATA_KEY_IMPL(FaviconDriverQt) + +} // namespace QtWebEngineCore diff --git a/src/core/favicon_driver_qt.h b/src/core/favicon_driver_qt.h new file mode 100644 index 000000000..b49017946 --- /dev/null +++ b/src/core/favicon_driver_qt.h @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef FAVICON_DRIVER_QT_H +#define FAVICON_DRIVER_QT_H + +#include "qtwebenginecoreglobal_p.h" + +#include "components/favicon/core/favicon_driver.h" +#include "components/favicon/core/favicon_handler.h" +#include "content/public/browser/favicon_status.h" +#include "content/public/browser/web_contents_observer.h" +#include "content/public/browser/web_contents_user_data.h" +#include "third_party/blink/public/mojom/favicon/favicon_url.mojom.h" + +namespace content { +class WebContents; +} + +namespace favicon { +class FaviconService; +} + +namespace QtWebEngineCore { + +class WebContentsAdapterClient; + +struct FaviconStatusQt : public content::FaviconStatus +{ + FaviconStatusQt(); + + // Type of the favicon::FaviconHandler that provided this icon. + favicon::FaviconDriverObserver::NotificationIconType source; +}; + +class FaviconDriverQt : public favicon::FaviconDriver, + public favicon::FaviconHandler::Delegate, + public content::WebContentsObserver, + public content::WebContentsUserData<FaviconDriverQt> +{ +public: + static void CreateForWebContents(content::WebContents *webContents, + favicon::FaviconService *faviconService, + WebContentsAdapterClient *viewClient); + + // FaviconDriver implementation. + void FetchFavicon(const GURL &page_url, bool is_same_document) override; + gfx::Image GetFavicon() const override; + bool FaviconIsValid() const override; + GURL GetActiveURL() override; + + GURL GetFaviconURL() const; + +protected: + FaviconDriverQt(content::WebContents *webContent, favicon::FaviconService *faviconService, + WebContentsAdapterClient *viewClient); + +private: + friend class content::WebContentsUserData<FaviconDriverQt>; + + // FaviconHandler::Delegate implementation. + int DownloadImage(const GURL &url, int max_image_size, ImageDownloadCallback callback) override; + void DownloadManifest(const GURL &url, ManifestDownloadCallback callback) override; + bool IsOffTheRecord() override; + void OnFaviconUpdated(const GURL &page_url, + favicon::FaviconDriverObserver::NotificationIconType icon_type, + const GURL &icon_url, bool icon_url_changed, + const gfx::Image &image) override; + void OnFaviconDeleted( + const GURL &page_url, + favicon::FaviconDriverObserver::NotificationIconType notification_icon_type) override; + void OnHandlerCompleted(favicon::FaviconHandler *handler) override; + + // content::WebContentsObserver implementation. + void DidUpdateFaviconURL(content::RenderFrameHost *render_frame_host, + const std::vector<blink::mojom::FaviconURLPtr> &candidates) override; + void DidUpdateWebManifestURL(content::RenderFrameHost *target_frame, + const base::Optional<GURL> &manifest_url) override; + void DidStartNavigation(content::NavigationHandle *navigation_handle) override; + void DidFinishNavigation(content::NavigationHandle *navigation_handle) override; + void DocumentOnLoadCompletedInMainFrame() override; + + // Informs FaviconService that the favicon for |url| is out of date. If + // |force_reload| is true, then discard information about favicon download + // failures. + void SetFaviconOutOfDateForPage(const GURL &url, bool force_reload); + + // Broadcasts new favicon URL candidates to FaviconHandlers. + void OnUpdateCandidates(const GURL &page_url, + const std::vector<favicon::FaviconURL> &candidates, + const GURL &manifest_url); + + void emitIconChangedIfNeeded(); + + // KeyedService used by FaviconDriverImpl. It may be null during testing, + // but if it is defined, it must outlive the FaviconDriverImpl. + favicon::FaviconService *m_faviconService; + + WebContentsAdapterClient *m_viewClient; + + // FaviconHandlers used to download the different kind of favicons. + std::vector<std::unique_ptr<favicon::FaviconHandler>> m_handlers; + + GURL m_bypassCachePageURL; + bool m_documentOnLoadCompleted = false; + + // nullopt until the actual list is reported via DidUpdateFaviconURL(). + base::Optional<std::vector<blink::mojom::FaviconURL>> m_faviconUrls; + // Web Manifest URL or empty URL if none. + GURL m_manifestUrl; + + int m_completedHandlersCount = 0; + FaviconStatusQt m_latestFavicon; + + WEB_CONTENTS_USER_DATA_KEY_DECL(); + DISALLOW_COPY_AND_ASSIGN(FaviconDriverQt); +}; + +} // namespace QtWebEngineCore + +#endif // FAVICON_DRIVER_QT_H diff --git a/src/core/favicon_manager.cpp b/src/core/favicon_manager.cpp deleted file mode 100644 index 3cb417c4f..000000000 --- a/src/core/favicon_manager.cpp +++ /dev/null @@ -1,437 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "favicon_manager.h" -#include "type_conversion.h" -#include "web_contents_adapter_client.h" -#include "web_engine_settings.h" - -#include "base/bind.h" -#include "content/public/browser/favicon_status.h" -#include "content/public/browser/navigation_entry.h" -#include "content/public/browser/web_contents.h" -#include "content/public/common/url_constants.h" -#include "net/base/data_url.h" -#include "third_party/skia/include/core/SkBitmap.h" -#include "third_party/skia/include/core/SkPixelRef.h" -#include "ui/gfx/geometry/size.h" - -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -#include <qiconengine.h> -#include <private/qicon_p.h> -#endif - -namespace QtWebEngineCore { - -static inline bool isResourceUrl(const QUrl &url) -{ - return !url.scheme().compare(QLatin1String("qrc")); -} - -static inline bool isDataUrl(const QUrl &url) -{ - return !url.scheme().compare(QLatin1String(url::kDataScheme)); -} - -static inline unsigned area(const QSize &size) -{ - return size.width() * size.height(); -} - - -FaviconManager::FaviconManager(content::WebContents *webContents, WebContentsAdapterClient *viewClient) - : m_webContents(webContents) - , m_viewClient(viewClient) - , m_candidateCount(0) - , m_weakFactory(new base::WeakPtrFactory<FaviconManager>(this)) -{ -} - -FaviconManager::~FaviconManager() -{ -} - -int FaviconManager::downloadIcon(const QUrl &url) -{ - static const uint32_t maxSize = 256; - static int fakeId = 0; - int id; - - bool cached = m_icons.contains(url); - if (isResourceUrl(url) || isDataUrl(url) || cached) { - id = --fakeId; - m_pendingRequests.insert(id, url); - } else { - id = m_webContents->DownloadImage( - toGurl(url), - true, // is_favicon - 0, // preferred_size - maxSize, - false, // normal cache policy - base::Bind(&FaviconManager::iconDownloadFinished, m_weakFactory->GetWeakPtr())); - } - - Q_ASSERT(!m_inProgressRequests.contains(id)); - m_inProgressRequests.insert(id, url); - - return id; -} - -void FaviconManager::iconDownloadFinished(int id, - int status, - const GURL &url, - const std::vector<SkBitmap> &bitmaps, - const std::vector<gfx::Size> &original_bitmap_sizes) -{ - Q_UNUSED(status); - Q_UNUSED(url); - Q_UNUSED(original_bitmap_sizes); - - storeIcon(id, toQIcon(bitmaps)); -} - -/* Pending requests are used to mark icons that are already downloaded (cached icons or icons - * stored in qrc). These requests are also stored in the m_inProgressRequests but the corresponding - * icons are stored in m_icons explicitly by this function. It is necessary to avoid - * m_inProgressRequests being emptied right before the next icon is added by a downloadIcon() call. - */ -void FaviconManager::downloadPendingRequests() -{ - for (auto it = m_pendingRequests.cbegin(), end = m_pendingRequests.cend(); it != end; ++it) { - QIcon icon; - - QUrl requestUrl = it.value(); - if (!m_icons.contains(requestUrl)) { - if (isResourceUrl(requestUrl)) { - icon = QIcon(requestUrl.toString().remove(0, 3)); - } else if (isDataUrl(requestUrl)) { - std::string mime_type, char_set, data; - if (net::DataURL::Parse(toGurl(requestUrl), &mime_type, &char_set, &data) && !data.empty()) { - const unsigned char *src_data = reinterpret_cast<const unsigned char *>(data.data()); - QImage image = QImage::fromData(src_data, data.size()); - icon.addPixmap(QPixmap::fromImage(image).copy()); - } - } - } - - storeIcon(it.key(), icon); - } - - m_pendingRequests.clear(); -} - -void FaviconManager::storeIcon(int id, const QIcon &icon) -{ - - // Icon download has been interrupted - if (!m_inProgressRequests.contains(id)) - return; - - QUrl requestUrl = m_inProgressRequests[id]; - FaviconInfo &faviconInfo = m_faviconInfoMap[requestUrl]; - - unsigned iconCount = 0; - if (!icon.isNull()) - iconCount = icon.availableSizes().count(); - - if (iconCount > 0) { - m_icons.insert(requestUrl, icon); - - faviconInfo.size = icon.availableSizes().at(0); - if (iconCount > 1) { - faviconInfo.multiSize = true; - unsigned bestArea = area(faviconInfo.size); - for (unsigned i = 1; i < iconCount; ++i) { - QSize iconSize = icon.availableSizes().at(i); - if (bestArea < area(iconSize)) { - faviconInfo.size = iconSize; - bestArea = area(iconSize); - } - } - } - } else if (id >= 0) { - // Reset size if icon cannot be downloaded - faviconInfo.size = QSize(0, 0); - } - - m_inProgressRequests.remove(id); - if (m_inProgressRequests.isEmpty()) { - QWebEngineSettings *settings = m_viewClient->webEngineSettings(); - bool touchIconsEnabled = settings->testAttribute(QWebEngineSettings::TouchIconsEnabled); - - generateCandidateIcon(touchIconsEnabled); - const QUrl &iconUrl = candidateIconUrl(touchIconsEnabled); - propagateIcon(iconUrl); - } -} - -void FaviconManager::propagateIcon(const QUrl &iconUrl) const -{ - content::NavigationEntry *entry = m_webContents->GetController().GetVisibleEntry(); - if (entry) { - content::FaviconStatus &favicon = entry->GetFavicon(); - favicon.url = toGurl(iconUrl); - favicon.valid = true; - } - - m_viewClient->iconChanged(iconUrl); -} - -QIcon FaviconManager::getIcon(const QUrl &url) const -{ - if (url.isEmpty()) - return m_candidateIcon; - - if (!m_icons.contains(url)) - return QIcon(); - - return m_icons[url]; -} - -FaviconInfo FaviconManager::getFaviconInfo(const QUrl &url) const -{ - Q_ASSERT(m_faviconInfoMap.contains(url)); - return m_faviconInfoMap[url]; -} - -QList<FaviconInfo> FaviconManager::getFaviconInfoList(bool candidatesOnly) const -{ - QList<FaviconInfo> faviconInfoList = m_faviconInfoMap.values(); - - if (candidatesOnly) { - const auto hasNoCandidate = [](const FaviconInfo &info) { return !info.candidate; }; - faviconInfoList.erase(std::remove_if(faviconInfoList.begin(), faviconInfoList.end(), - hasNoCandidate), - faviconInfoList.end()); - } - - return faviconInfoList; -} - -void FaviconManager::update(const QList<FaviconInfo> &candidates) -{ - updateCandidates(candidates); - - QWebEngineSettings *settings = m_viewClient->webEngineSettings(); - if (!settings->testAttribute(QWebEngineSettings::AutoLoadIconsForPage)) { - m_viewClient->iconChanged(QUrl()); - return; - } - - bool touchIconsEnabled = settings->testAttribute(QWebEngineSettings::TouchIconsEnabled); - - const QList<FaviconInfo> &faviconInfoList = getFaviconInfoList(true /* candidates only */); - for (auto it = faviconInfoList.cbegin(), end = faviconInfoList.cend(); it != end; ++it) { - if (!touchIconsEnabled && !(it->type & FaviconInfo::Favicon)) - continue; - - if (it->isValid()) - downloadIcon(it->url); - } - - downloadPendingRequests(); - - // Reset icon if nothing was downloaded - if (m_inProgressRequests.isEmpty()) { - content::NavigationEntry *entry = m_webContents->GetController().GetVisibleEntry(); - if (entry && !entry->GetFavicon().valid) - m_viewClient->iconChanged(QUrl()); - } -} - -void FaviconManager::updateCandidates(const QList<FaviconInfo> &candidates) -{ - // Invalidate types of the already stored candidate icons because it might differ - // among pages. - for (FaviconInfo candidateFaviconInfo : candidates) { - const QUrl &candidateUrl = candidateFaviconInfo.url; - if (m_faviconInfoMap.contains(candidateUrl)) - m_faviconInfoMap[candidateUrl].type = FaviconInfo::InvalidIcon; - } - - m_candidateCount = candidates.count(); - for (FaviconInfo candidateFaviconInfo : candidates) { - const QUrl &candidateUrl = candidateFaviconInfo.url; - - if (!m_faviconInfoMap.contains(candidateUrl)) - m_faviconInfoMap.insert(candidateUrl, candidateFaviconInfo); - else { - // The same icon URL can be used for different types. - m_faviconInfoMap[candidateUrl].type |= candidateFaviconInfo.type; - } - - m_faviconInfoMap[candidateUrl].candidate = true; - } -} - -void FaviconManager::resetCandidates() -{ - // Interrupt in progress icon downloads - m_pendingRequests.clear(); - m_inProgressRequests.clear(); - - m_candidateCount = 0; - m_candidateIcon = QIcon(); - for (auto it = m_faviconInfoMap.begin(), end = m_faviconInfoMap.end(); it != end; ++it) - it->candidate = false; -} - -bool FaviconManager::hasCandidate() const -{ - return (m_candidateCount > 0); -} - -QUrl FaviconManager::candidateIconUrl(bool touchIconsEnabled) const -{ - QUrl iconUrl; - const QList<FaviconInfo> &faviconInfoList = getFaviconInfoList(true /* candidates only */); - - unsigned bestArea = 0; - for (auto it = faviconInfoList.cbegin(), end = faviconInfoList.cend(); it != end; ++it) { - if (!touchIconsEnabled && !(it->type & FaviconInfo::Favicon)) - continue; - - if (it->isValid() && bestArea < area(it->size)) { - iconUrl = it->url; - bestArea = area(it->size); - } - } - - return iconUrl; -} - -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -static QPixmap getUnscaledPixmap(QIcon icon, const QSize &size) -{ - QPixmap pixmap = icon.data_ptr()->engine->pixmap(size, QIcon::Normal, QIcon::Off); - pixmap.setDevicePixelRatio(1.0); - return pixmap; -} -#else -static QPixmap getUnscaledPixmap(const QIcon &icon, const QSize &size) -{ - return icon.pixmap(size, 1.0); -} -#endif - -void FaviconManager::generateCandidateIcon(bool touchIconsEnabled) -{ - Q_ASSERT(m_candidateCount); - - m_candidateIcon = QIcon(); - const QList<FaviconInfo> &faviconInfoList = getFaviconInfoList(true /* candidates only */); - - for (auto it = faviconInfoList.cbegin(), end = faviconInfoList.cend(); it != end; ++it) { - if (!touchIconsEnabled && !(it->type & FaviconInfo::Favicon)) - continue; - - if (!it->isValid() || !it->isDownloaded()) - continue; - - const QIcon &icon = getIcon(it->url); - - if (!it->multiSize) { - if (!m_candidateIcon.availableSizes().contains(it->size)) - m_candidateIcon.addPixmap(getUnscaledPixmap(icon, it->size)); - - continue; - } - - const auto sizes = icon.availableSizes(); - for (const QSize &size : sizes) { - if (!m_candidateIcon.availableSizes().contains(size)) - m_candidateIcon.addPixmap(getUnscaledPixmap(icon, size)); - } - } -} - -void FaviconManager::copyStateFrom(FaviconManager *source) -{ - m_faviconInfoMap = source->m_faviconInfoMap; - m_icons = source->m_icons; -} - -FaviconInfo::FaviconInfo() - : url(QUrl()) - , type(FaviconInfo::InvalidIcon) - , size(QSize(0, 0)) - , candidate(false) - , multiSize(false) -{ -} - -FaviconInfo::FaviconInfo(const FaviconInfo &other) - : url(other.url) - , type(other.type) - , size(other.size) - , candidate(other.candidate) - , multiSize(other.multiSize) -{ -} - -FaviconInfo::FaviconInfo(const QUrl &url, FaviconInfo::FaviconTypeFlags type) - : url(url) - , type(type) - , size(QSize(0, 0)) - , candidate(false) - , multiSize(false) -{ -} - -FaviconInfo::~FaviconInfo() -{ -} - -bool FaviconInfo::isValid() const -{ - if (type == FaviconInfo::InvalidIcon) - return false; - - if (url.isEmpty() || !url.isValid()) - return false; - - return true; -} - -bool FaviconInfo::isDownloaded() const -{ - return area(size) > 0; -} - -} // namespace QtWebEngineCore diff --git a/src/core/favicon_manager.h b/src/core/favicon_manager.h deleted file mode 100644 index a6e5822a9..000000000 --- a/src/core/favicon_manager.h +++ /dev/null @@ -1,151 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#ifndef FAVICON_MANAGER_H -#define FAVICON_MANAGER_H - -#include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h> -#include <memory> -#include <QtCore/QMap> -#include <QtCore/QObject> -#include <QtCore/QSize> -#include <QtCore/QUrl> -#include <QtGui/QIcon> - -#include "web_engine_settings.h" - -class GURL; -class SkBitmap; - -namespace gfx { -class Size; -} - -namespace content { -class WebContents; -} - -namespace base { -template<class T> -class WeakPtrFactory; -} - -namespace QtWebEngineCore { - -class WebContentsAdapterClient; - -// Based on src/3rdparty/chromium/content/public/common/favicon_url.h -class Q_WEBENGINECORE_PRIVATE_EXPORT FaviconInfo { -public: - enum FaviconTypeFlag { - InvalidIcon = 0, - Favicon = 1 << 0, - TouchIcon = 1 << 1, - TouchPrecomposedIcon = 1 << 2 - }; - Q_DECLARE_FLAGS(FaviconTypeFlags, FaviconTypeFlag) - - FaviconInfo(); - FaviconInfo(const FaviconInfo &); - FaviconInfo(const QUrl &, FaviconInfo::FaviconTypeFlags); - ~FaviconInfo(); - - bool isValid() const; - bool isDownloaded() const; - - QUrl url; - FaviconTypeFlags type; - // Stores the largest size in case of multi-size icon - QSize size; - bool candidate; - bool multiSize; -}; - - -class Q_WEBENGINECORE_PRIVATE_EXPORT FaviconManager { - -public: - FaviconManager(content::WebContents *, WebContentsAdapterClient *); - ~FaviconManager(); - - QIcon getIcon(const QUrl &url = QUrl()) const; - FaviconInfo getFaviconInfo(const QUrl &) const; - QList<FaviconInfo> getFaviconInfoList(bool) const; - void copyStateFrom(FaviconManager *source); - -private: - void update(const QList<FaviconInfo> &); - void updateCandidates(const QList<FaviconInfo> &); - void resetCandidates(); - bool hasCandidate() const; - QUrl candidateIconUrl(bool touchIconsEnabled) const; - void generateCandidateIcon(bool touchIconsEnabled); - int downloadIcon(const QUrl &); - void iconDownloadFinished(int, int, const GURL &, const std::vector<SkBitmap> &, const std::vector<gfx::Size> &); - void storeIcon(int, const QIcon &); - void downloadPendingRequests(); - void propagateIcon(const QUrl &) const; - -private: - content::WebContents *m_webContents; - WebContentsAdapterClient *m_viewClient; - QMap<QUrl, FaviconInfo> m_faviconInfoMap; - int m_candidateCount; - QIcon m_candidateIcon; - QMap<QUrl, QIcon> m_icons; - QMap<int, QUrl> m_inProgressRequests; - QMap<int, QUrl> m_pendingRequests; - std::unique_ptr<base::WeakPtrFactory<FaviconManager>> m_weakFactory; - friend class WebContentsDelegateQt; -}; - -} // namespace QtWebEngineCore - -#endif // FAVICON_MANAGER_H diff --git a/src/core/favicon_service_factory_qt.cpp b/src/core/favicon_service_factory_qt.cpp new file mode 100644 index 000000000..898882486 --- /dev/null +++ b/src/core/favicon_service_factory_qt.cpp @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "favicon_service_factory_qt.h" + +#include "base/files/file_util.h" +#include "components/favicon/core/favicon_service_impl.h" +#include "components/history/content/browser/content_visit_delegate.h" +#include "components/history/content/browser/history_database_helper.h" +#include "components/history/core/browser/history_backend_client.h" +#include "components/history/core/browser/history_database_params.h" +#include "components/history/core/browser/history_service.h" +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "content/public/browser/browser_context.h" +#include "url/gurl.h" + +namespace QtWebEngineCore { + +void HistoryClientQt::OnHistoryServiceCreated(history::HistoryService *history_service) +{ + Q_UNUSED(history_service); +} + +void HistoryClientQt::Shutdown() { } + +bool HistoryClientQt::CanAddURL(const GURL &url) +{ + Q_UNUSED(url); + return true; +} + +void HistoryClientQt::NotifyProfileError(sql::InitStatus init_status, + const std::string &diagnostics) +{ + Q_UNUSED(init_status); + Q_UNUSED(diagnostics); +} + +std::unique_ptr<history::HistoryBackendClient> HistoryClientQt::CreateBackendClient() +{ + return nullptr; +} + +// static +history::HistoryService * +HistoryServiceFactoryQt::GetForBrowserContext(content::BrowserContext *context) +{ + if (context->IsOffTheRecord()) + return nullptr; + + if (!base::PathExists(context->GetPath())) + return nullptr; + + return static_cast<history::HistoryService *>( + GetInstance()->GetServiceForBrowserContext(context, true)); +} + +// static +HistoryServiceFactoryQt *HistoryServiceFactoryQt::GetInstance() +{ + return base::Singleton<HistoryServiceFactoryQt>::get(); +} + +HistoryServiceFactoryQt::HistoryServiceFactoryQt() + : BrowserContextKeyedServiceFactory("HistoryService", + BrowserContextDependencyManager::GetInstance()) +{ +} + +HistoryServiceFactoryQt::~HistoryServiceFactoryQt() { } + +content::BrowserContext * +HistoryServiceFactoryQt::GetBrowserContextToUse(content::BrowserContext *context) const +{ + return context; +} + +KeyedService * +HistoryServiceFactoryQt::BuildServiceInstanceFor(content::BrowserContext *context) const +{ + Q_ASSERT(!context->IsOffTheRecord()); + Q_ASSERT(base::PathExists(context->GetPath())); + + std::unique_ptr<history::HistoryService> historyService( + new history::HistoryService(std::make_unique<HistoryClientQt>(), nullptr)); + if (!historyService->Init(history::HistoryDatabaseParamsForPath(context->GetPath()))) { + return nullptr; + } + return historyService.release(); +} + +bool FaviconClientQt::IsNativeApplicationURL(const GURL &url) +{ + Q_UNUSED(url); + return false; +} + +bool FaviconClientQt::IsReaderModeURL(const GURL &url) +{ + Q_UNUSED(url) + return false; +} + +const GURL FaviconClientQt::GetOriginalUrlFromReaderModeUrl(const GURL &url) +{ + return url; +} + +base::CancelableTaskTracker::TaskId FaviconClientQt::GetFaviconForNativeApplicationURL( + const GURL &url, const std::vector<int> &desired_sizes_in_pixel, + favicon_base::FaviconResultsCallback callback, base::CancelableTaskTracker *tracker) +{ + Q_UNUSED(url); + Q_UNUSED(desired_sizes_in_pixel); + Q_UNUSED(callback); + Q_UNUSED(tracker); + + return base::CancelableTaskTracker::kBadTaskId; +} + +// static +favicon::FaviconService * +FaviconServiceFactoryQt::GetForBrowserContext(content::BrowserContext *context) +{ + return static_cast<favicon::FaviconService *>( + GetInstance()->GetServiceForBrowserContext(context, true)); +} + +// static +FaviconServiceFactoryQt *FaviconServiceFactoryQt::GetInstance() +{ + return base::Singleton<FaviconServiceFactoryQt>::get(); +} + +FaviconServiceFactoryQt::FaviconServiceFactoryQt() + : BrowserContextKeyedServiceFactory("FaviconService", + BrowserContextDependencyManager::GetInstance()) +{ +} + +FaviconServiceFactoryQt::~FaviconServiceFactoryQt() { } + +content::BrowserContext * +FaviconServiceFactoryQt::GetBrowserContextToUse(content::BrowserContext *context) const +{ + return context; +} + +KeyedService * +FaviconServiceFactoryQt::BuildServiceInstanceFor(content::BrowserContext *context) const +{ + history::HistoryService *historyService = static_cast<history::HistoryService *>( + HistoryServiceFactoryQt::GetInstance()->GetForBrowserContext(context)); + return new favicon::FaviconServiceImpl(std::make_unique<FaviconClientQt>(), historyService); +} + +} // namespace QtWebEngineCore diff --git a/src/core/favicon_service_factory_qt.h b/src/core/favicon_service_factory_qt.h new file mode 100644 index 000000000..1ba0db076 --- /dev/null +++ b/src/core/favicon_service_factory_qt.h @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef FAVICON_SERVICE_FACTORY_QT_H +#define FAVICON_SERVICE_FACTORY_QT_H + +#include "qtwebenginecoreglobal_p.h" + +#include "base/memory/singleton.h" +#include "base/task/cancelable_task_tracker.h" +#include "components/favicon/core/favicon_client.h" +#include "components/history/core/browser/history_client.h" +#include "components/keyed_service/content/browser_context_keyed_service_factory.h" + +class GURL; + +namespace content { +class BrowserContext; +} + +namespace favicon { +class FaviconService; +} + +namespace history { +class HistoryBackendClient; +class HistoryService; +} + +namespace QtWebEngineCore { + +class HistoryClientQt : public history::HistoryClient +{ +public: + HistoryClientQt() { } + virtual ~HistoryClientQt() { } + + void OnHistoryServiceCreated(history::HistoryService *history_service) override; + void Shutdown() override; + bool CanAddURL(const GURL &url) override; + void NotifyProfileError(sql::InitStatus init_status, const std::string &diagnostics) override; + std::unique_ptr<history::HistoryBackendClient> CreateBackendClient() override; +}; + +class HistoryServiceFactoryQt : public BrowserContextKeyedServiceFactory +{ +public: + static history::HistoryService *GetForBrowserContext(content::BrowserContext *context); + static HistoryServiceFactoryQt *GetInstance(); + +private: + friend struct base::DefaultSingletonTraits<HistoryServiceFactoryQt>; + + HistoryServiceFactoryQt(); + ~HistoryServiceFactoryQt() override; + + // BrowserContextKeyedServiceFactory: + content::BrowserContext * + GetBrowserContextToUse(content::BrowserContext *context) const override; + KeyedService *BuildServiceInstanceFor(content::BrowserContext *context) const override; +}; + +class FaviconClientQt : public favicon::FaviconClient +{ +public: + FaviconClientQt() { } + virtual ~FaviconClientQt() { } + + bool IsNativeApplicationURL(const GURL &url) override; + bool IsReaderModeURL(const GURL &url) override; + const GURL GetOriginalUrlFromReaderModeUrl(const GURL &url) override; + base::CancelableTaskTracker::TaskId + GetFaviconForNativeApplicationURL(const GURL &url, + const std::vector<int> &desired_sizes_in_pixel, + favicon_base::FaviconResultsCallback callback, + base::CancelableTaskTracker *tracker) override; +}; + +class FaviconServiceFactoryQt : public BrowserContextKeyedServiceFactory +{ +public: + static favicon::FaviconService *GetForBrowserContext(content::BrowserContext *context); + static FaviconServiceFactoryQt *GetInstance(); + +private: + friend struct base::DefaultSingletonTraits<FaviconServiceFactoryQt>; + + FaviconServiceFactoryQt(); + ~FaviconServiceFactoryQt() override; + + // BrowserContextKeyedServiceFactory: + content::BrowserContext * + GetBrowserContextToUse(content::BrowserContext *context) const override; + KeyedService *BuildServiceInstanceFor(content::BrowserContext *context) const override; +}; + +} // namespace QtWebEngineCore + +#endif // FAVICON_SERVICE_FACTORY_QT_H diff --git a/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp b/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp index bca059ae6..e01e82aa9 100644 --- a/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp +++ b/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp @@ -56,6 +56,7 @@ #include "extensions/extension_system_qt.h" #include "web_contents_delegate_qt.h" +#include "web_engine_settings.h" #include <string> diff --git a/src/core/profile_adapter.cpp b/src/core/profile_adapter.cpp index 9a6275a84..204974c28 100644 --- a/src/core/profile_adapter.cpp +++ b/src/core/profile_adapter.cpp @@ -39,6 +39,10 @@ #include "profile_adapter.h" +#include "components/favicon/core/favicon_service.h" +#include "components/history/content/browser/history_database_helper.h" +#include "components/history/core/browser/history_database_params.h" +#include "components/history/core/browser/history_service.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/browsing_data_remover.h" @@ -51,6 +55,7 @@ #include "api/qwebengineurlscheme.h" #include "content_browser_client_qt.h" #include "download_manager_delegate_qt.h" +#include "favicon_service_factory_qt.h" #include "permission_manager_qt.h" #include "profile_adapter_client.h" #include "profile_io_data_qt.h" @@ -151,6 +156,8 @@ void ProfileAdapter::setStorageName(const QString &storageName) m_profile->m_profileIOData->resetNetworkContext(); if (m_visitedLinksManager) resetVisitedLinksManager(); + + reinitializeHistoryService(); } } @@ -164,6 +171,14 @@ void ProfileAdapter::setOffTheRecord(bool offTheRecord) m_profile->m_profileIOData->resetNetworkContext(); if (m_visitedLinksManager) resetVisitedLinksManager(); + + if (offTheRecord) { + favicon::FaviconService *faviconService = + FaviconServiceFactoryQt::GetForBrowserContext(m_profile.data()); + faviconService->SetHistoryService(nullptr); + } else if (!m_name.isEmpty()) { + reinitializeHistoryService(); + } } ProfileQt *ProfileAdapter::profile() @@ -273,6 +288,9 @@ void ProfileAdapter::setDataPath(const QString &path) m_profile->m_profileIOData->resetNetworkContext(); if (!m_offTheRecord && m_visitedLinksManager) resetVisitedLinksManager(); + + if (!m_offTheRecord) + reinitializeHistoryService(); } void ProfileAdapter::setDownloadPath(const QString &path) @@ -652,6 +670,21 @@ void ProfileAdapter::resetVisitedLinksManager() m_visitedLinksManager.reset(new VisitedLinksManagerQt(m_profile.data(), persistVisitedLinks())); } +void ProfileAdapter::reinitializeHistoryService() +{ + Q_ASSERT(!m_profile->IsOffTheRecord()); + if (m_profile->ensureDirectoryExists()) { + favicon::FaviconService *faviconService = + FaviconServiceFactoryQt::GetForBrowserContext(m_profile.data()); + history::HistoryService *historyService = static_cast<history::HistoryService *>( + HistoryServiceFactoryQt::GetInstance()->GetForBrowserContext(m_profile.data())); + Q_ASSERT(historyService); + faviconService->SetHistoryService(historyService); + } else { + qWarning("Favicon database is not available for this profile."); + } +} + void ProfileAdapter::setUseForGlobalCertificateVerification(bool enable) { if (m_usedForGlobalCertificateVerification == enable) diff --git a/src/core/profile_adapter.h b/src/core/profile_adapter.h index fecb338ad..979316b4a 100644 --- a/src/core/profile_adapter.h +++ b/src/core/profile_adapter.h @@ -220,6 +220,7 @@ private: void updateCustomUrlSchemeHandlers(); void resetVisitedLinksManager(); bool persistVisitedLinks() const; + void reinitializeHistoryService(); QString m_name; bool m_offTheRecord; diff --git a/src/core/profile_qt.cpp b/src/core/profile_qt.cpp index 36303605f..ae1169558 100644 --- a/src/core/profile_qt.cpp +++ b/src/core/profile_qt.cpp @@ -58,6 +58,7 @@ #include "content/public/browser/storage_partition.h" #include "base/base_paths.h" +#include "base/files/file_util.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/prefs/pref_member.h" #include "components/prefs/pref_service.h" @@ -298,4 +299,21 @@ content::PlatformNotificationService *ProfileQt::platformNotificationService() return m_platformNotificationService.get(); } +bool ProfileQt::ensureDirectoryExists() +{ + const base::FilePath &path = GetPath(); + + if (base::PathExists(path)) + return true; + + base::File::Error error; + if (base::CreateDirectoryAndGetError(path, &error)) + return true; + + std::string errorstr = base::File::ErrorToString(error); + qWarning("Cannot create directory %s. Error: %s.", path.AsUTF8Unsafe().c_str(), + errorstr.c_str()); + return false; +} + } // namespace QtWebEngineCore diff --git a/src/core/profile_qt.h b/src/core/profile_qt.h index 11b567b97..349532939 100644 --- a/src/core/profile_qt.h +++ b/src/core/profile_qt.h @@ -119,6 +119,7 @@ public: PrefServiceAdapter &prefServiceAdapter(); const PrefServiceAdapter &prefServiceAdapter() const; + bool ensureDirectoryExists(); private: friend class ContentBrowserClientQt; diff --git a/src/core/qtwebengine.gni b/src/core/qtwebengine.gni index 49217603f..8f3cac727 100644 --- a/src/core/qtwebengine.gni +++ b/src/core/qtwebengine.gni @@ -19,6 +19,8 @@ deps = [ "//base", "//components/cdm/renderer", "//components/error_page/common", + "//components/favicon/content", + "//components/history/content/browser", "//components/keyed_service/content", "//components/navigation_interception", "//components/network_hints/browser", diff --git a/src/core/type_conversion.cpp b/src/core/type_conversion.cpp index a4cc57b76..e8f8131b6 100644 --- a/src/core/type_conversion.cpp +++ b/src/core/type_conversion.cpp @@ -39,9 +39,11 @@ #include "type_conversion.h" +#include <components/favicon_base/favicon_util.h> #include <net/cert/x509_certificate.h> #include <net/cert/x509_util.h> #include <ui/events/event_constants.h> +#include <ui/gfx/image/image.h> #include <ui/gfx/image/image_skia.h> #include "third_party/blink/public/mojom/favicon/favicon_url.mojom.h" @@ -216,6 +218,23 @@ SkBitmap toSkBitmap(const QImage &image) return bitmapCopy; } +QIcon toQIcon(const gfx::Image &image) +{ + // Based on ExtractSkBitmapsToStore in chromium/components/favicon/core/favicon_service_impl.cc + gfx::ImageSkia image_skia = image.AsImageSkia(); + image_skia.EnsureRepsForSupportedScales(); + const std::vector<gfx::ImageSkiaRep> &image_reps = image_skia.image_reps(); + std::vector<SkBitmap> bitmaps; + const std::vector<float> favicon_scales = favicon_base::GetFaviconScales(); + for (size_t i = 0; i < image_reps.size(); ++i) { + // Don't save if the scale isn't one of supported favicon scales. + if (!base::Contains(favicon_scales, image_reps[i].scale())) + continue; + bitmaps.push_back(image_reps[i].GetBitmap()); + } + return toQIcon(bitmaps); +} + QIcon toQIcon(const std::vector<SkBitmap> &bitmaps) { if (!bitmaps.size()) @@ -257,33 +276,6 @@ int flagsFromModifiers(Qt::KeyboardModifiers modifiers) return modifierFlags; } -FaviconInfo::FaviconTypeFlags toQt(blink::mojom::FaviconIconType type) -{ - switch (type) { - case blink::mojom::FaviconIconType::kFavicon: - return FaviconInfo::Favicon; - case blink::mojom::FaviconIconType::kTouchIcon: - return FaviconInfo::TouchIcon; - case blink::mojom::FaviconIconType::kTouchPrecomposedIcon: - return FaviconInfo::TouchPrecomposedIcon; - case blink::mojom::FaviconIconType::kInvalid: - return FaviconInfo::InvalidIcon; - } - Q_UNREACHABLE(); - return FaviconInfo::InvalidIcon; -} - -FaviconInfo toFaviconInfo(const blink::mojom::FaviconURLPtr &favicon_url) -{ - FaviconInfo info; - info.url = toQt(favicon_url->icon_url); - info.type = toQt(favicon_url->icon_type); - // TODO: Add support for rel sizes attribute (favicon_url.icon_sizes): - // http://www.w3schools.com/tags/att_link_sizes.asp - info.size = QSize(0, 0); - return info; -} - void convertToQt(const SkMatrix44 &m, QMatrix4x4 &c) { QMatrix4x4 qtMatrix( diff --git a/src/core/type_conversion.h b/src/core/type_conversion.h index 85fd763b4..fff130218 100644 --- a/src/core/type_conversion.h +++ b/src/core/type_conversion.h @@ -52,7 +52,6 @@ #include <base/strings/nullable_string16.h> #include "base/files/file_path.h" #include "base/time/time.h" -#include "favicon_manager.h" #include "net/cookies/canonical_cookie.h" #include "third_party/blink/public/mojom/favicon/favicon_url.mojom-forward.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -68,6 +67,7 @@ QT_FORWARD_DECLARE_CLASS(QMatrix4x4) QT_FORWARD_DECLARE_CLASS(QSslCertificate) namespace gfx { +class Image; class ImageSkiaRep; } @@ -222,6 +222,7 @@ QImage toQImage(const SkBitmap &bitmap); QImage toQImage(const gfx::ImageSkiaRep &imageSkiaRep); SkBitmap toSkBitmap(const QImage &image); +QIcon toQIcon(const gfx::Image &image); QIcon toQIcon(const std::vector<SkBitmap> &bitmaps); void convertToQt(const SkMatrix44 &m, QMatrix4x4 &c); @@ -272,8 +273,6 @@ inline QStringList fromVector(const std::vector<base::string16> &vector) return result; } -FaviconInfo toFaviconInfo(const blink::mojom::FaviconURLPtr &favicon_url); - QList<QSslCertificate> toCertificateChain(net::X509Certificate *certificate); Qt::InputMethodHints toQtInputMethodHints(ui::TextInputType inputType); diff --git a/src/core/visited_links_manager_qt.cpp b/src/core/visited_links_manager_qt.cpp index 37343cc39..15f655012 100644 --- a/src/core/visited_links_manager_qt.cpp +++ b/src/core/visited_links_manager_qt.cpp @@ -90,27 +90,12 @@ bool VisitedLinksManagerQt::containsUrl(const QUrl &url) const return m_visitedLinkWriter->IsVisited(toGurl(url)); } -static void ensureDirectoryExists(const base::FilePath &path) -{ - if (base::PathExists(path)) - return; - - base::File::Error error; - if (base::CreateDirectoryAndGetError(path, &error)) - return; - - std::string errorstr = base::File::ErrorToString(error); - qWarning("Cannot create directory %s. Error: %s.", - path.AsUTF8Unsafe().c_str(), - errorstr.c_str()); -} - VisitedLinksManagerQt::VisitedLinksManagerQt(ProfileQt *profile, bool persistVisitedLinks) : m_delegate(new VisitedLinkDelegateQt) { Q_ASSERT(profile); if (persistVisitedLinks) - ensureDirectoryExists(profile->GetPath()); + profile->ensureDirectoryExists(); m_visitedLinkWriter.reset(new visitedlink::VisitedLinkWriter(profile, m_delegate.data(), persistVisitedLinks)); m_visitedLinkWriter->Init(); } diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index f5656f571..16e91e6c7 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -45,6 +45,8 @@ #include "devtools_frontend_qt.h" #include "download_manager_delegate_qt.h" +#include "favicon_driver_qt.h" +#include "favicon_service_factory_qt.h" #include "media_capture_devices_dispatcher.h" #if QT_CONFIG(webengine_printing_and_pdf) #include "printing/print_view_manager_qt.h" @@ -69,6 +71,7 @@ #include "base/task/sequence_manager/thread_controller_with_message_pump_impl.h" #include "base/values.h" #include "chrome/browser/tab_contents/form_interaction_tab_helper.h" +#include "components/favicon/core/favicon_service.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/renderer_host/text_input_manager.h" #include "content/browser/web_contents/web_contents_impl.h" @@ -532,6 +535,10 @@ void WebContentsAdapter::initialize(content::SiteInstance *site) extensions::ExtensionWebContentsObserverQt::CreateForWebContents(webContents()); #endif + content::BrowserContext *context = webContents()->GetBrowserContext(); + FaviconDriverQt::CreateForWebContents( + webContents(), FaviconServiceFactoryQt::GetForBrowserContext(context), m_adapterClient); + // Create an instance of WebEngineVisitedLinksManager to catch the first // content::NOTIFICATION_RENDERER_PROCESS_CREATED event. This event will // force to initialize visited links in VisitedLinkSlave. @@ -818,12 +825,15 @@ QUrl WebContentsAdapter::requestedUrl() const QUrl WebContentsAdapter::iconUrl() const { CHECK_INITIALIZED(QUrl()); - if (content::NavigationEntry* entry = m_webContents->GetController().GetVisibleEntry()) { - content::FaviconStatus &favicon = entry->GetFavicon(); - if (favicon.valid) - return toQt(favicon.url); - } - return QUrl(); + FaviconDriverQt *driver = FaviconDriverQt::FromWebContents(webContents()); + return toQt(driver->GetFaviconURL()); +} + +QIcon WebContentsAdapter::icon() const +{ + CHECK_INITIALIZED(QIcon()); + FaviconDriverQt *driver = FaviconDriverQt::FromWebContents(webContents()); + return toQIcon(driver->GetFavicon()); } QString WebContentsAdapter::pageTitle() const @@ -1805,12 +1815,6 @@ WebContentsAdapterClient::renderProcessExitStatus(int terminationStatus) { return status; } -FaviconManager *WebContentsAdapter::faviconManager() -{ - CHECK_INITIALIZED(nullptr); - return m_webContentsDelegate->faviconManager(); -} - FindTextHelper *WebContentsAdapter::findTextHelper() { CHECK_INITIALIZED(nullptr); diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h index b05ddeb4d..f4905e1d4 100644 --- a/src/core/web_contents_adapter.h +++ b/src/core/web_contents_adapter.h @@ -138,6 +138,7 @@ public: QString pageTitle() const; QString selectedText() const; QUrl iconUrl() const; + QIcon icon() const; void undo(); void redo(); @@ -212,7 +213,6 @@ public: QWebChannel *webChannel() const; void setWebChannel(QWebChannel *, uint worldId); #endif - FaviconManager *faviconManager(); FindTextHelper *findTextHelper(); QPointF lastScrollOffset() const; diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index 5d11f43c3..34e1f7ad1 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -46,7 +46,6 @@ #include "profile_adapter.h" #include "color_chooser_controller.h" #include "color_chooser_qt.h" -#include "favicon_manager.h" #include "file_picker_controller.h" #include "media_capture_devices_dispatcher.h" #include "profile_qt.h" @@ -102,7 +101,6 @@ static WebContentsAdapterClient::JavaScriptConsoleMessageLevel mapToJavascriptCo WebContentsDelegateQt::WebContentsDelegateQt(content::WebContents *webContents, WebContentsAdapterClient *adapterClient) : m_viewClient(adapterClient) - , m_faviconManager(new FaviconManager(webContents, adapterClient)) , m_findTextHelper(new FindTextHelper(webContents, adapterClient)) , m_loadingState(determineLoadingState(webContents)) , m_didStartLoadingSeen(m_loadingState == LoadingState::Loading) @@ -362,8 +360,6 @@ void WebContentsDelegateQt::DidStartNavigation(content::NavigationHandle *naviga if (!navigation_handle->IsInMainFrame() || !web_contents()->IsLoadingToDifferentDocument()) return; - m_faviconManager->resetCandidates(); - m_loadingInfo.url = toQt(navigation_handle->GetURL()); // IsErrorPage is only set after navigation commit, so check it otherwise: error page shouldn't have navigation entry bool isErrorPage = m_loadingInfo.triggersErrorPage && !navigation_handle->GetNavigationEntry(); @@ -426,7 +422,6 @@ void WebContentsDelegateQt::DidFinishNavigation(content::NavigationHandle *navig // The load will succede as an error-page load later, and we reported the original error above if (navigation_handle->IsErrorPage()) { // Now report we are starting to load an error-page. - m_faviconManager->resetCandidates(); emitLoadStarted(true); // If it is already committed we will not see another DidFinishNavigation call or a DidFinishLoad call. @@ -533,9 +528,6 @@ void WebContentsDelegateQt::DidFinishLoad(content::RenderFrameHost* render_frame return; } - if (!m_faviconManager->hasCandidate()) - m_viewClient->iconChanged(QUrl()); - content::NavigationEntry *entry = web_contents()->GetController().GetActiveEntry(); int http_statuscode = entry ? entry->GetHttpStatusCode() : 0; bool errorPageEnabled = webEngineSettings()->testAttribute(QWebEngineSettings::ErrorPageEnabled); @@ -547,21 +539,6 @@ void WebContentsDelegateQt::DidFinishLoad(content::RenderFrameHost* render_frame m_loadingInfo.triggersErrorPage = triggersErrorPage; } -void WebContentsDelegateQt::DidUpdateFaviconURL(content::RenderFrameHost *render_frame_host, const std::vector<blink::mojom::FaviconURLPtr> &candidates) -{ - QList<FaviconInfo> faviconCandidates; - faviconCandidates.reserve(static_cast<int>(candidates.size())); - for (const blink::mojom::FaviconURLPtr &candidate : candidates) { - // Store invalid candidates too for later debugging via API - faviconCandidates.append(toFaviconInfo(candidate)); - } - - // Favicon URL can be changed from JavaScript too. Thus we need to reset - // the current candidate icon list to not handle previous icon as a candidate. - m_faviconManager->resetCandidates(); - m_faviconManager->update(faviconCandidates); -} - void WebContentsDelegateQt::WebContentsCreated(content::WebContents * /*source_contents*/, int /*opener_render_process_id*/, int /*opener_render_frame_id*/, const std::string &/*frame_name*/, @@ -867,11 +844,6 @@ void WebContentsDelegateQt::ResourceLoadComplete(content::RenderFrameHost* rende } } -FaviconManager *WebContentsDelegateQt::faviconManager() -{ - return m_faviconManager.data(); -} - FindTextHelper *WebContentsDelegateQt::findTextHelper() { return m_findTextHelper.data(); @@ -890,7 +862,6 @@ void WebContentsDelegateQt::copyStateFrom(WebContentsDelegateQt *source) { m_title = source->m_title; NavigationStateChanged(web_contents(), content::INVALIDATE_TYPE_URL); - m_faviconManager->copyStateFrom(source->m_faviconManager.data()); } WebContentsDelegateQt::LoadingState WebContentsDelegateQt::determineLoadingState(content::WebContents *contents) diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h index c3676d996..d6adcd77c 100644 --- a/src/core/web_contents_delegate_qt.h +++ b/src/core/web_contents_delegate_qt.h @@ -49,7 +49,6 @@ #include "base/callback.h" #include "color_chooser_controller.h" -#include "favicon_manager.h" #include "find_text_helper.h" #include "javascript_dialog_manager_qt.h" #include <QtCore/qlist.h> @@ -166,7 +165,6 @@ public: void DidFailLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url, int error_code) override; void DidFinishLoad(content::RenderFrameHost *render_frame_host, const GURL &validated_url) override; void BeforeUnloadFired(bool proceed, const base::TimeTicks& proceed_time) override; - void DidUpdateFaviconURL(content::RenderFrameHost *render_frame_host, const std::vector<blink::mojom::FaviconURLPtr> &candidates) override; void OnVisibilityChanged(content::Visibility visibility) override; void DidFirstVisuallyNonEmptyPaint() override; void ActivateContents(content::WebContents* contents) override; @@ -180,7 +178,6 @@ public: void selectClientCert(const QSharedPointer<ClientCertSelectController> &); void requestFeaturePermission(ProfileAdapter::PermissionType feature, const QUrl &requestingOrigin); void launchExternalURL(const QUrl &url, ui::PageTransition page_transition, bool is_main_frame, bool has_user_gesture); - FaviconManager *faviconManager(); FindTextHelper *findTextHelper(); void setSavePageInfo(const SavePageInfo &spi) { m_savePageInfo = spi; } @@ -221,7 +218,6 @@ private: int &streamCount(blink::mojom::MediaStreamType type); WebContentsAdapterClient *m_viewClient; - QScopedPointer<FaviconManager> m_faviconManager; QScopedPointer<FindTextHelper> m_findTextHelper; SavePageInfo m_savePageInfo; QSharedPointer<FilePickerController> m_filePickerController; diff --git a/src/core/web_engine_library_info.cpp b/src/core/web_engine_library_info.cpp index 249f50613..6b11cf0cd 100644 --- a/src/core/web_engine_library_info.cpp +++ b/src/core/web_engine_library_info.cpp @@ -38,6 +38,7 @@ ** ****************************************************************************/ +#include "qtwebenginecoreglobal_p.h" #include "web_engine_library_info.h" #include "base/base_paths.h" diff --git a/src/webenginequick/api/qquickwebenginefaviconprovider.cpp b/src/webenginequick/api/qquickwebenginefaviconprovider.cpp index f817e4016..23397003e 100644 --- a/src/webenginequick/api/qquickwebenginefaviconprovider.cpp +++ b/src/webenginequick/api/qquickwebenginefaviconprovider.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWebEngine module of the Qt Toolkit. @@ -39,7 +39,6 @@ #include "qquickwebenginefaviconprovider_p_p.h" -#include "favicon_manager.h" #include "qquickwebengineview_p.h" #include "qquickwebengineview_p_p.h" #include "web_contents_adapter.h" @@ -47,21 +46,65 @@ #include <QtGui/QIcon> #include <QtGui/QPixmap> -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -#include <QtGui/qiconengine.h> -#include <QtGui/private/qicon_p.h> -#endif - QT_BEGIN_NAMESPACE -using QtWebEngineCore::FaviconInfo; -using QtWebEngineCore::FaviconManager; - static inline unsigned area(const QSize &size) { return size.width() * size.height(); } +static QSize largestSize(const QList<QSize> &availableSizes) +{ + QSize result; + for (const QSize &size : availableSizes) { + if (area(size) > area(result)) + result = size; + } + + return result; +} + +static QSize fitSize(const QList<QSize> &availableSizes, const QSize &requestedSize) +{ + Q_ASSERT(availableSizes.count()); + QSize result = largestSize(availableSizes); + if (availableSizes.count() == 1 || area(requestedSize) >= area(result)) + return result; + + for (const QSize &size : availableSizes) { + if (area(size) == area(requestedSize)) + return size; + + if (area(requestedSize) < area(size) && area(size) < area(result)) + result = size; + } + + return result; +} + +static QPixmap extractPixmap(const QIcon &icon, const QSize &requestedSize) +{ + Q_ASSERT(!icon.isNull()); + + // If source size is not specified, use the largest icon + if (!requestedSize.isValid()) + return icon.pixmap(largestSize(icon.availableSizes()), 1.0).copy(); + + const QSize &size = fitSize(icon.availableSizes(), requestedSize); + const QPixmap &iconPixmap = icon.pixmap(size, 1.0); + return iconPixmap.scaled(requestedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation).copy(); +} + +static QQuickWebEngineView *findViewById(const QString &id, QList<QQuickWebEngineView *> *views) +{ + for (QQuickWebEngineView *view : *views) { + if (view->icon() == QQuickWebEngineFaviconProvider::faviconProviderUrl(QUrl(id))) + return view; + } + + return nullptr; +} + QString QQuickWebEngineFaviconProvider::identifier() { return QStringLiteral("favicon"); @@ -75,7 +118,8 @@ QUrl QQuickWebEngineFaviconProvider::faviconProviderUrl(const QUrl &url) QUrl providerUrl; providerUrl.setScheme(QStringLiteral("image")); providerUrl.setHost(identifier()); - providerUrl.setPath(QStringLiteral("/%1").arg(url.toString(QUrl::RemoveQuery | QUrl::RemoveFragment))); + providerUrl.setPath( + QStringLiteral("/%1").arg(url.toString(QUrl::RemoveQuery | QUrl::RemoveFragment))); if (url.hasQuery()) providerUrl.setQuery(url.query(QUrl::FullyDecoded)); if (url.hasFragment()) @@ -86,125 +130,29 @@ QUrl QQuickWebEngineFaviconProvider::faviconProviderUrl(const QUrl &url) QQuickWebEngineFaviconProvider::QQuickWebEngineFaviconProvider() : QQuickImageProvider(QQuickImageProvider::Pixmap) - , m_latestView(0) { } -QQuickWebEngineFaviconProvider::~QQuickWebEngineFaviconProvider() -{ - qDeleteAll(m_iconUrlMap); -} +QQuickWebEngineFaviconProvider::~QQuickWebEngineFaviconProvider() { } -QUrl QQuickWebEngineFaviconProvider::attach(QQuickWebEngineView *view, const QUrl &iconUrl) -{ - if (iconUrl.isEmpty()) - return QUrl(); - - m_latestView = view; - - if (!m_iconUrlMap.contains(view)) - m_iconUrlMap.insert(view, new QList<QUrl>()); - - QList<QUrl> *iconUrls = m_iconUrlMap[view]; - if (!iconUrls->contains(iconUrl)) - iconUrls->append(iconUrl); - - return faviconProviderUrl(iconUrl); -} - -void QQuickWebEngineFaviconProvider::detach(QQuickWebEngineView *view) -{ - QList<QUrl> *iconUrls = m_iconUrlMap.take(view); - delete iconUrls; -} - -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -static QPixmap getUnscaledPixmap(QIcon icon, const QSize &size) -{ - QPixmap pixmap = icon.data_ptr()->engine->pixmap(size, QIcon::Normal, QIcon::Off); - pixmap.setDevicePixelRatio(1.0); - return pixmap; -} -#else -static QPixmap getUnscaledPixmap(const QIcon &icon, const QSize &size) -{ - return icon.pixmap(size, 1.0); -} -#endif - -QPixmap QQuickWebEngineFaviconProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) +QPixmap QQuickWebEngineFaviconProvider::requestPixmap(const QString &id, QSize *size, + const QSize &requestedSize) { Q_UNUSED(size); Q_UNUSED(requestedSize); - QUrl iconUrl(id); - QQuickWebEngineView *view = viewForIconUrl(iconUrl); - - if (!view || iconUrl.isEmpty()) + if (m_views.isEmpty()) return QPixmap(); - FaviconManager *faviconManager = view->d_ptr->adapter->faviconManager(); - - Q_ASSERT(faviconManager); - const FaviconInfo &faviconInfo = faviconManager->getFaviconInfo(iconUrl); - const QIcon &icon = faviconManager->getIcon(faviconInfo.candidate ? QUrl() : iconUrl); - - Q_ASSERT(!icon.isNull()); - const QSize &bestSize = faviconInfo.size; - - // If source size is not specified, use the best quality - if (!requestedSize.isValid()) { - if (size) - *size = bestSize; - - return getUnscaledPixmap(icon, bestSize).copy(); - } - - const QSize &fitSize = findFitSize(icon.availableSizes(), requestedSize, bestSize); - const QPixmap &iconPixmap = getUnscaledPixmap(icon, fitSize); - - if (size) - *size = iconPixmap.size(); - - return iconPixmap.scaled(requestedSize, Qt::KeepAspectRatio, Qt::SmoothTransformation).copy(); -} - -QQuickWebEngineView *QQuickWebEngineFaviconProvider::viewForIconUrl(const QUrl &iconUrl) const -{ - // The most common use case is that the requested iconUrl belongs to the - // latest WebEngineView which was raised an iconChanged signal. - if (m_latestView) { - QList<QUrl> *iconUrls = m_iconUrlMap[m_latestView]; - if (iconUrls && iconUrls->contains(iconUrl)) - return m_latestView; - } - - for (auto it = m_iconUrlMap.cbegin(), end = m_iconUrlMap.cend(); it != end; ++it) { - if (it.value()->contains(iconUrl)) - return it.key(); - } - - return 0; -} - -QSize QQuickWebEngineFaviconProvider::findFitSize(const QList<QSize> &availableSizes, - const QSize &requestedSize, - const QSize &bestSize) const -{ - Q_ASSERT(availableSizes.count()); - if (availableSizes.count() == 1 || area(requestedSize) >= area(bestSize)) - return bestSize; - - QSize fitSize = bestSize; - for (const QSize &size : availableSizes) { - if (area(size) == area(requestedSize)) - return size; + QQuickWebEngineView *view = findViewById(id, &m_views); + if (!view) + return QPixmap(); - if (area(requestedSize) < area(size) && area(size) < area(fitSize)) - fitSize = size; - } + QIcon icon = view->d_ptr->adapter->icon(); + if (icon.isNull()) + return QPixmap(); - return fitSize; + return extractPixmap(icon, requestedSize).copy(); } QT_END_NAMESPACE diff --git a/src/webenginequick/api/qquickwebenginefaviconprovider_p_p.h b/src/webenginequick/api/qquickwebenginefaviconprovider_p_p.h index 80d2f65f2..d284a73d5 100644 --- a/src/webenginequick/api/qquickwebenginefaviconprovider_p_p.h +++ b/src/webenginequick/api/qquickwebenginefaviconprovider_p_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWebEngine module of the Qt Toolkit. @@ -52,15 +52,15 @@ // #include <QtWebEngineQuick/private/qtwebengineglobal_p.h> +#include <QtCore/QList> #include <QtQuick/QQuickImageProvider> -#include <QtCore/QMap> - QT_BEGIN_NAMESPACE class QQuickWebEngineView; -class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineFaviconProvider : public QQuickImageProvider { +class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineFaviconProvider : public QQuickImageProvider +{ public: static QString identifier(); static QUrl faviconProviderUrl(const QUrl &); @@ -68,18 +68,13 @@ public: QQuickWebEngineFaviconProvider(); ~QQuickWebEngineFaviconProvider(); - QUrl attach(QQuickWebEngineView *, const QUrl &); - void detach(QQuickWebEngineView *); - + void attach(QQuickWebEngineView *view) { m_views.append(view); } + void detach(QQuickWebEngineView *view) { m_views.removeAll(view); } QPixmap requestPixmap(const QString &, QSize *, const QSize &) override; private: - QQuickWebEngineView *viewForIconUrl(const QUrl &) const; - QSize findFitSize(const QList<QSize> &, const QSize &, const QSize &) const; - - QMap<QQuickWebEngineView *, QList<QUrl> *> m_iconUrlMap; - QQuickWebEngineView *m_latestView; + QList<QQuickWebEngineView *> m_views; }; QT_END_NAMESPACE diff --git a/src/webenginequick/api/qquickwebengineview.cpp b/src/webenginequick/api/qquickwebengineview.cpp index 5524b8954..2e6a2f428 100644 --- a/src/webenginequick/api/qquickwebengineview.cpp +++ b/src/webenginequick/api/qquickwebengineview.cpp @@ -132,7 +132,6 @@ QQuickWebEngineViewPrivate::QQuickWebEngineViewPrivate() , m_testSupport(0) #endif , contextMenuExtraItems(0) - , faviconProvider(0) , loadProgress(0) , m_fullscreenMode(false) , isLoading(false) @@ -179,8 +178,8 @@ QQuickWebEngineViewPrivate::~QQuickWebEngineViewPrivate() { Q_ASSERT(m_profileInitialized); m_profile->d_ptr->removeWebContentsAdapterClient(this); - if (faviconProvider) - faviconProvider->detach(q_ptr); + if (m_faviconProvider) + m_faviconProvider->detach(q_ptr); // q_ptr->d_ptr might be null due to destroy() if (q_ptr->d_ptr) bindViewAndWidget(q_ptr, nullptr); @@ -408,20 +407,7 @@ void QQuickWebEngineViewPrivate::iconChanged(const QUrl &url) if (iconUrl == QQuickWebEngineFaviconProvider::faviconProviderUrl(url)) return; - if (!faviconProvider) { - QQmlEngine *engine = qmlEngine(q); - - // TODO: this is a workaround for QTBUG-65044 - if (!engine) - return; - - Q_ASSERT(engine); - faviconProvider = static_cast<QQuickWebEngineFaviconProvider *>( - engine->imageProvider(QQuickWebEngineFaviconProvider::identifier())); - Q_ASSERT(faviconProvider); - } - - iconUrl = faviconProvider->attach(q, url); + iconUrl = QQuickWebEngineFaviconProvider::faviconProviderUrl(url); m_history->reset(); QTimer::singleShot(0, q, &QQuickWebEngineView::iconChanged); } @@ -904,6 +890,17 @@ void QQuickWebEngineViewPrivate::ensureContentsAdapter() else adapter->loadDefault(); } + + if (!m_faviconProvider) { + QQmlEngine *engine = qmlEngine(q_ptr); + // TODO: this is a workaround for QTBUG-65044 + if (!engine) + return; + m_faviconProvider = static_cast<QQuickWebEngineFaviconProvider *>( + engine->imageProvider(QQuickWebEngineFaviconProvider::identifier())); + m_faviconProvider->attach(q_ptr); + Q_ASSERT(m_faviconProvider); + } } void QQuickWebEngineViewPrivate::initializationFinished() diff --git a/src/webenginequick/api/qquickwebengineview_p.h b/src/webenginequick/api/qquickwebengineview_p.h index ca3b5349e..5b8231cbf 100644 --- a/src/webenginequick/api/qquickwebengineview_p.h +++ b/src/webenginequick/api/qquickwebengineview_p.h @@ -70,7 +70,6 @@ class QQuickWebEngineAction; class QQuickWebEngineAuthenticationDialogRequest; class QQuickWebEngineClientCertificateSelection; class QQuickWebEngineColorDialogRequest; -class QQuickWebEngineFaviconProvider; class QQuickWebEngineFileDialogRequest; class QQuickWebEngineHistory; class QQuickWebEngineJavaScriptDialogRequest; diff --git a/src/webenginequick/api/qquickwebengineview_p_p.h b/src/webenginequick/api/qquickwebengineview_p_p.h index 115c13e06..1b50de26a 100644 --- a/src/webenginequick/api/qquickwebengineview_p_p.h +++ b/src/webenginequick/api/qquickwebengineview_p_p.h @@ -196,7 +196,6 @@ public: QUrl m_url; QString m_html; QUrl iconUrl; - QQuickWebEngineFaviconProvider *faviconProvider; int loadProgress; bool m_fullscreenMode; bool isLoading; @@ -230,6 +229,7 @@ private: QWebEngineContextMenuRequest *m_contextMenuRequest; LoadVisuallyCommittedState m_loadVisuallyCommittedState = NotCommitted; QScopedPointer<QQuickWebEngineScriptCollection> m_scriptCollection; + QQuickWebEngineFaviconProvider *m_faviconProvider = nullptr; }; #ifndef QT_NO_ACCESSIBILITY diff --git a/tests/auto/core/qwebenginecookiestore/tst_qwebenginecookiestore.cpp b/tests/auto/core/qwebenginecookiestore/tst_qwebenginecookiestore.cpp index 0e8248508..ef3b84691 100644 --- a/tests/auto/core/qwebenginecookiestore/tst_qwebenginecookiestore.cpp +++ b/tests/auto/core/qwebenginecookiestore/tst_qwebenginecookiestore.cpp @@ -294,9 +294,9 @@ void tst_QWebEngineCookieStore::basicFilterOverHTTP() QVERIFY(loadSpy.takeFirst().takeFirst().toBool()); QVERIFY(!cookieRequestHeader.isEmpty()); QTRY_COMPARE(cookieAddedSpy.count(), 1); - QTRY_COMPARE(accessTested.loadAcquire(), 7); + QTRY_COMPARE(accessTested.loadAcquire(), 6); - QTRY_COMPARE(serverSpy.count(), 6); + QTRY_COMPARE(serverSpy.count(), 5); client->deleteAllCookies(); QTRY_COMPARE(cookieRemovedSpy.count(), 1); @@ -313,9 +313,9 @@ void tst_QWebEngineCookieStore::basicFilterOverHTTP() // Test cookies are NOT added: QTest::qWait(100); QCOMPARE(cookieAddedSpy.count(), 1); - QTRY_COMPARE(accessTested.loadAcquire(), 11); + QTRY_COMPARE(accessTested.loadAcquire(), 9); - QTRY_COMPARE(serverSpy.count(), 9); + QTRY_COMPARE(serverSpy.count(), 7); page.triggerAction(QWebEnginePage::Reload); QTRY_COMPARE(loadSpy.count(), 1); @@ -324,7 +324,7 @@ void tst_QWebEngineCookieStore::basicFilterOverHTTP() QCOMPARE(cookieAddedSpy.count(), 1); // Wait for last GET /favicon.ico - QTRY_COMPARE(serverSpy.count(), 12); + QTRY_COMPARE(serverSpy.count(), 9); (void) httpServer.stop(); QCOMPARE(resourceFirstParty.size(), accessTested.loadAcquire()); diff --git a/tests/auto/quick/qmltests/CMakeLists.txt b/tests/auto/quick/qmltests/CMakeLists.txt index b5898cc2a..1c77e1a05 100644 --- a/tests/auto/quick/qmltests/CMakeLists.txt +++ b/tests/auto/quick/qmltests/CMakeLists.txt @@ -16,6 +16,7 @@ set(testList tst_activeFocusOnPress.qml tst_audioMuted.qml tst_desktopBehaviorLoadHtml.qml + tst_favicon.qml tst_findText.qml tst_focusOnNavigation.qml tst_fullScreenRequest.qml @@ -53,8 +54,6 @@ endif() if(QT_FEATURE_webengine_testsupport) list(APPEND testList - tst_favicon.qml - tst_faviconDownload.qml tst_inputMethod.qml tst_javaScriptDialogs.qml tst_linkHovered.qml diff --git a/tests/auto/quick/qmltests/data/favicon-misc.html b/tests/auto/quick/qmltests/data/favicon-misc.html index 9e788bdf4..03d1086ff 100644 --- a/tests/auto/quick/qmltests/data/favicon-misc.html +++ b/tests/auto/quick/qmltests/data/favicon-misc.html @@ -1,8 +1,8 @@ <html> <head> <title>Favicon Test</title> - <link rel="shortcut icon" href="icons/qt32.ico" /> - <link rel="apple-touch-icon" href="icons/qt144.png" /> + <link rel="shortcut icon" href="icons/qt32.ico" sizes="32x32" /> + <link rel="apple-touch-icon" href="icons/qt144.png" sizes="144x144"/> <link rel="shortcut icon" href="icons/unavailable.ico" /> </head> <body> diff --git a/tests/auto/quick/qmltests/data/tst_favicon.qml b/tests/auto/quick/qmltests/data/tst_favicon.qml index fc8b90542..4d13d1e76 100644 --- a/tests/auto/quick/qmltests/data/tst_favicon.qml +++ b/tests/auto/quick/qmltests/data/tst_favicon.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWebEngine module of the Qt Toolkit. @@ -26,30 +26,26 @@ ** ****************************************************************************/ -import QtQuick 2.0 -import QtTest 1.0 -import QtWebEngine 1.3 -import QtWebEngine.testsupport 1.0 -import QtQuick.Window 2.0 -import "../../qmltests/data" 1.0 +import QtQuick +import QtTest +import QtWebEngine +import Test.util +import "../../qmltests/data" TestWebEngineView { id: webEngineView width: 200 height: 400 - testSupport: WebEngineTestSupport { - property var errorPageLoadStatus: null + TempDir { id: tempDir } - function waitForErrorPageLoadSucceeded() { - var success = _waitFor(function() { return testSupport.errorPageLoadStatus == WebEngineView.LoadSucceededStatus }) - testSupport.errorPageLoadStatus = null - return success - } + property QtObject defaultProfile: WebEngineProfile { + offTheRecord: true + } - errorPage.onLoadingChanged: function(load) { - errorPageLoadStatus = load.status - } + property QtObject nonOTRProfile: WebEngineProfile { + persistentStoragePath: tempDir.path() + '/WebEngineFavicon' + offTheRecord: false } function removeFaviconProviderPrefix(url) { @@ -58,10 +54,10 @@ TestWebEngineView { function getFaviconPixel(faviconImage) { var grabImage = Qt.createQmlObject(" - import QtQuick 2.5\n + import QtQuick\n Image { }", testCase) var faviconCanvas = Qt.createQmlObject(" - import QtQuick 2.5\n + import QtQuick\n Canvas { }", testCase) testCase.tryVerify(function() { return faviconImage.status == Image.Ready }); @@ -104,12 +100,22 @@ TestWebEngineView { function init() { // It is worth to restore the initial state with loading a blank page before all test functions. - webEngineView.url = 'about:blank' - verify(webEngineView.waitForLoadSucceeded()) - iconChangedSpy.clear() + webEngineView.url = 'about:blank'; + verify(webEngineView.waitForLoadSucceeded()); + iconChangedSpy.clear(); + webEngineView.settings.touchIconsEnabled = false; + webEngineView.settings.autoLoadIconsForPage = true; } - function test_faviconLoad() { + function test_faviconLoad_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_faviconLoad(row) { + webEngineView.profile = row.profile compare(iconChangedSpy.count, 0) var url = Qt.resolvedUrl("favicon.html") @@ -119,11 +125,20 @@ TestWebEngineView { iconChangedSpy.wait() compare(iconChangedSpy.count, 1) - compare(favicon.width, 48) - compare(favicon.height, 48) + tryCompare(favicon, "status", Image.Ready) + compare(favicon.width, 32) + compare(favicon.height, 32) + } + + function test_faviconLoadEncodedUrl_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; } - function test_faviconLoadEncodedUrl() { + function test_faviconLoadEncodedUrl(row) { + webEngineView.profile = row.profile compare(iconChangedSpy.count, 0) var url = Qt.resolvedUrl("favicon2.html?favicon=load should work with#whitespace!") @@ -133,11 +148,62 @@ TestWebEngineView { iconChangedSpy.wait() compare(iconChangedSpy.count, 1) - compare(favicon.width, 16) - compare(favicon.height, 16) + tryCompare(favicon, "status", Image.Ready) + compare(favicon.width, 32) + compare(favicon.height, 32) } - function test_noFavicon() { + function test_faviconLoadAfterHistoryNavigation_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_faviconLoadAfterHistoryNavigation(row) { + webEngineView.profile = row.profile + compare(iconChangedSpy.count, 0) + + var iconUrl + + webEngineView.url = Qt.resolvedUrl("favicon.html") + verify(webEngineView.waitForLoadSucceeded()) + tryCompare(iconChangedSpy, "count", 1) + iconUrl = removeFaviconProviderPrefix(webEngineView.icon) + compare(iconUrl, Qt.resolvedUrl("icons/favicon.png")) + + iconChangedSpy.clear() + webEngineView.url = Qt.resolvedUrl("favicon-shortcut.html") + verify(webEngineView.waitForLoadSucceeded()) + tryCompare(iconChangedSpy, "count", 2) + iconUrl = removeFaviconProviderPrefix(webEngineView.icon) + compare(iconUrl, Qt.resolvedUrl("icons/qt32.ico")) + + iconChangedSpy.clear() + webEngineView.goBack(); + verify(webEngineView.waitForLoadSucceeded()) + tryCompare(iconChangedSpy, "count", 2) + iconUrl = removeFaviconProviderPrefix(webEngineView.icon) + compare(iconUrl, Qt.resolvedUrl("icons/favicon.png")) + + iconChangedSpy.clear() + webEngineView.goForward(); + verify(webEngineView.waitForLoadSucceeded()) + tryCompare(iconChangedSpy, "count", 2) + iconUrl = removeFaviconProviderPrefix(webEngineView.icon) + compare(iconUrl, Qt.resolvedUrl("icons/qt32.ico")) + } + + + function test_noFavicon_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_noFavicon(row) { + webEngineView.profile = row.profile compare(iconChangedSpy.count, 0) var url = Qt.resolvedUrl("test1.html") @@ -150,7 +216,15 @@ TestWebEngineView { compare(iconUrl, Qt.resolvedUrl("")) } - function test_aboutBlank() { + function test_aboutBlank_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_aboutBlank(row) { + webEngineView.profile = row.profile compare(iconChangedSpy.count, 0) var url = Qt.resolvedUrl("about:blank") @@ -163,7 +237,15 @@ TestWebEngineView { compare(iconUrl, Qt.resolvedUrl("")) } - function test_unavailableFavicon() { + function test_unavailableFavicon_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_unavailableFavicon(row) { + webEngineView.profile = row.profile compare(iconChangedSpy.count, 0) var url = Qt.resolvedUrl("favicon-unavailable.html") @@ -176,15 +258,25 @@ TestWebEngineView { compare(iconUrl, Qt.resolvedUrl("")) } - function test_errorPageEnabled() { - WebEngine.settings.errorPageEnabled = true + function test_errorPageEnabled_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_errorPageEnabled(row) { + webEngineView.profile = row.profile + webEngineView.settings.errorPageEnabled = true compare(iconChangedSpy.count, 0) var url = Qt.resolvedUrl("http://url.invalid") webEngineView.url = url verify(webEngineView.waitForLoadFailed(20000)) - verify(webEngineView.testSupport.waitForErrorPageLoadSucceeded()) + // FIXME: Wait for error page load to finish. + // This should be done without testSupport API. + wait(500) compare(iconChangedSpy.count, 0) @@ -192,8 +284,16 @@ TestWebEngineView { compare(iconUrl, Qt.resolvedUrl("")) } - function test_errorPageDisabled() { - WebEngine.settings.errorPageEnabled = false + function test_errorPageDisabled_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_errorPageDisabled(row) { + webEngineView.profile = row.profile + webEngineView.settings.errorPageEnabled = false compare(iconChangedSpy.count, 0) @@ -207,7 +307,15 @@ TestWebEngineView { compare(iconUrl, Qt.resolvedUrl("")) } - function test_bestFavicon() { + function test_bestFavicon_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_bestFavicon(row) { + webEngineView.profile = row.profile compare(iconChangedSpy.count, 0) var url, iconUrl @@ -221,6 +329,7 @@ TestWebEngineView { iconUrl = removeFaviconProviderPrefix(webEngineView.icon) // Touch icon is ignored compare(iconUrl, Qt.resolvedUrl("icons/qt32.ico")) + tryCompare(favicon, "status", Image.Ready) compare(favicon.width, 32) compare(favicon.height, 32) @@ -230,23 +339,25 @@ TestWebEngineView { webEngineView.url = url verify(webEngineView.waitForLoadSucceeded()) - iconChangedSpy.wait() - verify(iconChangedSpy.count >= 1) + tryCompare(iconChangedSpy, "count", 2) iconUrl = removeFaviconProviderPrefix(webEngineView.icon) - // If the icon URL is empty we have to wait for - // the second iconChanged signal that propagates the expected URL - if (iconUrl == Qt.resolvedUrl("")) { - tryCompare(iconChangedSpy, "count", 2) - iconUrl = removeFaviconProviderPrefix(webEngineView.icon) - } + // If touch icon is disabled, FaviconHandler propagates the icon closest to size 16x16 + compare(iconUrl, Qt.resolvedUrl("icons/qt32.ico")) + tryCompare(favicon, "status", Image.Ready) + compare(favicon.width, 32) + compare(favicon.height, 32) + } - compare(iconUrl, Qt.resolvedUrl("icons/qt144.png")) - compare(favicon.width, 144) - compare(favicon.height, 144) + function test_touchIcon_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; } - function test_touchIcon() { + function test_touchIcon(row) { + webEngineView.profile = row.profile compare(iconChangedSpy.count, 0) var url = Qt.resolvedUrl("favicon-touch.html") @@ -260,7 +371,7 @@ TestWebEngineView { compare(favicon.width, 0) compare(favicon.height, 0) - WebEngine.settings.touchIconsEnabled = true + webEngineView.settings.touchIconsEnabled = true url = Qt.resolvedUrl("favicon-touch.html") webEngineView.url = url @@ -270,11 +381,20 @@ TestWebEngineView { iconUrl = removeFaviconProviderPrefix(webEngineView.icon) compare(iconUrl, Qt.resolvedUrl("icons/qt144.png")) compare(iconChangedSpy.count, 1) + tryCompare(favicon, "status", Image.Ready) compare(favicon.width, 144) compare(favicon.height, 144) } - function test_multiIcon() { + function test_multiIcon_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_multiIcon(row) { + webEngineView.profile = row.profile compare(iconChangedSpy.count, 0) var url = Qt.resolvedUrl("favicon-multi.html") @@ -283,61 +403,24 @@ TestWebEngineView { iconChangedSpy.wait() compare(iconChangedSpy.count, 1) - compare(favicon.width, 64) - compare(favicon.height, 64) + tryCompare(favicon, "status", Image.Ready) + compare(favicon.width, 32) + compare(favicon.height, 32) } - function test_faviconProvider_data() { + function test_dynamicFavicon_data() { return [ - { tag: "multi 8x8", url: Qt.resolvedUrl("favicon-multi-gray.html"), size: 8, value: 16 }, - { tag: "multi 16x16", url: Qt.resolvedUrl("favicon-multi-gray.html"), size: 16, value: 16 }, - { tag: "multi 17x17", url: Qt.resolvedUrl("favicon-multi-gray.html"), size: 17, value: 32 }, - { tag: "multi 31x31", url: Qt.resolvedUrl("favicon-multi-gray.html"), size: 31, value: 32 }, - { tag: "multi 32x32", url: Qt.resolvedUrl("favicon-multi-gray.html"), size: 32, value: 32 }, - { tag: "multi 33x33", url: Qt.resolvedUrl("favicon-multi-gray.html"), size: 33, value: 64 }, - { tag: "multi 64x64", url: Qt.resolvedUrl("favicon-multi-gray.html"), size: 64, value: 64 }, - { tag: "multi 128x128", url: Qt.resolvedUrl("favicon-multi-gray.html"), size: 128, value: 128 }, - { tag: "multi 255x255", url: Qt.resolvedUrl("favicon-multi-gray.html"), size: 255, value: 255 }, - { tag: "multi 256x256", url: Qt.resolvedUrl("favicon-multi-gray.html"), size: 256, value: 255 }, - { tag: "candidate 8x8", url: Qt.resolvedUrl("favicon-candidates-gray.html"), size: 8, value: 16 }, - { tag: "candidate 16x16", url: Qt.resolvedUrl("favicon-candidates-gray.html"), size: 16, value: 16 }, - { tag: "candidate 17x17", url: Qt.resolvedUrl("favicon-candidates-gray.html"), size: 17, value: 32 }, - { tag: "candidate 31x31", url: Qt.resolvedUrl("favicon-candidates-gray.html"), size: 31, value: 32 }, - { tag: "candidate 32x32", url: Qt.resolvedUrl("favicon-candidates-gray.html"), size: 32, value: 32 }, - { tag: "candidate 33x33", url: Qt.resolvedUrl("favicon-candidates-gray.html"), size: 33, value: 64 }, - { tag: "candidate 64x64", url: Qt.resolvedUrl("favicon-candidates-gray.html"), size: 64, value: 64 }, - { tag: "candidate 128x128", url: Qt.resolvedUrl("favicon-candidates-gray.html"), size: 128, value: 128 }, - { tag: "candidate 255x255", url: Qt.resolvedUrl("favicon-candidates-gray.html"), size: 255, value: 255 }, - { tag: "candidate 256x256", url: Qt.resolvedUrl("favicon-candidates-gray.html"), size: 256, value: 255 }, + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, ]; } - function test_faviconProvider(row) { - var faviconImage = Qt.createQmlObject(" - import QtQuick 2.5\n - Image { sourceSize: Qt.size(width, height) }", testCase) - + function test_dynamicFavicon(row) { + webEngineView.profile = row.profile compare(iconChangedSpy.count, 0) - webEngineView.url = row.url - verify(webEngineView.waitForLoadSucceeded()) - - iconChangedSpy.wait() - compare(iconChangedSpy.count, 1) - - faviconImage.width = row.size / Screen.devicePixelRatio - faviconImage.height = row.size / Screen.devicePixelRatio - faviconImage.source = webEngineView.icon - - var pixel = getFaviconPixel(faviconImage); - compare(pixel[0], row.value) - - faviconImage.destroy() - } - - function test_dynamicFavicon() { var faviconImage = Qt.createQmlObject(" - import QtQuick 2.5\n + import QtQuick\n Image { width: 16; height: 16; sourceSize: Qt.size(width, height); }", testCase) faviconImage.source = Qt.binding(function() { return webEngineView.icon; }); @@ -377,9 +460,17 @@ TestWebEngineView { faviconImage.destroy() } - function test_touchIconWithSameURL() + function test_touchIconWithSameURL_data() { + return [ + { tag: "OTR", profile: defaultProfile }, + { tag: "non-OTR", profile: nonOTRProfile }, + ]; + } + + function test_touchIconWithSameURL(row) { - WebEngine.settings.touchIconsEnabled = false; + webEngineView.profile = row.profile; + compare(iconChangedSpy.count, 0); var icon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII="; @@ -409,5 +500,53 @@ TestWebEngineView { tryCompare(iconChangedSpy, "count", 1); verify(!webEngineView.icon.toString().replace(/^image:\/\/favicon\//, '')); } + + function test_iconsDisabled_data() { + return [ + { tag: "misc", url: Qt.resolvedUrl("favicon-misc.html") }, + { tag: "shortcut", url: Qt.resolvedUrl("favicon-shortcut.html") }, + { tag: "single", url: Qt.resolvedUrl("favicon-single.html") }, + { tag: "touch", url: Qt.resolvedUrl("favicon-touch.html") }, + { tag: "unavailable", url: Qt.resolvedUrl("favicon-unavailable.html") }, + ]; + } + + function test_iconsDisabled(row) { + webEngineView.settings.autoLoadIconsForPage = false + webEngineView.profile = defaultProfile + compare(iconChangedSpy.count, 0) + + webEngineView.url = row.url + verify(webEngineView.waitForLoadSucceeded()) + + compare(iconChangedSpy.count, 0) + + var iconUrl = webEngineView.icon + compare(iconUrl, Qt.resolvedUrl("")) + } + + function test_touchIconsEnabled_data() { + return [ + { tag: "misc", url: Qt.resolvedUrl("favicon-misc.html"), expectedIconUrl: Qt.resolvedUrl("icons/qt144.png") }, + { tag: "shortcut", url: Qt.resolvedUrl("favicon-shortcut.html"), expectedIconUrl: Qt.resolvedUrl("icons/qt144.png") }, + { tag: "single", url: Qt.resolvedUrl("favicon-single.html"), expectedIconUrl: Qt.resolvedUrl("icons/qt32.ico") }, + { tag: "touch", url: Qt.resolvedUrl("favicon-touch.html"), expectedIconUrl: Qt.resolvedUrl("icons/qt144.png") }, + ]; + } + + function test_touchIconsEnabled(row) { + webEngineView.settings.touchIconsEnabled = true + webEngineView.profile = defaultProfile + compare(iconChangedSpy.count, 0) + + webEngineView.url = row.url + verify(webEngineView.waitForLoadSucceeded()) + + iconChangedSpy.wait() + compare(iconChangedSpy.count, 1) + + var iconUrl = removeFaviconProviderPrefix(webEngineView.icon) + compare(iconUrl, row.expectedIconUrl) + } } } diff --git a/tests/auto/quick/qmltests/data/tst_faviconDownload.qml b/tests/auto/quick/qmltests/data/tst_faviconDownload.qml deleted file mode 100644 index 7d9c39814..000000000 --- a/tests/auto/quick/qmltests/data/tst_faviconDownload.qml +++ /dev/null @@ -1,121 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.0 -import QtTest 1.0 -import QtWebEngine 1.3 -import "../../qmltests/data" 1.0 - -TestWebEngineView { - id: webEngineView - width: 200 - height: 400 - - function removeFaviconProviderPrefix(url) { - return url.toString().substring(16) - } - - SignalSpy { - id: iconChangedSpy - target: webEngineView - signalName: "iconChanged" - } - - TestCase { - id: testCase - name: "WebEngineFaviconDownload" - - function init() { - WebEngine.settings.autoLoadIconsForPage = true - WebEngine.settings.touchIconsEnabled = false - - if (webEngineView.icon != '') { - // If this is not the first test, then load a blank page without favicon, restoring the initial state. - webEngineView.url = 'about:blank' - verify(webEngineView.waitForLoadSucceeded()) - iconChangedSpy.wait() - } - - iconChangedSpy.clear() - } - - function cleanupTestCase() { - WebEngine.settings.autoLoadIconsForPage = true - WebEngine.settings.touchIconsEnabled = false - } - - function test_downloadIconsDisabled_data() { - return [ - { tag: "misc", url: Qt.resolvedUrl("favicon-misc.html") }, - { tag: "shortcut", url: Qt.resolvedUrl("favicon-shortcut.html") }, - { tag: "single", url: Qt.resolvedUrl("favicon-single.html") }, - { tag: "touch", url: Qt.resolvedUrl("favicon-touch.html") }, - { tag: "unavailable", url: Qt.resolvedUrl("favicon-unavailable.html") }, - ]; - } - - function test_downloadIconsDisabled(row) { - WebEngine.settings.autoLoadIconsForPage = false - - compare(iconChangedSpy.count, 0) - - webEngineView.url = row.url - verify(webEngineView.waitForLoadSucceeded()) - - compare(iconChangedSpy.count, 0) - - var iconUrl = webEngineView.icon - compare(iconUrl, Qt.resolvedUrl("")) - } - - function test_downloadTouchIconsEnabled_data() { - return [ - { tag: "misc", url: Qt.resolvedUrl("favicon-misc.html"), expectedIconUrl: Qt.resolvedUrl("icons/qt144.png") }, - { tag: "shortcut", url: Qt.resolvedUrl("favicon-shortcut.html"), expectedIconUrl: Qt.resolvedUrl("icons/qt144.png") }, - { tag: "single", url: Qt.resolvedUrl("favicon-single.html"), expectedIconUrl: Qt.resolvedUrl("icons/qt32.ico") }, - { tag: "touch", url: Qt.resolvedUrl("favicon-touch.html"), expectedIconUrl: Qt.resolvedUrl("icons/qt144.png") }, - ]; - } - - function test_downloadTouchIconsEnabled(row) { - WebEngine.settings.touchIconsEnabled = true - - compare(iconChangedSpy.count, 0) - - webEngineView.url = row.url - verify(webEngineView.waitForLoadSucceeded()) - - iconChangedSpy.wait() - compare(iconChangedSpy.count, 1) - - var iconUrl = removeFaviconProviderPrefix(webEngineView.icon) - compare(iconUrl, row.expectedIconUrl) - } - } -} - diff --git a/tests/auto/widgets/CMakeLists.txt b/tests/auto/widgets/CMakeLists.txt index 7072329c3..f7955b1f8 100644 --- a/tests/auto/widgets/CMakeLists.txt +++ b/tests/auto/widgets/CMakeLists.txt @@ -5,7 +5,7 @@ if(NOT boot2qt) add_subdirectory(qwebengineprofile) add_subdirectory(qwebengineview) endif() -add_subdirectory(faviconmanager) +add_subdirectory(favicon) add_subdirectory(loadsignals) add_subdirectory(origins) add_subdirectory(proxy) diff --git a/tests/auto/widgets/faviconmanager/CMakeLists.txt b/tests/auto/widgets/favicon/CMakeLists.txt index 89bee5a2a..64c4efc91 100644 --- a/tests/auto/widgets/faviconmanager/CMakeLists.txt +++ b/tests/auto/widgets/favicon/CMakeLists.txt @@ -1,14 +1,14 @@ include(../../util/util.cmake) -qt_internal_add_test(tst_faviconmanager +qt_internal_add_test(tst_favicon SOURCES - tst_faviconmanager.cpp + tst_favicon.cpp LIBRARIES Qt::WebEngineWidgets Test::Util ) -set(tst_faviconmanager_resource_files +set(tst_favicon_resource_files "resources/favicon-misc.html" "resources/favicon-multi.html" "resources/favicon-shortcut.html" @@ -21,9 +21,9 @@ set(tst_faviconmanager_resource_files "resources/test1.html" ) -qt_add_resource(tst_faviconmanager "tst_faviconmanager" +qt_add_resource(tst_favicon "tst_favicon" PREFIX "/" FILES - ${tst_faviconmanager_resource_files} + ${tst_favicon_resource_files} ) diff --git a/tests/auto/widgets/faviconmanager/faviconmanager.pro b/tests/auto/widgets/favicon/favicon.pro index e99c7f493..e99c7f493 100644 --- a/tests/auto/widgets/faviconmanager/faviconmanager.pro +++ b/tests/auto/widgets/favicon/favicon.pro diff --git a/tests/auto/widgets/faviconmanager/resources/favicon-misc.html b/tests/auto/widgets/favicon/resources/favicon-misc.html index 9e788bdf4..ea587886f 100644 --- a/tests/auto/widgets/faviconmanager/resources/favicon-misc.html +++ b/tests/auto/widgets/favicon/resources/favicon-misc.html @@ -1,8 +1,8 @@ <html> <head> <title>Favicon Test</title> - <link rel="shortcut icon" href="icons/qt32.ico" /> - <link rel="apple-touch-icon" href="icons/qt144.png" /> + <link rel="shortcut icon" href="icons/qt32.ico" sizes="32x32" /> + <link rel="apple-touch-icon" href="icons/qt144.png" sizes="144x144" /> <link rel="shortcut icon" href="icons/unavailable.ico" /> </head> <body> diff --git a/tests/auto/widgets/faviconmanager/resources/favicon-multi.html b/tests/auto/widgets/favicon/resources/favicon-multi.html index cc5f3fd66..56eeca8c4 100644 --- a/tests/auto/widgets/faviconmanager/resources/favicon-multi.html +++ b/tests/auto/widgets/favicon/resources/favicon-multi.html @@ -1,7 +1,7 @@ <html> <head> <title>Multi-sized Favicon Test</title> - <link rel="shortcut icon" sizes="16x16 32x23 64x64" href="icons/qtmulti.ico" /> + <link rel="shortcut icon" sizes="16x16 32x32 64x64" href="icons/qtmulti.ico" /> </head> <body> <h1>Multi-sized Favicon Test</h1> diff --git a/tests/auto/widgets/faviconmanager/resources/favicon-shortcut.html b/tests/auto/widgets/favicon/resources/favicon-shortcut.html index 786cdb816..786cdb816 100644 --- a/tests/auto/widgets/faviconmanager/resources/favicon-shortcut.html +++ b/tests/auto/widgets/favicon/resources/favicon-shortcut.html diff --git a/tests/auto/widgets/faviconmanager/resources/favicon-single.html b/tests/auto/widgets/favicon/resources/favicon-single.html index eb4675c75..eb4675c75 100644 --- a/tests/auto/widgets/faviconmanager/resources/favicon-single.html +++ b/tests/auto/widgets/favicon/resources/favicon-single.html diff --git a/tests/auto/widgets/faviconmanager/resources/favicon-touch.html b/tests/auto/widgets/favicon/resources/favicon-touch.html index 271783434..271783434 100644 --- a/tests/auto/widgets/faviconmanager/resources/favicon-touch.html +++ b/tests/auto/widgets/favicon/resources/favicon-touch.html diff --git a/tests/auto/widgets/faviconmanager/resources/favicon-unavailable.html b/tests/auto/widgets/favicon/resources/favicon-unavailable.html index c45664294..c45664294 100644 --- a/tests/auto/widgets/faviconmanager/resources/favicon-unavailable.html +++ b/tests/auto/widgets/favicon/resources/favicon-unavailable.html diff --git a/tests/auto/widgets/faviconmanager/resources/icons/qt144.png b/tests/auto/widgets/favicon/resources/icons/qt144.png Binary files differindex 050b1e066..050b1e066 100644 --- a/tests/auto/widgets/faviconmanager/resources/icons/qt144.png +++ b/tests/auto/widgets/favicon/resources/icons/qt144.png diff --git a/tests/auto/widgets/faviconmanager/resources/icons/qt32.ico b/tests/auto/widgets/favicon/resources/icons/qt32.ico Binary files differindex 2f6fcb5bc..2f6fcb5bc 100644 --- a/tests/auto/widgets/faviconmanager/resources/icons/qt32.ico +++ b/tests/auto/widgets/favicon/resources/icons/qt32.ico diff --git a/tests/auto/widgets/faviconmanager/resources/icons/qtmulti.ico b/tests/auto/widgets/favicon/resources/icons/qtmulti.ico Binary files differindex 81e5a22e8..81e5a22e8 100644 --- a/tests/auto/widgets/faviconmanager/resources/icons/qtmulti.ico +++ b/tests/auto/widgets/favicon/resources/icons/qtmulti.ico diff --git a/tests/auto/widgets/faviconmanager/resources/test1.html b/tests/auto/widgets/favicon/resources/test1.html index b323f966e..b323f966e 100644 --- a/tests/auto/widgets/faviconmanager/resources/test1.html +++ b/tests/auto/widgets/favicon/resources/test1.html diff --git a/tests/auto/widgets/faviconmanager/tst_faviconmanager.cpp b/tests/auto/widgets/favicon/tst_favicon.cpp index 8e9bb2470..377699aaa 100644 --- a/tests/auto/widgets/faviconmanager/tst_faviconmanager.cpp +++ b/tests/auto/widgets/favicon/tst_favicon.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtWebEngine module of the Qt Toolkit. @@ -29,13 +29,13 @@ #include <QtTest/QtTest> #include <util.h> -#include <qwebenginepage.h> -#include <qwebengineprofile.h> -#include <qwebenginesettings.h> -#include <qwebengineview.h> +#include <QWebEnginePage> +#include <QWebEngineProfile> +#include <QWebEngineSettings> +#include <QWebEngineView> - -class tst_FaviconManager : public QObject { +class tst_Favicon : public QObject +{ Q_OBJECT public Q_SLOTS: @@ -48,15 +48,14 @@ private Q_SLOTS: void faviconLoad(); void faviconLoadFromResources(); void faviconLoadEncodedUrl(); + void faviconLoadAfterHistoryNavigation(); void noFavicon(); void aboutBlank(); void unavailableFavicon(); void errorPageEnabled(); void errorPageDisabled(); - void bestFavicon(); void touchIcon(); void multiIcon(); - void candidateIcon(); void downloadIconsDisabled_data(); void downloadIconsDisabled(); void downloadTouchIconsEnabled_data(); @@ -70,8 +69,7 @@ private: QWebEngineProfile *m_profile; }; - -void tst_FaviconManager::init() +void tst_Favicon::init() { m_profile = new QWebEngineProfile(this); m_view = new QWebEngineView(); @@ -79,23 +77,17 @@ void tst_FaviconManager::init() m_view->setPage(m_page); } +void tst_Favicon::initTestCase() { } -void tst_FaviconManager::initTestCase() -{ -} - -void tst_FaviconManager::cleanupTestCase() -{ -} - +void tst_Favicon::cleanupTestCase() { } -void tst_FaviconManager::cleanup() +void tst_Favicon::cleanup() { delete m_view; delete m_profile; } -void tst_FaviconManager::faviconLoad() +void tst_Favicon::faviconLoad() { if (!QDir(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()).exists()) W_QSKIP(QString("This test requires access to resources found in '%1'") @@ -125,12 +117,12 @@ void tst_FaviconManager::faviconLoad() const QIcon &icon = m_page->icon(); QVERIFY(!icon.isNull()); - QCOMPARE(icon.availableSizes().count(), 1); - QSize iconSize = icon.availableSizes().first(); - QCOMPARE(iconSize, QSize(32, 32)); + QCOMPARE(icon.availableSizes().count(), 2); + QVERIFY(icon.availableSizes().contains(QSize(16, 16))); + QVERIFY(icon.availableSizes().contains(QSize(32, 32))); } -void tst_FaviconManager::faviconLoadFromResources() +void tst_Favicon::faviconLoadFromResources() { QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool))); QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl))); @@ -150,12 +142,12 @@ void tst_FaviconManager::faviconLoadFromResources() const QIcon &icon = m_page->icon(); QVERIFY(!icon.isNull()); - QCOMPARE(icon.availableSizes().count(), 1); - QSize iconSize = icon.availableSizes().first(); - QCOMPARE(iconSize, QSize(32, 32)); + QCOMPARE(icon.availableSizes().count(), 2); + QVERIFY(icon.availableSizes().contains(QSize(16, 16))); + QVERIFY(icon.availableSizes().contains(QSize(32, 32))); } -void tst_FaviconManager::faviconLoadEncodedUrl() +void tst_Favicon::faviconLoadEncodedUrl() { if (!QDir(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()).exists()) W_QSKIP(QString("This test requires access to resources found in '%1'") @@ -187,12 +179,43 @@ void tst_FaviconManager::faviconLoadEncodedUrl() const QIcon &icon = m_page->icon(); QVERIFY(!icon.isNull()); - QCOMPARE(icon.availableSizes().count(), 1); - QSize iconSize = icon.availableSizes().first(); - QCOMPARE(iconSize, QSize(32, 32)); + QCOMPARE(icon.availableSizes().count(), 2); + QVERIFY(icon.availableSizes().contains(QSize(16, 16))); + QVERIFY(icon.availableSizes().contains(QSize(32, 32))); +} + +void tst_Favicon::faviconLoadAfterHistoryNavigation() +{ + QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool))); + QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl))); + QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon))); + + m_page->load(QUrl("qrc:/resources/favicon-single.html")); + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000); + QTRY_COMPARE(iconUrlChangedSpy.count(), 1); + QTRY_COMPARE(iconChangedSpy.count(), 1); + QCOMPARE(m_page->iconUrl(), QUrl("qrc:/resources/icons/qt32.ico")); + + m_page->load(QUrl("qrc:/resources/favicon-multi.html")); + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 2, 30000); + QTRY_COMPARE(iconUrlChangedSpy.count(), 3); + QTRY_COMPARE(iconChangedSpy.count(), 3); + QCOMPARE(m_page->iconUrl(), QUrl("qrc:/resources/icons/qtmulti.ico")); + + m_page->triggerAction(QWebEnginePage::Back); + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 3, 30000); + QTRY_COMPARE(iconUrlChangedSpy.count(), 5); + QTRY_COMPARE(iconChangedSpy.count(), 5); + QCOMPARE(m_page->iconUrl(), QUrl("qrc:/resources/icons/qt32.ico")); + + m_page->triggerAction(QWebEnginePage::Forward); + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 4, 30000); + QTRY_COMPARE(iconUrlChangedSpy.count(), 7); + QTRY_COMPARE(iconChangedSpy.count(), 7); + QCOMPARE(m_page->iconUrl(), QUrl("qrc:/resources/icons/qtmulti.ico")); } -void tst_FaviconManager::noFavicon() +void tst_Favicon::noFavicon() { if (!QDir(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()).exists()) W_QSKIP(QString("This test requires access to resources found in '%1'") @@ -217,7 +240,7 @@ void tst_FaviconManager::noFavicon() QVERIFY(m_page->icon().isNull()); } -void tst_FaviconManager::aboutBlank() +void tst_Favicon::aboutBlank() { QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool))); QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl))); @@ -234,7 +257,7 @@ void tst_FaviconManager::aboutBlank() QVERIFY(m_page->icon().isNull()); } -void tst_FaviconManager::unavailableFavicon() +void tst_Favicon::unavailableFavicon() { if (!QDir(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()).exists()) W_QSKIP(QString("This test requires access to resources found in '%1'") @@ -259,7 +282,7 @@ void tst_FaviconManager::unavailableFavicon() QVERIFY(m_page->icon().isNull()); } -void tst_FaviconManager::errorPageEnabled() +void tst_Favicon::errorPageEnabled() { m_page->settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, true); @@ -278,7 +301,7 @@ void tst_FaviconManager::errorPageEnabled() QVERIFY(m_page->icon().isNull()); } -void tst_FaviconManager::errorPageDisabled() +void tst_Favicon::errorPageDisabled() { m_page->settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false); @@ -297,80 +320,7 @@ void tst_FaviconManager::errorPageDisabled() QVERIFY(m_page->icon().isNull()); } -void tst_FaviconManager::bestFavicon() -{ - if (!QDir(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()).exists()) - W_QSKIP(QString("This test requires access to resources found in '%1'") - .arg(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()) - .toLatin1() - .constData(), - SkipAll); - - QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool))); - QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl))); - QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon))); - - QUrl url, iconUrl; - QIcon icon; - QSize iconSize; - - url = QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() - + QLatin1String("/resources/favicon-misc.html")); - m_page->load(url); - - QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000); - QTRY_COMPARE(iconUrlChangedSpy.count(), 1); - QTRY_COMPARE(iconChangedSpy.count(), 1); - - iconUrl = iconUrlChangedSpy.at(0).at(0).toString(); - QCOMPARE(iconUrl, m_page->iconUrl()); - // Touch icon is ignored - QCOMPARE(iconUrl, - QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() - + QLatin1String("/resources/icons/qt32.ico"))); - - icon = m_page->icon(); - QVERIFY(!icon.isNull()); - - QCOMPARE(icon.availableSizes().count(), 1); - iconSize = icon.availableSizes().first(); - QCOMPARE(iconSize, QSize(32, 32)); - - loadFinishedSpy.clear(); - iconUrlChangedSpy.clear(); - iconChangedSpy.clear(); - - url = QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() - + QLatin1String("/resources/favicon-shortcut.html")); - m_page->load(url); - - QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000); - QTRY_VERIFY(iconUrlChangedSpy.count() >= 1); - QTRY_VERIFY(iconChangedSpy.count() >= 1); - - iconUrl = iconUrlChangedSpy.last().at(0).toString(); - - // If the icon URL is empty we have to wait for - // the second iconChanged signal that propagates the expected URL - if (iconUrl.isEmpty()) { - QTRY_COMPARE(iconUrlChangedSpy.count(), 2); - QTRY_COMPARE(iconChangedSpy.count(), 2); - iconUrl = iconUrlChangedSpy.last().at(0).toString(); - } - - QCOMPARE(iconUrl, m_page->iconUrl()); - QCOMPARE(iconUrl, - QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() - + QLatin1String("/resources/icons/qt144.png"))); - - icon = m_page->icon(); - QVERIFY(!icon.isNull()); - - QVERIFY(icon.availableSizes().count() >= 1); - QVERIFY(icon.availableSizes().contains(QSize(144, 144))); -} - -void tst_FaviconManager::touchIcon() +void tst_Favicon::touchIcon() { if (!QDir(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()).exists()) W_QSKIP(QString("This test requires access to resources found in '%1'") @@ -395,7 +345,7 @@ void tst_FaviconManager::touchIcon() QVERIFY(m_page->icon().isNull()); } -void tst_FaviconManager::multiIcon() +void tst_Favicon::multiIcon() { if (!QDir(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()).exists()) W_QSKIP(QString("This test requires access to resources found in '%1'") @@ -410,61 +360,60 @@ void tst_FaviconManager::multiIcon() QUrl url = QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + QLatin1String("/resources/favicon-multi.html")); + QUrl iconUrl; + QIcon icon; + + // If touch icons are disabled, the favicon is provided in two sizes (16x16 and 32x32) according + // to the supported scale factors (100P, 200P). + m_page->settings()->setAttribute(QWebEngineSettings::TouchIconsEnabled, false); m_page->load(url); QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000); QTRY_COMPARE(iconUrlChangedSpy.count(), 1); QTRY_COMPARE(iconChangedSpy.count(), 1); - QUrl iconUrl = iconUrlChangedSpy.at(0).at(0).toString(); + iconUrl = iconUrlChangedSpy.at(0).at(0).toString(); QCOMPARE(m_page->iconUrl(), iconUrl); QCOMPARE(iconUrl, QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + QLatin1String("/resources/icons/qtmulti.ico"))); - const QIcon &icon = m_page->icon(); + icon = m_page->icon(); QVERIFY(!icon.isNull()); - QCOMPARE(icon.availableSizes().count(), 3); + QCOMPARE(icon.availableSizes().count(), 2); QVERIFY(icon.availableSizes().contains(QSize(16, 16))); QVERIFY(icon.availableSizes().contains(QSize(32, 32))); - QVERIFY(icon.availableSizes().contains(QSize(64, 64))); -} -void tst_FaviconManager::candidateIcon() -{ - if (!QDir(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()).exists()) - W_QSKIP(QString("This test requires access to resources found in '%1'") - .arg(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()) - .toLatin1() - .constData(), - SkipAll); - - QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool))); - QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl))); - QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon))); + // Reset + loadFinishedSpy.clear(); + m_page->load(QUrl("about:blank")); + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000); + iconUrlChangedSpy.clear(); + iconChangedSpy.clear(); + loadFinishedSpy.clear(); + icon = QIcon(); - QUrl url = QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() - + QLatin1String("/resources/favicon-shortcut.html")); + // If touch icons are enabled, the largest icon is provided. + m_page->settings()->setAttribute(QWebEngineSettings::TouchIconsEnabled, true); m_page->load(url); QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000); QTRY_COMPARE(iconUrlChangedSpy.count(), 1); QTRY_COMPARE(iconChangedSpy.count(), 1); - QUrl iconUrl = iconUrlChangedSpy.at(0).at(0).toString(); + iconUrl = iconUrlChangedSpy.at(0).at(0).toString(); QCOMPARE(m_page->iconUrl(), iconUrl); QCOMPARE(iconUrl, QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() - + QLatin1String("/resources/icons/qt144.png"))); + + QLatin1String("/resources/icons/qtmulti.ico"))); - const QIcon &icon = m_page->icon(); + icon = m_page->icon(); QVERIFY(!icon.isNull()); - QCOMPARE(icon.availableSizes().count(), 2); - QVERIFY(icon.availableSizes().contains(QSize(32, 32))); - QVERIFY(icon.availableSizes().contains(QSize(144, 144))); + QCOMPARE(icon.availableSizes().count(), 1); + QVERIFY(icon.availableSizes().contains(QSize(64, 64))); } -void tst_FaviconManager::downloadIconsDisabled_data() +void tst_Favicon::downloadIconsDisabled_data() { QTest::addColumn<QUrl>("url"); QTest::newRow("misc") << QUrl("qrc:/resources/favicon-misc.html"); @@ -474,7 +423,7 @@ void tst_FaviconManager::downloadIconsDisabled_data() QTest::newRow("unavailable") << QUrl("qrc:/resources/favicon-unavailable.html"); } -void tst_FaviconManager::downloadIconsDisabled() +void tst_Favicon::downloadIconsDisabled() { QFETCH(QUrl, url); @@ -494,18 +443,22 @@ void tst_FaviconManager::downloadIconsDisabled() QVERIFY(m_page->icon().isNull()); } -void tst_FaviconManager::downloadTouchIconsEnabled_data() +void tst_Favicon::downloadTouchIconsEnabled_data() { QTest::addColumn<QUrl>("url"); QTest::addColumn<QUrl>("expectedIconUrl"); QTest::addColumn<QSize>("expectedIconSize"); - QTest::newRow("misc") << QUrl("qrc:/resources/favicon-misc.html") << QUrl("qrc:/resources/icons/qt144.png") << QSize(144, 144); - QTest::newRow("shortcut") << QUrl("qrc:/resources/favicon-shortcut.html") << QUrl("qrc:/resources/icons/qt144.png") << QSize(144, 144); - QTest::newRow("single") << QUrl("qrc:/resources/favicon-single.html") << QUrl("qrc:/resources/icons/qt32.ico") << QSize(32, 32); - QTest::newRow("touch") << QUrl("qrc:/resources/favicon-touch.html") << QUrl("qrc:/resources/icons/qt144.png") << QSize(144, 144); + QTest::newRow("misc") << QUrl("qrc:/resources/favicon-misc.html") + << QUrl("qrc:/resources/icons/qt144.png") << QSize(144, 144); + QTest::newRow("shortcut") << QUrl("qrc:/resources/favicon-shortcut.html") + << QUrl("qrc:/resources/icons/qt144.png") << QSize(144, 144); + QTest::newRow("single") << QUrl("qrc:/resources/favicon-single.html") + << QUrl("qrc:/resources/icons/qt32.ico") << QSize(32, 32); + QTest::newRow("touch") << QUrl("qrc:/resources/favicon-touch.html") + << QUrl("qrc:/resources/icons/qt144.png") << QSize(144, 144); } -void tst_FaviconManager::downloadTouchIconsEnabled() +void tst_Favicon::downloadTouchIconsEnabled() { QFETCH(QUrl, url); QFETCH(QUrl, expectedIconUrl); @@ -530,23 +483,27 @@ void tst_FaviconManager::downloadTouchIconsEnabled() const QIcon &icon = m_page->icon(); QVERIFY(!icon.isNull()); - QVERIFY(icon.availableSizes().count() >= 1); - QVERIFY(icon.availableSizes().contains(expectedIconSize)); + QCOMPARE(icon.availableSizes().count(), 1); + QCOMPARE(icon.availableSizes().first(), expectedIconSize); } -void tst_FaviconManager::dynamicFavicon() +void tst_Favicon::dynamicFavicon() { QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool))); QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl))); QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon))); QMap<Qt::GlobalColor, QString> colors; - colors.insert(Qt::red, QString("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg==")); - colors.insert(Qt::green, QString("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M/wHwAEBgIApD5fRAAAAABJRU5ErkJggg==")); - colors.insert(Qt::blue, QString("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPj/HwADBwIAMCbHYQAAAABJRU5ErkJggg==")); + colors.insert(Qt::red, + QString("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg==")); + colors.insert(Qt::green, + QString("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M/wHwAEBgIApD5fRAAAAABJRU5ErkJggg==")); + colors.insert(Qt::blue, + QString("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPj/HwADBwIAMCbHYQAAAABJRU5ErkJggg==")); m_page->setHtml("<html>" - "<link rel='icon' type='image/png' href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII='/>" + "<link rel='icon' type='image/png' " + "href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII='/>" "</html>"); QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000); QTRY_COMPARE(iconUrlChangedSpy.count(), 1); @@ -556,14 +513,17 @@ void tst_FaviconManager::dynamicFavicon() for (Qt::GlobalColor color : colors.keys()) { iconChangedSpy.clear(); - evaluateJavaScriptSync(m_page, "document.getElementsByTagName('link')[0].href = 'data:image/png;base64," + colors[color] + "';"); + evaluateJavaScriptSync( + m_page, + "document.getElementsByTagName('link')[0].href = 'data:image/png;base64," + colors[color] + "';"); QTRY_COMPARE(iconChangedSpy.count(), 1); - QTRY_COMPARE(m_page->iconUrl().toString(), QString("data:image/png;base64," + colors[color])); + QTRY_COMPARE(m_page->iconUrl().toString(), + QString("data:image/png;base64," + colors[color])); QCOMPARE(m_page->icon().pixmap(1, 1).toImage().pixelColor(0, 0), QColor(color)); } } -void tst_FaviconManager::touchIconWithSameURL() +void tst_Favicon::touchIconWithSameURL() { m_page->settings()->setAttribute(QWebEngineSettings::TouchIconsEnabled, false); @@ -578,7 +538,8 @@ void tst_FaviconManager::touchIconWithSameURL() "</html>"); QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000); - // The default favicon has to be loaded even if its URL is also set as a touch icon while touch icons are disabled. + // The default favicon has to be loaded even if its URL is also set as a touch icon while touch + // icons are disabled. QTRY_COMPARE(iconUrlChangedSpy.count(), 1); QCOMPARE(m_page->iconUrl().toString(), icon); QTRY_COMPARE(iconChangedSpy.count(), 1); @@ -592,14 +553,13 @@ void tst_FaviconManager::touchIconWithSameURL() "</html>"); QTRY_COMPARE(loadFinishedSpy.count(), 1); - // This page only has a touch icon. With disabled touch icons we don't expect any icon to be shown even if the same icon - // was loaded previously. + // This page only has a touch icon. With disabled touch icons we don't expect any icon to be + // shown even if the same icon was loaded previously. QTRY_COMPARE(iconUrlChangedSpy.count(), 1); QVERIFY(m_page->iconUrl().toString().isEmpty()); QTRY_COMPARE(iconChangedSpy.count(), 1); - } -QTEST_MAIN(tst_FaviconManager) +QTEST_MAIN(tst_Favicon) -#include "tst_faviconmanager.moc" +#include "tst_favicon.moc" diff --git a/tests/auto/widgets/faviconmanager/tst_faviconmanager.qrc b/tests/auto/widgets/favicon/tst_favicon.qrc index a352f8a83..a352f8a83 100644 --- a/tests/auto/widgets/faviconmanager/tst_faviconmanager.qrc +++ b/tests/auto/widgets/favicon/tst_favicon.qrc diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index 432a91224..170afaafc 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -311,7 +311,8 @@ void tst_QWebEngineView::changePage() if (!fromIsNullPage) { QVERIFY(!pageFrom->iconUrl().isEmpty()); QCOMPARE(spyIconUrl.last().value(0).toUrl(), pageFrom->iconUrl()); - QCOMPARE(spyIcon.last().value(0).value<QIcon>(), pageFrom->icon()); + QCOMPARE(spyIcon.last().value(0).value<QIcon>().availableSizes(), + pageFrom->icon().availableSizes()); } QScopedPointer<QWebEnginePage> pageTo(new QWebEnginePage); @@ -340,7 +341,8 @@ void tst_QWebEngineView::changePage() QCOMPARE(pageFrom->iconUrl() == pageTo->iconUrl(), iconIsSame); if (!iconIsSame) { QCOMPARE(spyIconUrl.last().value(0).toUrl(), pageTo->iconUrl()); - QCOMPARE(spyIcon.last().value(0).value<QIcon>(), pageTo->icon()); + QCOMPARE(spyIcon.last().value(0).value<QIcon>().availableSizes(), + pageTo->icon().availableSizes()); } // verify no emits on destroy with the same number of signals in spy diff --git a/tests/manual/quick/faviconbrowser/AddressBar.qml b/tests/manual/quick/faviconbrowser/AddressBar.qml deleted file mode 100644 index c79b74f30..000000000 --- a/tests/manual/quick/faviconbrowser/AddressBar.qml +++ /dev/null @@ -1,102 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 - -Rectangle { - id: root - - property int progress: 0 - property url iconUrl: "" - property url pageUrl: "" - - signal accepted(url addressUrl) - - clip: true - - onActiveFocusChanged: { - if (activeFocus) - addressField.forceActiveFocus(); - } - - Rectangle { - width: addressField.width / 100 * root.progress - height: root.height - - visible: root.progress < 100 - - color: "#b6dca6" - radius: root.radius - } - - TextField { - id: addressField - anchors.fill: parent - - Image { - anchors.verticalCenter: addressField.verticalCenter - x: 5; z: parent.z + 1 - width: 16; height: 16 - sourceSize: Qt.size(width, height) - source: root.iconUrl - visible: root.progress == 100 - } - - Text { - text: root.progress < 0 ? "" : root.progress + "%" - x: 5; z: parent.z + 1 - font.bold: true - anchors.verticalCenter: parent.verticalCenter - - visible: root.progress < 100 - } - - style: TextFieldStyle { - padding.left: 30 - - background: Rectangle { - color: "transparent" - border.color: "black" - border.width: 1 - radius: root.radius - } - } - - onActiveFocusChanged: { - if (activeFocus) - selectAll(); - else - deselect(); - } - - text: root.pageUrl - onAccepted: root.accepted(utils.fromUserInput(text)) - } -} diff --git a/tests/manual/quick/faviconbrowser/FaviconPanel.qml b/tests/manual/quick/faviconbrowser/FaviconPanel.qml deleted file mode 100644 index 857019d9a..000000000 --- a/tests/manual/quick/faviconbrowser/FaviconPanel.qml +++ /dev/null @@ -1,234 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 -import QtQuick.Layouts 1.1 - -Item { - id: root - - property url iconUrl: "" - property int iconSize: 128 - property int iconMinimumSize: 8 - property int iconMaximumSize: 256 - - RowLayout { - anchors.fill: parent - spacing: 2 - - Rectangle { - Layout.fillWidth: true - Layout.fillHeight: true - - RowLayout { - anchors.fill: parent - spacing: 2 - - Rectangle { - Layout.fillHeight: true - Layout.preferredWidth: (parent.width - 2 * parent.spacing) / 3 - - border.color: "black" - border.width: 1 - clip: true - - Text { - z: parent.z + 1 - anchors.top: parent.top - anchors.topMargin: 5 - anchors.left: parent.left - anchors.leftMargin: 5 - font.bold: true - - text: "faviconImage" - } - - Image { - id: faviconImage - anchors.centerIn: parent - - width: root.iconSize - height: width - sourceSize: Qt.size(width, height) - - source: root.iconUrl - - onStatusChanged: { - if (status == Image.Ready) { - grabToImage(function(result) { - grabImage.source = result.url; - }); - } - - if (status == Image.Null) - grabImage.source = ""; - } - } - } - - Rectangle { - Layout.fillHeight: true - Layout.preferredWidth: (parent.width - 2 * parent.spacing) / 3 - - border.color: "black" - border.width: 1 - clip: true - - Text { - z: parent.z + 1 - anchors.top: parent.top - anchors.topMargin: 5 - anchors.left: parent.left - anchors.leftMargin: 5 - font.bold: true - - text: "grabImage" - } - - Image { - id: grabImage - anchors.centerIn: parent - - width: root.iconSize - height: width - - onStatusChanged: { - if (status == Image.Ready || status == Image.Null) - faviconCanvas.requestPaint(); - } - } - } - - Rectangle { - Layout.fillHeight: true - Layout.preferredWidth: (parent.width - 2 * parent.spacing) / 3 - - border.color: "black" - border.width: 1 - clip: true - - Text { - z: parent.z + 1 - anchors.top: parent.top - anchors.topMargin: 5 - anchors.left: parent.left - anchors.leftMargin: 5 - font.bold: true - - text: "faviconCanvas" - } - - Canvas { - id: faviconCanvas - anchors.centerIn: parent - - width: root.iconSize - height: width - - onPaint: { - var ctx = getContext("2d"); - ctx.reset(); - ctx.clearRect(0, 0, width, height); - - if (grabImage.source == "") - return; - - ctx.drawImage(grabImage, 0, 0, width, height); - - var imageData = ctx.getImageData(width/2, height/2, width/2, height/2); - var pixel = imageData.data; - - verbose.append("pixel(" + width/2 + ", " + height/2 + "): " + pixel[0] + ", " + pixel[1] + ", " + pixel[2]); - } - } - } - } - } - - Rectangle { - Layout.fillHeight: true - Layout.preferredWidth: 100 - - Slider { - id: faviconSizeSlider - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.bottom: faviconSizeSpin.top - - orientation: Qt.Vertical - minimumValue: root.iconMinimumSize - maximumValue: root.iconMaximumSize - stepSize: 1 - tickmarksEnabled: true - value: root.iconSize - - onValueChanged: { - if (pressed && value != root.iconSize) - root.iconSize = value; - } - } - - SpinBox { - id: faviconSizeSpin - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - - minimumValue: root.iconMinimumSize - maximumValue: root.iconMaximumSize - value: root.iconSize - - onEditingFinished: { - if (value != root.iconSize) - root.iconSize = value; - } - } - } - - TextArea { - id: verbose - - Layout.fillHeight: true - Layout.preferredWidth: 310 - - readOnly: true - tabChangesFocus: true - - font.family: "Monospace" - font.pointSize: 12 - - textFormat: TextEdit.RichText - frameVisible: false - - style: TextAreaStyle { - backgroundColor: "lightgray" - } - } - } -} diff --git a/tests/manual/quick/faviconbrowser/faviconbrowser.pro b/tests/manual/quick/faviconbrowser/faviconbrowser.pro deleted file mode 100644 index d997d6322..000000000 --- a/tests/manual/quick/faviconbrowser/faviconbrowser.pro +++ /dev/null @@ -1,23 +0,0 @@ -QT += qml quick webenginequick -qtHaveModule(widgets) { - QT += widgets # QApplication is required to get native styling with QtQuickControls -} - -TARGET = faviconbrowser -TEMPLATE = app - - -SOURCES = \ - main.cpp - -HEADERS = \ - utils.h - -OTHER_FILES += \ - main.qml \ - AddressBar.qml \ - FaviconPanel.qml - -RESOURCES += \ - faviconbrowser.qrc - diff --git a/tests/manual/quick/faviconbrowser/faviconbrowser.qrc b/tests/manual/quick/faviconbrowser/faviconbrowser.qrc deleted file mode 100644 index b641fa2fa..000000000 --- a/tests/manual/quick/faviconbrowser/faviconbrowser.qrc +++ /dev/null @@ -1,17 +0,0 @@ -<!DOCTYPE RCC><RCC version="1.0"> - <qresource prefix="/"> - <file>main.qml</file> - <file>AddressBar.qml</file> - <file>FaviconPanel.qml</file> - </qresource> - <qresource prefix="test"> - <file alias="favicon-multi-gray.html">../../../auto/quick/qmltests2/data/favicon-multi-gray.html</file> - <file alias="favicon-candidates-gray.html">../../../auto/quick/qmltests2/data/favicon-candidates-gray.html</file> - <file alias="icons/grayicons.ico">../../../auto/quick/qmltests2/data/icons/grayicons.ico</file> - <file alias="icons/gray16.png">../../../auto/quick/qmltests2/data/icons/gray16.png</file> - <file alias="icons/gray32.png">../../../auto/quick/qmltests2/data/icons/gray32.png</file> - <file alias="icons/gray64.png">../../../auto/quick/qmltests2/data/icons/gray64.png</file> - <file alias="icons/gray128.png">../../../auto/quick/qmltests2/data/icons/gray128.png</file> - <file alias="icons/gray255.png">../../../auto/quick/qmltests2/data/icons/gray255.png</file> - </qresource> -</RCC> diff --git a/tests/manual/quick/faviconbrowser/main.cpp b/tests/manual/quick/faviconbrowser/main.cpp deleted file mode 100644 index d1faadfa0..000000000 --- a/tests/manual/quick/faviconbrowser/main.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "utils.h" - -#ifndef QT_NO_WIDGETS -#include <QtWidgets/QApplication> -typedef QApplication Application; -#else -#include <QtGui/QGuiApplication> -typedef QGuiApplication Application; -#endif -#include <QtQml/QQmlApplicationEngine> -#include <QtQml/QQmlContext> -#include <QtWebEngineQuick/qtwebengineglobal.h> - -int main(int argc, char **argv) -{ - Application app(argc, argv); - - QtWebEngine::initialize(); - - QQmlApplicationEngine appEngine; - Utils utils; - appEngine.rootContext()->setContextProperty("utils", &utils); - appEngine.load(QUrl("qrc:/main.qml")); - - return app.exec(); -} diff --git a/tests/manual/quick/faviconbrowser/main.qml b/tests/manual/quick/faviconbrowser/main.qml deleted file mode 100644 index c8e2bdbd5..000000000 --- a/tests/manual/quick/faviconbrowser/main.qml +++ /dev/null @@ -1,170 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Layouts 1.1 -import QtWebEngine 1.3 -import Qt.labs.settings 1.0 - -ApplicationWindow { - width: 1300 - height: 900 - visible: true - - Item { - id: bookmarkUrls - - property url multiTest: Qt.resolvedUrl("qrc:/test/favicon-multi-gray.html") - property url candidatesTest: Qt.resolvedUrl("qrc:/test/favicon-candidates-gray.html") - property url aboutBlank: Qt.resolvedUrl("about:blank") - property url qtHome: Qt.resolvedUrl("http://www.qt.io/") - } - - Settings { - id: appSettings - - property alias autoLoadIconsForPage: autoLoadIconsForPage.checked - property alias touchIconsEnabled: touchIconsEnabled.checked - } - - SplitView { - anchors.fill: parent - orientation: Qt.Vertical - - FaviconPanel { - id: faviconPanel - - Layout.fillWidth: true - Layout.minimumHeight: 200 - - Layout.margins: 2 - - iconUrl: webEngineView && webEngineView.icon - } - - ColumnLayout { - Layout.fillWidth: true - Layout.fillHeight: true - Layout.topMargin: 2 - - AddressBar { - id: addressBar - - Layout.fillWidth: true - Layout.leftMargin: 5 - Layout.rightMargin: 5 - height: 25 - - color: "white" - radius: 4 - - progress: webEngineView && webEngineView.loadProgress - iconUrl: webEngineView && webEngineView.icon - pageUrl: webEngineView && webEngineView.url - - onAccepted: webEngineView.url = addressUrl - } - - Rectangle { - id: toolBar - - Layout.fillWidth: true - Layout.leftMargin: 5 - Layout.rightMargin: 5 - Layout.preferredHeight: 25 - - RowLayout { - anchors.verticalCenter: parent.verticalCenter - - Button { - text: "Multi-sized Favicon Test" - onClicked: webEngineView.url = bookmarkUrls.multiTest - enabled: webEngineView.url != bookmarkUrls.multiTest - } - - Button { - text: "Candidate Favicons Test" - onClicked: webEngineView.url = bookmarkUrls.candidatesTest - enabled: webEngineView.url != bookmarkUrls.candidatesTest - } - - Button { - text: "About Blank" - onClicked: webEngineView.url = bookmarkUrls.aboutBlank - enabled: webEngineView.url != bookmarkUrls.aboutBlank - } - - Button { - text: "Qt Home Page" - onClicked: webEngineView.url = bookmarkUrls.qtHome - enabled: webEngineView.url != bookmarkUrls.qtHome - } - } - - ToolButton { - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - - menu: Menu { - MenuItem { - id: autoLoadIconsForPage - text: "Icons On" - checkable: true - checked: WebEngine.settings.autoLoadIconsForPage - - onCheckedChanged: webEngineView.reload() - } - - MenuItem { - id: touchIconsEnabled - text: "Touch Icons On" - checkable: true - checked: WebEngine.settings.touchIconsEnabled - enabled: autoLoadIconsForPage.checked - - onCheckedChanged: webEngineView.reload() - } - } - } - } - - WebEngineView { - id: webEngineView - - Layout.fillWidth: true - Layout.fillHeight: true - - settings.autoLoadIconsForPage: appSettings.autoLoadIconsForPage - settings.touchIconsEnabled: appSettings.touchIconsEnabled - - Component.onCompleted: webEngineView.url = bookmarkUrls.multiTest - } - } - } -} diff --git a/tests/manual/quick/faviconbrowser/utils.h b/tests/manual/quick/faviconbrowser/utils.h deleted file mode 100644 index 9deef0b61..000000000 --- a/tests/manual/quick/faviconbrowser/utils.h +++ /dev/null @@ -1,49 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef UTILS_H -#define UTILS_H - -#include <QtCore/QFileInfo> -#include <QtCore/QUrl> - -class Utils : public QObject { - Q_OBJECT -public: - Q_INVOKABLE static QUrl fromUserInput(const QString& userInput); -}; - -inline QUrl Utils::fromUserInput(const QString& userInput) -{ - QFileInfo fileInfo(userInput); - if (fileInfo.exists()) - return QUrl::fromLocalFile(fileInfo.absoluteFilePath()); - return QUrl::fromUserInput(userInput); -} - -#endif // UTILS_H |