blob: 923360d0d966a8c9af20b84a6570e1c5a4290b1b [file] [log] [blame]
Sean Toppinge91b0972018-10-25 20:59:121// Copyright 2018 The Chromium Authors. All rights reserved.
2// 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
Chad Duffin4aa9c042019-01-11 00:51:558#include <string>
9#include <vector>
10
Jiawei Lidf9ad18a2019-07-07 05:31:0211#include "base/callback.h"
Jiawei Li830fcfd2019-02-12 20:12:1712#include "base/containers/flat_set.h"
Chad Duffin4aa9c042019-01-11 00:51:5513#include "base/observer_list.h"
Zhaoxin2fe094a2020-02-11 23:35:4514#include "base/process/process.h"
Jiawei Li3446cb72021-06-07 14:11:5615#include "chromecast/bindings/public/mojom/api_bindings.mojom.h"
Sean Topping92d0465b2021-07-16 01:11:3316#include "chromecast/browser/mojom/cast_web_contents.mojom.h"
17#include "chromecast/browser/web_types.h"
Chad Duffin4aa9c042019-01-11 00:51:5518#include "chromecast/common/mojom/feature_manager.mojom.h"
Chih-Hsuan Kuo7b4fb102020-03-04 08:21:4919#include "content/public/common/media_playback_renderer_type.mojom.h"
Ken Rockot48c7b502020-11-20 23:33:5920#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
Sean Topping92d0465b2021-07-16 01:11:3321#include "mojo/public/cpp/bindings/pending_receiver.h"
22#include "mojo/public/cpp/bindings/receiver.h"
23#include "mojo/public/cpp/bindings/remote_set.h"
Jiawei Li830fcfd2019-02-12 20:12:1724#include "services/service_manager/public/cpp/binder_registry.h"
25#include "services/service_manager/public/cpp/interface_provider.h"
Anton Bikineev3f85f032021-05-15 17:58:2426#include "third_party/abseil-cpp/absl/types/optional.h"
Chris Hamilton825f2ed2020-01-30 21:46:4127#include "third_party/blink/public/common/messaging/web_message_port.h"
Sean Toppingf0a1d572019-06-17 23:03:4428#include "ui/gfx/geometry/rect.h"
Sean Toppinge91b0972018-10-25 20:59:1229#include "url/gurl.h"
30
Sean Topping2d4e54e2019-06-25 00:04:0431namespace blink {
32class AssociatedInterfaceProvider;
33} // namespace blink
34
Sean Toppinge91b0972018-10-25 20:59:1235namespace content {
Ryan Keane0d0493d2021-05-25 16:59:5536class NavigationHandle;
Sean Toppinge91b0972018-10-25 20:59:1237class WebContents;
38} // namespace content
39
Sean Toppinge91b0972018-10-25 20:59:1240namespace chromecast {
41
Sean Topping0e8ac572019-01-30 03:05:4342struct RendererFeature {
43 const std::string name;
44 base::Value value;
45};
46
Sean Toppinge91b0972018-10-25 20:59:1247// Simplified WebContents wrapper class for Cast platforms.
Sean Topping7414eed2019-04-10 23:04:2148//
49// Proper usage of content::WebContents relies on understanding the meaning
50// behind various WebContentsObserver methods, and then translating those
51// signals into some concrete state. CastWebContents does *not* own the
52// underlying WebContents (usually whatever class implements
53// content::WebContentsDelegate is the actual owner).
54//
55// =============================================================================
56// Lifetime
57// =============================================================================
58// CastWebContents *must* be created before WebContents begins loading any
59// content. Once content begins loading (via CWC::LoadUrl() or one of the
60// WebContents navigation APIs), CastWebContents will calculate its state based
61// on the status of the WebContents' *main* RenderFrame. Events from sub-frames
62// (e.g. iframes) are ignored, since we expect the web app to take care of
63// sub-frame errors.
64//
65// We consider the CastWebContents to be in a LOADED state when the content of
Jiawei Li042aaca2021-03-30 00:15:5366// the main frame is fully loaded and running (all resources fetched,
67// redirection finished, JS is running). Iframes might still be loading in this
68// case, but in general we consider the page to be in a presentable state at
69// this stage, so it is appropriate to display the WebContents to the user.
Sean Topping7414eed2019-04-10 23:04:2170//
71// During or after the page is loaded, there are multiple error conditions that
72// can occur. The following events will cause the page to enter an ERROR state:
73//
74// 1. If the main frame is served an HTTP error page (such as a 404 page), then
75// it means the desired content wasn't loaded.
76//
77// 2. If the main frame fails to load, such as when the browser blocked the URL
78// request, we treat this as an error.
79//
80// 3. The RenderProcess for the main frame could crash, so the page is not in a
81// usable state.
82//
83// The CastWebContents user can respond to these errors in a few ways: The
84// content can be reloaded, or the entire page activity can be cancelled. If we
85// totally cancel the activity, we prefer to notify the user with an error
86// screen or visible/audible error message. Otherwise, a silent retry is
87// preferred.
88//
89// CastWebContents can be used to close the underlying WebContents gracefully
90// via CWC::Close(). This initiates web page tear-down logic so that the web
91// app has a chance to perform its own finalization logic in JS. Next, we call
92// WebContents::ClosePage(), which defers the page closure logic to the
93// content::WebContentsDelegate. Usually, it will run its own finalization
94// logic and then destroy the WebContents. CastWebContents will be notified of
95// the WebContents destruction and enter the DESTROYED state. In the event
96// the page isn't destroyed, the page will enter the CLOSED state automatically
97// after a timeout. CastWebContents users should not try to reload the page, as
98// page closure is intentional.
99//
100// The web app may decide to close itself (such as via "window.close()" in JS).
101// This is similar to initiating the close flow via CWC::Close(), with the end
102// result being the same. We consider this an intentional closure, and should
103// not attempt to reload the page.
104//
105// Once CastWebContents is in the DESTROYED state, it is not really usable
106// anymore; most of the methods will simply no-op, and no more observer signals
107// will be emitted.
108//
109// CastWebContents can be deleted at any time, *except* during Observer
110// notifications. If the owner wants to destroy CastWebContents as a result of
111// an Observer event, it should post a task to destroy CastWebContents.
Sean Topping92d0465b2021-07-16 01:11:33112class CastWebContents : public mojom::CastWebContents {
Sean Toppinge91b0972018-10-25 20:59:12113 public:
114 class Delegate {
115 public:
Sean Toppingf0a1d572019-06-17 23:03:44116 // Notify that an inner WebContents was created. |inner_contents| is created
117 // in a default-initialized state with no delegate, and can be safely
118 // initialized by the delegate.
119 virtual void InnerContentsCreated(CastWebContents* inner_contents,
120 CastWebContents* outer_contents) {}
121
122 protected:
123 virtual ~Delegate() {}
124 };
125
Sean Topping92d0465b2021-07-16 01:11:33126 // Observers must use Observer::Observe(cast_web_contents | nullptr) to
127 // add/remove themselves from the observer list. The Observer must not destroy
128 // CastWebContents during any of these events, otherwise other observers might
129 // try to use a freed pointer to |cast_web_contents|.
130 class Observer : public mojom::CastWebContentsObserver {
Sean Toppingf0a1d572019-06-17 23:03:44131 public:
132 Observer();
133
Sean Topping92d0465b2021-07-16 01:11:33134 // Adds |this| to the CastWebContents observer list. Observe(nullptr) will
135 // remove |this| from the observer list of the current CastWebContents being
136 // observed.
137 void Observe(CastWebContents* cast_web_contents);
138
139 // =========================================================================
140 // Observer Methods
141 // =========================================================================
142
Sean Toppinge91b0972018-10-25 20:59:12143 // Advertises page state for the CastWebContents.
Sean Topping92d0465b2021-07-16 01:11:33144 void PageStateChanged(PageState page_state) override {}
Sean Toppinge91b0972018-10-25 20:59:12145
146 // Called when the page has stopped. e.g.: A 404 occurred when loading the
147 // page or if the render process for the main frame crashes. |error_code|
148 // will return a net::Error describing the failure, or net::OK if the page
Sean Topping7414eed2019-04-10 23:04:21149 // closed intentionally.
Sean Toppinge91b0972018-10-25 20:59:12150 //
151 // After this method, the page state will be one of the following:
Sean Topping7414eed2019-04-10 23:04:21152 // CLOSED: Page was closed as expected and the WebContents exists. The page
153 // should generally not be reloaded, since the page closure was
154 // triggered intentionally.
155 // ERROR: Page is in an error state. It should be reloaded or deleted.
Sean Toppinge91b0972018-10-25 20:59:12156 // DESTROYED: Page was closed due to deletion of WebContents. The
157 // CastWebContents instance is no longer usable and should be deleted.
Sean Topping92d0465b2021-07-16 01:11:33158 void PageStopped(PageState page_state, int error_code) override {}
Sean Toppinge91b0972018-10-25 20:59:12159
Sean Toppingf0a1d572019-06-17 23:03:44160 // A new RenderFrame was created for the WebContents. |frame_interfaces| are
161 // provided by the new frame.
162 virtual void RenderFrameCreated(
163 int render_process_id,
164 int render_frame_id,
Sean Topping2d4e54e2019-06-25 00:04:04165 service_manager::InterfaceProvider* frame_interfaces,
166 blink::AssociatedInterfaceProvider* frame_associated_interfaces) {}
Chad Duffin4aa9c042019-01-11 00:51:55167
Ryan Keane0d0493d2021-05-25 16:59:55168 // Called when the navigation is ready to be committed in the WebContents'
169 // main frame.
170 virtual void MainFrameReadyToCommitNavigation(
171 content::NavigationHandle* navigation_handle) {}
172
Jiawei Lic3354ee2019-12-13 23:48:35173 // A navigation has finished in the WebContents' main frame.
Sean Topping92d0465b2021-07-16 01:11:33174 void MainFrameFinishedNavigation() override {}
Jiawei Lic3354ee2019-12-13 23:48:35175
Sean Toppingf0a1d572019-06-17 23:03:44176 // These methods are calls forwarded from WebContentsObserver.
Sean Topping92d0465b2021-07-16 01:11:33177 void UpdateTitle(const std::string& title) override {}
178 void UpdateFaviconURL(const GURL& url) override {}
179 void DidFirstVisuallyNonEmptyPaint() override {}
Sean Toppingf0a1d572019-06-17 23:03:44180 virtual void MainFrameResized(const gfx::Rect& bounds) {}
Chad Duffin4aa9c042019-01-11 00:51:55181
Sean Topping7414eed2019-04-10 23:04:21182 // Notifies that a resource for the main frame failed to load.
183 virtual void ResourceLoadFailed(CastWebContents* cast_web_contents) {}
184
Zhaoxin2fe094a2020-02-11 23:35:45185 // Propagates the process information via observer, in particular to
186 // the underlying OnRendererProcessStarted() method.
Sean Topping92d0465b2021-07-16 01:11:33187 void OnRenderProcessReady(int pid) override {}
Zhaoxin2fe094a2020-02-11 23:35:45188
Sean Toppinge8648a22020-04-29 18:41:00189 // Notify media playback state changes for the underlying WebContents.
Sean Topping92d0465b2021-07-16 01:11:33190 void MediaPlaybackChanged(bool media_playing) override {}
Chad Duffin4aa9c042019-01-11 00:51:55191
192 // Removes |this| from the ObserverList in the implementation of
193 // |cast_web_contents_|. This is only invoked by CastWebContents and is used
194 // to ensure that once the observed CastWebContents object is destructed the
195 // CastWebContents::Observer does not invoke any additional function calls
196 // on it.
197 void ResetCastWebContents();
198
199 protected:
Sean Topping92d0465b2021-07-16 01:11:33200 ~Observer() override;
Chad Duffin4aa9c042019-01-11 00:51:55201
202 CastWebContents* cast_web_contents_;
Sean Topping92d0465b2021-07-16 01:11:33203 mojo::Receiver<mojom::CastWebContentsObserver> receiver_{this};
Sean Toppinge91b0972018-10-25 20:59:12204 };
205
Sean Topping6735aaf2019-03-20 19:20:12206 static std::vector<CastWebContents*>& GetAll();
207
Jiawei Lia64a082b2019-12-06 21:17:26208 // Returns the CastWebContents that wraps the content::WebContents, or nullptr
209 // if the CastWebContents does not exist.
210 static CastWebContents* FromWebContents(content::WebContents* web_contents);
211
Sean Topping92d0465b2021-07-16 01:11:33212 CastWebContents();
213 ~CastWebContents() override;
Sean Toppinge91b0972018-10-25 20:59:12214
Sean Topping6735aaf2019-03-20 19:20:12215 // Tab identifier for the WebContents, mainly used by the tabs extension API.
216 // Tab IDs may be re-used, but no two live CastWebContents should have the
217 // same tab ID at any given time.
218 virtual int tab_id() const = 0;
219
Randy Rossic6bb3ab2020-08-11 18:02:52220 // An identifier for the WebContents, mainly used by platform views service.
221 // IDs may be re-used but are unique among all live CastWebContents.
222 virtual int id() const = 0;
223
Sean Topping0e8ac572019-01-30 03:05:43224 // TODO(seantopping): Hide this, clients shouldn't use WebContents directly.
Sean Toppinge91b0972018-10-25 20:59:12225 virtual content::WebContents* web_contents() const = 0;
226 virtual PageState page_state() const = 0;
227
Jiawei Lic3354ee2019-12-13 23:48:35228 // Returns the PID of the main frame process if valid.
Anton Bikineev3f85f032021-05-15 17:58:24229 virtual absl::optional<pid_t> GetMainFrameRenderProcessPid() const = 0;
Jiawei Lic3354ee2019-12-13 23:48:35230
Sean Topping92d0465b2021-07-16 01:11:33231 // mojom::CastWebContents implementation:
232 void LoadUrl(const GURL& url) override = 0;
233 void ClosePage() override = 0;
234 void SetWebVisibilityAndPaint(bool visible) override = 0;
235 void BlockMediaLoading(bool blocked) override = 0;
236 void BlockMediaStarting(bool blocked) override = 0;
237 void EnableBackgroundVideoPlayback(bool enabled) override = 0;
238 void SetEnabledForRemoteDebugging(bool enabled) override = 0;
239 void AddObserver(
240 mojo::PendingRemote<mojom::CastWebContentsObserver> observer) override;
241
Sean Topping0e8ac572019-01-30 03:05:43242 // ===========================================================================
243 // Initialization and Setup
244 // ===========================================================================
245
Sean Topping0e8ac572019-01-30 03:05:43246 // Add a set of features for all renderers in the WebContents. Features are
247 // configured when `CastWebContents::RenderFrameCreated` is invoked.
248 virtual void AddRendererFeatures(std::vector<RendererFeature> features) = 0;
249
Sean Topping92d0465b2021-07-16 01:11:33250 // TODO(b/149041392): This can be an initialization parameter.
Sean Topping0e8ac572019-01-30 03:05:43251 virtual void AllowWebAndMojoWebUiBindings() = 0;
252 virtual void ClearRenderWidgetHostView() = 0;
253
Sean Topping805f50e2021-05-21 00:55:47254 // Associates transparent app properties to a given session ID. This data is
255 // used elsewhere in the browser to gate output stream selection. We expose
256 // this API on CastWebContents for the sake of convenience.
257 virtual void SetAppProperties(const std::string& session_id,
258 bool is_audio_app) = 0;
259
Guohui Deng87c1e4c2021-07-12 22:16:50260 // TODO(b/191718807) need to pass App's page permissions here.
Guohui Dengdf50b812021-07-23 21:07:26261 virtual void SetCastPermissionUserData(const std::string& app_id,
262 const GURL& app_web_url) = 0;
Guohui Deng87c1e4c2021-07-12 22:16:50263
Sean Topping0e8ac572019-01-30 03:05:43264 // ===========================================================================
265 // Page Lifetime
266 // ===========================================================================
267
Sean Toppinge91b0972018-10-25 20:59:12268 // Stop the page immediately. This will automatically invoke
269 // Delegate::OnPageStopped(error_code), allowing the delegate to delete or
Sean Topping7414eed2019-04-10 23:04:21270 // reload the page without waiting for the WebContents owner to tear down the
271 // page.
Sean Toppinge91b0972018-10-25 20:59:12272 virtual void Stop(int error_code) = 0;
273
Sean Topping8a343862019-05-09 22:19:14274 // ===========================================================================
Jiawei Lidf9ad18a2019-07-07 05:31:02275 // Page Communication
276 // ===========================================================================
277
Jiawei Li3446cb72021-06-07 14:11:56278 // Executes a UTF-8 encoded |script| for every subsequent page load where
279 // the frame's URL has an origin reflected in |origins|. The script is
280 // executed early, prior to the execution of the document's scripts.
281 //
282 // Scripts are identified by a client-managed |id|. Any
283 // script previously injected using the same |id| will be replaced.
284 //
285 // The order in which multiple bindings are executed is the same as the
286 // order in which the bindings were added. If a script is added which
287 // clobbers an existing script of the same |id|, the previous script's
288 // precedence in the injection order will be preserved.
289 // |script| and |id| must be non-empty string.
290 virtual void AddBeforeLoadJavaScript(uint64_t id,
291 base::StringPiece script) = 0;
292
Jiawei Libba76072019-07-29 23:00:25293 // Posts a message to the frame's onMessage handler.
294 //
295 // `target_origin` restricts message delivery to the specified origin.
296 // If `target_origin` is "*", then the message will be sent to the
297 // document regardless of its origin.
298 // See html.spec.whatwg.org/multipage/web-messaging.html sect. 9.4.3
299 // for more details on how the target origin policy is applied.
300 // Should be called on UI thread.
Chris Hamilton825f2ed2020-01-30 21:46:41301 virtual void PostMessageToMainFrame(
302 const std::string& target_origin,
303 const std::string& data,
304 std::vector<blink::WebMessagePort> ports) = 0;
Jiawei Libba76072019-07-29 23:00:25305
Jiawei Li5283ad42020-03-27 21:26:05306 // Executes a string of JavaScript in the main frame's context.
307 // This is no-op if the main frame is not available.
308 // Pass in a callback to receive a result when it is available.
309 // If there is no need to receive the result, pass in a
310 // default-constructed callback. If provided, the callback
311 // will be invoked on the UI thread.
312 virtual void ExecuteJavaScript(
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58313 const std::u16string& javascript,
Jiawei Li5283ad42020-03-27 21:26:05314 base::OnceCallback<void(base::Value)> callback) = 0;
315
Jiawei Li3446cb72021-06-07 14:11:56316 // Connects and fetches JS API bindings from |api_bindings_remote|.
317 // This method will fetch bindings scripts from |api_bindings_remote|
318 // immediately after the invocation, all of the bindings should be
319 // initialized before this point.
320 virtual void ConnectToBindingsService(
321 mojo::PendingRemote<mojom::ApiBindings> api_bindings_remote) = 0;
322
Jiawei Lidf9ad18a2019-07-07 05:31:02323 // ===========================================================================
Sean Topping8a343862019-05-09 22:19:14324 // Utility Methods
325 // ===========================================================================
326
Jiawei Li830fcfd2019-02-12 20:12:17327 // Used to expose CastWebContents's |binder_registry_| to Delegate.
328 // Delegate should register its mojo interface binders via this function
329 // when it is ready.
330 virtual service_manager::BinderRegistry* binder_registry() = 0;
331
Ken Rockot48c7b502020-11-20 23:33:59332 // Asks the CastWebContents to bind an interface receiver using either its
333 // registry or any registered InterfaceProvider.
334 virtual bool TryBindReceiver(mojo::GenericPendingReceiver& receiver) = 0;
335
Julie Jeongeun Kim641f4752019-12-04 01:53:22336 // Used for owner to pass its |InterfaceProvider| pointers to CastWebContents.
337 // It is owner's responsibility to make sure each |InterfaceProvider| pointer
338 // has distinct mojo interface set.
Jiawei Li830fcfd2019-02-12 20:12:17339 using InterfaceSet = base::flat_set<std::string>;
340 virtual void RegisterInterfaceProvider(
341 const InterfaceSet& interface_set,
342 service_manager::InterfaceProvider* interface_provider) = 0;
343
Jiawei Lia64a082b2019-12-06 21:17:26344 // Returns true if WebSQL database is configured enabled for this
345 // CastWebContents.
346 virtual bool is_websql_enabled() = 0;
347
348 // Returns true if mixer audio is enabled.
349 virtual bool is_mixer_audio_enabled() = 0;
350
Sean Toppingabf3be592020-03-11 23:20:35351 // Returns whether or not CastWebContents binder_registry() is valid for
352 // binding interfaces.
353 virtual bool can_bind_interfaces() = 0;
354
Sean Topping92d0465b2021-07-16 01:11:33355 // Binds a receiver for remote control of CastWebContents.
356 void BindReceiver(mojo::PendingReceiver<mojom::CastWebContents> receiver);
357
358 protected:
359 mojo::Receiver<mojom::CastWebContents> receiver_{this};
360 mojo::RemoteSet<mojom::CastWebContentsObserver> observers_;
361
Sean Toppinge91b0972018-10-25 20:59:12362 private:
Sean Topping92d0465b2021-07-16 01:11:33363 friend class Observer;
364
365 // These functions should only be invoked by CastWebContents::Observer in a
366 // valid sequence, enforced via SequenceChecker.
367 virtual void AddObserver(Observer* observer) = 0;
368 virtual void RemoveObserver(Observer* observer) = 0;
369
Sean Toppinge91b0972018-10-25 20:59:12370 DISALLOW_COPY_AND_ASSIGN(CastWebContents);
371};
372
Sean Toppinge91b0972018-10-25 20:59:12373} // namespace chromecast
374
375#endif // CHROMECAST_BROWSER_CAST_WEB_CONTENTS_H_