blob: c8eebd25a10ea5bc73a3788a7b3f10930d8628b7 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LiICENSE file.
#include "third_party/blink/renderer/modules/background_fetch/background_fetch_icon_loader.h"
#include "base/time/time.h"
#include "third_party/blink/public/common/manifest/manifest_icon_selector.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/platform/web_size.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_image_resource.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/modules/background_fetch/background_fetch_bridge.h"
#include "third_party/blink/renderer/modules/manifest/image_resource_type_converters.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/text/string_impl.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/threading.h"
namespace blink {
namespace {
constexpr base::TimeDelta kIconFetchTimeout = base::TimeDelta::FromSeconds(30);
constexpr int kMinimumIconSizeInPx = 0;
} // namespace
BackgroundFetchIconLoader::BackgroundFetchIconLoader()
: threaded_icon_loader_(MakeGarbageCollected<ThreadedIconLoader>()) {}
void BackgroundFetchIconLoader::Start(
BackgroundFetchBridge* bridge,
ExecutionContext* execution_context,
HeapVector<Member<ManifestImageResource>> icons,
IconCallback icon_callback) {
DCHECK_GE(icons.size(), 1u);
DCHECK(bridge);
icons_ = std::move(icons);
bridge->GetIconDisplaySize(
WTF::Bind(&BackgroundFetchIconLoader::DidGetIconDisplaySizeIfSoLoadIcon,
WrapWeakPersistent(this), WrapWeakPersistent(execution_context),
std::move(icon_callback)));
}
void BackgroundFetchIconLoader::DidGetIconDisplaySizeIfSoLoadIcon(
ExecutionContext* execution_context,
IconCallback icon_callback,
const gfx::Size& icon_display_size_pixels) {
// If |icon_display_size_pixels| is empty then no image will be displayed by
// the UI powering Background Fetch. Bail out immediately.
if (icon_display_size_pixels.IsEmpty()) {
std::move(icon_callback)
.Run(SkBitmap(), -1 /* ideal_to_chosen_icon_size_times_hundred */);
return;
}
KURL best_icon_url = PickBestIconForDisplay(
execution_context, icon_display_size_pixels.height());
if (best_icon_url.IsEmpty()) {
// None of the icons provided was suitable.
std::move(icon_callback)
.Run(SkBitmap(), -1 /* ideal_to_chosen_icon_size_times_hundred */);
return;
}
icon_callback_ = std::move(icon_callback);
ResourceRequest resource_request(best_icon_url);
resource_request.SetRequestContext(mojom::blink::RequestContextType::IMAGE);
resource_request.SetRequestDestination(
network::mojom::RequestDestination::kImage);
resource_request.SetPriority(ResourceLoadPriority::kMedium);
resource_request.SetKeepalive(true);
resource_request.SetMode(network::mojom::RequestMode::kNoCors);
resource_request.SetCredentialsMode(
network::mojom::CredentialsMode::kInclude);
resource_request.SetSkipServiceWorker(true);
resource_request.SetTimeoutInterval(kIconFetchTimeout);
threaded_icon_loader_->Start(execution_context, resource_request,
icon_display_size_pixels,
WTF::Bind(&BackgroundFetchIconLoader::DidGetIcon,
WrapWeakPersistent(this)));
}
KURL BackgroundFetchIconLoader::PickBestIconForDisplay(
ExecutionContext* execution_context,
int ideal_size_pixels) {
WebVector<Manifest::ImageResource> icons;
for (auto& icon : icons_) {
// Update the src of |icon| to include the base URL in case relative paths
// were used.
icon->setSrc(execution_context->CompleteURL(icon->src()));
Manifest::ImageResource candidate_icon =
blink::ConvertManifestImageResource(icon);
// Provide default values for 'purpose' and 'sizes' if they are missing.
if (candidate_icon.sizes.empty())
candidate_icon.sizes.emplace_back(gfx::Size(0, 0));
if (candidate_icon.purpose.empty()) {
candidate_icon.purpose.emplace_back(
mojom::ManifestImageResource_Purpose::ANY);
}
icons.emplace_back(candidate_icon);
}
return KURL(ManifestIconSelector::FindBestMatchingSquareIcon(
icons.ReleaseVector(), ideal_size_pixels, kMinimumIconSizeInPx,
mojom::ManifestImageResource_Purpose::ANY));
}
void BackgroundFetchIconLoader::Stop() {
threaded_icon_loader_->Stop();
}
void BackgroundFetchIconLoader::DidGetIcon(SkBitmap icon, double resize_scale) {
if (icon.isNull()) {
std::move(icon_callback_).Run(icon, -1);
return;
}
int ideal_to_chosen_icon_size_times_hundred = std::round(resize_scale) * 100;
std::move(icon_callback_).Run(icon, ideal_to_chosen_icon_size_times_hundred);
}
void BackgroundFetchIconLoader::Trace(Visitor* visitor) const {
visitor->Trace(icons_);
visitor->Trace(threaded_icon_loader_);
}
} // namespace blink