blob: fb48c9f27017a6e87e1b2299eacd1fcf5163d347 [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/ui/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/payments/constants.h"
#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/image_fetcher/core/image_fetcher_service.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "url/gurl.h"
namespace autofill {
namespace {
// The image radius value for card art images.
constexpr int kCardArtImageRadius = 3; // 3dp
// The SkAlpha value for the image grey overlay.
constexpr double kImageOverlayAlpha = 0.04; // 4%
// The border color used for card art images.
constexpr SkColor kCardArtBorderColor = SkColorSetARGB(0xFF, 0xE3, 0xE3, 0xE3);
// The stroke width of the card art border.
constexpr int kCardArtBorderStrokeWidth = 2;
// The width and length card art is resized to.
constexpr int kCardArtImageWidth = 40;
constexpr int kCardArtImageHeight = 24;
// The width and length the new FOP display card art is resized to.
constexpr int kNewFopCardArtImageWidth = 48;
constexpr int kNewFopCardArtImageHeight = 30;
int CardArtImageWidth() {
return base::FeatureList::IsEnabled(
features::kAutofillEnableNewFopDisplayDesktop)
? kNewFopCardArtImageWidth
: kCardArtImageWidth;
}
int CardArtImageHeight() {
return base::FeatureList::IsEnabled(
features::kAutofillEnableNewFopDisplayDesktop)
? kNewFopCardArtImageHeight
: kCardArtImageHeight;
}
} // namespace
AutofillImageFetcherImpl::AutofillImageFetcherImpl(ProfileKey* key)
: key_(key) {}
AutofillImageFetcherImpl::~AutofillImageFetcherImpl() = default;
image_fetcher::ImageFetcher* AutofillImageFetcherImpl::GetImageFetcher() {
InitializeImageFetcher();
return image_fetcher_;
}
base::WeakPtr<AutofillImageFetcher> AutofillImageFetcherImpl::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
GURL AutofillImageFetcherImpl::ResolveImageURL(const GURL& image_url,
ImageType image_type) const {
switch (image_type) {
case ImageType::kCreditCardArtImage:
// TODO(crbug.com/40221039): There is only one gstatic card art image we
// are using currently, that returns as metadata when it isn't. Remove
// this logic when the static image is deprecated, and we send rich card
// art instead.
if (image_url.spec() == kCapitalOneCardArtUrl) {
return GURL(kCapitalOneLargeCardArtUrl);
}
// When kAutofillEnableNewCardArtAndNetworkImages is enabled, we take the
// image at height 48 with its ratio width and resize to Size(40, 24)
// later
return GURL(image_url.spec() + "=h48-pa");
case ImageType::kPixAccountImage:
// Pay with Pix is only queried in Chrome on Android.
NOTREACHED();
case ImageType::kValuableImage:
return GURL(image_url.spec() + "=h96-w96-cc-rp");
}
}
gfx::Image AutofillImageFetcherImpl::ResolveCardArtImage(
const GURL& card_art_url,
const gfx::Image& card_art_image) {
if (card_art_url == kCapitalOneLargeCardArtUrl) {
// Render Capital One asset directly. No need to calculate and add grey
// border to image.
return card_art_image;
}
// Create the outer rectangle. The outer rectangle is for the
// entire image which includes the card art and additional border.
gfx::RectF outer_rect = gfx::RectF(CardArtImageWidth(), CardArtImageHeight());
// The inner rectangle only includes the card art. To calculate the
// inner rectangle, we need to factor the space that the border stroke
// will take up.
gfx::RectF inner_rect = gfx::RectF(
/*x=*/kCardArtBorderStrokeWidth, /*y=*/kCardArtBorderStrokeWidth,
/*width=*/CardArtImageWidth() - (kCardArtBorderStrokeWidth * 2),
/*height=*/CardArtImageHeight() - (kCardArtBorderStrokeWidth * 2));
gfx::Canvas canvas =
gfx::Canvas(gfx::Size(CardArtImageWidth(), CardArtImageHeight()),
/*image_scale=*/1.0f, /*is_opaque=*/false);
cc::PaintFlags card_art_paint;
card_art_paint.setAntiAlias(true);
// Draw card art with rounded corners in the inner rectangle.
canvas.DrawRoundRect(inner_rect, kCardArtImageRadius, card_art_paint);
canvas.DrawImageInt(
gfx::ImageSkiaOperations::CreateResizedImage(
card_art_image.AsImageSkia(), skia::ImageOperations::RESIZE_BEST,
gfx::Size(CardArtImageWidth(), CardArtImageHeight())),
outer_rect.x(), outer_rect.y(), card_art_paint);
// Draw border around card art using outer rectangle.
card_art_paint.setStrokeWidth(kCardArtBorderStrokeWidth);
card_art_paint.setColor(kCardArtBorderColor);
card_art_paint.setStyle(cc::PaintFlags::kStroke_Style);
canvas.DrawRoundRect(outer_rect, kCardArtImageRadius, card_art_paint);
// Add radius around entire image.
return gfx::Image(gfx::ImageSkiaOperations::CreateImageWithRoundRectClip(
kCardArtImageRadius,
gfx::ImageSkia::CreateFromBitmap(canvas.GetBitmap(), 1.0f)));
}
gfx::Image AutofillImageFetcherImpl::ResolveValuableImage(
const gfx::Image& valuable_image) {
// Increase image scale from 1.0 to 4.0 to render higher quality images on
// high resolution displays. This decreases the image size from 96x96 to
// 24x24.
return gfx::Image(
gfx::ImageSkia::CreateFromBitmap(valuable_image.AsBitmap(), 4.0f));
}
// 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::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;
}
image_fetcher_ = image_fetcher_service->GetImageFetcher(
image_fetcher::ImageFetcherConfig::kDiskCacheOnly);
}
} // namespace autofill