1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_MEDIA_CAPTURED_SURFACE_CONTROLLER_H_
#define CONTENT_BROWSER_MEDIA_CAPTURED_SURFACE_CONTROLLER_H_
#include <memory>
#include "base/callback_list.h"
#include "base/functional/callback.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/media/captured_surface_control_permission_manager.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_media_capture_id.h"
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
namespace content {
// Encapsulates the permission state and logic associated with the Captured
// Surface Control API. Objects of this class live on the IO thread.
class CONTENT_EXPORT CapturedSurfaceController {
public:
using CapturedSurfaceControlResult =
::blink::mojom::CapturedSurfaceControlResult;
// Wheel deltas are clamped to this arbitrary, reasonable value.
// We clamp rather than report an error because "reasonable" is not
// well-defined as of the time being, let alone in an interoperable way.
inline static constexpr int32_t kMaxWheelDeltaMagnitude = 1000000;
static std::unique_ptr<CapturedSurfaceController> CreateForTesting(
GlobalRenderFrameHostId capturer_rfh_id,
WebContentsMediaCaptureId captured_wc_id,
std::unique_ptr<CapturedSurfaceControlPermissionManager>
permission_manager,
base::RepeatingCallback<void(int)> on_zoom_level_change_callback,
base::RepeatingCallback<void(base::WeakPtr<WebContents>)>
wc_resolution_callback);
CapturedSurfaceController(
GlobalRenderFrameHostId capturer_rfh_id,
WebContentsMediaCaptureId captured_wc_id,
base::RepeatingCallback<void(int)> on_zoom_level_change_callback);
virtual ~CapturedSurfaceController();
CapturedSurfaceController(const CapturedSurfaceController&) = delete;
CapturedSurfaceController& operator=(const CapturedSurfaceController&) =
delete;
// Set the captured WebContents this controller is associated with.
// This may be called with a null `WebContentsMediaCaptureId`.
virtual void UpdateCaptureTarget(WebContentsMediaCaptureId captured_wc_id);
// Produce a wheel event on the captured surface.
//
// * `action` represents the wheel event that should be forwarded to the
// captured surface.
// * `reply_callback` reports success/failure back to the caller.
virtual void SendWheel(
blink::mojom::CapturedWheelActionPtr action,
base::OnceCallback<void(CapturedSurfaceControlResult)> reply_callback);
// Updates the zoom level of the captured tab.
virtual void UpdateZoomLevel(
blink::mojom::ZoomLevelAction action,
base::OnceCallback<void(CapturedSurfaceControlResult)> reply_callback);
virtual void RequestPermission(
base::OnceCallback<void(CapturedSurfaceControlResult)> reply_callback);
struct CapturedSurfaceInfo final {
CapturedSurfaceInfo(
base::WeakPtr<WebContents> captured_wc,
std::unique_ptr<base::CallbackListSubscription,
BrowserThread::DeleteOnUIThread> subscription,
int subscription_version,
int initial_zoom_level);
CapturedSurfaceInfo(CapturedSurfaceInfo&& other);
CapturedSurfaceInfo& operator=(CapturedSurfaceInfo&& other);
~CapturedSurfaceInfo();
base::WeakPtr<WebContents> captured_wc;
std::unique_ptr<base::CallbackListSubscription,
BrowserThread::DeleteOnUIThread>
subscription;
int subscription_version;
int initial_zoom_level;
};
private:
using PermissionResult =
CapturedSurfaceControlPermissionManager::PermissionResult;
void OnZoomLevelChange(int subscription_version, int zoom_level);
CapturedSurfaceController(
GlobalRenderFrameHostId capturer_rfh_id,
WebContentsMediaCaptureId captured_wc_id,
std::unique_ptr<CapturedSurfaceControlPermissionManager>
permission_manager,
base::RepeatingCallback<void(int)> on_zoom_level_change_callback,
base::RepeatingCallback<void(base::WeakPtr<WebContents>)>
wc_resolution_callback);
// Manage the resolution of WebContents-IDs into base::WeakPtr<WebContents>.
void ResolveCapturedSurface(WebContentsMediaCaptureId captured_wc_id);
void OnCapturedSurfaceResolved(
std::optional<CapturedSurfaceInfo> captured_surface);
const GlobalRenderFrameHostId capturer_rfh_id_;
// References the captured tab through its WebContents.
//
// Set to nullopt when:
// * The captured surface is not a tab.
// * Right after construction, before the ID is first resolved (on the
// UI thread) to a valid base::WeakPtr<WebContents>.
// * Whenever the captured tab changes, and UpdateCaptureTarget() is
// called. This triggers a new resolution, and in the intervening time,
// this will be set back to nullptr.
//
// Set to a concrete value otherwise.
// However, this concrete value can be nullptr, (1) as with any WeakPtr,
// or (2) if the ID failed to resolve to a valid WebContents.
//
// Note that `this` lives on the IO thread, and it is not possible to
// check the value of the underlying WebContents* here, or even compare
// it to nullptr.
//
// In the unlikely-yet-possible case that SendWheel() or SetZoomLevel()
// are called while the task to resolve is pending, those calls will
// fail gracefully. Subsequent calls are valid and can succeed.
// TODO(crbug.com/41493349): Add UMA to measure how often this happens
// and determine whether it's worth the effort to fix.
std::optional<base::WeakPtr<WebContents>> captured_wc_;
// Counts the pending resolutions, so that `captured_wc_` would only
// be set to a concrete values when the last one resolves.
int pending_wc_resolutions_ = 0;
std::unique_ptr<CapturedSurfaceControlPermissionManager> permission_manager_;
// Callback to be invoked whenever an ID's resolution to a
// base::WeakPtr<WebContents> completes.
const base::RepeatingCallback<void(base::WeakPtr<WebContents>)>
wc_resolution_callback_;
// `zoom_level_subscription_` controls the lifetime of a subscriptions to
// zoom-level updates for a captured tab. If the capture is switched over to a
// new tab, the subscription is re-initialized and `subscription_version_` is
// incremented so that callback invocations from the previous subscriptions
// may be ignored.
std::unique_ptr<base::CallbackListSubscription,
BrowserThread::DeleteOnUIThread>
zoom_level_subscription_;
int subscription_version_ = 0;
const base::RepeatingCallback<void(int)> on_zoom_level_change_callback_;
base::WeakPtrFactory<CapturedSurfaceController> weak_factory_{this};
};
} // namespace content
#endif // CONTENT_BROWSER_MEDIA_CAPTURED_SURFACE_CONTROLLER_H_
|