1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
android_webview / browser / icon_helper.cc [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "android_webview/browser/icon_helper.h"
#include "base/check_op.h"
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/hash/hash.h"
#include "base/notreached.h"
#include "components/favicon_base/select_favicon_frames.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents.h"
#include "third_party/blink/public/mojom/favicon/favicon_url.mojom.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/geometry/size.h"
using content::BrowserThread;
using content::WebContents;
namespace android_webview {
namespace {
const int kLargestIconSize = 192;
} // namespace
IconHelper::IconHelper(WebContents* web_contents)
: WebContentsObserver(web_contents),
listener_(nullptr),
missing_favicon_urls_() {}
IconHelper::~IconHelper() {
}
void IconHelper::SetListener(Listener* listener) {
listener_ = listener;
}
void IconHelper::DownloadFaviconCallback(
int id,
int http_status_code,
const GURL& image_url,
const std::vector<SkBitmap>& bitmaps,
const std::vector<gfx::Size>& original_bitmap_sizes) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (http_status_code == 404) {
MarkUnableToDownloadFavicon(image_url);
return;
}
if (bitmaps.size() == 0) {
return;
}
// We can protentially have multiple frames of the icon
// in different sizes. We need more fine grain API spec
// to let clients pick out the frame they want.
if (listener_) {
std::vector<size_t> best_indices;
SelectFaviconFrameIndices(original_bitmap_sizes,
std::vector<int>(1U, kLargestIconSize),
&best_indices, nullptr);
listener_->OnReceivedIcon(
image_url,
bitmaps[best_indices.size() == 0 ? 0 : best_indices.front()]);
}
}
void IconHelper::DidUpdateFaviconURL(
content::RenderFrameHost* render_frame_host,
const std::vector<blink::mojom::FaviconURLPtr>& candidates) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
for (const auto& candidate : candidates) {
if (!candidate->icon_url.is_valid())
continue;
switch (candidate->icon_type) {
case blink::mojom::FaviconIconType::kFavicon:
if ((listener_ &&
!listener_->ShouldDownloadFavicon(candidate->icon_url)) ||
WasUnableToDownloadFavicon(candidate->icon_url)) {
break;
}
web_contents()->DownloadImage(
candidate->icon_url,
true, // Is a favicon
gfx::Size(), // No preferred size
kLargestIconSize, // Max bitmap size
false, // Normal cache policy
base::BindOnce(&IconHelper::DownloadFaviconCallback,
base::Unretained(this)));
break;
case blink::mojom::FaviconIconType::kTouchIcon:
if (listener_)
listener_->OnReceivedTouchIconUrl(candidate->icon_url.spec(), false);
break;
case blink::mojom::FaviconIconType::kTouchPrecomposedIcon:
if (listener_)
listener_->OnReceivedTouchIconUrl(candidate->icon_url.spec(), true);
break;
case blink::mojom::FaviconIconType::kInvalid:
// Silently ignore it. Only trigger a callback on valid icons.
break;
default:
NOTREACHED();
}
}
}
void IconHelper::DidStartNavigation(content::NavigationHandle* navigation) {
if (navigation->IsInPrimaryMainFrame() &&
navigation->GetReloadType() == content::ReloadType::BYPASSING_CACHE) {
ClearUnableToDownloadFavicons();
}
}
void IconHelper::MarkUnableToDownloadFavicon(const GURL& icon_url) {
MissingFaviconURLHash url_hash = base::FastHash(icon_url.spec());
missing_favicon_urls_.insert(url_hash);
}
bool IconHelper::WasUnableToDownloadFavicon(const GURL& icon_url) const {
MissingFaviconURLHash url_hash = base::FastHash(icon_url.spec());
return base::Contains(missing_favicon_urls_, url_hash);
}
void IconHelper::ClearUnableToDownloadFavicons() {
missing_favicon_urls_.clear();
}
} // namespace android_webview