blob: 6d59e9cc565f16ec5ac5714e13179baffa825e7e [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"
Sean Topping6c9e3932021-08-23 21:25:3314#include "base/observer_list_types.h"
Zhaoxin2fe094a2020-02-11 23:35:4515#include "base/process/process.h"
Jiawei Li3446cb72021-06-07 14:11:5616#include "chromecast/bindings/public/mojom/api_bindings.mojom.h"
Sean Topping6c9e3932021-08-23 21:25:3317#include "chromecast/browser/cast_web_contents_observer.h"
Sean Topping92d0465b2021-07-16 01:11:3318#include "chromecast/browser/mojom/cast_web_contents.mojom.h"
19#include "chromecast/browser/web_types.h"
Chad Duffin4aa9c042019-01-11 00:51:5520#include "chromecast/common/mojom/feature_manager.mojom.h"
Chih-Hsuan Kuo7b4fb102020-03-04 08:21:4921#include "content/public/common/media_playback_renderer_type.mojom.h"
Ken Rockot48c7b502020-11-20 23:33:5922#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
Sean Topping92d0465b2021-07-16 01:11:3323#include "mojo/public/cpp/bindings/pending_receiver.h"
Sean Topping6c9e3932021-08-23 21:25:3324#include "mojo/public/cpp/bindings/receiver_set.h"
Sean Topping92d0465b2021-07-16 01:11:3325#include "mojo/public/cpp/bindings/remote_set.h"
Jiawei Li830fcfd2019-02-12 20:12:1726#include "services/service_manager/public/cpp/interface_provider.h"
Anton Bikineev3f85f032021-05-15 17:58:2427#include "third_party/abseil-cpp/absl/types/optional.h"
Chris Hamilton825f2ed2020-01-30 21:46:4128#include "third_party/blink/public/common/messaging/web_message_port.h"
Sean Toppingf0a1d572019-06-17 23:03:4429#include "ui/gfx/geometry/rect.h"
Sean Toppinge91b0972018-10-25 20:59:1230#include "url/gurl.h"
31
Sean Toppinge91b0972018-10-25 20:59:1232namespace content {
Ryan Keane0d0493d2021-05-25 16:59:5533class NavigationHandle;
Sean Toppinge91b0972018-10-25 20:59:1234class WebContents;
35} // namespace content
36
Sean Toppinge91b0972018-10-25 20:59:1237namespace chromecast {
38
Sean Topping0e8ac572019-01-30 03:05:4339struct RendererFeature {
40 const std::string name;
41 base::Value value;
42};
43
Sean Toppinge91b0972018-10-25 20:59:1244// Simplified WebContents wrapper class for Cast platforms.
Sean Topping7414eed2019-04-10 23:04:2145//
46// Proper usage of content::WebContents relies on understanding the meaning
47// behind various WebContentsObserver methods, and then translating those
48// signals into some concrete state. CastWebContents does *not* own the
49// underlying WebContents (usually whatever class implements
50// content::WebContentsDelegate is the actual owner).
51//
52// =============================================================================
53// Lifetime
54// =============================================================================
55// CastWebContents *must* be created before WebContents begins loading any
56// content. Once content begins loading (via CWC::LoadUrl() or one of the
57// WebContents navigation APIs), CastWebContents will calculate its state based
58// on the status of the WebContents' *main* RenderFrame. Events from sub-frames
59// (e.g. iframes) are ignored, since we expect the web app to take care of
60// sub-frame errors.
61//
62// We consider the CastWebContents to be in a LOADED state when the content of
Jiawei Li042aaca2021-03-30 00:15:5363// the main frame is fully loaded and running (all resources fetched,
64// redirection finished, JS is running). Iframes might still be loading in this
65// case, but in general we consider the page to be in a presentable state at
66// this stage, so it is appropriate to display the WebContents to the user.
Sean Topping7414eed2019-04-10 23:04:2167//
68// During or after the page is loaded, there are multiple error conditions that
69// can occur. The following events will cause the page to enter an ERROR state:
70//
71// 1. If the main frame is served an HTTP error page (such as a 404 page), then
72// it means the desired content wasn't loaded.
73//
74// 2. If the main frame fails to load, such as when the browser blocked the URL
75// request, we treat this as an error.
76//
77// 3. The RenderProcess for the main frame could crash, so the page is not in a
78// usable state.
79//
80// The CastWebContents user can respond to these errors in a few ways: The
81// content can be reloaded, or the entire page activity can be cancelled. If we
82// totally cancel the activity, we prefer to notify the user with an error
83// screen or visible/audible error message. Otherwise, a silent retry is
84// preferred.
85//
86// CastWebContents can be used to close the underlying WebContents gracefully
87// via CWC::Close(). This initiates web page tear-down logic so that the web
88// app has a chance to perform its own finalization logic in JS. Next, we call
89// WebContents::ClosePage(), which defers the page closure logic to the
90// content::WebContentsDelegate. Usually, it will run its own finalization
91// logic and then destroy the WebContents. CastWebContents will be notified of
92// the WebContents destruction and enter the DESTROYED state. In the event
93// the page isn't destroyed, the page will enter the CLOSED state automatically
94// after a timeout. CastWebContents users should not try to reload the page, as
95// page closure is intentional.
96//
97// The web app may decide to close itself (such as via "window.close()" in JS).
98// This is similar to initiating the close flow via CWC::Close(), with the end
99// result being the same. We consider this an intentional closure, and should
100// not attempt to reload the page.
101//
102// Once CastWebContents is in the DESTROYED state, it is not really usable
103// anymore; most of the methods will simply no-op, and no more observer signals
104// will be emitted.
105//
106// CastWebContents can be deleted at any time, *except* during Observer
107// notifications. If the owner wants to destroy CastWebContents as a result of
108// an Observer event, it should post a task to destroy CastWebContents.
Sean Topping92d0465b2021-07-16 01:11:33109class CastWebContents : public mojom::CastWebContents {
Sean Toppinge91b0972018-10-25 20:59:12110 public:
Sean Topping6c9e3932021-08-23 21:25:33111 // Synchronous in-process observer for CastWebContents. Observers must not
112 // destroy CastWebContents in any of the methods below.
113 class Observer : public base::CheckedObserver {
Sean Toppingf0a1d572019-06-17 23:03:44114 public:
115 Observer();
116
Sean Topping92d0465b2021-07-16 01:11:33117 // Adds |this| to the CastWebContents observer list. Observe(nullptr) will
118 // remove |this| from the observer list of the current CastWebContents being
119 // observed.
120 void Observe(CastWebContents* cast_web_contents);
121
Ryan Keane0d0493d2021-05-25 16:59:55122 // Called when the navigation is ready to be committed in the WebContents'
123 // main frame.
124 virtual void MainFrameReadyToCommitNavigation(
125 content::NavigationHandle* navigation_handle) {}
126
Sean Topping6c9e3932021-08-23 21:25:33127 // Sets |cast_web_contents_| to |nullptr| but does not remove the Observer
128 // from the ObserverList. Called for each Observer during CastWebContents
129 // destruction; we don't use Observe(nullptr) since it would mutate the
130 // ObserverList during iteration.
Chad Duffin4aa9c042019-01-11 00:51:55131 void ResetCastWebContents();
132
133 protected:
Sean Topping92d0465b2021-07-16 01:11:33134 ~Observer() override;
Chad Duffin4aa9c042019-01-11 00:51:55135
136 CastWebContents* cast_web_contents_;
Sean Toppinge91b0972018-10-25 20:59:12137 };
138
Sean Topping6735aaf2019-03-20 19:20:12139 static std::vector<CastWebContents*>& GetAll();
140
Jiawei Lia64a082b2019-12-06 21:17:26141 // Returns the CastWebContents that wraps the content::WebContents, or nullptr
142 // if the CastWebContents does not exist.
143 static CastWebContents* FromWebContents(content::WebContents* web_contents);
144
Sean Topping92d0465b2021-07-16 01:11:33145 CastWebContents();
146 ~CastWebContents() override;
Sean Toppinge91b0972018-10-25 20:59:12147
Sean Topping6735aaf2019-03-20 19:20:12148 // Tab identifier for the WebContents, mainly used by the tabs extension API.
149 // Tab IDs may be re-used, but no two live CastWebContents should have the
150 // same tab ID at any given time.
151 virtual int tab_id() const = 0;
152
Randy Rossic6bb3ab2020-08-11 18:02:52153 // An identifier for the WebContents, mainly used by platform views service.
154 // IDs may be re-used but are unique among all live CastWebContents.
155 virtual int id() const = 0;
156
Sean Topping0e8ac572019-01-30 03:05:43157 // TODO(seantopping): Hide this, clients shouldn't use WebContents directly.
Sean Toppinge91b0972018-10-25 20:59:12158 virtual content::WebContents* web_contents() const = 0;
159 virtual PageState page_state() const = 0;
160
Sean Topping92d0465b2021-07-16 01:11:33161 // mojom::CastWebContents implementation:
Sean Topping6c9e3932021-08-23 21:25:33162 void SetAppProperties(const std::string& app_id,
163 const std::string& session_id,
164 bool is_audio_app,
165 const GURL& app_web_url) override = 0;
166 void AddRendererFeatures(base::Value features) override = 0;
167 void SetInterfacesForRenderer(mojo::PendingRemote<mojom::RemoteInterfaces>
168 remote_interfaces) override = 0;
Sean Topping92d0465b2021-07-16 01:11:33169 void LoadUrl(const GURL& url) override = 0;
170 void ClosePage() override = 0;
171 void SetWebVisibilityAndPaint(bool visible) override = 0;
172 void BlockMediaLoading(bool blocked) override = 0;
173 void BlockMediaStarting(bool blocked) override = 0;
174 void EnableBackgroundVideoPlayback(bool enabled) override = 0;
Sean Topping6c9e3932021-08-23 21:25:33175 void ConnectToBindingsService(
176 mojo::PendingRemote<mojom::ApiBindings> api_bindings_remote) override = 0;
Sean Topping92d0465b2021-07-16 01:11:33177 void SetEnabledForRemoteDebugging(bool enabled) override = 0;
178 void AddObserver(
179 mojo::PendingRemote<mojom::CastWebContentsObserver> observer) override;
Sean Topping6c9e3932021-08-23 21:25:33180 void GetMainFramePid(GetMainFramePidCallback cb) override = 0;
Sean Topping92d0465b2021-07-16 01:11:33181
Sean Topping0e8ac572019-01-30 03:05:43182 // ===========================================================================
183 // Initialization and Setup
184 // ===========================================================================
185
Sean Topping92d0465b2021-07-16 01:11:33186 // TODO(b/149041392): This can be an initialization parameter.
Sean Topping0e8ac572019-01-30 03:05:43187 virtual void AllowWebAndMojoWebUiBindings() = 0;
188 virtual void ClearRenderWidgetHostView() = 0;
189
Sean Topping0e8ac572019-01-30 03:05:43190 // ===========================================================================
191 // Page Lifetime
192 // ===========================================================================
193
Sean Toppinge91b0972018-10-25 20:59:12194 // Stop the page immediately. This will automatically invoke
195 // Delegate::OnPageStopped(error_code), allowing the delegate to delete or
Sean Topping7414eed2019-04-10 23:04:21196 // reload the page without waiting for the WebContents owner to tear down the
197 // page.
Sean Toppinge91b0972018-10-25 20:59:12198 virtual void Stop(int error_code) = 0;
199
Sean Topping8a343862019-05-09 22:19:14200 // ===========================================================================
Jiawei Lidf9ad18a2019-07-07 05:31:02201 // Page Communication
202 // ===========================================================================
203
Jiawei Li3446cb72021-06-07 14:11:56204 // Executes a UTF-8 encoded |script| for every subsequent page load where
205 // the frame's URL has an origin reflected in |origins|. The script is
206 // executed early, prior to the execution of the document's scripts.
207 //
208 // Scripts are identified by a client-managed |id|. Any
209 // script previously injected using the same |id| will be replaced.
210 //
211 // The order in which multiple bindings are executed is the same as the
212 // order in which the bindings were added. If a script is added which
213 // clobbers an existing script of the same |id|, the previous script's
214 // precedence in the injection order will be preserved.
215 // |script| and |id| must be non-empty string.
216 virtual void AddBeforeLoadJavaScript(uint64_t id,
217 base::StringPiece script) = 0;
218
Jiawei Libba76072019-07-29 23:00:25219 // Posts a message to the frame's onMessage handler.
220 //
221 // `target_origin` restricts message delivery to the specified origin.
222 // If `target_origin` is "*", then the message will be sent to the
223 // document regardless of its origin.
224 // See html.spec.whatwg.org/multipage/web-messaging.html sect. 9.4.3
225 // for more details on how the target origin policy is applied.
226 // Should be called on UI thread.
Chris Hamilton825f2ed2020-01-30 21:46:41227 virtual void PostMessageToMainFrame(
228 const std::string& target_origin,
229 const std::string& data,
230 std::vector<blink::WebMessagePort> ports) = 0;
Jiawei Libba76072019-07-29 23:00:25231
Jiawei Li5283ad42020-03-27 21:26:05232 // Executes a string of JavaScript in the main frame's context.
233 // This is no-op if the main frame is not available.
234 // Pass in a callback to receive a result when it is available.
235 // If there is no need to receive the result, pass in a
236 // default-constructed callback. If provided, the callback
237 // will be invoked on the UI thread.
238 virtual void ExecuteJavaScript(
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58239 const std::u16string& javascript,
Jiawei Li5283ad42020-03-27 21:26:05240 base::OnceCallback<void(base::Value)> callback) = 0;
241
Jiawei Lidf9ad18a2019-07-07 05:31:02242 // ===========================================================================
Sean Topping8a343862019-05-09 22:19:14243 // Utility Methods
244 // ===========================================================================
245
Ken Rockot48c7b502020-11-20 23:33:59246 // Asks the CastWebContents to bind an interface receiver using either its
247 // registry or any registered InterfaceProvider.
248 virtual bool TryBindReceiver(mojo::GenericPendingReceiver& receiver) = 0;
249
Julie Jeongeun Kim641f4752019-12-04 01:53:22250 // Used for owner to pass its |InterfaceProvider| pointers to CastWebContents.
251 // It is owner's responsibility to make sure each |InterfaceProvider| pointer
252 // has distinct mojo interface set.
Jiawei Li830fcfd2019-02-12 20:12:17253 using InterfaceSet = base::flat_set<std::string>;
254 virtual void RegisterInterfaceProvider(
255 const InterfaceSet& interface_set,
256 service_manager::InterfaceProvider* interface_provider) = 0;
257
Jiawei Lia64a082b2019-12-06 21:17:26258 // Returns true if WebSQL database is configured enabled for this
259 // CastWebContents.
260 virtual bool is_websql_enabled() = 0;
261
262 // Returns true if mixer audio is enabled.
263 virtual bool is_mixer_audio_enabled() = 0;
264
Sean Topping92d0465b2021-07-16 01:11:33265 // Binds a receiver for remote control of CastWebContents.
266 void BindReceiver(mojo::PendingReceiver<mojom::CastWebContents> receiver);
267
268 protected:
Sean Topping6c9e3932021-08-23 21:25:33269 mojo::ReceiverSet<mojom::CastWebContents> receivers_;
Sean Topping92d0465b2021-07-16 01:11:33270 mojo::RemoteSet<mojom::CastWebContentsObserver> observers_;
Sean Topping6c9e3932021-08-23 21:25:33271 base::ObserverList<Observer> sync_observers_;
Sean Topping92d0465b2021-07-16 01:11:33272
Sean Toppinge91b0972018-10-25 20:59:12273 private:
Sean Topping92d0465b2021-07-16 01:11:33274 friend class Observer;
275
276 // These functions should only be invoked by CastWebContents::Observer in a
277 // valid sequence, enforced via SequenceChecker.
Sean Topping6c9e3932021-08-23 21:25:33278 void AddObserver(Observer* observer);
279 void RemoveObserver(Observer* observer);
Sean Topping92d0465b2021-07-16 01:11:33280
Sean Toppinge91b0972018-10-25 20:59:12281 DISALLOW_COPY_AND_ASSIGN(CastWebContents);
282};
283
Sean Toppinge91b0972018-10-25 20:59:12284} // namespace chromecast
285
286#endif // CHROMECAST_BROWSER_CAST_WEB_CONTENTS_H_