blob: 8e7f66bded2581de7fdba70451786fdecf358819 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/autofill/autofill_image_fetcher_impl.h"
#include "chrome/browser/image_fetcher/image_fetcher_service_factory.h"
#include "chrome/browser/profiles/profile_key.h"
#include "components/autofill/core/browser/data_model/credit_card_art_image.h"
#include "components/autofill/core/browser/metrics/autofill_metrics.h"
#include "components/autofill/core/common/autofill_tick_clock.h"
#include "components/image_fetcher/core/cached_image_fetcher.h"
#include "components/image_fetcher/core/image_fetcher_service.h"
#include "components/image_fetcher/core/request_metadata.h"
#include "net/http/http_status_code.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_operations.h"
namespace autofill {
namespace {
constexpr char kUmaClientName[] = "AutofillImageFetcher";
constexpr net::NetworkTrafficAnnotationTag kCardArtImageTrafficAnnotation =
net::DefineNetworkTrafficAnnotation("autofill_image_fetcher_card_art_image",
R"(
semantics {
sender: "Autofill Image Fetcher"
description:
"Fetches customized card art images for credit cards stored in "
"Chrome. Images are hosted on Google static content server, "
"the data source may come from third parties (credit card issuers)."
trigger: "When new credit card data is sent to Chrome if the card "
"has a related card art image, and when the credit card data in "
"the web database is refreshed and any card art image is missing."
data: "URL of the image to be fetched."
destination: GOOGLE_OWNED_SERVICE
}
policy {
cookies_allowed: NO
setting:
"Users can enable or disable this feature in Chromium settings by "
"toggling 'Credit cards and addresses using Google Payments', "
"under 'Advanced sync settings...'."
chrome_policy {
AutoFillEnabled {
policy_options {mode: MANDATORY}
AutoFillEnabled: false
}
}
})");
// The SkAlpha value for the image grey overlay.
constexpr double kImageOverlayAlpha = 0.04; // 4%
} // namespace
AutofillImageFetcherImpl::AutofillImageFetcherImpl(ProfileKey* key)
: key_(key) {}
AutofillImageFetcherImpl::~AutofillImageFetcherImpl() = default;
void AutofillImageFetcherImpl::FetchImagesForURLs(
base::span<const GURL> card_art_urls,
base::OnceCallback<void(const CardArtImageData&)> callback) {
InitializeImageFetcher();
if (!image_fetcher_) {
std::move(callback).Run({});
return;
}
// Construct a BarrierCallback and so that the inner `callback` is invoked
// only when all the images are fetched.
const auto barrier_callback =
base::BarrierCallback<std::unique_ptr<CreditCardArtImage>>(
card_art_urls.size(), std::move(callback));
for (const auto& card_art_url : card_art_urls)
FetchImageForURL(barrier_callback, card_art_url);
}
void AutofillImageFetcherImpl::OnCardArtImageFetched(
base::OnceCallback<void(std::unique_ptr<CreditCardArtImage>)>
barrier_callback,
const GURL& card_art_url,
const absl::optional<base::TimeTicks>& fetch_image_request_timestamp,
const gfx::Image& card_art_image,
const image_fetcher::RequestMetadata& metadata) {
// In case of an invalid url, `fetch_image_request_timestamp` is nullopt, and
// hence we don't report any UMA metrics.
if (fetch_image_request_timestamp.has_value()) {
AutofillMetrics::LogImageFetcherRequestLatency(
AutofillTickClock::NowTicks() - *fetch_image_request_timestamp);
}
AutofillMetrics::LogImageFetchResult(/*succeeded=*/!card_art_image.IsEmpty());
auto credit_card_art_image =
std::make_unique<CreditCardArtImage>(card_art_url, gfx::Image());
if (!card_art_image.IsEmpty()) {
credit_card_art_image->card_art_image =
AutofillImageFetcherImpl::ApplyGreyOverlay(card_art_image);
}
std::move(barrier_callback).Run(std::move(credit_card_art_image));
}
// static
gfx::Image AutofillImageFetcherImpl::ApplyGreyOverlay(const gfx::Image& image) {
// Create a solid dark grey mask for the image.
gfx::ImageSkia mask = gfx::ImageSkiaOperations::CreateColorMask(
image.AsImageSkia(), SK_ColorDKGRAY);
// Apply the mask to the original card art image with alpha set to
// `kImageOverlayAlpha`.
return gfx::Image(gfx::ImageSkiaOperations::CreateBlendedImage(
image.AsImageSkia(), mask, kImageOverlayAlpha));
}
void AutofillImageFetcherImpl::FetchImageForURL(
base::OnceCallback<void(std::unique_ptr<CreditCardArtImage>)>
barrier_callback,
const GURL& card_art_url) {
if (!card_art_url.is_valid()) {
OnCardArtImageFetched(std::move(barrier_callback), card_art_url,
absl::nullopt, gfx::Image(),
image_fetcher::RequestMetadata());
return;
}
GURL url;
// TODO(crbug.com/1313616): There is only one gstatic card art image we are
// using currently. Remove this logic and append FIFE URL suffix by default
// when the static image is deprecated.
// Check if the image is stored in Static Content Service. If not append the
// FIFE URL option to fetch the correct image.
if (card_art_url ==
GURL(
"https://www.gstatic.com/autofill/virtualcard/icon/capitalone.png")) {
url = card_art_url;
} else {
// A FIFE image fetching param suffix is appended to the URL. This means the
// image should be of Size(32, 20), and should be center cropped.
url = GURL(card_art_url.spec() + "=w32-h20-n");
}
image_fetcher::ImageFetcherParams params(kCardArtImageTrafficAnnotation,
kUmaClientName);
image_fetcher_->FetchImage(
url,
base::BindOnce(&AutofillImageFetcherImpl::OnCardArtImageFetched,
weak_ptr_factory_.GetWeakPtr(),
std::move(barrier_callback), card_art_url,
AutofillTickClock::NowTicks()),
std::move(params));
}
void AutofillImageFetcherImpl::InitializeImageFetcher() {
if (image_fetcher_)
return;
// Lazily initialize the `image_fetcher_`, since
// ImageFetcherServiceFactory relies on the initialization of the profile, and
// when AutofillImageFetcher is created, the initialization of the profile is
// not done yet.
image_fetcher::ImageFetcherService* image_fetcher_service =
ImageFetcherServiceFactory::GetForKey(key_);
if (!image_fetcher_service)
return;
// TODO(crbug.com/1382289): Fix and change the config back to kDiskCacheOnly.
image_fetcher_ = image_fetcher_service->GetImageFetcher(
image_fetcher::ImageFetcherConfig::kNetworkOnly);
}
} // namespace autofill