summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPeter Varga <pvarga@inf.u-szeged.hu>2015-12-01 10:50:02 +0100
committerPeter Varga <pvarga@inf.u-szeged.hu>2016-02-03 16:21:12 +0000
commit41d69eb0fa2375f0da6ba9b35136f5598be4b3a4 (patch)
tree3c754447cf5d1c854eb1bc7fdbe3d6777fcdac0c /src
parent4713387c052d54e0f5ea02efaeaa25931d1cd7ee (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.pro3
-rw-r--r--src/core/favicon_manager.cpp390
-rw-r--r--src/core/favicon_manager.h120
-rw-r--r--src/core/favicon_manager_p.h106
-rw-r--r--src/core/type_conversion.cpp45
-rw-r--r--src/core/type_conversion.h6
-rw-r--r--src/core/web_contents_adapter.cpp6
-rw-r--r--src/core/web_contents_adapter.h2
-rw-r--r--src/core/web_contents_delegate_qt.cpp47
-rw-r--r--src/core/web_contents_delegate_qt.h3
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