blob: 89974494279f9b16b8c76f26ce08d658a168873f [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// 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_app_info_fetcher.h"
#include "base/base64.h"
#include "base/bind_helpers.h"
#include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/browser/service_worker/service_worker_context_wrapper.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/manifest_icon_downloader.h"
#include "content/public/browser/manifest_icon_selector.h"
#include "ui/gfx/image/image.h"
namespace content {
namespace {
// TODO(gogerald): Choose appropriate icon size dynamically on different
// platforms.
// Here we choose a large ideal icon size to be big enough for all platforms.
// Note that we only scale down for this icon size but not scale up.
const int kPaymentAppIdealIconSize = 0xFFFF;
const int kPaymentAppMinimumIconSize = 0;
} // namespace
PaymentAppInfoFetcher::PaymentAppInfo::PaymentAppInfo() {}
PaymentAppInfoFetcher::PaymentAppInfo::~PaymentAppInfo() {}
PaymentAppInfoFetcher::PaymentAppInfoFetcher()
: context_process_id_(-1),
context_frame_id_(-1),
fetched_payment_app_info_(base::MakeUnique<PaymentAppInfo>()) {}
PaymentAppInfoFetcher::~PaymentAppInfoFetcher() {}
void PaymentAppInfoFetcher::Start(
const GURL& context_url,
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
PaymentAppInfoFetchCallback callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
context_url_ = context_url;
callback_ = std::move(callback);
std::unique_ptr<std::vector<std::pair<int, int>>> provider_hosts =
service_worker_context->GetProviderHostIds(context_url.GetOrigin());
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::BindOnce(&PaymentAppInfoFetcher::StartFromUIThread, this,
std::move(provider_hosts)));
}
void PaymentAppInfoFetcher::StartFromUIThread(
const std::unique_ptr<std::vector<std::pair<int, int>>>& provider_hosts) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (provider_hosts->size() == 0U) {
PostPaymentAppInfoFetchResultToIOThread();
return;
}
for (const auto& frame : *provider_hosts) {
RenderFrameHostImpl* render_frame_host =
RenderFrameHostImpl::FromID(frame.first, frame.second);
if (!render_frame_host)
continue;
WebContentsImpl* web_content = static_cast<WebContentsImpl*>(
WebContents::FromRenderFrameHost(render_frame_host));
if (!web_content || web_content->IsHidden() ||
context_url_.spec().compare(
web_content->GetLastCommittedURL().spec()) != 0) {
continue;
}
context_process_id_ = frame.first;
context_frame_id_ = frame.second;
web_content->GetManifest(base::Bind(
&PaymentAppInfoFetcher::FetchPaymentAppManifestCallback, this));
return;
}
PostPaymentAppInfoFetchResultToIOThread();
}
void PaymentAppInfoFetcher::FetchPaymentAppManifestCallback(
const GURL& url,
const Manifest& manifest) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (url.is_empty() || manifest.IsEmpty()) {
PostPaymentAppInfoFetchResultToIOThread();
return;
}
fetched_payment_app_info_->prefer_related_applications =
manifest.prefer_related_applications;
for (const auto& related_application : manifest.related_applications) {
fetched_payment_app_info_->related_applications.emplace_back(
StoredRelatedApplication());
if (!related_application.platform.is_null()) {
base::UTF16ToUTF8(
related_application.platform.string().c_str(),
related_application.platform.string().length(),
&(fetched_payment_app_info_->related_applications.back().platform));
}
if (!related_application.id.is_null()) {
base::UTF16ToUTF8(
related_application.id.string().c_str(),
related_application.id.string().length(),
&(fetched_payment_app_info_->related_applications.back().id));
}
}
if (manifest.name.is_null() ||
!base::UTF16ToUTF8(manifest.name.string().c_str(),
manifest.name.string().length(),
&(fetched_payment_app_info_->name))) {
PostPaymentAppInfoFetchResultToIOThread();
return;
}
GURL icon_url = ManifestIconSelector::FindBestMatchingIcon(
manifest.icons, kPaymentAppIdealIconSize, kPaymentAppMinimumIconSize,
Manifest::Icon::ANY);
if (!icon_url.is_valid()) {
PostPaymentAppInfoFetchResultToIOThread();
return;
}
RenderFrameHostImpl* render_frame_host =
RenderFrameHostImpl::FromID(context_process_id_, context_frame_id_);
if (!render_frame_host) {
PostPaymentAppInfoFetchResultToIOThread();
return;
}
WebContents* web_content =
WebContents::FromRenderFrameHost(render_frame_host);
if (!web_content) {
PostPaymentAppInfoFetchResultToIOThread();
return;
}
if (!content::ManifestIconDownloader::Download(
web_content, icon_url, kPaymentAppIdealIconSize,
kPaymentAppMinimumIconSize,
base::Bind(&PaymentAppInfoFetcher::OnIconFetched, this))) {
PostPaymentAppInfoFetchResultToIOThread();
}
}
void PaymentAppInfoFetcher::OnIconFetched(const SkBitmap& icon) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (icon.drawsNothing()) {
PostPaymentAppInfoFetchResultToIOThread();
return;
}
gfx::Image decoded_image = gfx::Image::CreateFrom1xBitmap(icon);
scoped_refptr<base::RefCountedMemory> raw_data = decoded_image.As1xPNGBytes();
base::Base64Encode(
base::StringPiece(raw_data->front_as<char>(), raw_data->size()),
&(fetched_payment_app_info_->icon));
PostPaymentAppInfoFetchResultToIOThread();
}
void PaymentAppInfoFetcher::PostPaymentAppInfoFetchResultToIOThread() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::BindOnce(std::move(callback_),
std::move(fetched_payment_app_info_)));
}
} // namespace content