blob: 81a7b5f03c3031a5ea414ecb4c7027aa21abf4c1 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_PAINT_PREVIEW_BROWSER_PAINT_PREVIEW_BASE_SERVICE_H_
#define COMPONENTS_PAINT_PREVIEW_BROWSER_PAINT_PREVIEW_BASE_SERVICE_H_
#include <memory>
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "base/unguessable_token.h"
#include "build/build_config.h"
#include "components/paint_preview/browser/paint_preview_file_mixin.h"
#include "components/paint_preview/browser/paint_preview_policy.h"
#include "components/paint_preview/common/capture_result.h"
#include "components/paint_preview/common/file_utils.h"
#include "components/paint_preview/common/mojom/paint_preview_recorder.mojom.h"
#include "components/paint_preview/common/mojom/paint_preview_types.mojom.h"
#include "components/paint_preview/common/proto/paint_preview.pb.h"
#include "components/paint_preview/common/redaction_params.h"
#include "components/paint_preview/common/serialized_recording.h"
#include "content/public/browser/web_contents.h"
namespace paint_preview {
// A base class that serves as the Public API for Paint Previews.
// Features that want to use Paint Previews should extend this class.
// This service supports both in-memery and in-file captures.
//
// The KeyedService provides a 1:1 mapping between the service and a key or
// profile allowing each feature built on Paint Previews to reliably store
// necessary data to the right directory on disk.
//
// [NOTE] for file system captures:
// - PaintPreviewFileMixin object needs to be supplied.
// - Implementations of the service should be created by implementing a factory
// that extends one of:
// - BrowserContextKeyedServiceFactory
// OR preferably the
// - SimpleKeyedServiceFactory
class PaintPreviewBaseService : public KeyedService {
public:
enum class CaptureStatus : int {
kOk = 0,
kContentUnsupported,
kClientCreationFailed,
kCaptureFailed,
};
struct CaptureParams {
CaptureParams();
CaptureParams(const CaptureParams&);
CaptureParams& operator=(const CaptureParams&);
CaptureParams(CaptureParams&&);
CaptureParams& operator=(CaptureParams&&);
raw_ptr<content::WebContents> web_contents = nullptr;
// In case of specifying, an individual |render_frame_host| and its
// descendents will be captured. In case of nullptr, full page contents will
// be captured.
//
// Generally, leaving this as nullptr is what you should be doing for most
// features. Specifying a |render_frame_host| is intended for capturing
// individual subframes and should be used for only a few use cases.
raw_ptr<content::RenderFrameHost> render_frame_host = nullptr;
// Store artifacts in the file system or in memory buffers.
RecordingPersistence persistence;
// |root_dir| should be created using
// GetFileManager()->CreateOrGetDirectoryFor(). However, to provide
// flexibility in managing the lifetime of created objects and ease cleanup
// if a capture fails the service implementation is responsible for
// implementing this management and tracking the directories in existence.
// Data in a directory will contain:
// - a number of SKPs listed as <guid>.skp (one per frame)
//
// Will be ignored if persistence = kMemoryBuffer
raw_ptr<const base::FilePath> root_dir = nullptr;
// The captured area is clipped to |clip_rect| if it is non-zero.
gfx::Rect clip_rect;
// If not `kNone`, overrides the x coordinate of `clip_rect` with some
// renderer-computed value.
mojom::ClipCoordOverride clip_x_coord_override =
mojom::ClipCoordOverride::kNone;
// If not `kNone`, overrides the y coordinate of `clip_rect` with some
// renderer-computed value.
mojom::ClipCoordOverride clip_y_coord_override =
mojom::ClipCoordOverride::kNone;
// Whether to record links.
bool capture_links{false};
// Cap the perframe SkPicture size to |max_per_capture_size| if non-zero.
size_t max_per_capture_size{0};
// 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};
// Params for redacting content from the screenshot.
RedactionParams redaction_params;
};
using OnCapturedCallback =
base::OnceCallback<void(CaptureStatus, std::unique_ptr<CaptureResult>)>;
// Creates a service instance for a feature. Artifacts produced will live in
// |profile_dir|/paint_preview/|ascii_feature_name|. Implementers of the
// factory can also elect their factory to not construct services in the event
// a profile |is_off_the_record|. The |policy| object is responsible for
// determining whether or not a given WebContents is amenable to paint
// preview. If nullptr is passed as |policy| all content is deemed amenable.
//
// NOTE: Pass nullptr as |file_mixin| if you're planning to use the service
// for only in-memory captures.
PaintPreviewBaseService(std::unique_ptr<PaintPreviewFileMixin> file_mixin,
std::unique_ptr<PaintPreviewPolicy> policy,
bool is_off_the_record);
~PaintPreviewBaseService() override;
PaintPreviewFileMixin* GetFileMixin() { return file_mixin_.get(); }
// Returns whether the created service is off the record.
bool IsOffTheRecord() const { return is_off_the_record_; }
// Captures need to run on the Browser UI thread! Captures may involve child
// frames so the PaintPreviewClient (WebContentsObserver) must be stored as
// WebContentsUserData which is not thread safe and must only be accessible
// from a specific sequence i.e. the UI thread.
//
// Captures the main frame of |capture_params.web_contents| (an observer for
// capturing Paint Previews is created for web contents if it does not exist).
// The capture is attributed to the URL of the main frame. On completion the
// status of the capture is provided via |callback|.
//
// See |PaintPreviewBaseService::CaptureParams| for more info about the
// capture parameters.
void CapturePaintPreview(CaptureParams capture_params,
OnCapturedCallback callback);
private:
void OnCaptured(base::ScopedClosureRunner capture_handle,
base::TimeTicks start_time,
OnCapturedCallback callback,
base::UnguessableToken guid,
mojom::PaintPreviewStatus status,
std::unique_ptr<CaptureResult> result);
std::unique_ptr<PaintPreviewFileMixin> file_mixin_;
std::unique_ptr<PaintPreviewPolicy> policy_;
bool is_off_the_record_;
base::WeakPtrFactory<PaintPreviewBaseService> weak_ptr_factory_{this};
PaintPreviewBaseService(const PaintPreviewBaseService&) = delete;
PaintPreviewBaseService& operator=(const PaintPreviewBaseService&) = delete;
};
std::string ToString(PaintPreviewBaseService::CaptureStatus status);
} // namespace paint_preview
#endif // COMPONENTS_PAINT_PREVIEW_BROWSER_PAINT_PREVIEW_BASE_SERVICE_H_