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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
content / browser / payments / payment_instrument_icon_fetcher.cc [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/payments/payment_instrument_icon_fetcher.h"
#include <limits>
#include <string_view>
#include <utility>
#include "base/base64.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/task/sequenced_task_runner.h"
#include "components/payments/content/icon/icon_size.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/manifest_icon_downloader.h"
#include "third_party/blink/public/common/manifest/manifest_icon_selector.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/codec/png_codec.h"
namespace content {
namespace {
void DownloadBestMatchingIcon(
const GURL& scope,
std::unique_ptr<std::vector<GlobalRenderFrameHostId>> frame_routing_ids,
const std::vector<blink::Manifest::ImageResource>& icons,
PaymentInstrumentIconFetcher::PaymentInstrumentIconFetcherCallback
callback);
WebContents* GetWebContentsFromFrameRoutingIds(
const GURL& scope,
const std::vector<GlobalRenderFrameHostId>& frame_routing_ids);
void OnIconFetched(
const GURL& scope,
std::unique_ptr<std::vector<GlobalRenderFrameHostId>> frame_routing_ids,
const std::vector<blink::Manifest::ImageResource>& icons,
PaymentInstrumentIconFetcher::PaymentInstrumentIconFetcherCallback callback,
const SkBitmap& bitmap) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (bitmap.drawsNothing()) {
if (icons.empty()) {
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), std::string()));
} else {
// If could not download or decode the chosen image(e.g. not supported,
// invalid), try it again with remaining icons.
DownloadBestMatchingIcon(scope, std::move(frame_routing_ids), icons,
std::move(callback));
}
return;
}
std::optional<std::vector<uint8_t>> bitmap_data =
gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, /*discard_transparency=*/false);
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback),
base::Base64Encode(bitmap_data.value())));
}
void DownloadBestMatchingIcon(
const GURL& scope,
std::unique_ptr<std::vector<GlobalRenderFrameHostId>> frame_routing_ids,
const std::vector<blink::Manifest::ImageResource>& icons,
PaymentInstrumentIconFetcher::PaymentInstrumentIconFetcherCallback
callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
WebContents* web_contents =
GetWebContentsFromFrameRoutingIds(scope, *frame_routing_ids);
if (web_contents == nullptr) {
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), std::string()));
return;
}
gfx::NativeView native_view = web_contents->GetNativeView();
GURL icon_url = blink::ManifestIconSelector::FindBestMatchingIcon(
icons, payments::IconSizeCalculator::IdealIconHeight(native_view),
payments::IconSizeCalculator::MinimumIconHeight(),
ManifestIconDownloader::kMaxWidthToHeightRatio,
blink::mojom::ManifestImageResource_Purpose::ANY);
if (!icon_url.is_valid()) {
// If the icon url is invalid, it's better to give the information to
// developers in advance unlike when fetching or decoding fails. We already
// checked whether they are valid in renderer side. So, if the icon url is
// invalid, it's something wrong.
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), std::string()));
return;
}
std::vector<blink::Manifest::ImageResource> copy_icons;
for (const auto& icon : icons) {
if (icon.src != icon_url) {
copy_icons.emplace_back(icon);
}
}
bool can_download_icon = ManifestIconDownloader::Download(
web_contents, icon_url,
payments::IconSizeCalculator::IdealIconHeight(native_view),
payments::IconSizeCalculator::MinimumIconHeight(),
/* maximum_icon_size_in_px= */ std::numeric_limits<int>::max(),
base::BindOnce(&OnIconFetched, scope, std::move(frame_routing_ids),
copy_icons, std::move(callback)),
false /* square_only */);
DCHECK(can_download_icon);
}
WebContents* GetWebContentsFromFrameRoutingIds(
const GURL& scope,
const std::vector<GlobalRenderFrameHostId>& frame_routing_ids) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
for (const auto& ids : frame_routing_ids) {
RenderFrameHostImpl* render_frame_host =
RenderFrameHostImpl::FromID(ids.child_id, ids.frame_routing_id);
if (!render_frame_host)
continue;
WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
WebContents::FromRenderFrameHost(render_frame_host));
if (!web_contents || web_contents->IsHidden() ||
scope.DeprecatedGetOriginAsURL().spec().compare(
web_contents->GetLastCommittedURL()
.DeprecatedGetOriginAsURL()
.spec()) != 0) {
continue;
}
return web_contents;
}
return nullptr;
}
} // namespace
// static
void PaymentInstrumentIconFetcher::Start(
const GURL& scope,
std::unique_ptr<std::vector<GlobalRenderFrameHostId>> provider_hosts,
const std::vector<blink::Manifest::ImageResource>& icons,
PaymentInstrumentIconFetcherCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DownloadBestMatchingIcon(scope, std::move(provider_hosts), icons,
std::move(callback));
}
} // namespace content