blob: ac0249e5723b222151381a9d680a1169aa8a7004 [file] [log] [blame]
Avi Drissmand878a5012022-09-12 19:13:301// Copyright 2018 The Chromium Authors
Sean Toppinge91b0972018-10-25 20:59:122// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROMECAST_BROWSER_CAST_WEB_CONTENTS_H_
6#define CHROMECAST_BROWSER_CAST_WEB_CONTENTS_H_
7
Helmut Januschka430ce472024-01-31 22:31:408#include <optional>
Chad Duffin4aa9c042019-01-11 00:51:559#include <string>
Helmut Januschka430ce472024-01-31 22:31:4010#include <string_view>
Chad Duffin4aa9c042019-01-11 00:51:5511#include <vector>
12
Jiawei Li830fcfd2019-02-12 20:12:1713#include "base/containers/flat_set.h"
Avi Drissman710fdab2023-01-11 04:37:3614#include "base/functional/callback_forward.h"
Chad Duffin4aa9c042019-01-11 00:51:5515#include "base/observer_list.h"
Sean Topping6c9e3932021-08-23 21:25:3316#include "base/observer_list_types.h"
Zhaoxin2fe094a2020-02-11 23:35:4517#include "base/process/process.h"
Jiawei Li3446cb72021-06-07 14:11:5618#include "chromecast/bindings/public/mojom/api_bindings.mojom.h"
Sean Topping6c9e3932021-08-23 21:25:3319#include "chromecast/browser/cast_web_contents_observer.h"
Sean Topping92d0465b2021-07-16 01:11:3320#include "chromecast/browser/mojom/cast_web_contents.mojom.h"
21#include "chromecast/browser/web_types.h"
Chad Duffin4aa9c042019-01-11 00:51:5522#include "chromecast/common/mojom/feature_manager.mojom.h"
Sean Topping0436b462021-10-12 21:38:5623#include "chromecast/mojo/interface_bundle.h"
Chih-Hsuan Kuo7b4fb102020-03-04 08:21:4924#include "content/public/common/media_playback_renderer_type.mojom.h"
Ken Rockot48c7b502020-11-20 23:33:5925#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
Sean Topping92d0465b2021-07-16 01:11:3326#include "mojo/public/cpp/bindings/pending_receiver.h"
Sean Topping077ba6d82021-11-02 22:48:4227#include "mojo/public/cpp/bindings/receiver.h"
Sean Toppinge0c5a95c2021-11-12 23:13:4928#include "mojo/public/cpp/bindings/receiver_set.h"
Sean Topping92d0465b2021-07-16 01:11:3329#include "mojo/public/cpp/bindings/remote_set.h"
Jiawei Li830fcfd2019-02-12 20:12:1730#include "services/service_manager/public/cpp/interface_provider.h"
Chris Hamilton825f2ed2020-01-30 21:46:4131#include "third_party/blink/public/common/messaging/web_message_port.h"
Sean Toppingf0a1d572019-06-17 23:03:4432#include "ui/gfx/geometry/rect.h"
Sean Toppinge91b0972018-10-25 20:59:1233#include "url/gurl.h"
34
35namespace content {
Ryan Keane0d0493d2021-05-25 16:59:5536class NavigationHandle;
Sean Toppinge91b0972018-10-25 20:59:1237class WebContents;
38} // namespace content
39
Simeon Anfinrudc337a1522023-01-23 22:15:1640namespace media_control {
41class MediaBlocker;
42} // namespace media_control
43
Sean Toppinge91b0972018-10-25 20:59:1244namespace chromecast {
45
Sean Topping0e8ac572019-01-30 03:05:4346struct RendererFeature {
47 const std::string name;
48 base::Value value;
49};
50
Sean Toppinge91b0972018-10-25 20:59:1251// Simplified WebContents wrapper class for Cast platforms.
Sean Topping7414eed2019-04-10 23:04:2152//
53// Proper usage of content::WebContents relies on understanding the meaning
54// behind various WebContentsObserver methods, and then translating those
55// signals into some concrete state. CastWebContents does *not* own the
56// underlying WebContents (usually whatever class implements
57// content::WebContentsDelegate is the actual owner).
58//
59// =============================================================================
60// Lifetime
61// =============================================================================
62// CastWebContents *must* be created before WebContents begins loading any
63// content. Once content begins loading (via CWC::LoadUrl() or one of the
64// WebContents navigation APIs), CastWebContents will calculate its state based
65// on the status of the WebContents' *main* RenderFrame. Events from sub-frames
66// (e.g. iframes) are ignored, since we expect the web app to take care of
67// sub-frame errors.
68//
69// We consider the CastWebContents to be in a LOADED state when the content of
Jiawei Li042aaca2021-03-30 00:15:5370// the main frame is fully loaded and running (all resources fetched,
71// redirection finished, JS is running). Iframes might still be loading in this
72// case, but in general we consider the page to be in a presentable state at
73// this stage, so it is appropriate to display the WebContents to the user.
Sean Topping7414eed2019-04-10 23:04:2174//
75// During or after the page is loaded, there are multiple error conditions that
76// can occur. The following events will cause the page to enter an ERROR state:
77//
78// 1. If the main frame is served an HTTP error page (such as a 404 page), then
79// it means the desired content wasn't loaded.
80//
81// 2. If the main frame fails to load, such as when the browser blocked the URL
82// request, we treat this as an error.
83//
84// 3. The RenderProcess for the main frame could crash, so the page is not in a
85// usable state.
86//
87// The CastWebContents user can respond to these errors in a few ways: The
88// content can be reloaded, or the entire page activity can be cancelled. If we
89// totally cancel the activity, we prefer to notify the user with an error
90// screen or visible/audible error message. Otherwise, a silent retry is
91// preferred.
92//
93// CastWebContents can be used to close the underlying WebContents gracefully
94// via CWC::Close(). This initiates web page tear-down logic so that the web
95// app has a chance to perform its own finalization logic in JS. Next, we call
96// WebContents::ClosePage(), which defers the page closure logic to the
97// content::WebContentsDelegate. Usually, it will run its own finalization
98// logic and then destroy the WebContents. CastWebContents will be notified of
99// the WebContents destruction and enter the DESTROYED state. In the event
100// the page isn't destroyed, the page will enter the CLOSED state automatically
101// after a timeout. CastWebContents users should not try to reload the page, as
102// page closure is intentional.
103//
104// The web app may decide to close itself (such as via "window.close()" in JS).
105// This is similar to initiating the close flow via CWC::Close(), with the end
106// result being the same. We consider this an intentional closure, and should
107// not attempt to reload the page.
108//
109// Once CastWebContents is in the DESTROYED state, it is not really usable
110// anymore; most of the methods will simply no-op, and no more observer signals
111// will be emitted.
112//
113// CastWebContents can be deleted at any time, *except* during Observer
114// notifications. If the owner wants to destroy CastWebContents as a result of
115// an Observer event, it should post a task to destroy CastWebContents.
Sean Topping92d0465b2021-07-16 01:11:33116class CastWebContents : public mojom::CastWebContents {
Sean Toppinge91b0972018-10-25 20:59:12117 public:
Sean Topping6c9e3932021-08-23 21:25:33118 // Synchronous in-process observer for CastWebContents. Observers must not
119 // destroy CastWebContents in any of the methods below.
120 class Observer : public base::CheckedObserver {
Sean Toppingf0a1d572019-06-17 23:03:44121 public:
122 Observer();
123
Sean Topping92d0465b2021-07-16 01:11:33124 // Adds |this| to the CastWebContents observer list. Observe(nullptr) will
125 // remove |this| from the observer list of the current CastWebContents being
126 // observed.
127 void Observe(CastWebContents* cast_web_contents);
128
Ryan Keane0d0493d2021-05-25 16:59:55129 // Called when the navigation is ready to be committed in the WebContents'
130 // main frame.
131 virtual void MainFrameReadyToCommitNavigation(
132 content::NavigationHandle* navigation_handle) {}
133
Vigen Issahhanjan77d798c22021-11-30 23:36:11134 // Notify that an inner WebContents was created. |inner_contents| is created
135 // in a default-initialized state with no delegate, and can be safely
136 // initialized by the delegate.
137 virtual void InnerContentsCreated(CastWebContents* inner_contents,
138 CastWebContents* outer_contents) {}
139
Vigen Issahhanjanc2911072022-06-06 18:20:45140 // Notify the page state changed.
141 virtual void PageStateChanged(PageState page_state) {}
142
143 // Notify the page stopped.
144 virtual void PageStopped(PageState page_state, int32_t error_code) {}
145
Vigen Issahhanjan89fc4f3c2022-08-05 02:14:38146 // Notify media playback state changes for the underlying WebContents.
147 virtual void MediaPlaybackChanged(bool media_playing) {}
148
Sean Topping6c9e3932021-08-23 21:25:33149 // Sets |cast_web_contents_| to |nullptr| but does not remove the Observer
150 // from the ObserverList. Called for each Observer during CastWebContents
151 // destruction; we don't use Observe(nullptr) since it would mutate the
152 // ObserverList during iteration.
Chad Duffin4aa9c042019-01-11 00:51:55153 void ResetCastWebContents();
154
155 protected:
Sean Topping92d0465b2021-07-16 01:11:33156 ~Observer() override;
Chad Duffin4aa9c042019-01-11 00:51:55157
158 CastWebContents* cast_web_contents_;
Sean Toppinge91b0972018-10-25 20:59:12159 };
160
Sean Topping6735aaf2019-03-20 19:20:12161 static std::vector<CastWebContents*>& GetAll();
162
Jiawei Lia64a082b2019-12-06 21:17:26163 // Returns the CastWebContents that wraps the content::WebContents, or nullptr
164 // if the CastWebContents does not exist.
165 static CastWebContents* FromWebContents(content::WebContents* web_contents);
166
Sean Topping92d0465b2021-07-16 01:11:33167 CastWebContents();
Peter Boströmae0ffa02021-10-05 17:08:33168
169 CastWebContents(const CastWebContents&) = delete;
170 CastWebContents& operator=(const CastWebContents&) = delete;
171
Sean Topping92d0465b2021-07-16 01:11:33172 ~CastWebContents() override;
Sean Toppinge91b0972018-10-25 20:59:12173
Sean Topping6735aaf2019-03-20 19:20:12174 // Tab identifier for the WebContents, mainly used by the tabs extension API.
175 // Tab IDs may be re-used, but no two live CastWebContents should have the
176 // same tab ID at any given time.
177 virtual int tab_id() const = 0;
178
Randy Rossic6bb3ab2020-08-11 18:02:52179 // An identifier for the WebContents, mainly used by platform views service.
180 // IDs may be re-used but are unique among all live CastWebContents.
181 virtual int id() const = 0;
182
Sean Topping0e8ac572019-01-30 03:05:43183 // TODO(seantopping): Hide this, clients shouldn't use WebContents directly.
Sean Toppinge91b0972018-10-25 20:59:12184 virtual content::WebContents* web_contents() const = 0;
185 virtual PageState page_state() const = 0;
Simeon Anfinrudc337a1522023-01-23 22:15:16186 virtual const media_control::MediaBlocker* media_blocker() const = 0;
Sean Toppinge91b0972018-10-25 20:59:12187
Sean Topping92d0465b2021-07-16 01:11:33188 // mojom::CastWebContents implementation:
Sean Topping6c9e3932021-08-23 21:25:33189 void SetAppProperties(const std::string& app_id,
190 const std::string& session_id,
191 bool is_audio_app,
Guohui Dengedbf8032021-09-29 21:34:19192 const GURL& app_web_url,
193 bool enforce_feature_permissions,
194 const std::vector<int32_t>& feature_permissions,
195 const std::vector<std::string>&
196 additional_feature_permission_origins) override = 0;
Sean Topping077ba6d82021-11-02 22:48:42197 void SetGroupInfo(const std::string& session_id,
198 bool is_multizone_launch) override = 0;
Lukasz Anforowicz46cda462023-02-07 18:54:38199 void AddRendererFeatures(base::Value::Dict features) override = 0;
Sean Topping6c9e3932021-08-23 21:25:33200 void SetInterfacesForRenderer(mojo::PendingRemote<mojom::RemoteInterfaces>
201 remote_interfaces) override = 0;
Sean Topping92d0465b2021-07-16 01:11:33202 void LoadUrl(const GURL& url) override = 0;
203 void ClosePage() override = 0;
204 void SetWebVisibilityAndPaint(bool visible) override = 0;
205 void BlockMediaLoading(bool blocked) override = 0;
206 void BlockMediaStarting(bool blocked) override = 0;
207 void EnableBackgroundVideoPlayback(bool enabled) override = 0;
Sean Topping6c9e3932021-08-23 21:25:33208 void ConnectToBindingsService(
209 mojo::PendingRemote<mojom::ApiBindings> api_bindings_remote) override = 0;
Sean Topping92d0465b2021-07-16 01:11:33210 void SetEnabledForRemoteDebugging(bool enabled) override = 0;
211 void AddObserver(
212 mojo::PendingRemote<mojom::CastWebContentsObserver> observer) override;
Sean Topping6c9e3932021-08-23 21:25:33213 void GetMainFramePid(GetMainFramePidCallback cb) override = 0;
Sean Topping92d0465b2021-07-16 01:11:33214
Sean Topping0e8ac572019-01-30 03:05:43215 // ===========================================================================
Sean Topping0e8ac572019-01-30 03:05:43216 // Page Lifetime
217 // ===========================================================================
218
Sean Toppinge91b0972018-10-25 20:59:12219 // Stop the page immediately. This will automatically invoke
220 // Delegate::OnPageStopped(error_code), allowing the delegate to delete or
Sean Topping7414eed2019-04-10 23:04:21221 // reload the page without waiting for the WebContents owner to tear down the
222 // page.
Sean Toppinge91b0972018-10-25 20:59:12223 virtual void Stop(int error_code) = 0;
224
Sean Topping8a343862019-05-09 22:19:14225 // ===========================================================================
Jiawei Lidf9ad18a2019-07-07 05:31:02226 // Page Communication
227 // ===========================================================================
228
Jiawei Li3446cb72021-06-07 14:11:56229 // Executes a UTF-8 encoded |script| for every subsequent page load where
230 // the frame's URL has an origin reflected in |origins|. The script is
231 // executed early, prior to the execution of the document's scripts.
232 //
233 // Scripts are identified by a client-managed |id|. Any
234 // script previously injected using the same |id| will be replaced.
235 //
236 // The order in which multiple bindings are executed is the same as the
237 // order in which the bindings were added. If a script is added which
238 // clobbers an existing script of the same |id|, the previous script's
239 // precedence in the injection order will be preserved.
240 // |script| and |id| must be non-empty string.
241 virtual void AddBeforeLoadJavaScript(uint64_t id,
Helmut Januschka430ce472024-01-31 22:31:40242 std::string_view script) = 0;
Jiawei Li3446cb72021-06-07 14:11:56243
Jiawei Libba76072019-07-29 23:00:25244 // Posts a message to the frame's onMessage handler.
245 //
246 // `target_origin` restricts message delivery to the specified origin.
247 // If `target_origin` is "*", then the message will be sent to the
248 // document regardless of its origin.
249 // See html.spec.whatwg.org/multipage/web-messaging.html sect. 9.4.3
250 // for more details on how the target origin policy is applied.
251 // Should be called on UI thread.
Chris Hamilton825f2ed2020-01-30 21:46:41252 virtual void PostMessageToMainFrame(
253 const std::string& target_origin,
254 const std::string& data,
255 std::vector<blink::WebMessagePort> ports) = 0;
Jiawei Libba76072019-07-29 23:00:25256
Jiawei Li5283ad42020-03-27 21:26:05257 // Executes a string of JavaScript in the main frame's context.
258 // This is no-op if the main frame is not available.
259 // Pass in a callback to receive a result when it is available.
260 // If there is no need to receive the result, pass in a
261 // default-constructed callback. If provided, the callback
262 // will be invoked on the UI thread.
263 virtual void ExecuteJavaScript(
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58264 const std::u16string& javascript,
Jiawei Li5283ad42020-03-27 21:26:05265 base::OnceCallback<void(base::Value)> callback) = 0;
266
Jiawei Lidf9ad18a2019-07-07 05:31:02267 // ===========================================================================
Sean Topping8a343862019-05-09 22:19:14268 // Utility Methods
269 // ===========================================================================
270
Ken Rockot48c7b502020-11-20 23:33:59271 // Asks the CastWebContents to bind an interface receiver using either its
272 // registry or any registered InterfaceProvider.
273 virtual bool TryBindReceiver(mojo::GenericPendingReceiver& receiver) = 0;
274
Sean Topping0436b462021-10-12 21:38:56275 // Locally-registered interfaces which are exposed to render frames.
276 virtual InterfaceBundle* local_interfaces() = 0;
277
Jiawei Lia64a082b2019-12-06 21:17:26278 // Returns true if WebSQL database is configured enabled for this
279 // CastWebContents.
280 virtual bool is_websql_enabled() = 0;
281
282 // Returns true if mixer audio is enabled.
283 virtual bool is_mixer_audio_enabled() = 0;
284
Sean Toppinge0c5a95c2021-11-12 23:13:49285 // Binds an owning receiver for remote control of CastWebContents. When the
286 // CastWebContents is managed by CastWebService, its lifetime is scoped to the
287 // duration of the connection. Only one owner can be bound at a time.
288 void BindOwnerReceiver(
289 mojo::PendingReceiver<mojom::CastWebContents> receiver);
290
291 // Binds a non-owning receiver for CastWebContents. This can be called by
292 // multiple clients.
293 void BindSharedReceiver(
294 mojo::PendingReceiver<mojom::CastWebContents> receiver);
Sean Topping92d0465b2021-07-16 01:11:33295
Sean Topping077ba6d82021-11-02 22:48:42296 // |cb| is called when |receiver_| is disconnected. This allows the web
297 // service to destroy CastWebContents which are owned via a remote handle.
298 void SetDisconnectCallback(base::OnceClosure cb);
299
Sean Topping92d0465b2021-07-16 01:11:33300 protected:
Sean Toppinge0c5a95c2021-11-12 23:13:49301 mojo::Receiver<mojom::CastWebContents> owner_receiver_{this};
302 mojo::ReceiverSet<mojom::CastWebContents> shared_receivers_;
Sean Topping92d0465b2021-07-16 01:11:33303 mojo::RemoteSet<mojom::CastWebContentsObserver> observers_;
Sean Topping6c9e3932021-08-23 21:25:33304 base::ObserverList<Observer> sync_observers_;
Sean Topping92d0465b2021-07-16 01:11:33305
Sean Toppinge91b0972018-10-25 20:59:12306 private:
Sean Topping92d0465b2021-07-16 01:11:33307 friend class Observer;
308
309 // These functions should only be invoked by CastWebContents::Observer in a
310 // valid sequence, enforced via SequenceChecker.
Sean Topping6c9e3932021-08-23 21:25:33311 void AddObserver(Observer* observer);
312 void RemoveObserver(Observer* observer);
Sean Topping077ba6d82021-11-02 22:48:42313
314 void OnDisconnect();
315
316 base::OnceClosure disconnect_cb_;
Sean Toppinge91b0972018-10-25 20:59:12317};
318
Sean Toppinge91b0972018-10-25 20:59:12319} // namespace chromecast
320
321#endif // CHROMECAST_BROWSER_CAST_WEB_CONTENTS_H_