910e62b5创建于 1月15日历史提交
// Copyright 2014 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_DEVTOOLS_PROTOCOL_PAGE_HANDLER_H_
#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_PAGE_HANDLER_H_

#include <stddef.h>

#include <map>
#include <memory>
#include <optional>
#include <string>
#include <variant>
#include <vector>

#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "build/build_config.h"
#include "cc/trees/render_frame_metadata.h"
#include "content/browser/devtools/devtools_video_consumer.h"
#include "content/browser/devtools/protocol/devtools_domain_handler.h"
#include "content/browser/devtools/protocol/devtools_download_manager_delegate.h"
#include "content/browser/devtools/protocol/page.h"
#include "content/browser/preloading/prerender/prerender_final_status.h"
#include "content/browser/renderer_host/back_forward_cache_impl.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/public/browser/download_manager.h"
#include "content/public/browser/javascript_dialog_manager.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_observer.h"
#include "content/public/common/javascript_dialog_type.h"
#include "third_party/blink/public/mojom/manifest/manifest.mojom-forward.h"
#include "url/gurl.h"

class SkBitmap;

namespace base {
class UnguessableToken;
}

namespace gfx {
class Image;
}  // namespace gfx

namespace content {

class BackForwardCacheCanStoreDocumentResult;
class DevToolsAgentHostImpl;
class FrameTreeNode;
class NavigationRequest;
class RenderFrameHostImpl;
class WebContentsImpl;

namespace protocol {

class BrowserHandler;
class EmulationHandler;

class PageHandler : public DevToolsDomainHandler,
                    public Page::Backend,
                    public RenderWidgetHostObserver,
                    public download::DownloadItem::Observer {
 public:
  PageHandler(
      EmulationHandler* emulation_handler,
      BrowserHandler* browser_handler,
      bool allow_unsafe_operations,
      bool is_trusted,
      std::optional<url::Origin> navigation_initiator_origin,
      bool may_read_local_files,
      base::RepeatingCallback<void(std::string)> prepare_for_reload_callback);

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

  ~PageHandler() override;

  static std::vector<PageHandler*> EnabledForWebContents(
      WebContentsImpl* contents);
  static std::vector<PageHandler*> ForAgentHost(DevToolsAgentHostImpl* host);

  void Wire(UberDispatcher* dispatcher) override;
  void SetRenderer(int process_host_id,
                   RenderFrameHostImpl* frame_host) override;
  // Instrumentation signals.
  void DidAttachInterstitialPage();
  void DidDetachInterstitialPage();
  using JavaScriptDialogCallback =
      content::JavaScriptDialogManager::DialogClosedCallback;
  void DidRunJavaScriptDialog(const GURL& url,
                              const base::UnguessableToken& frame_id,
                              const std::u16string& message,
                              const std::u16string& default_prompt,
                              JavaScriptDialogType dialog_type,
                              bool has_non_devtools_handlers,
                              JavaScriptDialogCallback callback);
  void DidRunBeforeUnloadConfirm(const GURL& url,
                                 const base::UnguessableToken& frame_id,
                                 bool has_non_devtools_handlers,
                                 JavaScriptDialogCallback callback);
  void DidCloseJavaScriptDialog(const base::UnguessableToken& frame_id,
                                bool success,
                                const std::u16string& user_input);
  void NavigationReset(NavigationRequest* navigation_request);
  void DownloadWillBegin(FrameTreeNode* ftn, download::DownloadItem* item);
  void DidStartNavigating(FrameTreeNode& ftn,
                          const GURL& url,
                          const base::UnguessableToken& loader_id,
                          const blink::mojom::NavigationType& navigation_type);

  void OnFrameDetached(const base::UnguessableToken& frame_id);
  void DidChangeFrameLoadingState(const FrameTreeNode& ftn);

  bool ShouldBypassCSP();
  void BackForwardCacheNotUsed(
      const NavigationRequest* nav_request,
      const BackForwardCacheCanStoreDocumentResult* result,
      const BackForwardCacheCanStoreTreeResult* tree_result);

  void IsPrerenderingAllowed(bool& is_allowed);
  void ReadyToCommitNavigation(NavigationRequest* navigation_request);

  Response Enable(
      std::optional<bool> enable_file_chooser_opened_event) override;
  Response Disable() override;

  Response Crash() override;
  Response Close() override;
  void Reload(std::optional<bool> bypassCache,
              std::optional<std::string> script_to_evaluate_on_load,
              std::optional<std::string> loader_id,
              std::unique_ptr<ReloadCallback> callback) override;
  void Navigate(const std::string& url,
                std::optional<std::string> referrer,
                std::optional<std::string> transition_type,
                std::optional<std::string> frame_id,
                std::optional<std::string> referrer_policy,
                std::unique_ptr<NavigateCallback> callback) override;
  Response StopLoading() override;

  using NavigationEntries = protocol::Array<Page::NavigationEntry>;
  Response GetNavigationHistory(
      int* current_index,
      std::unique_ptr<NavigationEntries>* entries) override;
  Response NavigateToHistoryEntry(int entry_id) override;
  Response ResetNavigationHistory() override;

  void CaptureScreenshot(
      std::optional<std::string> format,
      std::optional<int> quality,
      std::unique_ptr<Page::Viewport> clip,
      std::optional<bool> from_surface,
      std::optional<bool> capture_beyond_viewport,
      std::optional<bool> optimize_for_speed,
      std::unique_ptr<CaptureScreenshotCallback> callback) override;
  void CaptureSnapshot(
      std::optional<std::string> format,
      std::unique_ptr<CaptureSnapshotCallback> callback) override;
  Response StartScreencast(std::optional<std::string> format,
                           std::optional<int> quality,
                           std::optional<int> max_width,
                           std::optional<int> max_height,
                           std::optional<int> every_nth_frame) override;
  Response StopScreencast() override;
  Response ScreencastFrameAck(int session_id) override;

  Response HandleJavaScriptDialog(
      bool accept,
      std::optional<std::string> prompt_text) override;

  Response BringToFront() override;

  Response SetDownloadBehavior(
      const std::string& behavior,
      std::optional<std::string> download_path) override;

  void GetAppManifest(
      std::optional<std::string> manifest_id,
      std::unique_ptr<GetAppManifestCallback> callback) override;

  Response SetWebLifecycleState(const std::string& state) override;
  void GetInstallabilityErrors(
      std::unique_ptr<GetInstallabilityErrorsCallback> callback) override;

  void GetManifestIcons(
      std::unique_ptr<GetManifestIconsCallback> callback) override;

  void GetAppId(std::unique_ptr<GetAppIdCallback> callback) override;

  Response SetBypassCSP(bool enabled) override;
  Response AddCompilationCache(const std::string& url,
                               const Binary& data) override;

  Response SetPrerenderingAllowed(bool is_allowed) override;
  void GetAnnotatedPageContent(
      std::optional<bool> include_actionable_information,
      std::unique_ptr<GetAnnotatedPageContentCallback> callback) override;

  Response AssureTopLevelActiveFrame();

 private:
  struct PendingScreenshotRequest;

  using BitmapEncoder =
      base::RepeatingCallback<std::optional<std::vector<uint8_t>>(
          const SkBitmap& bitmap)>;

  void CaptureFullPageScreenshot(
      std::optional<std::string> format,
      std::optional<int> quality,
      std::optional<bool> optimize_for_speed,
      std::unique_ptr<CaptureScreenshotCallback> callback,
      const gfx::Size& full_page_size);
  bool ShouldCaptureNextScreencastFrame();
  void NotifyScreencastVisibility(bool visible);
  void OnFrameFromVideoConsumer(scoped_refptr<media::VideoFrame> frame);
  void ScreencastFrameCaptured(
      std::unique_ptr<Page::ScreencastFrameMetadata> metadata,
      const SkBitmap& bitmap);
  void ScreencastFrameEncoded(
      std::unique_ptr<Page::ScreencastFrameMetadata> metadata,
      std::optional<std::vector<uint8_t>> data);

  void ScreenshotCaptured(std::unique_ptr<PendingScreenshotRequest> request,
                          const gfx::Image& image);

  // RenderWidgetHostObserver overrides.
  void RenderWidgetHostVisibilityChanged(RenderWidgetHost* widget_host,
                                         bool became_visible) override;
  void RenderWidgetHostDestroyed(RenderWidgetHost* widget_host) override;

  // DownloadItem::Observer overrides
  void OnDownloadUpdated(download::DownloadItem* item) override;
  void OnDownloadDestroyed(download::DownloadItem* item) override;

  // Returns WebContents only if `host_` is a top level frame. Otherwise, it
  // returns Response with an error.
  using ResponseOrWebContents = std::variant<Response, WebContentsImpl*>;
  ResponseOrWebContents GetWebContentsForTopLevelActiveFrame();

  const bool allow_unsafe_operations_;
  const bool is_trusted_;
  const std::optional<url::Origin> navigation_initiator_origin_;
  const bool may_read_local_files_;

  bool enabled_;
  bool bypass_csp_ = false;

  BitmapEncoder screencast_encoder_;
  int screencast_max_width_;
  int screencast_max_height_;
  int capture_every_nth_frame_;
  int session_id_;
  int frame_counter_;
  int frames_in_flight_;

  // |video_consumer_| consumes video frames from FrameSinkVideoCapturerImpl,
  // and provides PageHandler with these frames via OnFrameFromVideoConsumer.
  // This is only used if Viz is enabled and if OS is not Android.
  std::unique_ptr<DevToolsVideoConsumer> video_consumer_;

  // The last surface size used to determine if frames with new sizes need
  // to be requested. This changes due to window resizing.
  gfx::Size last_surface_size_;

  raw_ptr<RenderFrameHostImpl> host_;
  raw_ptr<EmulationHandler> emulation_handler_;
  raw_ptr<BrowserHandler> browser_handler_;

  std::unique_ptr<Page::Frontend> frontend_;

  base::ScopedObservation<RenderWidgetHost, RenderWidgetHostObserver>
      observation_{this};
  JavaScriptDialogCallback pending_dialog_;
  // Maps DevTools navigation tokens to pending NavigateCallbacks.
  base::flat_map<base::UnguessableToken, std::unique_ptr<NavigateCallback>>
      navigate_callbacks_;
  base::flat_set<raw_ptr<download::DownloadItem, CtnExperimental>>
      pending_downloads_;

  bool is_prerendering_allowed_ = true;
  base::RepeatingCallback<void(std::string)> prepare_for_reload_callback_;
  bool have_pending_reload_ = false;
  std::string pending_script_to_evaluate_on_load_;

  base::WeakPtrFactory<PageHandler> weak_factory_{this};
};

}  // namespace protocol
}  // namespace content

#endif  // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_PAGE_HANDLER_H_