summaryrefslogtreecommitdiff
path: root/chromium/components/paint_preview
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2021-09-03 13:32:17 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2021-10-01 14:31:55 +0200
commit21ba0c5d4bf8fba15dddd97cd693bad2358b77fd (patch)
tree91be119f694044dfc1ff9fdc054459e925de9df0 /chromium/components/paint_preview
parent03c549e0392f92c02536d3f86d5e1d8dfa3435ac (diff)
downloadqtwebengine-chromium-21ba0c5d4bf8fba15dddd97cd693bad2358b77fd.tar.gz
BASELINE: Update Chromium to 92.0.4515.166
Change-Id: I42a050486714e9e54fc271f2a8939223a02ae364
Diffstat (limited to 'chromium/components/paint_preview')
-rw-r--r--chromium/components/paint_preview/OWNERS3
-rw-r--r--chromium/components/paint_preview/browser/file_manager.cc16
-rw-r--r--chromium/components/paint_preview/browser/file_manager.h5
-rw-r--r--chromium/components/paint_preview/browser/paint_preview_base_service.cc4
-rw-r--r--chromium/components/paint_preview/browser/paint_preview_base_service.h22
-rw-r--r--chromium/components/paint_preview/browser/paint_preview_base_service_unittest.cc25
-rw-r--r--chromium/components/paint_preview/browser/paint_preview_client.cc11
-rw-r--r--chromium/components/paint_preview/browser/paint_preview_client.h11
-rw-r--r--chromium/components/paint_preview/browser/paint_preview_client_unittest.cc6
-rw-r--r--chromium/components/paint_preview/browser/paint_preview_compositor_client_impl.cc2
-rw-r--r--chromium/components/paint_preview/browser/paint_preview_compositor_client_impl.h6
-rw-r--r--chromium/components/paint_preview/browser/paint_preview_file_mixin.cc4
-rw-r--r--chromium/components/paint_preview/browser/paint_preview_file_mixin.h4
-rw-r--r--chromium/components/paint_preview/browser/test_paint_preview_policy.cc2
-rw-r--r--chromium/components/paint_preview/common/capture_result.h14
-rw-r--r--chromium/components/paint_preview/common/mojom/paint_preview_recorder.mojom12
-rw-r--r--chromium/components/paint_preview/common/paint_preview_tracker.cc2
-rw-r--r--chromium/components/paint_preview/common/paint_preview_tracker.h6
-rw-r--r--chromium/components/paint_preview/common/recording_map.h2
-rw-r--r--chromium/components/paint_preview/common/serial_utils.cc50
-rw-r--r--chromium/components/paint_preview/common/serial_utils.h12
-rw-r--r--chromium/components/paint_preview/common/serial_utils_unittest.cc4
-rw-r--r--chromium/components/paint_preview/common/serialized_recording.cc29
-rw-r--r--chromium/components/paint_preview/common/serialized_recording.h25
-rw-r--r--chromium/components/paint_preview/common/serialized_recording_unittest.cc91
-rw-r--r--chromium/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java6
-rw-r--r--chromium/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameCoordinatorTest.java4
-rw-r--r--chromium/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediatorTest.java4
-rw-r--r--chromium/components/paint_preview/player/android/player_compositor_delegate_android.cc3
-rw-r--r--chromium/components/paint_preview/player/bitmap_request.cc2
-rw-r--r--chromium/components/paint_preview/player/bitmap_request.h6
-rw-r--r--chromium/components/paint_preview/player/player_compositor_delegate.cc12
-rw-r--r--chromium/components/paint_preview/player/player_compositor_delegate.h4
-rw-r--r--chromium/components/paint_preview/player/player_compositor_delegate_unittest.cc8
-rw-r--r--chromium/components/paint_preview/public/paint_preview_compositor_client.h4
-rw-r--r--chromium/components/paint_preview/renderer/paint_preview_recorder_browsertest.cc78
-rw-r--r--chromium/components/paint_preview/renderer/paint_preview_recorder_impl.cc35
-rw-r--r--chromium/components/paint_preview/renderer/paint_preview_recorder_utils.cc85
-rw-r--r--chromium/components/paint_preview/renderer/paint_preview_recorder_utils.h14
-rw-r--r--chromium/components/paint_preview/renderer/paint_preview_recorder_utils_unittest.cc236
40 files changed, 635 insertions, 234 deletions
diff --git a/chromium/components/paint_preview/OWNERS b/chromium/components/paint_preview/OWNERS
index f14326f08eb..a56f4c78c0c 100644
--- a/chromium/components/paint_preview/OWNERS
+++ b/chromium/components/paint_preview/OWNERS
@@ -1,4 +1,3 @@
ckitagawa@chromium.org
-mahmoudi@chromium.org
-vollick@chromium.org
+fredmello@chromium.org
yfriedman@chromium.org
diff --git a/chromium/components/paint_preview/browser/file_manager.cc b/chromium/components/paint_preview/browser/file_manager.cc
index 1d84ee21d11..4a84cdafb39 100644
--- a/chromium/components/paint_preview/browser/file_manager.cc
+++ b/chromium/components/paint_preview/browser/file_manager.cc
@@ -63,16 +63,16 @@ size_t FileManager::GetSizeOfArtifacts(const DirectoryKey& key) const {
}
}
-base::Optional<base::File::Info> FileManager::GetInfo(
+absl::optional<base::File::Info> FileManager::GetInfo(
const DirectoryKey& key) const {
DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
base::FilePath path;
StorageType storage_type = GetPathForKey(key, &path);
if (storage_type == FileManager::StorageType::kNone)
- return base::nullopt;
+ return absl::nullopt;
base::File::Info info;
if (!base::GetFileInfo(path, &info))
- return base::nullopt;
+ return absl::nullopt;
return info;
}
@@ -101,7 +101,7 @@ bool FileManager::CaptureExists(const DirectoryKey& key) const {
}
}
-base::Optional<base::FilePath> FileManager::CreateOrGetDirectory(
+absl::optional<base::FilePath> FileManager::CreateOrGetDirectory(
const DirectoryKey& key,
bool clear) const {
DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
@@ -119,7 +119,7 @@ base::Optional<base::FilePath> FileManager::CreateOrGetDirectory(
}
DVLOG(1) << "ERROR: failed to create directory: " << path
<< " with error code " << error;
- return base::nullopt;
+ return absl::nullopt;
}
case kDirectory:
return path;
@@ -129,17 +129,17 @@ base::Optional<base::FilePath> FileManager::CreateOrGetDirectory(
if (!base::CreateDirectoryAndGetError(dst_path, &error)) {
DVLOG(1) << "ERROR: failed to create directory: " << path
<< " with error code " << error;
- return base::nullopt;
+ return absl::nullopt;
}
if (!zip::Unzip(path, dst_path)) {
DVLOG(1) << "ERROR: failed to unzip: " << path << " to " << dst_path;
- return base::nullopt;
+ return absl::nullopt;
}
base::DeletePathRecursively(path);
return dst_path;
}
default:
- return base::nullopt;
+ return absl::nullopt;
}
}
diff --git a/chromium/components/paint_preview/browser/file_manager.h b/chromium/components/paint_preview/browser/file_manager.h
index 5fa5c55761e..67a0c6dec2e 100644
--- a/chromium/components/paint_preview/browser/file_manager.h
+++ b/chromium/components/paint_preview/browser/file_manager.h
@@ -10,7 +10,6 @@
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
-#include "base/time/time.h"
#include "components/paint_preview/browser/directory_key.h"
#include "components/paint_preview/common/proto/paint_preview.pb.h"
#include "url/gurl.h"
@@ -52,7 +51,7 @@ class FileManager : public base::RefCountedThreadSafe<FileManager> {
// Get statistics about the time of creation and size of artifacts.
size_t GetSizeOfArtifacts(const DirectoryKey& key) const;
- base::Optional<base::File::Info> GetInfo(const DirectoryKey& key) const;
+ absl::optional<base::File::Info> GetInfo(const DirectoryKey& key) const;
// Returns the total disk usage of all paint previews.
size_t GetTotalDiskUsage() const;
@@ -68,7 +67,7 @@ class FileManager : public base::RefCountedThreadSafe<FileManager> {
// assigns it to |directory|. The directory will be wiped if |clear| is true.
// Returns a path on success or nullopt on failure. If the directory was
// compressed then it will be uncompressed automatically.
- base::Optional<base::FilePath> CreateOrGetDirectory(const DirectoryKey& key,
+ absl::optional<base::FilePath> CreateOrGetDirectory(const DirectoryKey& key,
bool clear) const;
// Compresses the directory associated with |key|. Returns true on success or
diff --git a/chromium/components/paint_preview/browser/paint_preview_base_service.cc b/chromium/components/paint_preview/browser/paint_preview_base_service.cc
index 3181d624f78..9d12df92980 100644
--- a/chromium/components/paint_preview/browser/paint_preview_base_service.cc
+++ b/chromium/components/paint_preview/browser/paint_preview_base_service.cc
@@ -60,6 +60,10 @@ void PaintPreviewBaseService::CapturePaintPreview(CaptureParams capture_params,
(render_frame_host == web_contents->GetMainFrame());
params.inner.capture_links = capture_params.capture_links;
params.inner.max_capture_size = capture_params.max_per_capture_size;
+ params.inner.max_decoded_image_size_bytes =
+ capture_params.max_decoded_image_size_bytes;
+ params.inner.skip_accelerated_content =
+ capture_params.skip_accelerated_content;
// TODO(crbug/1064253): Consider moving to client so that this always happens.
// Although, it is harder to get this right in the client due to its
diff --git a/chromium/components/paint_preview/browser/paint_preview_base_service.h b/chromium/components/paint_preview/browser/paint_preview_base_service.h
index 84818fab236..2d742add21d 100644
--- a/chromium/components/paint_preview/browser/paint_preview_base_service.h
+++ b/chromium/components/paint_preview/browser/paint_preview_base_service.h
@@ -11,7 +11,6 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "base/optional.h"
#include "base/sequenced_task_runner.h"
#include "base/time/time.h"
#include "base/unguessable_token.h"
@@ -24,6 +23,7 @@
#include "components/paint_preview/common/proto/paint_preview.pb.h"
#include "components/paint_preview/common/serialized_recording.h"
#include "content/public/browser/web_contents.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace paint_preview {
@@ -85,6 +85,22 @@ class PaintPreviewBaseService : public KeyedService {
// Cap the perframe SkPicture size to |max_per_capture_size| if non-zero.
size_t max_per_capture_size;
+
+ // Limit on the maximum size of a decoded image that can be serialized.
+ // Any images with a decoded size exceeding this value will be discarded.
+ // This can be used to reduce the chance of an OOM during serialization and
+ // later during playback.
+ uint64_t max_decoded_image_size_bytes{std::numeric_limits<uint64_t>::max()};
+
+ // This flag will skip GPU accelerated content where applicable when
+ // capturing. This reduces hangs, capture time and may also reduce OOM
+ // crashes, but results in a lower fideltiy capture (i.e. the contents
+ // captured may not accurately reflect the content visible to the user at
+ // time of capture).
+ //
+ // At present this flag:
+ // - Shows a poster or blank space instead of live video frames.
+ bool skip_accelerated_content{false};
};
using OnCapturedCallback =
@@ -132,8 +148,8 @@ class PaintPreviewBaseService : public KeyedService {
mojom::PaintPreviewStatus status,
std::unique_ptr<CaptureResult> result);
- std::unique_ptr<PaintPreviewFileMixin> file_mixin_ = nullptr;
- std::unique_ptr<PaintPreviewPolicy> policy_ = nullptr;
+ std::unique_ptr<PaintPreviewFileMixin> file_mixin_;
+ std::unique_ptr<PaintPreviewPolicy> policy_;
bool is_off_the_record_;
base::WeakPtrFactory<PaintPreviewBaseService> weak_ptr_factory_{this};
diff --git a/chromium/components/paint_preview/browser/paint_preview_base_service_unittest.cc b/chromium/components/paint_preview/browser/paint_preview_base_service_unittest.cc
index 002447566c7..dcbde0b22ed 100644
--- a/chromium/components/paint_preview/browser/paint_preview_base_service_unittest.cc
+++ b/chromium/components/paint_preview/browser/paint_preview_base_service_unittest.cc
@@ -64,7 +64,7 @@ base::FilePath CreateDir(scoped_refptr<FileManager> manager,
base::BindOnce(&FileManager::CreateOrGetDirectory, manager, key, false),
base::BindOnce(
[](base::OnceClosure quit, base::FilePath* out,
- const base::Optional<base::FilePath>& path) {
+ const absl::optional<base::FilePath>& path) {
EXPECT_TRUE(path.has_value());
EXPECT_FALSE(path->empty());
*out = path.value();
@@ -178,7 +178,8 @@ class PaintPreviewBaseServiceTest
RecordingPersistence persistence,
gfx::Rect clip_rect,
bool capture_links,
- size_t max_per_capture_size) {
+ size_t max_per_capture_size,
+ uint64_t max_decoded_image_size_bytes) {
PaintPreviewBaseService::CaptureParams capture_params;
capture_params.web_contents = web_contents;
capture_params.root_dir = root_dir;
@@ -186,12 +187,13 @@ class PaintPreviewBaseServiceTest
capture_params.clip_rect = clip_rect;
capture_params.capture_links = capture_links;
capture_params.max_per_capture_size = max_per_capture_size;
+ capture_params.max_decoded_image_size_bytes = max_decoded_image_size_bytes;
return capture_params;
}
private:
- std::unique_ptr<SimpleFactoryKey> key_ = nullptr;
- std::unique_ptr<SimpleFactoryKey> rejection_policy_key_ = nullptr;
+ std::unique_ptr<SimpleFactoryKey> key_;
+ std::unique_ptr<SimpleFactoryKey> rejection_policy_key_;
};
TEST_P(PaintPreviewBaseServiceTest, CaptureMainFrame) {
@@ -200,9 +202,10 @@ TEST_P(PaintPreviewBaseServiceTest, CaptureMainFrame) {
params->clip_rect = gfx::Rect(0, 0, 0, 0);
params->is_main_frame = true;
params->max_capture_size = 50;
+ params->max_decoded_image_size_bytes = 1000;
recorder.SetExpectedParams(std::move(params));
auto response = mojom::PaintPreviewCaptureResponse::New();
- response->embedding_token = base::nullopt;
+ response->embedding_token = absl::nullopt;
if (GetParam() == RecordingPersistence::kMemoryBuffer) {
response->skp.emplace(mojo_base::BigBuffer());
}
@@ -218,7 +221,7 @@ TEST_P(PaintPreviewBaseServiceTest, CaptureMainFrame) {
base::RunLoop loop;
service->CapturePaintPreview(
CreateCaptureParams(web_contents(), &path, GetParam(),
- gfx::Rect(0, 0, 0, 0), true, 50),
+ gfx::Rect(0, 0, 0, 0), true, 50, 1000),
base::BindOnce(
[](base::OnceClosure quit_closure,
PaintPreviewBaseService::CaptureStatus expected_status,
@@ -273,7 +276,7 @@ TEST_P(PaintPreviewBaseServiceTest, CaptureFailed) {
params->max_capture_size = 0;
recorder.SetExpectedParams(std::move(params));
auto response = mojom::PaintPreviewCaptureResponse::New();
- response->embedding_token = base::nullopt;
+ response->embedding_token = absl::nullopt;
recorder.SetResponse(mojom::PaintPreviewStatus::kFailed, std::move(response));
OverrideInterface(&recorder);
@@ -286,7 +289,8 @@ TEST_P(PaintPreviewBaseServiceTest, CaptureFailed) {
base::RunLoop loop;
service->CapturePaintPreview(
CreateCaptureParams(web_contents(), &path, GetParam(),
- gfx::Rect(0, 0, 0, 0), true, 0),
+ gfx::Rect(0, 0, 0, 0), true, 0,
+ std::numeric_limits<uint64_t>::max()),
base::BindOnce(
[](base::OnceClosure quit_closure,
PaintPreviewBaseService::CaptureStatus expected_status,
@@ -309,7 +313,7 @@ TEST_P(PaintPreviewBaseServiceTest, CaptureDisallowed) {
params->max_capture_size = 0;
recorder.SetExpectedParams(std::move(params));
auto response = mojom::PaintPreviewCaptureResponse::New();
- response->embedding_token = base::nullopt;
+ response->embedding_token = absl::nullopt;
recorder.SetResponse(mojom::PaintPreviewStatus::kFailed, std::move(response));
OverrideInterface(&recorder);
@@ -322,7 +326,8 @@ TEST_P(PaintPreviewBaseServiceTest, CaptureDisallowed) {
base::RunLoop loop;
service->CapturePaintPreview(
CreateCaptureParams(web_contents(), &path, GetParam(),
- gfx::Rect(0, 0, 0, 0), true, 0),
+ gfx::Rect(0, 0, 0, 0), true, 0,
+ std::numeric_limits<uint64_t>::max()),
base::BindOnce(
[](base::OnceClosure quit_closure,
PaintPreviewBaseService::CaptureStatus expected_status,
diff --git a/chromium/components/paint_preview/browser/paint_preview_client.cc b/chromium/components/paint_preview/browser/paint_preview_client.cc
index d51d2ae76a3..7232b9be21b 100644
--- a/chromium/components/paint_preview/browser/paint_preview_client.cc
+++ b/chromium/components/paint_preview/browser/paint_preview_client.cc
@@ -15,6 +15,7 @@
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
#include "base/threading/scoped_blocking_call.h"
+#include "base/trace_event/trace_event.h"
#include "base/unguessable_token.h"
#include "components/paint_preview/common/capture_result.h"
#include "components/paint_preview/common/mojom/paint_preview_recorder.mojom-forward.h"
@@ -117,8 +118,12 @@ mojom::PaintPreviewCaptureParamsPtr CreateRecordingRequestParams(
// when clip_rects are used intentionally to limit capture time.
mojo_params->clip_rect_is_hint = true;
mojo_params->is_main_frame = capture_params.is_main_frame;
+ mojo_params->skip_accelerated_content =
+ capture_params.skip_accelerated_content;
mojo_params->file = std::move(file);
mojo_params->max_capture_size = capture_params.max_capture_size;
+ mojo_params->max_decoded_image_size_bytes =
+ capture_params.max_decoded_image_size_bytes;
return mojo_params;
}
@@ -313,6 +318,10 @@ void PaintPreviewClient::CapturePaintPreview(
document_data.accepted_tokens = CreateAcceptedTokenList(render_frame_host);
document_data.capture_links = params.inner.capture_links;
document_data.max_per_capture_size = params.inner.max_capture_size;
+ document_data.max_decoded_image_size_bytes =
+ params.inner.max_decoded_image_size_bytes;
+ document_data.skip_accelerated_content =
+ params.inner.skip_accelerated_content;
all_document_data_.insert(
{params.inner.document_guid, std::move(document_data)});
TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
@@ -337,6 +346,8 @@ void PaintPreviewClient::CaptureSubframePaintPreview(
params.is_main_frame = false;
params.capture_links = it->second.capture_links;
params.max_capture_size = it->second.max_per_capture_size;
+ params.max_decoded_image_size_bytes = it->second.max_decoded_image_size_bytes;
+ params.skip_accelerated_content = it->second.skip_accelerated_content;
CapturePaintPreviewInternal(params, render_subframe_host);
}
diff --git a/chromium/components/paint_preview/browser/paint_preview_client.h b/chromium/components/paint_preview/browser/paint_preview_client.h
index 1b3537afcc5..7d7e2559ccf 100644
--- a/chromium/components/paint_preview/browser/paint_preview_client.h
+++ b/chromium/components/paint_preview/browser/paint_preview_client.h
@@ -103,10 +103,11 @@ class PaintPreviewClient
// This corresponds to RenderFrameHost::EmbeddingToken.
base::UnguessableToken root_frame_token;
- // Got from the first recording params. Whether to capture links and the
+ // From the first recording params. Whether to capture links and the
// size limit per capture respectively.
bool capture_links = true;
size_t max_per_capture_size = 0;
+ uint64_t max_decoded_image_size_bytes{std::numeric_limits<uint64_t>::max()};
// UKM Source ID of the WebContent.
ukm::SourceId source_id;
@@ -143,6 +144,14 @@ class PaintPreviewClient
// destruction
bool should_clean_up_files = false;
+ // This flag will skip GPU accelerated content where applicable when
+ // capturing. This reduces hangs, capture time and may also reduce OOM
+ // crashes, but results in a lower fideltiy capture (i.e. the contents
+ // captured may not accurately reflect the content visible to the user at
+ // time of capture). See PaintPreviewBaseService::CaptureParams for a
+ // description of the effects of this flag.
+ bool skip_accelerated_content = false;
+
// Generates a file path based off |root_dir| and |frame_guid|. Will be in
// the form "{hexadecimal}.skp".
base::FilePath FilePathForFrame(const base::UnguessableToken& frame_guid);
diff --git a/chromium/components/paint_preview/browser/paint_preview_client_unittest.cc b/chromium/components/paint_preview/browser/paint_preview_client_unittest.cc
index 8718a99d4e9..47c17055719 100644
--- a/chromium/components/paint_preview/browser/paint_preview_client_unittest.cc
+++ b/chromium/components/paint_preview/browser/paint_preview_client_unittest.cc
@@ -104,6 +104,7 @@ mojom::PaintPreviewCaptureParamsPtr ToMojoParams(
params_ptr->guid = params.inner.document_guid;
params_ptr->is_main_frame = params.inner.is_main_frame;
params_ptr->clip_rect = params.inner.clip_rect;
+ params_ptr->skip_accelerated_content = params.inner.skip_accelerated_content;
return params_ptr;
}
@@ -161,7 +162,7 @@ TEST_P(PaintPreviewClientRenderViewHostTest, CaptureMainFrameMock) {
GURL expected_url = rfh->GetLastCommittedURL();
auto response = NewMockPaintPreviewCaptureResponse();
- response->embedding_token = base::nullopt;
+ response->embedding_token = absl::nullopt;
response->scroll_offsets = gfx::Size(5, 10);
PaintPreviewProto expected_proto;
@@ -290,11 +291,12 @@ TEST_P(PaintPreviewClientRenderViewHostTest, RenderFrameDeletedDuringCapture) {
PaintPreviewClient::PaintPreviewParams params(GetParam());
params.root_dir = temp_dir_.GetPath();
params.inner.is_main_frame = true;
+ params.inner.skip_accelerated_content = true;
content::RenderFrameHost* rfh = main_rfh();
auto response = NewMockPaintPreviewCaptureResponse();
- response->embedding_token = base::nullopt;
+ response->embedding_token = absl::nullopt;
base::RunLoop loop;
auto callback = base::BindOnce(
diff --git a/chromium/components/paint_preview/browser/paint_preview_compositor_client_impl.cc b/chromium/components/paint_preview/browser/paint_preview_compositor_client_impl.cc
index a4a008015ff..271386c74a2 100644
--- a/chromium/components/paint_preview/browser/paint_preview_compositor_client_impl.cc
+++ b/chromium/components/paint_preview/browser/paint_preview_compositor_client_impl.cc
@@ -25,7 +25,7 @@ PaintPreviewCompositorClientImpl::~PaintPreviewCompositorClientImpl() {
NotifyServiceOfInvalidation();
}
-const base::Optional<base::UnguessableToken>&
+const absl::optional<base::UnguessableToken>&
PaintPreviewCompositorClientImpl::Token() const {
DCHECK(default_task_runner_->RunsTasksInCurrentSequence());
return token_;
diff --git a/chromium/components/paint_preview/browser/paint_preview_compositor_client_impl.h b/chromium/components/paint_preview/browser/paint_preview_compositor_client_impl.h
index b8ec2b510db..4cf62e155df 100644
--- a/chromium/components/paint_preview/browser/paint_preview_compositor_client_impl.h
+++ b/chromium/components/paint_preview/browser/paint_preview_compositor_client_impl.h
@@ -6,12 +6,12 @@
#define COMPONENTS_PAINT_PREVIEW_BROWSER_PAINT_PREVIEW_COMPOSITOR_CLIENT_IMPL_H_
#include "base/callback_forward.h"
-#include "base/optional.h"
#include "base/unguessable_token.h"
#include "components/paint_preview/browser/paint_preview_compositor_service_impl.h"
#include "components/paint_preview/public/paint_preview_compositor_client.h"
#include "components/services/paint_preview_compositor/public/mojom/paint_preview_compositor.mojom.h"
#include "mojo/public/cpp/bindings/remote.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/geometry/rect.h"
#include "url/gurl.h"
@@ -36,7 +36,7 @@ class PaintPreviewCompositorClientImpl : public PaintPreviewCompositorClient {
~PaintPreviewCompositorClientImpl() override;
// PaintPreviewCompositorClient implementation.
- const base::Optional<base::UnguessableToken>& Token() const override;
+ const absl::optional<base::UnguessableToken>& Token() const override;
void SetDisconnectHandler(base::OnceClosure closure) override;
void BeginSeparatedFrameComposite(
mojom::PaintPreviewBeginCompositeRequestPtr request,
@@ -89,7 +89,7 @@ class PaintPreviewCompositorClientImpl : public PaintPreviewCompositorClient {
base::WeakPtr<PaintPreviewCompositorServiceImpl> service_;
CompositorPtr compositor_;
- base::Optional<base::UnguessableToken> token_;
+ absl::optional<base::UnguessableToken> token_;
base::OnceClosure user_disconnect_closure_;
base::WeakPtrFactory<PaintPreviewCompositorClientImpl> weak_ptr_factory_{
diff --git a/chromium/components/paint_preview/browser/paint_preview_file_mixin.cc b/chromium/components/paint_preview/browser/paint_preview_file_mixin.cc
index 3ad349dc92f..54ad65f5bd9 100644
--- a/chromium/components/paint_preview/browser/paint_preview_file_mixin.cc
+++ b/chromium/components/paint_preview/browser/paint_preview_file_mixin.cc
@@ -35,13 +35,13 @@ PaintPreviewFileMixin::~PaintPreviewFileMixin() = default;
void PaintPreviewFileMixin::GetCapturedPaintPreviewProto(
const DirectoryKey& key,
- base::Optional<base::TimeDelta> expiry_horizon,
+ absl::optional<base::TimeDelta> expiry_horizon,
OnReadProtoCallback on_read_proto_callback) {
task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(
[](scoped_refptr<FileManager> file_manager, const DirectoryKey& key,
- base::Optional<base::TimeDelta> expiry_horizon)
+ absl::optional<base::TimeDelta> expiry_horizon)
-> std::pair<PaintPreviewFileMixin::ProtoReadStatus,
std::unique_ptr<PaintPreviewProto>> {
if (expiry_horizon.has_value()) {
diff --git a/chromium/components/paint_preview/browser/paint_preview_file_mixin.h b/chromium/components/paint_preview/browser/paint_preview_file_mixin.h
index 0af1317ccd7..5a5b6fd14e0 100644
--- a/chromium/components/paint_preview/browser/paint_preview_file_mixin.h
+++ b/chromium/components/paint_preview/browser/paint_preview_file_mixin.h
@@ -57,7 +57,7 @@ class PaintPreviewFileMixin {
// will return the kExpired status.
virtual void GetCapturedPaintPreviewProto(
const DirectoryKey& key,
- base::Optional<base::TimeDelta> expiry_horizon,
+ absl::optional<base::TimeDelta> expiry_horizon,
OnReadProtoCallback on_read_proto_callback);
// Writes an Accessibility Tree snapshot to the directory listed in key.
@@ -76,4 +76,4 @@ class PaintPreviewFileMixin {
} // namespace paint_preview
-#endif // COMPONENTS_PAINT_PREVIEW_BROWSER_PAINT_PREVIEW_FILE_HELPER_H_
+#endif // COMPONENTS_PAINT_PREVIEW_BROWSER_PAINT_PREVIEW_FILE_MIXIN_H_
diff --git a/chromium/components/paint_preview/browser/test_paint_preview_policy.cc b/chromium/components/paint_preview/browser/test_paint_preview_policy.cc
index 986582ff6a7..8f29dab029c 100644
--- a/chromium/components/paint_preview/browser/test_paint_preview_policy.cc
+++ b/chromium/components/paint_preview/browser/test_paint_preview_policy.cc
@@ -5,9 +5,9 @@
#include "components/paint_preview/browser/test_paint_preview_policy.h"
#include "base/callback.h"
-#include "base/optional.h"
#include "components/paint_preview/browser/paint_preview_policy.h"
#include "content/public/browser/web_contents.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace paint_preview {
diff --git a/chromium/components/paint_preview/common/capture_result.h b/chromium/components/paint_preview/common/capture_result.h
index 8cebc54aa3d..0ccdaa014fd 100644
--- a/chromium/components/paint_preview/common/capture_result.h
+++ b/chromium/components/paint_preview/common/capture_result.h
@@ -41,6 +41,20 @@ struct RecordingParams {
// async ordering of captures from different frames making it hard to keep
// track of available headroom at the time of each capture triggering.
size_t max_capture_size;
+
+ // Limit on the maximum size of a decoded image that can be serialized.
+ // Any images with a decoded size exceeding this value will be discarded.
+ // This can be used to reduce the chance of an OOM during serialization and
+ // later during playback.
+ uint64_t max_decoded_image_size_bytes{std::numeric_limits<uint64_t>::max()};
+
+ // This flag will skip GPU accelerated content where applicable when
+ // capturing. This reduces hangs, capture time and may also reduce OOM
+ // crashes, but results in a lower fideltiy capture (i.e. the contents
+ // captured may not accurately reflect the content visible to the user at
+ // time of capture). See PaintPreviewBaseService::CaptureParams for a
+ // description of the effects of this flag.
+ bool skip_accelerated_content{false};
};
// The result of a capture of a WebContents, which may contain recordings of
diff --git a/chromium/components/paint_preview/common/mojom/paint_preview_recorder.mojom b/chromium/components/paint_preview/common/mojom/paint_preview_recorder.mojom
index 5779f87ecc3..e7f214e41b7 100644
--- a/chromium/components/paint_preview/common/mojom/paint_preview_recorder.mojom
+++ b/chromium/components/paint_preview/common/mojom/paint_preview_recorder.mojom
@@ -70,6 +70,18 @@ struct PaintPreviewCaptureParams {
// The maximum allowed size of a capture that can be produced. A value of
// 0 means the size is unrestricted.
uint64 max_capture_size;
+
+ // Limit on the maximum size of a decoded image that can be serialized.
+ // Any images with a decoded size exceeding this value will be discarded.
+ uint64 max_decoded_image_size_bytes;
+
+ // This flag will skip GPU accelerated content where applicable when
+ // capturing. This reduces hangs, capture time and may also reduce OOM
+ // crashes, but results in a lower fideltiy capture (i.e. the contents
+ // captured may not accurately reflect the content visible to the user at
+ // time of capture). See PaintPreviewBaseService::CaptureParams for a
+ // description of the effects of this flag.
+ bool skip_accelerated_content;
};
struct LinkData {
diff --git a/chromium/components/paint_preview/common/paint_preview_tracker.cc b/chromium/components/paint_preview/common/paint_preview_tracker.cc
index 4d87b57912c..280a5a24507 100644
--- a/chromium/components/paint_preview/common/paint_preview_tracker.cc
+++ b/chromium/components/paint_preview/common/paint_preview_tracker.cc
@@ -40,7 +40,7 @@ bool ShouldUseDenseGlyphUsage(SkTypeface* typeface) {
PaintPreviewTracker::PaintPreviewTracker(
const base::UnguessableToken& guid,
- const base::Optional<base::UnguessableToken>& embedding_token,
+ const absl::optional<base::UnguessableToken>& embedding_token,
bool is_main_frame)
: guid_(guid),
embedding_token_(embedding_token),
diff --git a/chromium/components/paint_preview/common/paint_preview_tracker.h b/chromium/components/paint_preview/common/paint_preview_tracker.h
index 2d3f5fcce5f..8bbe21454e7 100644
--- a/chromium/components/paint_preview/common/paint_preview_tracker.h
+++ b/chromium/components/paint_preview/common/paint_preview_tracker.h
@@ -29,14 +29,14 @@ class PaintPreviewTracker {
public:
PaintPreviewTracker(
const base::UnguessableToken& guid,
- const base::Optional<base::UnguessableToken>& embedding_token,
+ const absl::optional<base::UnguessableToken>& embedding_token,
bool is_main_frame);
~PaintPreviewTracker();
// Getters ------------------------------------------------------------------
const base::UnguessableToken& Guid() const { return guid_; }
- const base::Optional<base::UnguessableToken>& EmbeddingToken() const {
+ const absl::optional<base::UnguessableToken>& EmbeddingToken() const {
return embedding_token_;
}
bool IsMainFrame() const { return is_main_frame_; }
@@ -109,7 +109,7 @@ class PaintPreviewTracker {
private:
const base::UnguessableToken guid_;
- const base::Optional<base::UnguessableToken> embedding_token_;
+ const absl::optional<base::UnguessableToken> embedding_token_;
const bool is_main_frame_;
// TODO(crbug.com/1155544): Change this to an SkM44.
diff --git a/chromium/components/paint_preview/common/recording_map.h b/chromium/components/paint_preview/common/recording_map.h
index 9deeff43b20..597de94aa60 100644
--- a/chromium/components/paint_preview/common/recording_map.h
+++ b/chromium/components/paint_preview/common/recording_map.h
@@ -9,11 +9,11 @@
#include "base/containers/flat_map.h"
#include "base/files/file.h"
-#include "base/optional.h"
#include "components/paint_preview/common/capture_result.h"
#include "components/paint_preview/common/proto/paint_preview.pb.h"
#include "components/paint_preview/common/serialized_recording.h"
#include "mojo/public/cpp/base/big_buffer.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkRefCnt.h"
diff --git a/chromium/components/paint_preview/common/serial_utils.cc b/chromium/components/paint_preview/common/serial_utils.cc
index bee4ffe8e72..901419004da 100644
--- a/chromium/components/paint_preview/common/serial_utils.cc
+++ b/chromium/components/paint_preview/common/serial_utils.cc
@@ -76,40 +76,47 @@ sk_sp<SkData> SerializeTypeface(SkTypeface* typeface, void* ctx) {
sk_sp<SkData> SerializeImage(SkImage* image, void* ctx) {
ImageSerializationContext* context =
reinterpret_cast<ImageSerializationContext*>(ctx);
+ // Ignore texture backed content if any slipped through. This shouldn't occur
+ // now that ToSkPicture has a dedicated ImageProvider that forces software
+ // SkImage inputs, but this is a safeguard.
if (context->skip_texture_backed && image->isTextureBacked()) {
return SkData::MakeEmpty();
}
+ // If the decoded form of the image would result in it exceeding the allowable
+ // size then effectively delete it by providing no data.
const SkImageInfo& image_info = image->imageInfo();
- // If decoding/encoding the image would result in it exceeding the allowable
- // size, effectively delete it by providing no data.
- if (context->max_representation_size != 0 &&
- image_info.computeMinByteSize() > context->max_representation_size) {
+ if (context->max_decoded_image_size_bytes !=
+ std::numeric_limits<uint64_t>::max() &&
+ image_info.computeMinByteSize() > context->max_decoded_image_size_bytes) {
return SkData::MakeEmpty();
}
// If there already exists encoded data use it directly.
sk_sp<SkData> encoded_data = image->refEncodedData();
if (!encoded_data) {
+ // Use the default PNG at quality 100 as it is safe.
+ // TODO(crbug/1198304): Investigate supporting JPEG at quality 100 for
+ // opaque images.
encoded_data = image->encodeToData();
}
- // If encoding failed then no-op.
if (!encoded_data)
return SkData::MakeEmpty();
- // Ensure the encoded data fits in the restrictions if they are present.
- if ((context->remaining_image_size == std::numeric_limits<uint64_t>::max() ||
- context->remaining_image_size >= encoded_data->size()) &&
- (context->max_representation_size == 0 ||
- encoded_data->size() < context->max_representation_size)) {
- if (context->remaining_image_size != std::numeric_limits<uint64_t>::max())
- context->remaining_image_size -= encoded_data->size();
-
- return encoded_data;
+ // Ensure the encoded data fits in the size restriction if present.
+ // OOM Prevention: This avoids creating/keeping large serialized images
+ // in-memory during serialization if the size budget is already exceeded due
+ // to images.
+ if (context->remaining_image_size != std::numeric_limits<uint64_t>::max()) {
+ if (context->remaining_image_size < encoded_data->size()) {
+ context->memory_budget_exceeded = true;
+ return SkData::MakeEmpty();
+ }
+ context->remaining_image_size -= encoded_data->size();
}
- return SkData::MakeEmpty();
+ return encoded_data;
}
// Deserializes a clip rect for a subframe within the main SkPicture. These
@@ -207,10 +214,15 @@ SkSerialProcs MakeSerialProcs(PictureSerializationContext* picture_ctx,
//
// At present this uses the native representation, but skips serializing if
// loading to a bitmap for encoding might cause an OOM.
- if (image_ctx->max_representation_size > 0 ||
- image_ctx->remaining_image_size != std::numeric_limits<uint64_t>::max()) {
- procs.fImageProc = SerializeImage;
- procs.fImageCtx = image_ctx;
+ if (image_ctx) {
+ image_ctx->memory_budget_exceeded = false;
+ if (image_ctx->max_decoded_image_size_bytes !=
+ std::numeric_limits<uint64_t>::max() ||
+ image_ctx->remaining_image_size !=
+ std::numeric_limits<uint64_t>::max()) {
+ procs.fImageProc = SerializeImage;
+ procs.fImageCtx = image_ctx;
+ }
}
return procs;
}
diff --git a/chromium/components/paint_preview/common/serial_utils.h b/chromium/components/paint_preview/common/serial_utils.h
index 01608911e19..645d86f330b 100644
--- a/chromium/components/paint_preview/common/serial_utils.h
+++ b/chromium/components/paint_preview/common/serial_utils.h
@@ -57,15 +57,17 @@ struct ImageSerializationContext {
// max value of uint64_t.
uint64_t remaining_image_size{std::numeric_limits<uint64_t>::max()};
- // The maximum size of the representation for serialization. Images
- // that are larger than this when encoded or will need to be inflated to a
- // bitmap larger than this are skipped to avoid OOMs. If this value is 0 image
- // procs are skipped and the default behavior is used.
- uint64_t max_representation_size{0};
+ // The maximum size of a decoded image allowed for serialization. Images that
+ // are larger than this when decoded are skipped.
+ uint64_t max_decoded_image_size_bytes{std::numeric_limits<uint64_t>::max()};
// Skip texture backed images. Must be true if serialized off the main
// thread.
bool skip_texture_backed{false};
+
+ // Will be set to true post serialization if the `remaining_image_size` budget
+ // was exceeded.
+ bool memory_budget_exceeded{false};
};
// Maps a content ID to a clip rect.
diff --git a/chromium/components/paint_preview/common/serial_utils_unittest.cc b/chromium/components/paint_preview/common/serial_utils_unittest.cc
index 35410e9f253..65284a85711 100644
--- a/chromium/components/paint_preview/common/serial_utils_unittest.cc
+++ b/chromium/components/paint_preview/common/serial_utils_unittest.cc
@@ -165,6 +165,7 @@ TEST(PaintPreviewSerialUtils, TestImageContextLimitBudget) {
sk_sp<SkData> data = pic->serialize(&serial_procs);
EXPECT_NE(data, nullptr);
+ EXPECT_TRUE(ictx.memory_budget_exceeded);
SkDeserialProcs deserial_procs;
size_t deserialized_images = 0;
deserial_procs.fImageCtx = &deserialized_images;
@@ -202,7 +203,7 @@ TEST(PaintPreviewSerialUtils, TestImageContextLimitSize) {
TypefaceUsageMap usage_map;
TypefaceSerializationContext typeface_ctx(&usage_map);
ImageSerializationContext ictx;
- ictx.max_representation_size = 200;
+ ictx.max_decoded_image_size_bytes = 200;
SkSerialProcs serial_procs =
MakeSerialProcs(&picture_ctx, &typeface_ctx, &ictx);
@@ -212,6 +213,7 @@ TEST(PaintPreviewSerialUtils, TestImageContextLimitSize) {
sk_sp<SkData> data = pic->serialize(&serial_procs);
EXPECT_NE(data, nullptr);
+ EXPECT_FALSE(ictx.memory_budget_exceeded);
SkDeserialProcs deserial_procs;
size_t deserialized_images = 0;
deserial_procs.fImageCtx = &deserialized_images;
diff --git a/chromium/components/paint_preview/common/serialized_recording.cc b/chromium/components/paint_preview/common/serialized_recording.cc
index b5db42264c7..c0a7e62d84a 100644
--- a/chromium/components/paint_preview/common/serialized_recording.cc
+++ b/chromium/components/paint_preview/common/serialized_recording.cc
@@ -5,13 +5,13 @@
#include "components/paint_preview/common/serialized_recording.h"
#include "base/notreached.h"
-#include "base/optional.h"
#include "base/trace_event/common/trace_event_common.h"
#include "base/trace_event/trace_event.h"
#include "components/paint_preview/common/file_stream.h"
#include "components/paint_preview/common/paint_preview_tracker.h"
#include "components/paint_preview/common/serial_utils.h"
#include "mojo/public/cpp/base/big_buffer.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/skia/include/core/SkStream.h"
namespace paint_preview {
@@ -24,13 +24,20 @@ bool SerializeSkPicture(sk_sp<const SkPicture> skp,
PaintPreviewTracker* tracker,
SkWStream* out_stream) {
TypefaceSerializationContext typeface_context(tracker->GetTypefaceUsageMap());
+ ImageSerializationContext* image_context =
+ tracker->GetImageSerializationContext();
auto serial_procs = MakeSerialProcs(tracker->GetPictureSerializationContext(),
- &typeface_context,
- tracker->GetImageSerializationContext());
+ &typeface_context, image_context);
skp->serialize(out_stream, &serial_procs);
out_stream->flush();
- return true;
+
+ // If the memory budget was exceeded while serializing images and it is not
+ // tolerated (inferred from setting a max decoded image size) then abort.
+ const bool tolerates_discarding =
+ image_context->max_decoded_image_size_bytes !=
+ std::numeric_limits<uint64_t>::max();
+ return tolerates_discarding || !image_context->memory_budget_exceeded;
}
} // namespace
@@ -76,7 +83,7 @@ bool SerializedRecording::IsValid() const {
}
}
-base::Optional<SkpResult> SerializedRecording::Deserialize() && {
+absl::optional<SkpResult> SerializedRecording::Deserialize() && {
TRACE_EVENT0("paint_preview", "SerializedRecording::Deserialize");
SkpResult result;
SkDeserialProcs procs = MakeDeserialProcs(&result.ctx);
@@ -120,7 +127,7 @@ sk_sp<SkPicture> SerializedRecording::DeserializeWithContext(
bool RecordToFile(base::File file,
sk_sp<const SkPicture> skp,
PaintPreviewTracker* tracker,
- base::Optional<size_t> max_capture_size,
+ absl::optional<size_t> max_capture_size,
size_t* serialized_size) {
if (!file.IsValid())
return false;
@@ -137,25 +144,25 @@ bool RecordToFile(base::File file,
return !file_stream.DidWriteFail();
}
-base::Optional<mojo_base::BigBuffer> RecordToBuffer(
+absl::optional<mojo_base::BigBuffer> RecordToBuffer(
sk_sp<const SkPicture> skp,
PaintPreviewTracker* tracker,
- base::Optional<size_t> maybe_max_capture_size,
+ absl::optional<size_t> maybe_max_capture_size,
size_t* serialized_size) {
SkDynamicMemoryWStream memory_stream;
if (!SerializeSkPicture(skp, tracker, &memory_stream))
- return base::nullopt;
+ return absl::nullopt;
size_t max_capture_size = maybe_max_capture_size.value_or(SIZE_MAX);
if (max_capture_size == 0)
- return base::nullopt;
+ return absl::nullopt;
sk_sp<SkData> data = memory_stream.detachAsData();
*serialized_size = std::min(data->size(), max_capture_size);
mojo_base::BigBuffer buffer(
base::span<const uint8_t>(data->bytes(), *serialized_size));
if (data->size() > max_capture_size)
- return base::nullopt;
+ return absl::nullopt;
return {std::move(buffer)};
}
diff --git a/chromium/components/paint_preview/common/serialized_recording.h b/chromium/components/paint_preview/common/serialized_recording.h
index 337d3b19180..925994fcd0f 100644
--- a/chromium/components/paint_preview/common/serialized_recording.h
+++ b/chromium/components/paint_preview/common/serialized_recording.h
@@ -5,18 +5,15 @@
#ifndef COMPONENTS_PAINT_PREVIEW_COMMON_SERIALIZED_RECORDING_H_
#define COMPONENTS_PAINT_PREVIEW_COMMON_SERIALIZED_RECORDING_H_
-#include <memory>
-#include <utility>
-
#include "base/containers/flat_map.h"
#include "base/files/file.h"
#include "base/gtest_prod_util.h"
-#include "base/optional.h"
#include "base/unguessable_token.h"
#include "components/paint_preview/common/mojom/paint_preview_types.mojom-shared.h"
#include "components/paint_preview/common/serial_utils.h"
#include "mojo/public/cpp/base/big_buffer.h"
#include "mojo/public/cpp/bindings/union_traits.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/skia/include/core/SkRefCnt.h"
class SkPicture;
@@ -98,12 +95,22 @@ class SerializedRecording {
RecordingMapFromPaintPreviewProtoSingleFrame);
FRIEND_TEST_ALL_PREFIXES(PaintPreviewRecorderUtilsSerializeAsSkPictureTest,
Roundtrip);
+ FRIEND_TEST_ALL_PREFIXES(PaintPreviewRecorderUtilsSerializeAsSkPictureTest,
+ RoundtripWithImage);
+ FRIEND_TEST_ALL_PREFIXES(PaintPreviewRecorderUtilsSerializeAsSkPictureTest,
+ RoundtripWithLazyImage);
+ FRIEND_TEST_ALL_PREFIXES(PaintPreviewRecorderUtilsSerializeAsSkPictureTest,
+ RoundtripWithPaintWorklet);
+ FRIEND_TEST_ALL_PREFIXES(PaintPreviewRecorderUtilsSerializeAsSkPictureTest,
+ RoundtripWithTexture);
+ FRIEND_TEST_ALL_PREFIXES(PaintPreviewRecorderUtilsSerializeAsSkPictureTest,
+ RoundtripWithLazyTexture);
// Deserialize into an |SkPicture|. The result will not include any embedded
// subframes.
//
// This is not safe to call in the browser process.
- base::Optional<SkpResult> Deserialize() &&;
+ absl::optional<SkpResult> Deserialize() &&;
// Deserialize into an |SkPicture|. |ctx| should contain entries for any
// subframes that should be included in the output.
@@ -126,7 +133,7 @@ class SerializedRecording {
RecordingPersistence persistence_;
base::File file_;
- base::Optional<mojo_base::BigBuffer> buffer_;
+ absl::optional<mojo_base::BigBuffer> buffer_;
};
// Serialize and write |skp| to |file|.
@@ -140,7 +147,7 @@ class SerializedRecording {
bool RecordToFile(base::File file,
sk_sp<const SkPicture> skp,
PaintPreviewTracker* tracker,
- base::Optional<size_t> max_capture_size,
+ absl::optional<size_t> max_capture_size,
size_t* serialized_size);
// Serialize and write |recording| to a memory buffer.
@@ -151,10 +158,10 @@ bool RecordToFile(base::File file,
// serialized output.
//
// Returns the memory buffer on success.
-base::Optional<mojo_base::BigBuffer> RecordToBuffer(
+absl::optional<mojo_base::BigBuffer> RecordToBuffer(
sk_sp<const SkPicture> skp,
PaintPreviewTracker* tracker,
- base::Optional<size_t> max_capture_size,
+ absl::optional<size_t> max_capture_size,
size_t* serialized_size);
} // namespace paint_preview
diff --git a/chromium/components/paint_preview/common/serialized_recording_unittest.cc b/chromium/components/paint_preview/common/serialized_recording_unittest.cc
index 0cce745ac9a..1ba72b714c1 100644
--- a/chromium/components/paint_preview/common/serialized_recording_unittest.cc
+++ b/chromium/components/paint_preview/common/serialized_recording_unittest.cc
@@ -6,7 +6,6 @@
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/optional.h"
#include "base/threading/thread_restrictions.h"
#include "base/unguessable_token.h"
#include "components/paint_preview/common/capture_result.h"
@@ -15,6 +14,7 @@
#include "components/paint_preview/common/recording_map.h"
#include "components/paint_preview/common/serial_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkPaint.h"
@@ -70,6 +70,26 @@ sk_sp<const SkPicture> PaintPictureSingleGrayPixel() {
&expected_deserialization_context, {});
}
+sk_sp<const SkPicture> PaintPictureLargeImage(gfx::Size bounds) {
+ SkBitmap bitmap;
+ {
+ bitmap.allocPixels(
+ SkImageInfo::MakeN32Premul(bounds.width(), bounds.height()));
+ SkCanvas canvas(bitmap, SkSurfaceProps{});
+ canvas.drawColor(SK_ColorDKGRAY);
+ }
+
+ SkRect sk_bounds = SkRect::MakeWH(bounds.width(), bounds.height());
+ SkPictureRecorder recorder;
+ SkCanvas* canvas = recorder.beginRecording(sk_bounds);
+ SkPaint paint;
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(SK_ColorRED);
+ canvas->drawRect(sk_bounds, paint);
+ canvas->drawImage(SkImage::MakeFromBitmap(bitmap), 0, 0);
+ return recorder.finishRecordingAsPicture();
+}
+
SkBitmap CreateBitmapFromPicture(const SkPicture* pic) {
SkRect cull_rect = pic->cullRect();
SkBitmap bitmap;
@@ -113,18 +133,18 @@ TEST(PaintPreviewSerializedRecordingTest, RoundtripWithFileBacking) {
sk_sp<const SkPicture> pic = PaintPictureSingleGrayPixel();
base::FilePath path = temp_dir.GetPath().AppendASCII("root.skp");
- PaintPreviewTracker tracker(base::UnguessableToken::Create(), base::nullopt,
+ PaintPreviewTracker tracker(base::UnguessableToken::Create(), absl::nullopt,
/*is_main_frame=*/true);
size_t serialized_size = 0;
ASSERT_TRUE(RecordToFile(
base::File(path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE),
- pic, &tracker, base::nullopt, &serialized_size));
+ pic, &tracker, absl::nullopt, &serialized_size));
ASSERT_GE(serialized_size, 0u);
SerializedRecording recording(path);
ASSERT_TRUE(recording.IsValid());
- base::Optional<SkpResult> result = std::move(recording).Deserialize();
+ absl::optional<SkpResult> result = std::move(recording).Deserialize();
ASSERT_TRUE(result.has_value());
ASSERT_TRUE(result->ctx.empty());
ExpectPicturesEqual(result->skp, pic);
@@ -133,11 +153,11 @@ TEST(PaintPreviewSerializedRecordingTest, RoundtripWithFileBacking) {
TEST(PaintPreviewSerializedRecordingTest, RoundtripWithMemoryBufferBacking) {
sk_sp<const SkPicture> pic = PaintPictureSingleGrayPixel();
- PaintPreviewTracker tracker(base::UnguessableToken::Create(), base::nullopt,
+ PaintPreviewTracker tracker(base::UnguessableToken::Create(), absl::nullopt,
/*is_main_frame=*/true);
size_t serialized_size = 0;
- base::Optional<mojo_base::BigBuffer> buffer =
- RecordToBuffer(pic, &tracker, base::nullopt, &serialized_size);
+ absl::optional<mojo_base::BigBuffer> buffer =
+ RecordToBuffer(pic, &tracker, absl::nullopt, &serialized_size);
ASSERT_GE(serialized_size, 0u);
ASSERT_TRUE(buffer.has_value());
@@ -145,12 +165,47 @@ TEST(PaintPreviewSerializedRecordingTest, RoundtripWithMemoryBufferBacking) {
SerializedRecording(std::move(buffer.value()));
ASSERT_TRUE(recording.IsValid());
- base::Optional<SkpResult> result = std::move(recording).Deserialize();
+ absl::optional<SkpResult> result = std::move(recording).Deserialize();
ASSERT_TRUE(result.has_value());
ASSERT_TRUE(result->ctx.empty());
ExpectPicturesEqual(result->skp, pic);
}
+TEST(PaintPreviewSerializedRecordingTest, ImageDiscardingTolerated) {
+ sk_sp<const SkPicture> pic = PaintPictureLargeImage(gfx::Size(200, 200));
+
+ PaintPreviewTracker tracker(base::UnguessableToken::Create(), absl::nullopt,
+ /*is_main_frame=*/true);
+ auto* image_context = tracker.GetImageSerializationContext();
+ image_context->remaining_image_size = 200;
+ image_context->max_decoded_image_size_bytes = 300 * 300 * 4;
+ size_t serialized_size = 0;
+ absl::optional<mojo_base::BigBuffer> buffer =
+ RecordToBuffer(pic, &tracker, absl::nullopt, &serialized_size);
+ ASSERT_GE(serialized_size, 0u);
+ ASSERT_TRUE(buffer.has_value());
+ ASSERT_TRUE(image_context->memory_budget_exceeded);
+
+ SerializedRecording recording =
+ SerializedRecording(std::move(buffer.value()));
+ ASSERT_TRUE(recording.IsValid());
+}
+
+TEST(PaintPreviewSerializedRecordingTest, ImageDiscardingNotTolerated) {
+ sk_sp<const SkPicture> pic = PaintPictureLargeImage(gfx::Size(200, 200));
+
+ PaintPreviewTracker tracker(base::UnguessableToken::Create(), absl::nullopt,
+ /*is_main_frame=*/true);
+ auto* image_context = tracker.GetImageSerializationContext();
+ image_context->remaining_image_size = 200;
+ size_t serialized_size = 0;
+ absl::optional<mojo_base::BigBuffer> buffer =
+ RecordToBuffer(pic, &tracker, absl::nullopt, &serialized_size);
+ ASSERT_FALSE(buffer.has_value());
+ ASSERT_EQ(serialized_size, 0U);
+ ASSERT_TRUE(image_context->memory_budget_exceeded);
+}
+
TEST(PaintPreviewSerializedRecordingTest, InvalidBacking) {
SerializedRecording recording;
ASSERT_FALSE(recording.IsValid());
@@ -162,7 +217,7 @@ TEST(PaintPreviewSerializedRecordingTest, RoundtripHasEmbeddedContent) {
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
base::FilePath path = temp_dir.GetPath().AppendASCII("root.skp");
- PaintPreviewTracker tracker(base::UnguessableToken::Create(), base::nullopt,
+ PaintPreviewTracker tracker(base::UnguessableToken::Create(), absl::nullopt,
/*is_main_frame=*/true);
base::UnguessableToken subframe0 = base::UnguessableToken::Create();
@@ -178,13 +233,13 @@ TEST(PaintPreviewSerializedRecordingTest, RoundtripHasEmbeddedContent) {
size_t serialized_size = 0;
ASSERT_TRUE(RecordToFile(
base::File(path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE),
- pic, &tracker, base::nullopt, &serialized_size));
+ pic, &tracker, absl::nullopt, &serialized_size));
ASSERT_GE(serialized_size, 0u);
SerializedRecording recording(path);
ASSERT_TRUE(recording.IsValid());
- base::Optional<SkpResult> result = std::move(recording).Deserialize();
+ absl::optional<SkpResult> result = std::move(recording).Deserialize();
ASSERT_TRUE(result.has_value());
EXPECT_FALSE(result->ctx.empty());
@@ -199,11 +254,11 @@ TEST(PaintPreviewSerializedRecordingTest,
const base::UnguessableToken root_frame_guid =
base::UnguessableToken::Create();
- PaintPreviewTracker tracker(base::UnguessableToken::Create(), base::nullopt,
+ PaintPreviewTracker tracker(base::UnguessableToken::Create(), absl::nullopt,
/*is_main_frame=*/true);
size_t serialized_size = 0;
- base::Optional<mojo_base::BigBuffer> buffer =
- RecordToBuffer(pic, &tracker, base::nullopt, &serialized_size);
+ absl::optional<mojo_base::BigBuffer> buffer =
+ RecordToBuffer(pic, &tracker, absl::nullopt, &serialized_size);
ASSERT_GE(serialized_size, 0u);
ASSERT_TRUE(buffer.has_value());
@@ -218,7 +273,7 @@ TEST(PaintPreviewSerializedRecordingTest,
RecordingMap recording_map = std::move(pair.first);
EXPECT_FALSE(recording_map.empty());
ASSERT_NE(recording_map.find(root_frame_guid), recording_map.end());
- base::Optional<SkpResult> result =
+ absl::optional<SkpResult> result =
std::move(recording_map.at(root_frame_guid)).Deserialize();
ASSERT_TRUE(result.has_value());
@@ -237,13 +292,13 @@ TEST(PaintPreviewSerializedRecordingTest,
const base::UnguessableToken root_frame_guid =
base::UnguessableToken::Create();
- PaintPreviewTracker tracker(base::UnguessableToken::Create(), base::nullopt,
+ PaintPreviewTracker tracker(base::UnguessableToken::Create(), absl::nullopt,
/*is_main_frame=*/true);
size_t serialized_size = 0;
ASSERT_TRUE(RecordToFile(
base::File(root_path,
base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE),
- pic, &tracker, base::nullopt, &serialized_size));
+ pic, &tracker, absl::nullopt, &serialized_size));
ASSERT_GE(serialized_size, 0u);
PaintPreviewProto proto;
@@ -257,7 +312,7 @@ TEST(PaintPreviewSerializedRecordingTest,
RecordingMap recording_map = RecordingMapFromPaintPreviewProto(proto);
EXPECT_FALSE(recording_map.empty());
ASSERT_NE(recording_map.find(root_frame_guid), recording_map.end());
- base::Optional<SkpResult> result =
+ absl::optional<SkpResult> result =
std::move(recording_map.at(root_frame_guid)).Deserialize();
ASSERT_TRUE(result.has_value());
diff --git a/chromium/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java b/chromium/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java
index 3d372e64a2f..8b753b2e297 100644
--- a/chromium/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java
+++ b/chromium/components/paint_preview/player/android/javatests/src/org/chromium/components/paintpreview/player/PaintPreviewPlayerTest.java
@@ -217,6 +217,9 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase {
public boolean isAccessibilityEnabled() {
return false;
}
+
+ @Override
+ public void onAccessibilityNotSupported() {}
}, 0xffffffff, false);
mPlayerManager.setCompressOnClose(false);
});
@@ -427,6 +430,9 @@ public class PaintPreviewPlayerTest extends DummyUiActivityTestCase {
public boolean isAccessibilityEnabled() {
return false;
}
+
+ @Override
+ public void onAccessibilityNotSupported() {}
}, 0xffffffff, false);
mPlayerManager.setCompressOnClose(false);
getActivity().setContentView(mPlayerManager.getView());
diff --git a/chromium/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameCoordinatorTest.java b/chromium/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameCoordinatorTest.java
index b7980196d3c..702e336e19b 100644
--- a/chromium/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameCoordinatorTest.java
+++ b/chromium/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameCoordinatorTest.java
@@ -30,11 +30,11 @@ public class PlayerFrameCoordinatorTest {
PlayerFrameCoordinator rootCoordinator = new PlayerFrameCoordinator(
RuntimeEnvironment.systemContext, Mockito.mock(PlayerCompositorDelegate.class),
Mockito.mock(UnguessableToken.class), 100, 2000, 0, 0, true, null,
- Mockito.mock(PlayerGestureListener.class), null, null);
+ Mockito.mock(PlayerGestureListener.class), null, null, null);
PlayerFrameCoordinator childCoordinator = new PlayerFrameCoordinator(
RuntimeEnvironment.systemContext, Mockito.mock(PlayerCompositorDelegate.class),
Mockito.mock(UnguessableToken.class), 100, 200, 0, 0, true, null,
- Mockito.mock(PlayerGestureListener.class), null, null);
+ Mockito.mock(PlayerGestureListener.class), null, null, null);
rootCoordinator.addSubFrame(childCoordinator, new Rect(10, 20, 35, 40));
rootCoordinator.getMediator().setLayoutDimensions(100, 200);
diff --git a/chromium/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediatorTest.java b/chromium/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediatorTest.java
index 200d69446a8..2b5e670c066 100644
--- a/chromium/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediatorTest.java
+++ b/chromium/components/paint_preview/player/android/junit/src/org/chromium/components/paintpreview/player/frame/PlayerFrameMediatorTest.java
@@ -237,8 +237,8 @@ public class PlayerFrameMediatorTest {
mScroller = new OverScroller(ContextUtils.getApplicationContext());
mGestureListener = new PlayerGestureListener(null, () -> mHasUserInteraction = true, null);
Size contentSize = new Size(CONTENT_WIDTH, CONTENT_HEIGHT);
- mMediator = new PlayerFrameMediator(mModel, mCompositorDelegate, mGestureListener,
- mFrameGuid, contentSize, 0, 0);
+ mMediator = new PlayerFrameMediator(
+ mModel, mCompositorDelegate, mGestureListener, mFrameGuid, contentSize, 0, 0, null);
mScaleController =
new PlayerFrameScaleController(mModel.get(PlayerFrameProperties.SCALE_MATRIX),
mMediator, null, mGestureListener::onScale);
diff --git a/chromium/components/paint_preview/player/android/player_compositor_delegate_android.cc b/chromium/components/paint_preview/player/android/player_compositor_delegate_android.cc
index c9b11a35754..e827f4b6270 100644
--- a/chromium/components/paint_preview/player/android/player_compositor_delegate_android.cc
+++ b/chromium/components/paint_preview/player/android/player_compositor_delegate_android.cc
@@ -15,6 +15,7 @@
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
#include "base/trace_event/common/trace_event_common.h"
+#include "base/trace_event/trace_event.h"
#include "base/unguessable_token.h"
#include "components/paint_preview/browser/paint_preview_base_service.h"
#include "components/paint_preview/player/android/jni_headers/PlayerCompositorDelegateImpl_jni.h"
@@ -252,7 +253,7 @@ jint PlayerCompositorDelegateAndroid::RequestBitmap(
ScopedJavaGlobalRef<jobject>(j_error_callback), request_id_);
++request_id_;
- base::Optional<base::UnguessableToken> frame_guid;
+ absl::optional<base::UnguessableToken> frame_guid;
if (j_frame_guid) {
frame_guid =
base::android::UnguessableTokenAndroid::FromJavaUnguessableToken(
diff --git a/chromium/components/paint_preview/player/bitmap_request.cc b/chromium/components/paint_preview/player/bitmap_request.cc
index a09c52654e6..d777fae3652 100644
--- a/chromium/components/paint_preview/player/bitmap_request.cc
+++ b/chromium/components/paint_preview/player/bitmap_request.cc
@@ -7,7 +7,7 @@
namespace paint_preview {
BitmapRequest::BitmapRequest(
- const base::Optional<base::UnguessableToken>& frame_guid,
+ const absl::optional<base::UnguessableToken>& frame_guid,
const gfx::Rect& clip_rect,
float scale_factor,
BitmapRequestCallback callback)
diff --git a/chromium/components/paint_preview/player/bitmap_request.h b/chromium/components/paint_preview/player/bitmap_request.h
index b4de5299d3b..5b2fd37c819 100644
--- a/chromium/components/paint_preview/player/bitmap_request.h
+++ b/chromium/components/paint_preview/player/bitmap_request.h
@@ -6,9 +6,9 @@
#define COMPONENTS_PAINT_PREVIEW_PLAYER_BITMAP_REQUEST_H_
#include "base/callback.h"
-#include "base/optional.h"
#include "base/unguessable_token.h"
#include "components/services/paint_preview_compositor/public/mojom/paint_preview_compositor.mojom.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/geometry/rect.h"
@@ -19,7 +19,7 @@ struct BitmapRequest {
base::OnceCallback<void(mojom::PaintPreviewCompositor::BitmapStatus,
const SkBitmap&)>;
- BitmapRequest(const base::Optional<base::UnguessableToken>& frame_guid,
+ BitmapRequest(const absl::optional<base::UnguessableToken>& frame_guid,
const gfx::Rect& clip_rect,
float scale_factor,
BitmapRequestCallback callback);
@@ -28,7 +28,7 @@ struct BitmapRequest {
BitmapRequest& operator=(BitmapRequest&& other) noexcept;
BitmapRequest(BitmapRequest&& other) noexcept;
- base::Optional<base::UnguessableToken> frame_guid;
+ absl::optional<base::UnguessableToken> frame_guid;
gfx::Rect clip_rect;
float scale_factor;
BitmapRequestCallback callback;
diff --git a/chromium/components/paint_preview/player/player_compositor_delegate.cc b/chromium/components/paint_preview/player/player_compositor_delegate.cc
index 4b054152653..324d06dab1e 100644
--- a/chromium/components/paint_preview/player/player_compositor_delegate.cc
+++ b/chromium/components/paint_preview/player/player_compositor_delegate.cc
@@ -14,7 +14,6 @@
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/weak_ptr.h"
#include "base/notreached.h"
-#include "base/optional.h"
#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
@@ -32,6 +31,7 @@
#include "components/paint_preview/public/paint_preview_compositor_service.h"
#include "components/services/paint_preview_compositor/public/mojom/paint_preview_compositor.mojom.h"
#include "mojo/public/cpp/bindings/remote.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/geometry/rect.h"
@@ -62,15 +62,15 @@ BuildHitTesters(const PaintPreviewProto& proto) {
std::move(hit_testers));
}
-base::Optional<base::ReadOnlySharedMemoryRegion> ToReadOnlySharedMemory(
+absl::optional<base::ReadOnlySharedMemoryRegion> ToReadOnlySharedMemory(
const paint_preview::PaintPreviewProto& proto) {
auto region = base::WritableSharedMemoryRegion::Create(proto.ByteSizeLong());
if (!region.IsValid())
- return base::nullopt;
+ return absl::nullopt;
auto mapping = region.Map();
if (!mapping.IsValid())
- return base::nullopt;
+ return absl::nullopt;
proto.SerializeToArray(mapping.memory(), mapping.size());
return base::WritableSharedMemoryRegion::ConvertToReadOnly(std::move(region));
@@ -203,7 +203,7 @@ void PlayerCompositorDelegate::InitializeInternal(
}
int32_t PlayerCompositorDelegate::RequestBitmap(
- const base::Optional<base::UnguessableToken>& frame_guid,
+ const absl::optional<base::UnguessableToken>& frame_guid,
const gfx::Rect& clip_rect,
float scale_factor,
base::OnceCallback<void(mojom::PaintPreviewCompositor::BitmapStatus,
@@ -323,7 +323,7 @@ void PlayerCompositorDelegate::OnCompositorClientCreated(
TRACE_ID_LOCAL(this));
if (!proto_) {
paint_preview_service_->GetFileMixin()->GetCapturedPaintPreviewProto(
- key, base::nullopt,
+ key, absl::nullopt,
base::BindOnce(&PlayerCompositorDelegate::OnProtoAvailable,
weak_factory_.GetWeakPtr(), expected_url));
} else {
diff --git a/chromium/components/paint_preview/player/player_compositor_delegate.h b/chromium/components/paint_preview/player/player_compositor_delegate.h
index cf8bebf1814..8d4b803539f 100644
--- a/chromium/components/paint_preview/player/player_compositor_delegate.h
+++ b/chromium/components/paint_preview/player/player_compositor_delegate.h
@@ -10,7 +10,6 @@
#include "base/containers/flat_map.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/memory/weak_ptr.h"
-#include "base/optional.h"
#include "base/unguessable_token.h"
#include "components/paint_preview/browser/hit_tester.h"
#include "components/paint_preview/browser/paint_preview_base_service.h"
@@ -20,6 +19,7 @@
#include "components/paint_preview/public/paint_preview_compositor_service.h"
#include "components/services/paint_preview_compositor/public/mojom/paint_preview_compositor.mojom.h"
#include "mojo/public/cpp/bindings/remote.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
namespace base {
class MemoryPressureMonitor;
@@ -77,7 +77,7 @@ class PlayerCompositorDelegate {
// Pass this ID to `CancelBitmapRequest(int32_t)` to cancel the request if it
// hasn't already been sent.
int32_t RequestBitmap(
- const base::Optional<base::UnguessableToken>& frame_guid,
+ const absl::optional<base::UnguessableToken>& frame_guid,
const gfx::Rect& clip_rect,
float scale_factor,
base::OnceCallback<void(mojom::PaintPreviewCompositor::BitmapStatus,
diff --git a/chromium/components/paint_preview/player/player_compositor_delegate_unittest.cc b/chromium/components/paint_preview/player/player_compositor_delegate_unittest.cc
index e8fef04f627..90a85e86802 100644
--- a/chromium/components/paint_preview/player/player_compositor_delegate_unittest.cc
+++ b/chromium/components/paint_preview/player/player_compositor_delegate_unittest.cc
@@ -46,7 +46,7 @@ class FakePaintPreviewCompositorClient : public PaintPreviewCompositorClient {
FakePaintPreviewCompositorClient& operator=(
const FakePaintPreviewCompositorClient&) = delete;
- const base::Optional<base::UnguessableToken>& Token() const override {
+ const absl::optional<base::UnguessableToken>& Token() const override {
return token_;
}
@@ -123,7 +123,7 @@ class FakePaintPreviewCompositorClient : public PaintPreviewCompositorClient {
private:
mojom::PaintPreviewCompositor::BeginCompositeStatus response_status_;
- base::Optional<base::UnguessableToken> token_;
+ absl::optional<base::UnguessableToken> token_;
base::OnceClosure disconnect_handler_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
};
@@ -642,7 +642,7 @@ TEST_F(PlayerCompositorDelegateTest, CompressOnClose) {
false),
base::BindOnce(
[](base::FilePath* out,
- const base::Optional<base::FilePath>& file_path) {
+ const absl::optional<base::FilePath>& file_path) {
*out = file_path.value();
},
base::Unretained(&dir)));
@@ -845,7 +845,7 @@ TEST_F(PlayerCompositorDelegateTest, RequestMainFrameBitmapSuccess) {
base::RunLoop loop;
player_compositor_delegate.RequestBitmap(
- base::nullopt, gfx::Rect(10, 20, 30, 40), 1.0,
+ absl::nullopt, gfx::Rect(10, 20, 30, 40), 1.0,
base::BindOnce(
[](base::OnceClosure quit,
mojom::PaintPreviewCompositor::BitmapStatus status,
diff --git a/chromium/components/paint_preview/public/paint_preview_compositor_client.h b/chromium/components/paint_preview/public/paint_preview_compositor_client.h
index 9f49438c501..4fc22afdd16 100644
--- a/chromium/components/paint_preview/public/paint_preview_compositor_client.h
+++ b/chromium/components/paint_preview/public/paint_preview_compositor_client.h
@@ -6,9 +6,9 @@
#define COMPONENTS_PAINT_PREVIEW_PUBLIC_PAINT_PREVIEW_COMPOSITOR_CLIENT_H_
#include "base/callback_forward.h"
-#include "base/optional.h"
#include "base/unguessable_token.h"
#include "components/services/paint_preview_compositor/public/mojom/paint_preview_compositor.mojom.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
namespace gfx {
@@ -27,7 +27,7 @@ class PaintPreviewCompositorClient {
// Returns the token associated with the client. Will be null if the client
// isn't started.
- virtual const base::Optional<base::UnguessableToken>& Token() const = 0;
+ virtual const absl::optional<base::UnguessableToken>& Token() const = 0;
// Adds `closure` as a disconnect handler.
virtual void SetDisconnectHandler(base::OnceClosure closure) = 0;
diff --git a/chromium/components/paint_preview/renderer/paint_preview_recorder_browsertest.cc b/chromium/components/paint_preview/renderer/paint_preview_recorder_browsertest.cc
index b1a1e54f57a..fd928b6efc4 100644
--- a/chromium/components/paint_preview/renderer/paint_preview_recorder_browsertest.cc
+++ b/chromium/components/paint_preview/renderer/paint_preview_recorder_browsertest.cc
@@ -17,7 +17,10 @@
#include "content/public/test/render_view_test.h"
#include "content/public/test/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
+#include "third_party/blink/public/platform/web_runtime_features.h"
#include "third_party/blink/public/web/web_local_frame.h"
+#include "third_party/blink/public/web/web_testing_support.h"
#include "third_party/skia/include/core/SkPicture.h"
#include "ui/native_theme/native_theme_features.h"
@@ -25,6 +28,8 @@ namespace paint_preview {
namespace {
+constexpr char kCompositeAfterPaint[] = "CompositeAfterPaint";
+
// Checks that |status| == |expected_status| and loads |response| into
// |out_response| if |expected_status| == kOk. If |expected_status| != kOk
// |out_response| can safely be nullptr.
@@ -37,22 +42,39 @@ void OnCaptureFinished(mojom::PaintPreviewStatus expected_status,
*out_response = std::move(response);
}
+std::string CompositeAfterPaintToString(
+ const ::testing::TestParamInfo<bool>& cap_enabled) {
+ if (cap_enabled.param) {
+ return "WithCompositeAfterPaint";
+ }
+ return "NoCompositeAfterPaint";
+}
+
} // namespace
-class PaintPreviewRecorderRenderViewTest : public content::RenderViewTest {
+class PaintPreviewRecorderRenderViewTest
+ : public content::RenderViewTest,
+ public ::testing::WithParamInterface<bool> {
public:
- PaintPreviewRecorderRenderViewTest() {}
- ~PaintPreviewRecorderRenderViewTest() override {}
-
- void SetUp() override {
- ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
-
+ PaintPreviewRecorderRenderViewTest() {
+ std::vector<base::Feature> enabled;
// TODO(crbug/1022398): This is required to bypass a seemingly unrelated
// DCHECK for |use_overlay_scrollbars_| in NativeThemeAura on ChromeOS when
// painting scrollbars when first calling LoadHTML().
feature_list_.InitAndDisableFeature(features::kOverlayScrollbar);
+ blink::WebTestingSupport::SaveRuntimeFeatures();
+ }
+
+ ~PaintPreviewRecorderRenderViewTest() override {
+ // Restore blink runtime features to their original values.
+ blink::WebTestingSupport::ResetRuntimeFeatures();
+ }
+ void SetUp() override {
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
RenderViewTest::SetUp();
+ blink::WebRuntimeFeatures::EnableFeatureFromString(kCompositeAfterPaint,
+ GetParam());
}
content::RenderFrame* GetFrame() { return view_->GetMainRenderFrame(); }
@@ -93,7 +115,7 @@ class PaintPreviewRecorderRenderViewTest : public content::RenderViewTest {
base::test::ScopedFeatureList feature_list_;
};
-TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureMainFrameAndClipping) {
+TEST_P(PaintPreviewRecorderRenderViewTest, TestCaptureMainFrameAndClipping) {
LoadHTML(
"<!doctype html>"
"<body>"
@@ -158,19 +180,20 @@ TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureMainFrameAndClipping) {
0xFFFFFFFFU);
}
-TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureMainFrameWithScroll) {
+TEST_P(PaintPreviewRecorderRenderViewTest, TestCaptureMainFrameWithScroll) {
LoadHTML(
"<!doctype html>"
"<body>"
- " <div style='width: 600px; height: 80vh; "
+ " <div style='width: 600px; height: 200px; "
" background-color: #ff0000'>&nbsp;</div>"
- " <div style='width: 600px; height: 1200px; "
+ " <div style='width: 600px; height: 5000px; "
" background-color: #00ff00'>&nbsp;</div>"
"</body>");
// Scroll to bottom of page to ensure scroll position has no effect on
// capture.
ExecuteJavaScriptForTests("window.scrollTo(0,document.body.scrollHeight);");
+ content::RunAllTasksUntilIdle();
auto out_response = mojom::PaintPreviewCaptureResponse::New();
content::RenderFrame* frame = GetFrame();
@@ -204,7 +227,7 @@ TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureMainFrameWithScroll) {
EXPECT_EQ(bitmap.getColor(50, pic->cullRect().height() - 100), 0xFF00FF00U);
}
-TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureFragment) {
+TEST_P(PaintPreviewRecorderRenderViewTest, TestCaptureFragment) {
// Use position absolute position to check that the captured link dimensions
// match what is specified.
LoadHTML(
@@ -232,7 +255,7 @@ TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureFragment) {
EXPECT_EQ(out_response->links[0]->rect.height(), 30);
}
-TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureInvalidFile) {
+TEST_P(PaintPreviewRecorderRenderViewTest, TestCaptureInvalidFile) {
LoadHTML("<body></body>");
mojom::PaintPreviewCaptureParamsPtr params =
@@ -255,7 +278,7 @@ TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureInvalidFile) {
content::RunAllTasksUntilIdle();
}
-TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureInvalidXYClip) {
+TEST_P(PaintPreviewRecorderRenderViewTest, TestCaptureInvalidXYClip) {
LoadHTML("<body></body>");
mojom::PaintPreviewCaptureParamsPtr params =
@@ -280,7 +303,7 @@ TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureInvalidXYClip) {
content::RunAllTasksUntilIdle();
}
-TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureMainFrameAndLocalFrame) {
+TEST_P(PaintPreviewRecorderRenderViewTest, TestCaptureMainFrameAndLocalFrame) {
LoadHTML(
"<!doctype html>"
"<body style='min-height:1000px;'>"
@@ -299,7 +322,7 @@ TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureMainFrameAndLocalFrame) {
EXPECT_EQ(out_response->content_id_to_embedding_token.size(), 0U);
}
-TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureLocalFrame) {
+TEST_P(PaintPreviewRecorderRenderViewTest, TestCaptureLocalFrame) {
LoadHTML(
"<!doctype html>"
"<body style='min-height:1000px;'>"
@@ -318,7 +341,7 @@ TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureLocalFrame) {
EXPECT_EQ(out_response->content_id_to_embedding_token.size(), 0U);
}
-TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureUnclippedLocalFrame) {
+TEST_P(PaintPreviewRecorderRenderViewTest, TestCaptureUnclippedLocalFrame) {
LoadHTML(
"<!doctype html>"
"<body style='min-height:1000px;'>"
@@ -360,7 +383,7 @@ TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureUnclippedLocalFrame) {
EXPECT_EQ(bitmap.getColor(50, 800), 0xFFFF0000U);
}
-TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureCustomClipRect) {
+TEST_P(PaintPreviewRecorderRenderViewTest, TestCaptureCustomClipRect) {
LoadHTML(
"<!doctype html>"
"<body>"
@@ -406,7 +429,7 @@ TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureCustomClipRect) {
EXPECT_EQ(out_response->links[0]->rect.height(), 30);
}
-TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureWithClamp) {
+TEST_P(PaintPreviewRecorderRenderViewTest, TestCaptureWithClamp) {
LoadHTML(
"<!doctype html>"
"<body>"
@@ -440,7 +463,7 @@ TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureWithClamp) {
EXPECT_LT(pic->cullRect().width(), kLarge);
}
-TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureFullIfWidthHeightAre0) {
+TEST_P(PaintPreviewRecorderRenderViewTest, TestCaptureFullIfWidthHeightAre0) {
LoadHTML(
"<!doctype html>"
"<body>"
@@ -473,7 +496,7 @@ TEST_F(PaintPreviewRecorderRenderViewTest, TestCaptureFullIfWidthHeightAre0) {
EXPECT_GT(pic->cullRect().width(), 0U);
}
-TEST_F(PaintPreviewRecorderRenderViewTest, CaptureWithTranslate) {
+TEST_P(PaintPreviewRecorderRenderViewTest, CaptureWithTranslate) {
// URLs should be annotated correctly when a CSS transform is applied.
LoadHTML(
R"(
@@ -513,7 +536,7 @@ TEST_F(PaintPreviewRecorderRenderViewTest, CaptureWithTranslate) {
EXPECT_NEAR(out_response->links[0]->rect.height(), 20, 3);
}
-TEST_F(PaintPreviewRecorderRenderViewTest, CaptureWithTranslateThenRotate) {
+TEST_P(PaintPreviewRecorderRenderViewTest, CaptureWithTranslateThenRotate) {
// URLs should be annotated correctly when a CSS transform is applied.
LoadHTML(
R"(
@@ -555,7 +578,7 @@ TEST_F(PaintPreviewRecorderRenderViewTest, CaptureWithTranslateThenRotate) {
#endif
}
-TEST_F(PaintPreviewRecorderRenderViewTest, CaptureWithRotateThenTranslate) {
+TEST_P(PaintPreviewRecorderRenderViewTest, CaptureWithRotateThenTranslate) {
// URLs should be annotated correctly when a CSS transform is applied.
LoadHTML(
R"(
@@ -597,7 +620,7 @@ TEST_F(PaintPreviewRecorderRenderViewTest, CaptureWithRotateThenTranslate) {
#endif
}
-TEST_F(PaintPreviewRecorderRenderViewTest, CaptureWithScale) {
+TEST_P(PaintPreviewRecorderRenderViewTest, CaptureWithScale) {
// URLs should be annotated correctly when a CSS transform is applied.
LoadHTML(
R"(
@@ -637,7 +660,7 @@ TEST_F(PaintPreviewRecorderRenderViewTest, CaptureWithScale) {
EXPECT_NEAR(out_response->links[0]->rect.height(), 20, 3);
}
-TEST_F(PaintPreviewRecorderRenderViewTest, CaptureSaveRestore) {
+TEST_P(PaintPreviewRecorderRenderViewTest, CaptureSaveRestore) {
// URLs should be annotated correctly when a CSS transform is applied.
LoadHTML(
R"(
@@ -694,4 +717,9 @@ TEST_F(PaintPreviewRecorderRenderViewTest, CaptureSaveRestore) {
EXPECT_NEAR(out_response->links[1]->rect.height(), 20, 3);
}
+INSTANTIATE_TEST_SUITE_P(All,
+ PaintPreviewRecorderRenderViewTest,
+ testing::Values(true, false),
+ CompositeAfterPaintToString);
+
} // namespace paint_preview
diff --git a/chromium/components/paint_preview/renderer/paint_preview_recorder_impl.cc b/chromium/components/paint_preview/renderer/paint_preview_recorder_impl.cc
index 75efd829b7b..e17aaa71e77 100644
--- a/chromium/components/paint_preview/renderer/paint_preview_recorder_impl.cc
+++ b/chromium/components/paint_preview/renderer/paint_preview_recorder_impl.cc
@@ -11,18 +11,19 @@
#include "base/bind.h"
#include "base/bind_post_task.h"
#include "base/metrics/histogram_functions.h"
-#include "base/optional.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/task_runner.h"
#include "base/time/time.h"
#include "base/trace_event/common/trace_event_common.h"
+#include "base/trace_event/trace_event.h"
#include "cc/paint/paint_record.h"
#include "cc/paint/paint_recorder.h"
#include "components/paint_preview/common/paint_preview_tracker.h"
#include "components/paint_preview/common/serialized_recording.h"
#include "components/paint_preview/renderer/paint_preview_recorder_utils.h"
#include "content/public/renderer/render_frame.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
#include "third_party/blink/public/web/web_local_frame.h"
@@ -58,7 +59,7 @@ void BuildAndSendResponse(std::unique_ptr<PaintPreviewTracker> tracker,
FinishedRecording out,
CapturePaintPreviewCallback callback) {
if (out.status == mojom::PaintPreviewStatus::kOk) {
- BuildResponse(tracker.get(), out.response.get(), /*log=*/true);
+ BuildResponse(tracker.get(), out.response.get());
}
std::move(callback).Run(out.status, std::move(out.response));
}
@@ -68,7 +69,7 @@ void BuildAndSendResponse(std::unique_ptr<PaintPreviewTracker> tracker,
void RecordToFileOnThreadPool(sk_sp<const SkPicture> skp,
base::File skp_file,
std::unique_ptr<PaintPreviewTracker> tracker,
- base::Optional<size_t> max_capture_size,
+ absl::optional<size_t> max_capture_size,
FinishedRecording out,
CapturePaintPreviewCallback callback) {
TRACE_EVENT0("paint_preview", "RecordToFileOnThreadPool");
@@ -87,7 +88,7 @@ void RecordToFileOnThreadPool(sk_sp<const SkPicture> skp,
void SerializeFileRecording(sk_sp<const SkPicture> skp,
base::File skp_file,
std::unique_ptr<PaintPreviewTracker> tracker,
- base::Optional<size_t> max_capture_size,
+ absl::optional<size_t> max_capture_size,
FinishedRecording out,
CapturePaintPreviewCallback callback) {
base::ThreadPool::PostTask(
@@ -104,12 +105,12 @@ void SerializeFileRecording(sk_sp<const SkPicture> skp,
void SerializeMemoryBufferRecording(
sk_sp<const SkPicture> skp,
std::unique_ptr<PaintPreviewTracker> tracker,
- base::Optional<size_t> max_capture_size,
+ absl::optional<size_t> max_capture_size,
FinishedRecording out,
CapturePaintPreviewCallback callback) {
TRACE_EVENT0("paint_preview", "SerializeMemoryBufferRecording");
size_t serialized_size = 0;
- base::Optional<mojo_base::BigBuffer> buffer =
+ absl::optional<mojo_base::BigBuffer> buffer =
RecordToBuffer(skp, tracker.get(), max_capture_size, &serialized_size);
out.status = buffer.has_value() ? mojom::PaintPreviewStatus::kOk
: mojom::PaintPreviewStatus::kCaptureFailed;
@@ -126,7 +127,7 @@ void FinishRecordingOnUIThread(sk_sp<const cc::PaintRecord> recording,
std::unique_ptr<PaintPreviewTracker> tracker,
RecordingPersistence persistence,
base::File skp_file,
- base::Optional<size_t> max_capture_size,
+ absl::optional<size_t> max_capture_size,
mojom::PaintPreviewCaptureResponsePtr response,
CapturePaintPreviewCallback callback) {
TRACE_EVENT0("paint_preview", "FinishRecordingOnUIThread");
@@ -137,9 +138,9 @@ void FinishRecordingOnUIThread(sk_sp<const cc::PaintRecord> recording,
return;
}
- TRACE_EVENT_BEGIN0("paint_preview", "ParseGlyphsAndLinks");
- ParseGlyphsAndLinks(recording.get(), tracker.get());
- TRACE_EVENT_END0("paint_preview", "ParseGlyphsAndLinks");
+ TRACE_EVENT_BEGIN0("paint_preview", "PreProcessPaintOpBuffer");
+ PreProcessPaintOpBuffer(recording.get(), tracker.get());
+ TRACE_EVENT_END0("paint_preview", "PreProcessPaintOpBuffer");
// This cannot be done async if the recording contains a GPU accelerated
// image.
@@ -297,7 +298,8 @@ void PaintPreviewRecorderImpl::CapturePaintPreviewInternal(
base::TimeTicks start_time = base::TimeTicks::Now();
TRACE_EVENT_BEGIN0("paint_preview", "WebLocalFrame::CapturePaintPreview");
bool success = frame->CapturePaintPreview(
- bounds, canvas, /*include_linked_destinations=*/params->capture_links);
+ bounds, canvas, /*include_linked_destinations=*/params->capture_links,
+ /*skip_accelerated_content=*/params->skip_accelerated_content);
TRACE_EVENT_END0("paint_preview", "WebLocalFrame::CapturePaintPreview");
canvas->restore();
base::TimeDelta capture_time = base::TimeTicks::Now() - start_time;
@@ -330,17 +332,20 @@ void PaintPreviewRecorderImpl::CapturePaintPreviewInternal(
return;
}
- // Convert the special value |0| to |base::nullopt|.
- base::Optional<size_t> max_capture_size;
+ // Convert the special value |0| to |absl::nullopt|.
+ absl::optional<size_t> max_capture_size;
if (params->max_capture_size == 0) {
- max_capture_size = base::nullopt;
+ max_capture_size = absl::nullopt;
} else {
max_capture_size = params->max_capture_size;
auto* image_ctx = tracker->GetImageSerializationContext();
image_ctx->remaining_image_size = params->max_capture_size;
- image_ctx->max_representation_size = params->max_capture_size;
}
+ auto* image_ctx = tracker->GetImageSerializationContext();
+ image_ctx->max_decoded_image_size_bytes =
+ params->max_decoded_image_size_bytes;
+
FinishRecordingOnUIThread(recorder.finishRecordingAsPicture(), bounds,
std::move(tracker), params->persistence,
std::move(params->file), max_capture_size,
diff --git a/chromium/components/paint_preview/renderer/paint_preview_recorder_utils.cc b/chromium/components/paint_preview/renderer/paint_preview_recorder_utils.cc
index b9f9fb794ac..e4ec8a5a186 100644
--- a/chromium/components/paint_preview/renderer/paint_preview_recorder_utils.cc
+++ b/chromium/components/paint_preview/renderer/paint_preview_recorder_utils.cc
@@ -9,9 +9,8 @@
#include "base/bind.h"
#include "base/trace_event/common/trace_event_common.h"
#include "base/trace_event/trace_event.h"
-#include "cc/paint/draw_image.h"
-#include "cc/paint/image_provider.h"
#include "cc/paint/paint_image.h"
+#include "cc/paint/paint_image_builder.h"
#include "components/paint_preview/common/file_stream.h"
#include "components/paint_preview/common/paint_preview_tracker.h"
#include "mojo/public/cpp/base/shared_memory_utils.h"
@@ -20,8 +19,37 @@
namespace paint_preview {
-void ParseGlyphsAndLinks(const cc::PaintOpBuffer* buffer,
- PaintPreviewTracker* tracker) {
+namespace {
+
+// Converts a texture backed paint image in the PaintOpBuffer to one that is not
+// texture backed.
+cc::PaintImage MakeUnaccelerated(cc::PaintImage& paint_image) {
+ DCHECK(paint_image.IsTextureBacked());
+ auto sk_image = paint_image.GetSwSkImage();
+ if (sk_image->isLazyGenerated()) {
+ // Texture backed images should always be returned as SkImage_Raster type
+ // (bitmap). This is just a catchall in the event a lazy image is somehow
+ // returned in which case we should just raster it.
+ SkBitmap bitmap;
+ bitmap.allocPixels(sk_image->imageInfo(),
+ sk_image->imageInfo().minRowBytes());
+ if (!sk_image->readPixels(bitmap.pixmap(), 0, 0)) {
+ return paint_image;
+ }
+ // Make immutable to skip an extra copy.
+ bitmap.setImmutable();
+ sk_image = SkImage::MakeFromBitmap(bitmap);
+ }
+ return cc::PaintImageBuilder::WithDefault()
+ .set_id(cc::PaintImage::GetNextId())
+ .set_image(sk_image, cc::PaintImage::GetNextContentId())
+ .TakePaintImage();
+}
+
+} // namespace
+
+void PreProcessPaintOpBuffer(const cc::PaintOpBuffer* buffer,
+ PaintPreviewTracker* tracker) {
for (cc::PaintOpBuffer::Iterator it(buffer); it; ++it) {
switch (it->GetType()) {
case cc::PaintOpType::DrawTextBlob: {
@@ -33,7 +61,7 @@ void ParseGlyphsAndLinks(const cc::PaintOpBuffer* buffer,
// Recurse into nested records if they contain text blobs (equivalent to
// nested SkPictures).
auto* record_op = static_cast<cc::DrawRecordOp*>(*it);
- ParseGlyphsAndLinks(record_op->record.get(), tracker);
+ PreProcessPaintOpBuffer(record_op->record.get(), tracker);
break;
}
case cc::PaintOpType::Annotate: {
@@ -92,33 +120,26 @@ void ParseGlyphsAndLinks(const cc::PaintOpBuffer* buffer,
tracker->Translate(translate_op->dx, translate_op->dy);
break;
}
+ case cc::PaintOpType::DrawImage: {
+ auto* image_op = static_cast<cc::DrawImageOp*>(*it);
+ if (image_op->image.IsTextureBacked()) {
+ image_op->image = MakeUnaccelerated(image_op->image);
+ }
+ break;
+ }
+ case cc::PaintOpType::DrawImageRect: {
+ auto* image_op = static_cast<cc::DrawImageRectOp*>(*it);
+ if (image_op->image.IsTextureBacked()) {
+ image_op->image = MakeUnaccelerated(image_op->image);
+ }
+ break;
+ }
default:
continue;
}
}
}
-class SkPictureImageProvider : public cc::ImageProvider {
- public:
- SkPictureImageProvider() = default;
- ~SkPictureImageProvider() override = default;
-
- SkPictureImageProvider& operator=(const SkPictureImageProvider&) = delete;
- SkPictureImageProvider& operator=(SkPictureImageProvider&& other);
-
- // Converts GPU accelerated content into software rastered content using
- // GetSwSkImage().
- cc::ImageProvider::ScopedResult GetRasterContent(
- const cc::DrawImage& draw_image) override {
- const cc::PaintImage& paint_image = draw_image.paint_image();
- return cc::ImageProvider::ScopedResult(cc::DecodedDrawImage(
- paint_image.GetSwSkImage(), /*dark_mode_color_filter=*/nullptr,
- /*src_rect_offset=*/SkSize::Make(0, 0),
- /*scale_adjustment=*/SkSize::Make(1.f, 1.f),
- draw_image.filter_quality(), /*is_budgeted=*/true));
- }
-};
-
sk_sp<const SkPicture> PaintRecordToSkPicture(
sk_sp<const cc::PaintRecord> recording,
PaintPreviewTracker* tracker,
@@ -129,10 +150,9 @@ sk_sp<const SkPicture> PaintRecordToSkPicture(
base::BindRepeating(&PaintPreviewTracker::CustomDataToSkPictureCallback,
base::Unretained(tracker));
- SkPictureImageProvider raster_accelerated_images;
auto skp =
ToSkPicture(recording, SkRect::MakeWH(bounds.width(), bounds.height()),
- &raster_accelerated_images, custom_callback);
+ nullptr, custom_callback);
if (!skp || skp->cullRect().width() == 0 || skp->cullRect().height() == 0)
return nullptr;
@@ -141,18 +161,11 @@ sk_sp<const SkPicture> PaintRecordToSkPicture(
}
void BuildResponse(PaintPreviewTracker* tracker,
- mojom::PaintPreviewCaptureResponse* response,
- bool log) {
+ mojom::PaintPreviewCaptureResponse* response) {
// Ensure these always exist.
DCHECK(tracker);
DCHECK(response);
- // paint_preview::BuildResponse has been showing in a large number of crashes
- // under stack scans. In order to determine if these entries are "real" we
- // should log the calls and check the log output.
- if (log)
- LOG(WARNING) << "paint_preview::BuildResponse() called";
-
response->embedding_token = tracker->EmbeddingToken();
tracker->MoveLinks(&response->links);
diff --git a/chromium/components/paint_preview/renderer/paint_preview_recorder_utils.h b/chromium/components/paint_preview/renderer/paint_preview_recorder_utils.h
index adfab3e0e99..47ddf3dff2a 100644
--- a/chromium/components/paint_preview/renderer/paint_preview_recorder_utils.h
+++ b/chromium/components/paint_preview/renderer/paint_preview_recorder_utils.h
@@ -21,10 +21,13 @@ namespace paint_preview {
class PaintPreviewTracker;
-// Walks |buffer| to extract all the glyphs from its text blobs and links. The
-// extracted data is written to to |tracker|.
-void ParseGlyphsAndLinks(const cc::PaintOpBuffer* buffer,
- PaintPreviewTracker* tracker);
+// Pre processes the PaintOpBuffer prior to conversion to SkPicture.
+// 1. Walks |buffer| to extract all the glyphs from its text blobs and links.
+// The extracted data is written to `tracker`.
+// 2. Tracks geometry changes for frames and saves them to `tracker`.
+// 3. Unaccelerates GPU accelerated PaintImages.
+void PreProcessPaintOpBuffer(const cc::PaintOpBuffer* buffer,
+ PaintPreviewTracker* tracker);
// Convert |recording| into an SkPicture, tracking embedded content. Will return
// |nullptr| if the resulting picture failed or zero sized.
@@ -35,8 +38,7 @@ sk_sp<const SkPicture> PaintRecordToSkPicture(
// NOTE: |tracker| is effectively const here despite being passed by pointer.
void BuildResponse(PaintPreviewTracker* tracker,
- mojom::PaintPreviewCaptureResponse* response,
- bool log = false);
+ mojom::PaintPreviewCaptureResponse* response);
} // namespace paint_preview
diff --git a/chromium/components/paint_preview/renderer/paint_preview_recorder_utils_unittest.cc b/chromium/components/paint_preview/renderer/paint_preview_recorder_utils_unittest.cc
index 19a10d21c71..532e18b3989 100644
--- a/chromium/components/paint_preview/renderer/paint_preview_recorder_utils_unittest.cc
+++ b/chromium/components/paint_preview/renderer/paint_preview_recorder_utils_unittest.cc
@@ -14,12 +14,14 @@
#include "base/memory/discardable_memory_allocator.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/notreached.h"
-#include "base/optional.h"
#include "base/test/test_discardable_memory_allocator.h"
#include "base/unguessable_token.h"
#include "cc/paint/paint_canvas.h"
#include "cc/paint/paint_flags.h"
+#include "cc/paint/paint_image.h"
+#include "cc/paint/paint_image_builder.h"
#include "cc/paint/paint_recorder.h"
+#include "cc/paint/paint_worklet_input.h"
#include "components/paint_preview/common/file_stream.h"
#include "components/paint_preview/common/mojom/paint_preview_recorder.mojom-shared.h"
#include "components/paint_preview/common/paint_preview_tracker.h"
@@ -28,6 +30,7 @@
#include "mojo/public/cpp/base/big_buffer.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/skia/include/core/SkFont.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkTextBlob.h"
@@ -68,7 +71,7 @@ TEST(PaintPreviewRecorderUtilsTest, TestParseGlyphs) {
PaintPreviewTracker tracker(base::UnguessableToken::Create(),
base::UnguessableToken::Create(), true);
- ParseGlyphsAndLinks(record.get(), &tracker);
+ PreProcessPaintOpBuffer(record.get(), &tracker);
auto* usage_map = tracker.GetTypefaceUsageMap();
EXPECT_TRUE(usage_map->count(typeface->uniqueID()));
EXPECT_TRUE(
@@ -129,7 +132,7 @@ TEST(PaintPreviewRecorderUtilsTest, TestParseLinks) {
PaintPreviewTracker tracker(base::UnguessableToken::Create(),
base::UnguessableToken::Create(), true);
- ParseGlyphsAndLinks(record.get(), &tracker);
+ PreProcessPaintOpBuffer(record.get(), &tracker);
std::vector<mojom::LinkDataPtr> links;
tracker.MoveLinks(&links);
@@ -184,7 +187,7 @@ TEST(PaintPreviewRecorderUtilsTest, TestTransformSubframeRects) {
EXPECT_EQ(rect.width(), old_cull_rect.width());
EXPECT_EQ(rect.height(), old_cull_rect.height());
- ParseGlyphsAndLinks(record.get(), &tracker);
+ PreProcessPaintOpBuffer(record.get(), &tracker);
auto* picture_ctx = tracker.GetPictureSerializationContext();
ASSERT_EQ(picture_ctx->content_id_to_transformed_clip.size(), 1U);
@@ -218,26 +221,20 @@ class PaintPreviewRecorderUtilsSerializeAsSkPictureTest
cc::PaintFlags flags;
canvas->drawRect(SkRect::MakeWH(dimensions.width(), dimensions.height()),
flags);
- SkBitmap bitmap;
- bitmap.allocN32Pixels(dimensions.width(), dimensions.height());
- {
- SkCanvas sk_canvas(bitmap);
- sk_canvas.drawColor(SK_ColorRED);
- }
- canvas->drawImage(cc::PaintImage::CreateFromBitmap(bitmap), 0, 0);
}
void TearDown() override {
base::DiscardableMemoryAllocator::SetInstance(nullptr);
}
- base::Optional<SerializedRecording> SerializeAsSkPicture(
- base::Optional<size_t> max_capture_size,
+ absl::optional<SerializedRecording> SerializeAsSkPicture(
+ absl::optional<size_t> max_capture_size,
size_t* serialized_size) {
- auto skp = PaintRecordToSkPicture(recorder.finishRecordingAsPicture(),
- &tracker, dimensions);
+ auto recording = recorder.finishRecordingAsPicture();
+ PreProcessPaintOpBuffer(recording.get(), &tracker);
+ auto skp = PaintRecordToSkPicture(recording, &tracker, dimensions);
if (!skp)
- return base::nullopt;
+ return absl::nullopt;
canvas = nullptr;
@@ -245,30 +242,30 @@ class PaintPreviewRecorderUtilsSerializeAsSkPictureTest
case RecordingPersistence::kFileSystem: {
base::ScopedTempDir temp_dir;
if (!temp_dir.CreateUniqueTempDir())
- return base::nullopt;
+ return absl::nullopt;
base::FilePath file_path = temp_dir.GetPath().AppendASCII("test_file");
base::File write_file(
file_path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
if (!RecordToFile(std::move(write_file), skp, &tracker,
max_capture_size, serialized_size))
- return base::nullopt;
+ return absl::nullopt;
return {SerializedRecording(file_path)};
} break;
case RecordingPersistence::kMemoryBuffer: {
- base::Optional<mojo_base::BigBuffer> buffer =
+ absl::optional<mojo_base::BigBuffer> buffer =
RecordToBuffer(skp, &tracker, max_capture_size, serialized_size);
if (!buffer.has_value())
- return base::nullopt;
+ return absl::nullopt;
return {SerializedRecording(std::move(buffer.value()))};
} break;
}
NOTREACHED();
- return base::nullopt;
+ return absl::nullopt;
}
PaintPreviewTracker tracker;
@@ -298,16 +295,36 @@ TEST_P(PaintPreviewRecorderUtilsSerializeAsSkPictureTest, Roundtrip) {
ctx.insert(content_id);
size_t out_size = 0;
- auto recording = SerializeAsSkPicture(base::nullopt, &out_size);
+ auto recording = SerializeAsSkPicture(absl::nullopt, &out_size);
ASSERT_TRUE(recording.has_value());
- base::Optional<SkpResult> result = std::move(recording.value()).Deserialize();
+ absl::optional<SkpResult> result = std::move(recording.value()).Deserialize();
ASSERT_TRUE(result.has_value());
for (auto& content_id : ctx) {
EXPECT_TRUE(result->ctx.contains(content_id));
result->ctx.erase(content_id);
}
EXPECT_TRUE(result->ctx.empty());
+}
+
+TEST_P(PaintPreviewRecorderUtilsSerializeAsSkPictureTest, RoundtripWithImage) {
+ {
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(dimensions.width(), dimensions.height());
+ SkCanvas sk_canvas(bitmap);
+ sk_canvas.drawColor(SK_ColorRED);
+ cc::PaintImage paint_image = cc::PaintImage::CreateFromBitmap(bitmap);
+ ASSERT_FALSE(paint_image.IsLazyGenerated());
+ ASSERT_FALSE(paint_image.IsPaintWorklet());
+ canvas->drawImage(paint_image, 0U, 0U);
+ }
+
+ size_t out_size = 0;
+ auto recording = SerializeAsSkPicture(absl::nullopt, &out_size);
+ ASSERT_TRUE(recording.has_value());
+
+ absl::optional<SkpResult> result = std::move(recording.value()).Deserialize();
+ ASSERT_TRUE(result.has_value());
SkBitmap bitmap;
bitmap.allocN32Pixels(dimensions.width(), dimensions.height());
@@ -316,6 +333,179 @@ TEST_P(PaintPreviewRecorderUtilsSerializeAsSkPictureTest, Roundtrip) {
EXPECT_EQ(bitmap.getColor(10, 10), SK_ColorRED);
}
+class FakeTextureBacking : public cc::TextureBacking {
+ public:
+ explicit FakeTextureBacking(sk_sp<SkImage> image) : image_(image) {}
+
+ const SkImageInfo& GetSkImageInfo() override { return image_->imageInfo(); }
+ gpu::Mailbox GetMailbox() const override { return mailbox_; }
+ sk_sp<SkImage> GetAcceleratedSkImage() override { return nullptr; }
+ sk_sp<SkImage> GetSkImageViaReadback() override { return image_; }
+ bool readPixels(const SkImageInfo& dstInfo,
+ void* dstPixels,
+ size_t dstRowBytes,
+ int srcX,
+ int srcY) override {
+ return false;
+ }
+ void FlushPendingSkiaOps() override {}
+
+ private:
+ gpu::Mailbox mailbox_;
+ sk_sp<SkImage> image_;
+};
+
+TEST_P(PaintPreviewRecorderUtilsSerializeAsSkPictureTest,
+ RoundtripWithTexture) {
+ {
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(dimensions.width(), dimensions.height());
+ SkCanvas sk_canvas(bitmap);
+ sk_canvas.drawColor(SK_ColorRED);
+ cc::PaintImage paint_image =
+ cc::PaintImageBuilder::WithDefault()
+ .set_id(cc::PaintImage::GetNextId())
+ .set_texture_backing(
+ sk_sp<FakeTextureBacking>(
+ new FakeTextureBacking(SkImage::MakeFromBitmap(bitmap))),
+ cc::PaintImage::GetNextContentId())
+ .TakePaintImage();
+ canvas->drawImage(paint_image, 0U, 0U);
+ }
+
+ size_t out_size = 0;
+ auto recording = SerializeAsSkPicture(absl::nullopt, &out_size);
+ ASSERT_TRUE(recording.has_value());
+
+ absl::optional<SkpResult> result = std::move(recording.value()).Deserialize();
+ ASSERT_TRUE(result.has_value());
+
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(dimensions.width(), dimensions.height());
+ SkCanvas sk_canvas(bitmap);
+ sk_canvas.drawPicture(result->skp);
+ EXPECT_EQ(bitmap.getColor(10, 10), SK_ColorRED);
+}
+
+TEST_P(PaintPreviewRecorderUtilsSerializeAsSkPictureTest,
+ RoundtripWithLazyTexture) {
+ {
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(dimensions.width(), dimensions.height());
+ SkCanvas sk_canvas(bitmap);
+ sk_canvas.drawColor(SK_ColorRED);
+ auto sk_image = SkImage::MakeFromBitmap(bitmap);
+ auto data = sk_image->encodeToData();
+ auto lazy_sk_image = SkImage::MakeFromEncoded(data);
+ ASSERT_TRUE(lazy_sk_image->isLazyGenerated());
+ cc::PaintImage paint_image =
+ cc::PaintImageBuilder::WithDefault()
+ .set_id(cc::PaintImage::GetNextId())
+ .set_texture_backing(sk_sp<FakeTextureBacking>(
+ new FakeTextureBacking(lazy_sk_image)),
+ cc::PaintImage::GetNextContentId())
+ .TakePaintImage();
+ cc::PaintFlags paint;
+ paint.setBlendMode(SkBlendMode::kSrc);
+ auto rect = SkRect::MakeWH(dimensions.width(), dimensions.height());
+ canvas->drawImageRect(paint_image, rect, rect, SkSamplingOptions(), &paint,
+ SkCanvas::kStrict_SrcRectConstraint);
+ }
+
+ size_t out_size = 0;
+ auto recording = SerializeAsSkPicture(absl::nullopt, &out_size);
+ ASSERT_TRUE(recording.has_value());
+
+ absl::optional<SkpResult> result = std::move(recording.value()).Deserialize();
+ ASSERT_TRUE(result.has_value());
+
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(dimensions.width(), dimensions.height());
+ SkCanvas sk_canvas(bitmap);
+ sk_canvas.drawPicture(result->skp);
+ EXPECT_EQ(bitmap.getColor(10, 10), SK_ColorRED);
+}
+
+TEST_P(PaintPreviewRecorderUtilsSerializeAsSkPictureTest,
+ RoundtripWithLazyImage) {
+ {
+ cc::PaintRecorder inner_recorder;
+ cc::PaintCanvas* inner_canvas =
+ inner_recorder.beginRecording(dimensions.width(), dimensions.width());
+ inner_canvas->drawColor(SK_ColorRED);
+ cc::PaintImage paint_image =
+ cc::PaintImageBuilder::WithDefault()
+ .set_id(1)
+ .set_paint_record(inner_recorder.finishRecordingAsPicture(),
+ dimensions, cc::PaintImage::GetNextContentId())
+ .TakePaintImage();
+ ASSERT_TRUE(paint_image.IsLazyGenerated());
+ ASSERT_FALSE(paint_image.IsPaintWorklet());
+ canvas->drawImage(paint_image, 0U, 0U);
+ }
+
+ size_t out_size = 0;
+ auto recording = SerializeAsSkPicture(absl::nullopt, &out_size);
+ ASSERT_TRUE(recording.has_value());
+
+ absl::optional<SkpResult> result = std::move(recording.value()).Deserialize();
+ ASSERT_TRUE(result.has_value());
+
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(dimensions.width(), dimensions.height());
+ SkCanvas sk_canvas(bitmap);
+ sk_canvas.drawPicture(result->skp);
+ EXPECT_EQ(bitmap.getColor(10, 10), SK_ColorRED);
+}
+
+class TestPaintWorkletInput : public cc::PaintWorkletInput {
+ public:
+ explicit TestPaintWorkletInput(const gfx::SizeF& size)
+ : container_size_(size) {}
+
+ gfx::SizeF GetSize() const override { return container_size_; }
+ int WorkletId() const override { return 1U; }
+ const std::vector<PaintWorkletInput::PropertyKey>& GetPropertyKeys()
+ const override {
+ return property_keys_;
+ }
+
+ protected:
+ ~TestPaintWorkletInput() override = default;
+
+ private:
+ gfx::SizeF container_size_;
+ std::vector<PaintWorkletInput::PropertyKey> property_keys_;
+};
+
+TEST_P(PaintPreviewRecorderUtilsSerializeAsSkPictureTest,
+ RoundtripWithPaintWorklet) {
+ {
+ gfx::SizeF size(100, 50);
+ scoped_refptr<TestPaintWorkletInput> input =
+ base::MakeRefCounted<TestPaintWorkletInput>(size);
+ cc::PaintImage paint_image = cc::PaintImageBuilder::WithDefault()
+ .set_id(1)
+ .set_paint_worklet_input(std::move(input))
+ .TakePaintImage();
+ ASSERT_FALSE(paint_image.IsLazyGenerated());
+ ASSERT_TRUE(paint_image.IsPaintWorklet());
+ cc::PaintFlags paint;
+ paint.setBlendMode(SkBlendMode::kSrc);
+ auto rect = SkRect::MakeWH(dimensions.width(), dimensions.height());
+ canvas->drawImageRect(paint_image, rect, rect, SkSamplingOptions(), &paint,
+ SkCanvas::kStrict_SrcRectConstraint);
+ }
+
+ size_t out_size = 0;
+ auto recording = SerializeAsSkPicture(absl::nullopt, &out_size);
+ // The paint worklet needs to be skipped. Just make sure it doesn't crash.
+ ASSERT_TRUE(recording.has_value());
+
+ absl::optional<SkpResult> result = std::move(recording.value()).Deserialize();
+ ASSERT_TRUE(result.has_value());
+}
+
TEST_P(PaintPreviewRecorderUtilsSerializeAsSkPictureTest, FailIfExceedMaxSize) {
size_t out_size = 2;
auto recording = SerializeAsSkPicture({1}, &out_size);