blob: ab2ffb050a5a35b717caccd7e97fbf8f43786ebc [file] [log] [blame]
// Copyright 2021 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.
#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_WEB_CONTENTS_FRAME_TRACKER_H_
#define CONTENT_BROWSER_MEDIA_CAPTURE_WEB_CONTENTS_FRAME_TRACKER_H_
#include <utility>
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_media_capture_id.h"
#include "content/public/browser/web_contents_observer.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
namespace content {
class WebContentsVideoCaptureDevice;
class MouseCursorOverlayController;
class RenderFrameHost;
// Monitors the WebContents instance and notifies the parent
// WebContentsVideoCaptureDevice |device| class any time the frame sink or
// main render frame's view changes.
class CONTENT_EXPORT WebContentsFrameTracker
: public WebContentsObserver,
public base::SupportsWeakPtr<WebContentsFrameTracker> {
public:
// We generally retrieve certain properties by accessing fields on the
// WebContents object, however these properties may come from a different
// context in some circumstances, such as testing.
class Context {
public:
virtual ~Context() = default;
// Get bounds of the attached screen, if any.
virtual base::Optional<gfx::Rect> GetScreenBounds() = 0;
// While the DOM always has a FrameSinkId, we may want to capture
// a different frame sink ID overlaying the DOM content that represents
// what we actually want to capture.
virtual viz::FrameSinkId GetFrameSinkIdForCapture() = 0;
// Capturer count handling is tricky in testing, since setting it
// on the web contents uses a view even though the view may not be
// initialized in the test harness.
virtual void IncrementCapturerCount(const gfx::Size& capture_size) = 0;
virtual void DecrementCapturerCount() = 0;
};
// NOTE on lifetime: |device| should outlive the WebContentsFrameTracker. The
// |device| will be exclusively accessed on the sequence that is used to
// construct |this| (which must not be the UI thread).
WebContentsFrameTracker(base::WeakPtr<WebContentsVideoCaptureDevice> device,
MouseCursorOverlayController* cursor_controller);
WebContentsFrameTracker(WebContentsFrameTracker&&) = delete;
WebContentsFrameTracker(const WebContentsFrameTracker&) = delete;
WebContentsFrameTracker& operator=(const WebContentsFrameTracker&&) = delete;
WebContentsFrameTracker& operator=(const WebContentsFrameTracker&) = delete;
~WebContentsFrameTracker() final;
void WillStartCapturingWebContents(const gfx::Size& capture_size);
void DidStopCapturingWebContents();
// The preferred size calculated here is a strong suggestion to UI
// layout code to size the viewport such that physical rendering matches the
// exact capture size. This helps to eliminate redundant scaling operations
// during capture. Note that if there are multiple capturers, a "first past
// the post" system is used and the first capturer's preferred size is set.
gfx::Size CalculatePreferredSize(const gfx::Size& capture_size);
// WebContentsObserver overrides.
void RenderFrameCreated(RenderFrameHost* render_frame_host) final;
void RenderFrameDeleted(RenderFrameHost* render_frame_host) final;
void RenderFrameHostChanged(RenderFrameHost* old_host,
RenderFrameHost* new_host) final;
void WebContentsDestroyed() final;
void CaptureTargetChanged() final;
void SetWebContentsAndContextFromRoutingId(const GlobalFrameRoutingId& id);
// WebContents are retrieved on the UI thread normally, from the render IDs,
// so this method is provided for tests to set the web contents directly.
void SetWebContentsAndContextForTesting(WebContents* web_contents,
std::unique_ptr<Context> context);
private:
// Re-evaluates whether a new frame sink should be targeted for capture and
// notifies the device. If the WebContents instance is no longer being
// observed, the device is notified that the capture target has been
// permanently lost.
void OnPossibleTargetChange();
// Sets the target view for the cursor controller on non-Android platforms.
// Noop on Android.
void SetTargetView(gfx::NativeView view);
// |device_| may be dereferenced only by tasks run by |device_task_runner_|.
const base::WeakPtr<WebContentsVideoCaptureDevice> device_;
// The task runner to be used for device callbacks.
const scoped_refptr<base::SequencedTaskRunner> device_task_runner_;
// Owned by FrameSinkVideoCaptureDevice. This will be valid for the life of
// WebContentsFrameTracker because the WebContentsFrameTracker deleter task
// will be posted to the UI thread before the MouseCursorOverlayController
// deleter task.
#if !defined(OS_ANDROID)
MouseCursorOverlayController* cursor_controller_ = nullptr;
#endif
// We may not have a frame sink ID target at all times.
std::unique_ptr<Context> context_;
base::Optional<viz::FrameSinkId> target_frame_sink_id_;
gfx::NativeView target_native_view_ = gfx::NativeView();
// Indicates whether the WebContents's capturer count needs to be
// decremented.
bool is_capturing_ = false;
};
} // namespace content
#endif // CONTENT_BROWSER_MEDIA_CAPTURE_WEB_CONTENTS_FRAME_TRACKER_H_