diff options
author | Peter Varga <pvarga@inf.u-szeged.hu> | 2015-12-01 10:50:02 +0100 |
---|---|---|
committer | Peter Varga <pvarga@inf.u-szeged.hu> | 2016-02-03 16:21:12 +0000 |
commit | 41d69eb0fa2375f0da6ba9b35136f5598be4b3a4 (patch) | |
tree | 3c754447cf5d1c854eb1bc7fdbe3d6777fcdac0c /src | |
parent | 4713387c052d54e0f5ea02efaeaa25931d1cd7ee (diff) |
Add FaviconManager to core
The new icon manager uses the WebContents::DownloadImage() API for
downloading icons. It proposes the best quality among the available
favicons via the iconChanged signal.
Change-Id: I66a014365b6f6560ff34d40ee870aee84e4e70e4
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@theqtcompany.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/core/core_gyp_generator.pro | 3 | ||||
-rw-r--r-- | src/core/favicon_manager.cpp | 390 | ||||
-rw-r--r-- | src/core/favicon_manager.h | 120 | ||||
-rw-r--r-- | src/core/favicon_manager_p.h | 106 | ||||
-rw-r--r-- | src/core/type_conversion.cpp | 45 | ||||
-rw-r--r-- | src/core/type_conversion.h | 6 | ||||
-rw-r--r-- | src/core/web_contents_adapter.cpp | 6 | ||||
-rw-r--r-- | src/core/web_contents_adapter.h | 2 | ||||
-rw-r--r-- | src/core/web_contents_delegate_qt.cpp | 47 | ||||
-rw-r--r-- | src/core/web_contents_delegate_qt.h | 3 |
10 files changed, 712 insertions, 16 deletions
diff --git a/src/core/core_gyp_generator.pro b/src/core/core_gyp_generator.pro index 80bf662d6..5e6641d51 100644 --- a/src/core/core_gyp_generator.pro +++ b/src/core/core_gyp_generator.pro @@ -53,6 +53,7 @@ SOURCES = \ desktop_screen_qt.cpp \ dev_tools_http_handler_delegate_qt.cpp \ download_manager_delegate_qt.cpp \ + favicon_manager.cpp \ file_picker_controller.cpp \ gl_context_qt.cpp \ gl_surface_qt.cpp \ @@ -130,6 +131,8 @@ HEADERS = \ dev_tools_http_handler_delegate_qt.h \ download_manager_delegate_qt.h \ chromium_gpu_helper.h \ + favicon_manager_p.h \ + favicon_manager.h \ file_picker_controller.h \ gl_context_qt.h \ gl_surface_qt.h \ diff --git a/src/core/favicon_manager.cpp b/src/core/favicon_manager.cpp new file mode 100644 index 000000000..f3260b3c4 --- /dev/null +++ b/src/core/favicon_manager.cpp @@ -0,0 +1,390 @@ +/**************************************************************************** +** +** 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 "favicon_manager_p.h" + +#include "type_conversion.h" +#include "web_contents_adapter_client.h" + +#include "base/bind.h" +#include "content/public/browser/web_contents.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "third_party/skia/include/core/SkPixelRef.h" +#include "ui/gfx/geometry/size.h" + +#include <QtCore/QUrl> +#include <QtGui/QIcon> + +namespace QtWebEngineCore { + +static inline bool isResourceUrl(const QUrl &url) +{ + return !url.scheme().compare(QLatin1String("qrc")); +} + +static inline unsigned area(const QSize &size) +{ + return size.width() * size.height(); +} + + +FaviconManagerPrivate::FaviconManagerPrivate(content::WebContents *webContents, WebContentsAdapterClient *viewClient) + : m_webContents(webContents) + , m_viewClient(viewClient) + , m_weakFactory(this) +{ +} + +FaviconManagerPrivate::~FaviconManagerPrivate() +{ +} + +int FaviconManagerPrivate::downloadIcon(const QUrl &url, bool candidate) +{ + static int fakeId = 0; + int id; + + bool cached = candidate && m_icons.contains(url); + if (isResourceUrl(url) || cached) { + id = --fakeId; + m_pendingRequests.insert(id, url); + } else { + id = m_webContents->DownloadImage( + toGurl(url), + true, // is_favicon + 0, // no max size + false, // normal cache policy + base::Bind(&FaviconManagerPrivate::iconDownloadFinished, m_weakFactory.GetWeakPtr())); + } + + if (candidate) { + Q_ASSERT(!m_inProgressCandidateRequests.contains(id)); + m_inProgressCandidateRequests.insert(id, url); + } else { + Q_ASSERT(!m_inProgressCustomRequests.contains(id)); + m_inProgressCustomRequests.insert(id, url); + } + + return id; +} + +void FaviconManagerPrivate::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 as a workaround for avoiding signal iconChanged when + * accessing each cached icons or icons stored in qrc. They don't have to be downloaded + * thus the m_inProgressCustomRequests maybe emptied right before the next icon is added to + * in-progress-requests queue. The m_pendingRequests stores these requests until all + * candidates are added to the queue then pending requests should be cleaned up by this + * function. + */ +void FaviconManagerPrivate::downloadPendingRequests() +{ + Q_FOREACH (int id, m_pendingRequests.keys()) { + QIcon icon; + + QUrl requestUrl = m_pendingRequests[id]; + if (isResourceUrl(requestUrl) && !m_icons.contains(requestUrl)) + icon = QIcon(requestUrl.toString().remove(0, 3)); + + storeIcon(id, icon); + } + + m_pendingRequests.clear(); +} + +void FaviconManagerPrivate::storeIcon(int id, const QIcon &icon) +{ + Q_Q(FaviconManager); + + bool candidate = m_inProgressCandidateRequests.contains(id); + + QUrl requestUrl = candidate ? m_inProgressCandidateRequests[id] : m_inProgressCustomRequests[id]; + FaviconInfo &faviconInfo = q->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); + } + } + } + + q->m_hasDownloadedIcon = true; + } else if (id < 0) { + // Icon is cached + q->m_hasDownloadedIcon = true; + } else { + // Reset size if icon cannot be downloaded + faviconInfo.size = QSize(0, 0); + } + + if (candidate) { + m_inProgressCandidateRequests.remove(id); + if (m_inProgressCandidateRequests.isEmpty()) + m_viewClient->iconChanged(q->getProposedFaviconInfo().url); + } else { + m_inProgressCustomRequests.remove(id); + } + + Q_EMIT q->iconDownloaded(requestUrl); +} + +FaviconManager::FaviconManager(FaviconManagerPrivate *d) + : m_hasDownloadedIcon(false) +{ + Q_ASSERT(d); + d_ptr.reset(d); + + d->q_ptr = this; +} + +FaviconManager::~FaviconManager() +{ +} + +QIcon FaviconManager::getIcon(const QUrl &url) const +{ + Q_D(const FaviconManager); + return d->m_icons[url]; +} + +FaviconInfo FaviconManager::getFaviconInfo(const QUrl &url) const +{ + return m_faviconInfoMap[url]; +} + +QList<FaviconInfo> FaviconManager::getFaviconInfoList(bool candidatesOnly) const +{ + QList<FaviconInfo> faviconInfoList = m_faviconInfoMap.values(); + + if (candidatesOnly) { + QMutableListIterator<FaviconInfo> it(faviconInfoList); + while (it.hasNext()) { + if (!it.next().candidate) + it.remove(); + } + } + + return faviconInfoList; +} + + +void FaviconManager::downloadIcon(const QUrl &url, FaviconInfo::FaviconType iconType) +{ + Q_D(FaviconManager); + + // If the favicon cannot be found in the list that means that it is not a candidate + // for any visited page (including the current one). In this case the type of the icon + // is unknown: it has to be specified explicitly. + if (!m_faviconInfoMap.contains(url)) { + FaviconInfo newFaviconInfo(url, iconType); + m_faviconInfoMap.insert(url, newFaviconInfo); + } + + d->downloadIcon(url, false); + d->downloadPendingRequests(); +} + +void FaviconManager::removeIcon(const QUrl &url) +{ + Q_D(FaviconManager); + int removed = d->m_icons.remove(url); + + if (removed) { + Q_ASSERT(removed == 1); + Q_ASSERT(m_faviconInfoMap.contains(url)); + m_faviconInfoMap[url].size = QSize(0, 0); + } +} + +bool FaviconManager::hasAvailableCandidateIcon() const +{ + Q_D(const FaviconManager); + return m_hasDownloadedIcon || !d->m_inProgressCandidateRequests.isEmpty(); +} + +void FaviconManager::update(QList<FaviconInfo> &candidates) +{ + Q_D(FaviconManager); + updateCandidates(candidates); + + Q_FOREACH (FaviconInfo faviconInfo, m_faviconInfoMap.values()) { + if (!faviconInfo.candidate || faviconInfo.type != FaviconInfo::Favicon) + continue; + + if (faviconInfo.isValid()) + d->downloadIcon(faviconInfo.url, true); + } + + d->downloadPendingRequests(); +} + +void FaviconManager::updateCandidates(QList<FaviconInfo> &candidates) +{ + Q_FOREACH (FaviconInfo candidateFaviconInfo, candidates) { + QUrl candidateUrl = candidateFaviconInfo.url; + if (m_faviconInfoMap.contains(candidateUrl)) { + m_faviconInfoMap[candidateUrl].candidate = true; + // Update type in case of the icon was downloaded manually + m_faviconInfoMap[candidateUrl].type = candidateFaviconInfo.type; + continue; + } + + candidateFaviconInfo.candidate = true; + m_faviconInfoMap.insert(candidateUrl, candidateFaviconInfo); + } +} + +void FaviconManager::resetCandidates() +{ + m_hasDownloadedIcon = false; + Q_FOREACH (const QUrl key, m_faviconInfoMap.keys()) + m_faviconInfoMap[key].candidate = false; +} + + +FaviconInfo FaviconManager::getProposedFaviconInfo() const +{ + FaviconInfo proposedFaviconInfo = getFirstFaviconInfo(); + + // If nothing has been downloaded yet return the first favicon + // if there is available for dev-tools + if (!m_hasDownloadedIcon) + return proposedFaviconInfo; + + unsigned bestArea = area(proposedFaviconInfo.size); + Q_FOREACH (const FaviconInfo faviconInfo, m_faviconInfoMap.values()) { + if (!faviconInfo.candidate || faviconInfo.type != FaviconInfo::Favicon) + continue; + + if (faviconInfo.isValid() && bestArea < area(faviconInfo.size)) { + proposedFaviconInfo = faviconInfo; + bestArea = area(proposedFaviconInfo.size); + } + } + + return proposedFaviconInfo; +} + +FaviconInfo FaviconManager::getFirstFaviconInfo() const +{ + Q_FOREACH (const FaviconInfo faviconInfo, m_faviconInfoMap.values()) { + if (!faviconInfo.candidate || faviconInfo.type != FaviconInfo::Favicon) + continue; + + if (faviconInfo.isValid()) + return faviconInfo; + } + + return FaviconInfo(); +} + + + +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) +{ +} + +FaviconInfo::FaviconInfo(const QUrl &url, FaviconInfo::FaviconType 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 new file mode 100644 index 000000000..eaae8123f --- /dev/null +++ b/src/core/favicon_manager.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef FAVICON_MANAGER_H +#define FAVICON_MANAGER_H + +#include "qtwebenginecoreglobal.h" + +#include <QtCore/QMap> +#include <QtCore/QObject> +#include <QtCore/QSize> +#include <QtCore/QUrl> + +#include "web_engine_settings.h" + +namespace QtWebEngineCore { + +class FaviconManagerPrivate; + +// Based on src/3rdparty/chromium/content/public/common/favicon_url.h +class QWEBENGINE_EXPORT FaviconInfo { +public: + enum FaviconType { + InvalidIcon, + Favicon, + TouchIcon, + TouchPrecomposedIcon + }; + + FaviconInfo(); + FaviconInfo(const FaviconInfo &); + FaviconInfo(const QUrl &, FaviconInfo::FaviconType); + ~FaviconInfo(); + + bool isValid() const; + bool isDownloaded() const; + + QUrl url; + FaviconType type; + // Stores the size of the highest quality in case of multi-size icon + QSize size; + bool candidate; + bool multiSize; +}; + + +class QWEBENGINE_EXPORT FaviconManager : public QObject { + Q_OBJECT +public: + ~FaviconManager(); + + QIcon getIcon(const QUrl &) const; + FaviconInfo getFaviconInfo(const QUrl &) const; + QList<FaviconInfo> getFaviconInfoList(bool) const; + void downloadIcon(const QUrl &url, FaviconInfo::FaviconType iconType = FaviconInfo::Favicon); + void removeIcon(const QUrl &); + +Q_SIGNALS: + void iconDownloaded(const QUrl &url); + +private: + FaviconManager(FaviconManagerPrivate *); + + bool hasAvailableCandidateIcon() const; + void update(QList<FaviconInfo> &); + void updateCandidates(QList<FaviconInfo> &); + void resetCandidates(); + + FaviconInfo getProposedFaviconInfo() const; + FaviconInfo getFirstFaviconInfo() const; + + QMap<QUrl, FaviconInfo> m_faviconInfoMap; + bool m_hasDownloadedIcon; + + Q_DISABLE_COPY(FaviconManager) + Q_DECLARE_PRIVATE(FaviconManager) + QScopedPointer<FaviconManagerPrivate> d_ptr; + + friend class WebContentsDelegateQt; +}; + +} // namespace QtWebEngineCore + +#endif // FAVICON_MANAGER_H diff --git a/src/core/favicon_manager_p.h b/src/core/favicon_manager_p.h new file mode 100644 index 000000000..8358245a2 --- /dev/null +++ b/src/core/favicon_manager_p.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef FAVICON_MANAGER_P_H +#define FAVICON_MANAGER_P_H + +// +// 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. +// + +#include "qtwebenginecoreglobal_p.h" + +#include <QtCore/QMap> +#include <QtCore/QObject> +#include <vector> + +#include "base/memory/weak_ptr.h" + +QT_FORWARD_DECLARE_CLASS(QUrl) + +class GURL; +class SkBitmap; + +namespace gfx { + class Size; +} + +namespace content { + class WebContents; +} + +namespace QtWebEngineCore { + +class FaviconManager; +class WebContentsAdapterClient; + +class FaviconManagerPrivate { +public: + FaviconManagerPrivate(content::WebContents *, WebContentsAdapterClient *); + ~FaviconManagerPrivate(); + + int downloadIcon(const QUrl &, bool); + + void iconDownloadFinished(int, int, const GURL &, const std::vector<SkBitmap> &, const std::vector<gfx::Size> &); + void storeIcon(int, const QIcon &); + void downloadPendingRequests(); + + content::WebContents *m_webContents; + WebContentsAdapterClient *m_viewClient; + base::WeakPtrFactory<FaviconManagerPrivate> m_weakFactory; + + QMap<QUrl, QIcon> m_icons; + QMap<int, QUrl> m_inProgressCandidateRequests; + QMap<int, QUrl> m_inProgressCustomRequests; + QMap<int, QUrl> m_pendingRequests; + + Q_DECLARE_PUBLIC(FaviconManager) + FaviconManager *q_ptr; +}; + +} // namespace QtWebEngineCore + +#endif // FAVICON_MANAGER_P_H diff --git a/src/core/type_conversion.cpp b/src/core/type_conversion.cpp index ac458df31..ccfc2fdc6 100644 --- a/src/core/type_conversion.cpp +++ b/src/core/type_conversion.cpp @@ -128,6 +128,23 @@ QImage toQImage(const gfx::ImageSkiaRep &imageSkiaRep) return image; } +QIcon toQIcon(const std::vector<SkBitmap> &bitmaps) +{ + if (!bitmaps.size()) + return QIcon(); + + QIcon icon; + + for (unsigned i = 0; i < bitmaps.size(); ++i) { + SkBitmap bitmap = bitmaps[i]; + QImage image = toQImage(bitmap); + + icon.addPixmap(QPixmap::fromImage(image).copy()); + } + + return icon; +} + int flagsFromModifiers(Qt::KeyboardModifiers modifiers) { int modifierFlags = ui::EF_NONE; @@ -152,5 +169,33 @@ int flagsFromModifiers(Qt::KeyboardModifiers modifiers) return modifierFlags; } +FaviconInfo toFaviconInfo(const content::FaviconURL &favicon_url) +{ + FaviconInfo info; + + info.url = toQt(favicon_url.icon_url); + + switch (favicon_url.icon_type) { + case content::FaviconURL::FAVICON: + info.type = FaviconInfo::Favicon; + break; + case content::FaviconURL::TOUCH_ICON: + info.type = FaviconInfo::TouchIcon; + break; + case content::FaviconURL::TOUCH_PRECOMPOSED_ICON: + info.type = FaviconInfo::TouchPrecomposedIcon; + break; + default: + info.type = FaviconInfo::InvalidIcon; + break; + } + + // 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; +} + } // namespace QtWebEngineCore diff --git a/src/core/type_conversion.h b/src/core/type_conversion.h index 0f3357948..8789cf2b7 100644 --- a/src/core/type_conversion.h +++ b/src/core/type_conversion.h @@ -43,6 +43,7 @@ #include <QColor> #include <QDateTime> #include <QDir> +#include <QIcon> #include <QImage> #include <QMatrix4x4> #include <QNetworkCookie> @@ -53,6 +54,8 @@ #include "base/files/file_path.h" #include "base/time/time.h" #include "content/public/common/file_chooser_file_info.h" +#include "content/public/common/favicon_url.h" +#include "favicon_manager.h" #include "net/cookies/canonical_cookie.h" #include "third_party/skia/include/core/SkBitmap.h" #include "third_party/skia/include/core/SkColor.h" @@ -164,6 +167,7 @@ inline QImage toQImage(const SkBitmap &bitmap, QImage::Format format) QImage toQImage(const SkBitmap &bitmap); QImage toQImage(const gfx::ImageSkiaRep &imageSkiaRep); +QIcon toQIcon(const std::vector<SkBitmap> &bitmaps); inline QMatrix4x4 toQt(const SkMatrix44 &m) { @@ -261,6 +265,8 @@ inline QStringList fromVector(const std::vector<base::string16> &vector) } #endif +FaviconInfo toFaviconInfo(const content::FaviconURL &); + } // namespace QtWebEngineCore #endif // TYPE_CONVERSION_H diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index bf36a771c..eb4436018 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -1207,4 +1207,10 @@ WebContentsAdapterClient::renderProcessExitStatus(int terminationStatus) { return status; } +FaviconManager *WebContentsAdapter::faviconManager() +{ + Q_D(WebContentsAdapter); + return d->webContentsDelegate->faviconManager(); +} + } // namespace QtWebEngineCore diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h index e6aef23ec..c7c2c1edf 100644 --- a/src/core/web_contents_adapter.h +++ b/src/core/web_contents_adapter.h @@ -65,6 +65,7 @@ namespace QtWebEngineCore { class BrowserContextQt; class MessagePassingInterface; class WebContentsAdapterPrivate; +class FaviconManager; class QWEBENGINE_EXPORT WebContentsAdapter : public QSharedData { public: @@ -154,6 +155,7 @@ public: BrowserContextAdapter* browserContextAdapter(); QWebChannel *webChannel() const; void setWebChannel(QWebChannel *, uint worldId); + FaviconManager *faviconManager(); QPointF lastScrollOffset() const; QSizeF lastContentsSize() const; diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp index 95066a065..a3d2d816e 100644 --- a/src/core/web_contents_delegate_qt.cpp +++ b/src/core/web_contents_delegate_qt.cpp @@ -46,6 +46,8 @@ #include "browser_context_adapter.h" #include "color_chooser_qt.h" #include "color_chooser_controller.h" +#include "favicon_manager.h" +#include "favicon_manager_p.h" #include "file_picker_controller.h" #include "media_capture_devices_dispatcher.h" #include "network_delegate_qt.h" @@ -89,6 +91,7 @@ static WebContentsAdapterClient::JavaScriptConsoleMessageLevel mapToJavascriptCo WebContentsDelegateQt::WebContentsDelegateQt(content::WebContents *webContents, WebContentsAdapterClient *adapterClient) : m_viewClient(adapterClient) , m_lastReceivedFindReply(0) + , m_faviconManager(new FaviconManager(new FaviconManagerPrivate(webContents, adapterClient))) { webContents->SetDelegate(this); Observe(webContents); @@ -175,8 +178,10 @@ void WebContentsDelegateQt::DidStartProvisionalLoadForFrame(content::RenderFrame m_loadingErrorFrameList.append(render_frame_host->GetRoutingID()); // Trigger LoadStarted signal for main frame's error page only. - if (!render_frame_host->GetParent()) + if (!render_frame_host->GetParent()) { + m_faviconManager->resetCandidates(); m_viewClient->loadStarted(toQt(validated_url), true); + } return; } @@ -185,6 +190,7 @@ void WebContentsDelegateQt::DidStartProvisionalLoadForFrame(content::RenderFrame return; m_loadingErrorFrameList.clear(); + m_faviconManager->resetCandidates(); m_viewClient->loadStarted(toQt(validated_url)); } @@ -208,6 +214,7 @@ void WebContentsDelegateQt::DidFailLoad(content::RenderFrameHost* render_frame_h if (m_loadingErrorFrameList.removeOne(render_frame_host->GetRoutingID()) || render_frame_host->GetParent()) return; + m_viewClient->iconChanged(QUrl()); m_viewClient->loadFinished(false /* success */ , toQt(validated_url), false /* isErrorPage */, error_code, toQt(error_description)); m_viewClient->loadProgressChanged(0); } @@ -230,28 +237,31 @@ void WebContentsDelegateQt::DidFinishLoad(content::RenderFrameHost* render_frame m_viewClient->loadFinished(true, toQt(validated_url)); - content::NavigationEntry *entry = web_contents()->GetController().GetActiveEntry(); + content::NavigationEntry *entry = web_contents()->GetController().GetVisibleEntry(); if (!entry) return; - content::FaviconStatus &favicon = entry->GetFavicon(); - if (favicon.valid) - m_viewClient->iconChanged(toQt(favicon.url)); - else + + // No available icon for the current entry + if (!entry->GetFavicon().valid && !m_faviconManager->hasAvailableCandidateIcon()) m_viewClient->iconChanged(QUrl()); } -void WebContentsDelegateQt::DidUpdateFaviconURL(const std::vector<content::FaviconURL>& candidates) +void WebContentsDelegateQt::DidUpdateFaviconURL(const std::vector<content::FaviconURL> &candidates) { + QList<FaviconInfo> faviconCandidates; Q_FOREACH (content::FaviconURL candidate, candidates) { - if (candidate.icon_type == content::FaviconURL::FAVICON && !candidate.icon_url.is_empty()) { - content::NavigationEntry *entry = web_contents()->GetController().GetActiveEntry(); - if (!entry) - continue; - content::FaviconStatus &favicon = entry->GetFavicon(); - favicon.url = candidate.icon_url; - favicon.valid = toQt(candidate.icon_url).isValid(); - break; - } + // Store invalid candidates too for later debugging via API + faviconCandidates.append(toFaviconInfo(candidate)); + } + + m_faviconManager->update(faviconCandidates); + + content::NavigationEntry *entry = web_contents()->GetController().GetVisibleEntry(); + if (entry) { + FaviconInfo proposedFaviconInfo = m_faviconManager->getProposedFaviconInfo(); + content::FaviconStatus &favicon = entry->GetFavicon(); + favicon.url = toGurl(proposedFaviconInfo.url); + favicon.valid = proposedFaviconInfo.isValid(); } } @@ -426,4 +436,9 @@ void WebContentsDelegateQt::BeforeUnloadFired(content::WebContents *tab, bool pr m_viewClient->windowCloseRejected(); } +FaviconManager *WebContentsDelegateQt::faviconManager() +{ + return m_faviconManager.data(); +} + } // namespace QtWebEngineCore diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h index d646a1322..afa4030d0 100644 --- a/src/core/web_contents_delegate_qt.h +++ b/src/core/web_contents_delegate_qt.h @@ -48,6 +48,7 @@ #include "base/callback.h" #include "color_chooser_controller.h" +#include "favicon_manager.h" #include "javascript_dialog_manager_qt.h" #include <QtCore/qvector.h> #include <QtCore/qcompilerdetection.h> @@ -119,6 +120,7 @@ public: void allowCertificateError(const QSharedPointer<CertificateErrorController> &) ; void requestGeolocationPermission(const QUrl &requestingOrigin); void launchExternalURL(const QUrl &url, ui::PageTransition page_transition, bool is_main_frame); + FaviconManager *faviconManager(); private: WebContentsAdapter *createWindow(content::WebContents *new_contents, WindowOpenDisposition disposition, const gfx::Rect& initial_pos, bool user_gesture); @@ -127,6 +129,7 @@ private: QString m_lastSearchedString; int m_lastReceivedFindReply; QVector<int64> m_loadingErrorFrameList; + QScopedPointer<FaviconManager> m_faviconManager; }; } // namespace QtWebEngineCore |