blob: f6d0733bf2e18e8446e321ed7c1b57b8c64ca5c4 [file] [log] [blame]
// Copyright 2023 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/renderer_host/navigation_transitions/navigation_entry_screenshot.h"
#include "content/browser/renderer_host/navigation_transitions/navigation_entry_screenshot_cache.h"
#include "content/browser/renderer_host/navigation_transitions/navigation_transition_config.h"
#if BUILDFLAG(IS_ANDROID)
#include "base/functional/callback.h"
#include "base/task/bind_post_task.h"
#include "base/task/thread_pool.h"
#include "ui/android/resources/ui_resource_provider.h"
#endif
namespace content {
#if BUILDFLAG(IS_ANDROID)
namespace {
BASE_FEATURE(kNavigationEntryScreenshotCompression,
"NavigationEntryScreenshotCompression",
base::FEATURE_ENABLED_BY_DEFAULT);
static bool g_disable_compression_for_testing = false;
using CompressionDoneCallback = base::OnceCallback<void(sk_sp<SkPixelRef>)>;
void CompressNavigationScreenshotOnWorkerThread(
SkBitmap bitmap,
bool supports_etc_non_power_of_two,
CompressionDoneCallback done_callback) {
TRACE_EVENT0("navigation", "CompressNavigationScreenshotOnWorkerThread");
if (auto compressed_bitmap = ui::UIResourceProvider::CompressBitmap(
bitmap, supports_etc_non_power_of_two)) {
std::move(done_callback).Run(std::move(compressed_bitmap));
}
}
} // namespace
#endif
// static
const void* const NavigationEntryScreenshot::kUserDataKey =
&NavigationEntryScreenshot::kUserDataKey;
// static
void NavigationEntryScreenshot::SetDisableCompressionForTesting(bool disable) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
#if BUILDFLAG(IS_ANDROID)
g_disable_compression_for_testing = disable;
#endif
}
NavigationEntryScreenshot::NavigationEntryScreenshot(
const SkBitmap& bitmap,
NavigationTransitionData::UniqueId unique_id,
bool supports_etc_non_power_of_two)
: bitmap_(cc::UIResourceBitmap(bitmap)),
unique_id_(unique_id),
dimensions_without_compression_(bitmap_->GetSize()) {
CHECK(NavigationTransitionConfig::AreBackForwardTransitionsEnabled());
DCHECK_CURRENTLY_ON(BrowserThread::UI);
StartCompression(bitmap, supports_etc_non_power_of_two);
}
NavigationEntryScreenshot::~NavigationEntryScreenshot() {
if (cache_) {
cache_->OnNavigationEntryGone(unique_id_);
}
}
cc::UIResourceBitmap NavigationEntryScreenshot::GetBitmap(cc::UIResourceId uid,
bool resource_lost) {
// TODO(liuwilliam): Currently none of the impls of `GetBitmap` uses `uid` or
// `resource_lost`. Consider deleting them from the interface.
return GetBitmap();
}
size_t NavigationEntryScreenshot::SetCache(
NavigationEntryScreenshotCache* cache) {
CHECK(!cache_ || !cache);
cache_ = cache;
if (cache_ && compressed_bitmap_) {
bitmap_.reset();
}
return GetBitmap().SizeInBytes();
}
SkBitmap NavigationEntryScreenshot::GetBitmapForTesting() const {
return GetBitmap().GetBitmapForTesting(); // IN-TEST
}
size_t NavigationEntryScreenshot::CompressedSizeForTesting() const {
return !bitmap_ ? compressed_bitmap_->SizeInBytes() : 0u;
}
void NavigationEntryScreenshot::StartCompression(
const SkBitmap& bitmap,
bool supports_etc_non_power_of_two) {
#if BUILDFLAG(IS_ANDROID)
if (!base::FeatureList::IsEnabled(kNavigationEntryScreenshotCompression) ||
g_disable_compression_for_testing) {
return;
}
CompressionDoneCallback done_callback = base::BindPostTask(
GetUIThreadTaskRunner(),
base::BindOnce(&NavigationEntryScreenshot::OnCompressionFinished,
weak_factory_.GetWeakPtr()));
base::ThreadPool::PostTask(
FROM_HERE,
{base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
base::BindOnce(&CompressNavigationScreenshotOnWorkerThread, bitmap,
supports_etc_non_power_of_two, std::move(done_callback)));
#endif
}
void NavigationEntryScreenshot::OnCompressionFinished(
sk_sp<SkPixelRef> compressed_bitmap) {
CHECK(!compressed_bitmap_);
CHECK(bitmap_);
CHECK(compressed_bitmap);
const auto size =
gfx::Size(compressed_bitmap->width(), compressed_bitmap->height());
compressed_bitmap_ = cc::UIResourceBitmap(std::move(compressed_bitmap), size);
TRACE_EVENT2("navigation", "NavigationEntryScreenshot::OnCompressionFinished",
"old_size", bitmap_->SizeInBytes(), "new_size",
compressed_bitmap_->SizeInBytes());
// We defer discarding the uncompressed bitmap if there is no cache since it
// may still be in use in the UI.
if (cache_) {
bitmap_.reset();
cache_->OnScreenshotCompressed(unique_id_, GetBitmap().SizeInBytes());
}
}
const cc::UIResourceBitmap& NavigationEntryScreenshot::GetBitmap() const {
return bitmap_ ? *bitmap_ : *compressed_bitmap_;
}
} // namespace content