chromium/chromecast/browser/cast_web_contents_impl.h

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROMECAST_BROWSER_CAST_WEB_CONTENTS_IMPL_H_
#define CHROMECAST_BROWSER_CAST_WEB_CONTENTS_IMPL_H_

#include <map>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <string_view>
#include <vector>

#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/memory/platform_shared_memory_region.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "chromecast/bindings/public/mojom/api_bindings.mojom.h"
#include "chromecast/browser/cast_media_blocker.h"
#include "chromecast/browser/cast_web_contents.h"
#include "chromecast/browser/mojom/cast_web_service.mojom.h"
#include "chromecast/browser/named_message_port_connector_cast.h"
#include "chromecast/mojo/remote_interfaces.h"
#include "components/media_control/browser/media_blocker.h"
#include "components/on_load_script_injector/browser/on_load_script_injector_host.h"
#include "components/url_rewrite/browser/url_request_rewrite_rules_manager.h"
#include "content/public/browser/render_process_host_observer.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/media_playback_renderer_type.mojom.h"
#include "mojo/public/cpp/bindings/associated_receiver_set.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "third_party/blink/public/mojom/favicon/favicon_url.mojom-forward.h"

namespace content {
class NavigationHandle;
}  // namespace content

namespace chromecast {

namespace shell {
class RemoteDebuggingServer;
}  // namespace shell

class CastWebContentsImpl : public CastWebContents,
                            public content::RenderProcessHostObserver,
                            public content::WebContentsObserver {
 public:
  CastWebContentsImpl(content::WebContents* web_contents,
                      mojom::CastWebViewParamsPtr params);

  CastWebContentsImpl(const CastWebContentsImpl&) = delete;
  CastWebContentsImpl& operator=(const CastWebContentsImpl&) = delete;

  ~CastWebContentsImpl() override;

  content::WebContents* web_contents() const override;
  PageState page_state() const override;
  url_rewrite::UrlRequestRewriteRulesManager* url_rewrite_rules_manager()
      override;
  const media_control::MediaBlocker* media_blocker() const override;

  // CastWebContents implementation:
  int tab_id() const override;
  int id() const override;
  void SetAppProperties(const std::string& app_id,
                        const std::string& session_id,
                        bool is_audio_app,
                        const GURL& app_web_url,
                        bool enforce_feature_permissions,
                        const std::vector<int32_t>& feature_permissions,
                        const std::vector<std::string>&
                            additional_feature_permission_origins) override;
  void SetGroupInfo(const std::string& session_id,
                    bool is_multizone_launch) override;
  void AddRendererFeatures(base::Value::Dict features) override;
  void SetInterfacesForRenderer(
      mojo::PendingRemote<mojom::RemoteInterfaces> remote_interfaces) override;
  void SetUrlRewriteRules(
      url_rewrite::mojom::UrlRequestRewriteRulesPtr rules) override;
  void LoadUrl(const GURL& url) override;
  void ClosePage() override;
  void Stop(int error_code) override;
  void SetWebVisibilityAndPaint(bool visible) override;
  bool TryBindReceiver(mojo::GenericPendingReceiver& receiver) override;
  InterfaceBundle* local_interfaces() override;
  void BlockMediaLoading(bool blocked) override;
  void BlockMediaStarting(bool blocked) override;
  void EnableBackgroundVideoPlayback(bool enabled) override;
  void AddBeforeLoadJavaScript(uint64_t id, std::string_view script) override;
  void PostMessageToMainFrame(
      const std::string& target_origin,
      const std::string& data,
      std::vector<blink::WebMessagePort> ports) override;
  void ExecuteJavaScript(
      const std::u16string& javascript,
      base::OnceCallback<void(base::Value)> callback) override;
  void ConnectToBindingsService(
      mojo::PendingRemote<mojom::ApiBindings> api_bindings_remote) override;
  void SetEnabledForRemoteDebugging(bool enabled) override;
  void GetMainFramePid(GetMainFramePidCallback cb) override;
  bool is_websql_enabled() override;
  bool is_mixer_audio_enabled() override;

  // content::RenderProcessHostObserver implementation:
  void RenderProcessReady(content::RenderProcessHost* host) override;
  void RenderProcessExited(
      content::RenderProcessHost* host,
      const content::ChildProcessTerminationInfo& info) override;
  void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;

  // content::WebContentsObserver implementation:
  void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
  void PrimaryMainFrameRenderProcessGone(
      base::TerminationStatus status) override;
  void DidStartNavigation(
      content::NavigationHandle* navigation_handle) override;
  void DidRedirectNavigation(
      content::NavigationHandle* navigation_handle) override;
  void ReadyToCommitNavigation(
      content::NavigationHandle* navigation_handle) override;
  void DidFinishNavigation(
      content::NavigationHandle* navigation_handle) override;
  void DidFinishLoad(content::RenderFrameHost* render_frame_host,
                     const GURL& validated_url) override;
  void DidFailLoad(content::RenderFrameHost* render_frame_host,
                   const GURL& validated_url,
                   int error_code) override;
  void ResourceLoadComplete(
      content::RenderFrameHost* render_frame_host,
      const content::GlobalRequestID& request_id,
      const blink::mojom::ResourceLoadInfo& resource_load_info) override;
  void InnerWebContentsCreated(
      content::WebContents* inner_web_contents) override;
  void TitleWasSet(content::NavigationEntry* entry) override;
  void DidFirstVisuallyNonEmptyPaint() override;
  void WebContentsDestroyed() override;
  void DidUpdateFaviconURL(
      content::RenderFrameHost* render_frame_host,
      const std::vector<blink::mojom::FaviconURLPtr>& candidates) override;
  void MediaStartedPlaying(const MediaPlayerInfo& video_type,
                           const content::MediaPlayerId& id) override;
  void MediaStoppedPlaying(
      const MediaPlayerInfo& video_type,
      const content::MediaPlayerId& id,
      content::WebContentsObserver::MediaStoppedReason reason) override;

 private:
  // Constructor used to create inner CastWebContents. This allows inner
  // contents to share the same URL rewrite rules as the root.
  CastWebContentsImpl(content::WebContents* web_contents,
                      mojom::CastWebViewParamsPtr params,
                      CastWebContents* parent);
  void OnPageLoading();
  void OnPageLoaded();
  void UpdatePageState();
  void NotifyPageState();
  void TracePageLoadBegin(const GURL& url);
  void TracePageLoadEnd(const GURL& url);
  void DisableDebugging();
  void OnClosePageTimeout();
  void RemoveRenderProcessHostObserver();
  std::vector<chromecast::shell::mojom::FeaturePtr> GetRendererFeatures();
  void OnBindingsReceived(
      std::vector<chromecast::mojom::ApiBindingPtr> bindings);
  bool OnPortConnected(std::string_view port_name,
                       std::unique_ptr<cast_api_bindings::MessagePort> port);

  content::WebContents* web_contents_;
  mojom::CastWebViewParamsPtr params_;
  std::optional<url_rewrite::UrlRequestRewriteRulesManager>
      url_rewrite_rules_manager_;
  PageState page_state_;
  PageState last_state_;
  shell::RemoteDebuggingServer* const remote_debugging_server_;
  std::unique_ptr<CastMediaBlocker> media_blocker_;
  std::optional<std::vector<std::string>> activity_url_filter_;

  // Retained so that this observer can be removed before being destroyed:
  content::RenderProcessHost* main_process_host_;

  CastWebContents* const parent_cast_web_contents_ = nullptr;
  base::flat_set<std::unique_ptr<CastWebContents>> inner_contents_;
  base::Value::Dict renderer_features_;

  const int tab_id_;
  const int id_;
  base::TimeTicks start_loading_ticks_;

  // True once the main frame finishes loading and there are no outstanding
  // navigations.
  bool main_frame_loaded_;
  content::NavigationHandle* active_navigation_ = nullptr;

  bool closing_;
  bool stopped_;
  bool stop_notified_;
  bool notifying_;
  int last_error_;

  on_load_script_injector::OnLoadScriptInjectorHost<uint64_t> script_injector_;
  mojo::Remote<mojom::ApiBindings> api_bindings_;

  // If |ConnectToBindingsService| is invoked, |bindings_received_| is set
  // false. Following |LoadUrl| will be stored in |pending_load_url_|, and
  // will be invoked once bindings are received.
  bool bindings_received_{false};
  GURL pending_load_url_;

  // Used to open a MessageChannel for connecting API bindings.
  std::unique_ptr<NamedMessagePortConnectorCast> named_message_port_connector_;

  base::ObserverList<CastWebContentsObserver>::Unchecked observer_list_;

  InterfaceBundle local_interfaces_;
  RemoteInterfaces remote_interfaces_;

  const scoped_refptr<base::SequencedTaskRunner> task_runner_;

  SEQUENCE_CHECKER(sequence_checker_);
  base::WeakPtrFactory<CastWebContentsImpl> weak_factory_;
};

}  // namespace chromecast

#endif  // CHROMECAST_BROWSER_CAST_WEB_CONTENTS_IMPL_H_