Commit ec2d4b94 authored by Tanya Gupta's avatar Tanya Gupta Committed by Commit Bot

[LongScreenshots] Fleshed out LongScreenshots tab service more.

Added logic to call FDT in the tab service to capture the bitmap.

Change-Id: I9c0e01641b6393ded8227e82fddd0b63c895e45e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2533327Reviewed-by: default avatarKyle Milka <kmilka@chromium.org>
Reviewed-by: default avatarCalder Kitagawa <ckitagawa@chromium.org>
Commit-Queue: Tanya Gupta <tgupta@chromium.org>
Cr-Commit-Position: refs/heads/master@{#827965}
parent 972ec6fc
......@@ -13,5 +13,6 @@ source_set("services") {
deps = [
"//components/keyed_service/core",
"//components/paint_preview/browser",
"//components/paint_preview/common/mojom",
]
}
include_rules = [
"+components/paint_preview/common",
"+components/paint_preview/public",
"+components/services/paint_preview_compositor/public/mojom",
]
\ No newline at end of file
......@@ -5,15 +5,22 @@
#include "chrome/browser/long_screenshots/long_screenshots_tab_service.h"
#include "base/callback.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/memory/memory_pressure_monitor.h"
#include "components/paint_preview/browser/file_manager.h"
namespace long_screenshots {
namespace {
// TODO(tgupta): Evaluate whether this is the right size.
constexpr size_t kMaxPerCaptureSizeBytes = 5 * 1000L * 1000L; // 5 MB.
} // namespace
LongScreenshotsTabService::LongScreenshotsTabService(
const base::FilePath& profile_dir,
base::StringPiece ascii_feature_name,
std::unique_ptr<paint_preview::PaintPreviewPolicy> policy,
bool is_off_the_record)
: PaintPreviewBaseService(profile_dir,
ascii_feature_name,
std::move(policy),
......@@ -28,7 +35,32 @@ LongScreenshotsTabService::~LongScreenshotsTabService() {
void LongScreenshotsTabService::CaptureTab(int tab_id,
content::WebContents* contents,
FinishedCallback callback) {
// TODO(tgupta): Populate this.
// If the system is under memory pressure don't try to capture.
auto* memory_monitor = base::MemoryPressureMonitor::Get();
if (memory_monitor &&
memory_monitor->GetCurrentPressureLevel() >=
base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE) {
// TODO(tgupta): Consider returning a callback with an error message.
return;
}
// Mark |contents| as being captured so that the renderer doesn't go away
// until the capture is finished. This is done even before a file is created
// to ensure the renderer doesn't go away while that happens.
contents->IncrementCapturerCount(gfx::Size(), true);
auto file_manager = GetFileManager();
auto key = file_manager->CreateKey(tab_id);
GetTaskRunner()->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&paint_preview::FileManager::CreateOrGetDirectory,
GetFileManager(), key, true),
// TODO(tgupta): Check for AMP pages here and get the right node id.
base::BindOnce(&LongScreenshotsTabService::CaptureTabInternal,
weak_ptr_factory_.GetWeakPtr(), tab_id, key,
contents->GetMainFrame()->GetFrameTreeNodeId(),
contents->GetMainFrame()->GetGlobalFrameRoutingId(),
std::move(callback)));
}
void LongScreenshotsTabService::CaptureTabInternal(
......@@ -38,7 +70,31 @@ void LongScreenshotsTabService::CaptureTabInternal(
content::GlobalFrameRoutingId frame_routing_id,
FinishedCallback callback,
const base::Optional<base::FilePath>& file_path) {
// TODO(tgupta): Complete this function
if (!file_path.has_value()) {
std::move(callback).Run(Status::kDirectoryCreationFailed);
return;
}
auto* contents =
content::WebContents::FromFrameTreeNodeId(frame_tree_node_id);
// There is a small chance RenderFrameHost may be destroyed when the UI thread
// is used to create the directory. By doing a lookup for the RenderFrameHost
// and comparing it to the WebContent, we can ensure that the content is still
// available for capture and WebContents::GetMainFrame did not return a
// defunct pointer.
auto* rfh = content::RenderFrameHost::FromID(frame_routing_id);
if (!contents || !rfh || contents->IsBeingDestroyed() ||
contents->GetMainFrame() != rfh || !rfh->IsCurrent()) {
std::move(callback).Run(Status::kWebContentsGone);
return;
}
// TODO(tgupta): Modify this call to specify the size of the capture rather
// than the whole area.
CapturePaintPreview(
contents, file_path.value(), gfx::Rect(), true, kMaxPerCaptureSizeBytes,
base::BindOnce(&LongScreenshotsTabService::OnCaptured,
weak_ptr_factory_.GetWeakPtr(), tab_id, key,
frame_tree_node_id, std::move(callback)));
}
void LongScreenshotsTabService::OnCaptured(
......@@ -48,7 +104,14 @@ void LongScreenshotsTabService::OnCaptured(
FinishedCallback callback,
paint_preview::PaintPreviewBaseService::CaptureStatus status,
std::unique_ptr<paint_preview::CaptureResult> result) {
// TODO(tgupta): Populate this.
// TODO(tgupta): Continue to flesh this out to manage the documents. Consider
// having more detailed status messages to return to the caller.
if (status != PaintPreviewBaseService::CaptureStatus::kOk ||
!result->capture_success) {
std::move(callback).Run(Status::kCaptureFailed);
return;
}
std::move(callback).Run(Status::kOk);
}
void LongScreenshotsTabService::OnFinished(int tab_id,
......
......@@ -24,7 +24,8 @@ class WebContents;
namespace long_screenshots {
// A service for capturing Long Screenshots using PaintPreview.
// A service for capturing Long Screenshots using PaintPreview. Writes the
// retrieved bitmap to file.
class LongScreenshotsTabService
: public paint_preview::PaintPreviewBaseService {
public:
......@@ -53,7 +54,9 @@ class LongScreenshotsTabService
FinishedCallback callback);
private:
// The FTN ID is to look-up the content::WebContents.
// Retrieves the content::WebContents from the |frame_tree_node_id|
// (confirming that the contents are alive using the |frame_routing_id|).
// Calls PaintPreviewBaseService to retrieve the bitmap and write it to file.
void CaptureTabInternal(int tab_id,
const paint_preview::DirectoryKey& key,
int frame_tree_node_id,
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/long_screenshots/long_screenshots_tab_service.h"
#include <memory>
#include <utility>
#include <vector>
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/test/task_environment.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "components/paint_preview/common/mojom/paint_preview_recorder.mojom.h"
#include "content/public/test/navigation_simulator.h"
#include "content/public/test/test_utils.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
namespace long_screenshots {
namespace {
constexpr char kFeatureName[] = "tab_service_test";
// Override PaintPreviewRecorder with a mock version where the status and
// response can be manipulated based on the expected response.
class MockPaintPreviewRecorder
: public paint_preview::mojom::PaintPreviewRecorder {
public:
MockPaintPreviewRecorder() = default;
~MockPaintPreviewRecorder() override = default;
MockPaintPreviewRecorder(const MockPaintPreviewRecorder&) = delete;
MockPaintPreviewRecorder& operator=(const MockPaintPreviewRecorder&) = delete;
void CapturePaintPreview(
paint_preview::mojom::PaintPreviewCaptureParamsPtr params,
paint_preview::mojom::PaintPreviewRecorder::CapturePaintPreviewCallback
callback) override {
std::move(callback).Run(
status_, paint_preview::mojom::PaintPreviewCaptureResponse::New());
}
void SetResponse(paint_preview::mojom::PaintPreviewStatus status) {
status_ = status;
}
void BindRequest(mojo::ScopedInterfaceEndpointHandle handle) {
binding_.Bind(
mojo::PendingAssociatedReceiver<
paint_preview::mojom::PaintPreviewRecorder>(std::move(handle)));
}
private:
paint_preview::mojom::PaintPreviewStatus status_;
mojo::AssociatedReceiver<paint_preview::mojom::PaintPreviewRecorder> binding_{
this};
};
} // namespace
class LongScreenshotsTabServiceTest : public ChromeRenderViewHostTestHarness {
public:
LongScreenshotsTabServiceTest()
: ChromeRenderViewHostTestHarness(
base::test::TaskEnvironment::TimeSource::MOCK_TIME,
base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED) {}
~LongScreenshotsTabServiceTest() override = default;
LongScreenshotsTabServiceTest(const LongScreenshotsTabServiceTest&) = delete;
LongScreenshotsTabServiceTest& operator=(
const LongScreenshotsTabServiceTest&) = delete;
protected:
void SetUp() override {
ChromeRenderViewHostTestHarness::SetUp();
NavigateAndCommit(GURL("https://www.example.com/"),
ui::PageTransition::PAGE_TRANSITION_FIRST);
task_environment()->RunUntilIdle();
EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
service_ = std::make_unique<LongScreenshotsTabService>(
temp_dir_.GetPath(), kFeatureName, nullptr, false);
task_environment()->RunUntilIdle();
}
void TearDown() override { ChromeRenderViewHostTestHarness::TearDown(); }
LongScreenshotsTabService* GetService() { return service_.get(); }
void OverrideInterface(MockPaintPreviewRecorder* recorder) {
blink::AssociatedInterfaceProvider* remote_interfaces =
web_contents()->GetMainFrame()->GetRemoteAssociatedInterfaces();
remote_interfaces->OverrideBinderForTesting(
paint_preview::mojom::PaintPreviewRecorder::Name_,
base::BindRepeating(&MockPaintPreviewRecorder::BindRequest,
base::Unretained(recorder)));
}
const base::FilePath& GetPath() const { return temp_dir_.GetPath(); }
private:
std::unique_ptr<LongScreenshotsTabService> service_;
base::ScopedTempDir temp_dir_;
};
// Test a successful capturing of a tab.
TEST_F(LongScreenshotsTabServiceTest, CaptureTab) {
const int kTabId = 1U;
MockPaintPreviewRecorder recorder;
recorder.SetResponse(paint_preview::mojom::PaintPreviewStatus::kOk);
OverrideInterface(&recorder);
auto* service = GetService();
service->CaptureTab(
kTabId, web_contents(),
base::BindOnce([](LongScreenshotsTabService::Status status) {
EXPECT_EQ(status, LongScreenshotsTabService::Status::kOk);
}));
task_environment()->RunUntilIdle();
auto file_manager = service->GetFileManager();
auto key = file_manager->CreateKey(kTabId);
service->GetTaskRunner()->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&paint_preview::FileManager::DirectoryExists, file_manager,
key),
base::BindOnce([](bool exists) { EXPECT_TRUE(exists); }));
task_environment()->RunUntilIdle();
}
// Test when PaintPreviewRecorder returns a failure status code.
TEST_F(LongScreenshotsTabServiceTest, CaptureTabFailed) {
const int kTabId = 1U;
MockPaintPreviewRecorder recorder;
recorder.SetResponse(paint_preview::mojom::PaintPreviewStatus::kFailed);
OverrideInterface(&recorder);
auto* service = GetService();
service->CaptureTab(
kTabId, web_contents(),
base::BindOnce([](LongScreenshotsTabService::Status status) {
EXPECT_EQ(status, LongScreenshotsTabService::Status::kCaptureFailed);
}));
task_environment()->RunUntilIdle();
}
} // namespace long_screenshots
......@@ -3463,6 +3463,7 @@ test("unit_tests") {
"../browser/lite_video/lite_video_navigation_metrics_unittest.cc",
"../browser/lite_video/lite_video_user_blocklist_unittest.cc",
"../browser/logging_chrome_unittest.cc",
"../browser/long_screenshots/long_screenshots_tab_service_unittest.cc",
"../browser/media/history/media_history_keyed_service_unittest.cc",
"../browser/media/history/media_history_store_unittest.cc",
"../browser/media/media_engagement_contents_observer_unittest.cc",
......@@ -4120,6 +4121,7 @@ test("unit_tests") {
"//chrome:child_dependencies",
"//chrome:resources",
"//chrome:strings",
"//chrome/browser/long_screenshots:services",
"//chrome/browser/media/router:unittests",
"//chrome/browser/notifications:unit_tests",
"//chrome/browser/payments:unittests",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment