blob: 22a8449acc63fb1979185b20a2bcdfede1b749b6 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_WEBUI_TOP_CHROME_WEBUI_CONTENTS_WRAPPER_H_
#define CHROME_BROWSER_UI_WEBUI_TOP_CHROME_WEBUI_CONTENTS_WRAPPER_H_
#include <memory>
#include <utility>
#include "base/memory/weak_ptr.h"
#include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
#include "chrome/browser/task_manager/web_contents_tags.h"
#include "chrome/browser/ui/webui/top_chrome/top_chrome_web_ui_controller.h"
#include "chrome/browser/ui/webui/top_chrome/webui_contents_preload_manager.h"
#include "chrome/browser/ui/webui_name_variants.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/file_select_listener.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/common/referrer.h"
#include "third_party/blink/public/mojom/page/draggable_region.mojom.h"
#include "ui/base/models/menu_model.h"
namespace content {
class BrowserContext;
} // namespace content
// WebUIContentsWrapper wraps a WebContents that hosts a top chrome WebUI.
// This class notifies the Host when it should be shown or hidden via ShowUI()
// and CloseUI() in addition to passing through resize events so the Host can
// adjust bounds accordingly.
class WebUIContentsWrapper : public content::WebContentsDelegate,
public content::WebContentsObserver,
public TopChromeWebUIController::Embedder {
public:
class Host {
public:
virtual void CloseUI() = 0;
virtual void ShowUI() = 0;
virtual void ShowCustomContextMenu(
gfx::Point point,
std::unique_ptr<ui::MenuModel> menu_model) {}
virtual void HideCustomContextMenu() {}
virtual void ResizeDueToAutoResize(content::WebContents* source,
const gfx::Size& new_size) {}
virtual bool HandleKeyboardEvent(
content::WebContents* source,
const content::NativeWebKeyboardEvent& event);
virtual bool HandleContextMenu(content::RenderFrameHost& render_frame_host,
const content::ContextMenuParams& params);
virtual void RequestMediaAccessPermission(
content::WebContents* web_contents,
const content::MediaStreamRequest& request,
content::MediaResponseCallback callback) {}
virtual content::WebContents* OpenURLFromTab(
content::WebContents* source,
const content::OpenURLParams& params,
base::OnceCallback<void(content::NavigationHandle&)>
navigation_handle_callback);
virtual void RunFileChooser(
content::RenderFrameHost* render_frame_host,
scoped_refptr<content::FileSelectListener> listener,
const blink::mojom::FileChooserParams& params) {}
virtual void DraggableRegionsChanged(
const std::vector<blink::mojom::DraggableRegionPtr>& regions,
content::WebContents* contents) {}
};
WebUIContentsWrapper(const GURL& webui_url,
content::BrowserContext* browser_context,
int task_manager_string_id,
bool webui_resizes_host,
bool esc_closes_ui,
bool supports_draggable_regions,
const std::string& webui_name);
~WebUIContentsWrapper() override;
// content::WebContentsDelegate:
void ResizeDueToAutoResize(content::WebContents* source,
const gfx::Size& new_size) override;
content::KeyboardEventProcessingResult PreHandleKeyboardEvent(
content::WebContents* source,
const content::NativeWebKeyboardEvent& event) override;
bool HandleKeyboardEvent(
content::WebContents* source,
const content::NativeWebKeyboardEvent& event) override;
bool HandleContextMenu(content::RenderFrameHost& render_frame_host,
const content::ContextMenuParams& params) override;
std::unique_ptr<content::EyeDropper> OpenEyeDropper(
content::RenderFrameHost* frame,
content::EyeDropperListener* listener) override;
void RequestMediaAccessPermission(
content::WebContents* web_contents,
const content::MediaStreamRequest& request,
content::MediaResponseCallback callback) override;
content::WebContents* OpenURLFromTab(
content::WebContents* source,
const content::OpenURLParams& params,
base::OnceCallback<void(content::NavigationHandle&)>
navigation_handle_callback) override;
void RunFileChooser(content::RenderFrameHost* render_frame_host,
scoped_refptr<content::FileSelectListener> listener,
const blink::mojom::FileChooserParams& params) override;
void DraggableRegionsChanged(
const std::vector<blink::mojom::DraggableRegionPtr>& regions,
content::WebContents* contents) override;
// content::WebContentsObserver:
void PrimaryPageChanged(content::Page& page) override;
void PrimaryMainFrameRenderProcessGone(
base::TerminationStatus status) override;
// TopChromeWebUIController::Embedder:
void CloseUI() override;
void ShowUI() override;
void ShowContextMenu(gfx::Point point,
std::unique_ptr<ui::MenuModel> menu_model) override;
void HideContextMenu() override;
// Reloads the WebContents hosting the WebUI.
virtual void ReloadWebContents() = 0;
// True if the host can show the contents immediately.
bool is_ready_to_show() const { return is_ready_to_show_; }
bool supports_draggable_regions() const {
return supports_draggable_regions_;
}
// Gets weak ptr to prevent UAF.
virtual base::WeakPtr<WebUIContentsWrapper> GetWeakPtr() = 0;
base::WeakPtr<WebUIContentsWrapper::Host> GetHost();
void SetHost(base::WeakPtr<WebUIContentsWrapper::Host> host);
content::WebContents* web_contents() { return web_contents_.get(); }
void SetWebContentsForTesting(
std::unique_ptr<content::WebContents> web_contents);
private:
// If true will allow the wrapped WebContents to automatically resize its
// RenderWidgetHostView and send back updates to `Host` for the new size.
const bool webui_resizes_host_;
// Captures the content size when `webui_resizes_host` is true. This
// size is passed to Host::ResizeDueToAutoResize() host when the host is set.
gfx::Size contents_requested_size_;
bool is_ready_to_show_ = false;
// If true will cause the ESC key to close the UI during pre-handling.
const bool esc_closes_ui_;
// Set if the wrapped contents should enable web platform draggable regions,
// tagged using the -webkit-app-region CSS property.
const bool supports_draggable_regions_;
// The most recent draggable region set by DraggableRegionsChanged().
std::optional<std::vector<blink::mojom::DraggableRegionPtr>>
draggable_regions_;
base::WeakPtr<WebUIContentsWrapper::Host> host_;
std::unique_ptr<content::WebContents> web_contents_;
};
// WebUIContentsWrapperT is designed to be paired with the WebUIController
// subclass used by the hosted WebUI. This type information allows compile time
// checking that the WebUIController subclasses TopChromeWebUIController as
// expected.
template <typename T>
class WebUIContentsWrapperT : public WebUIContentsWrapper {
public:
// TODO(tluk): Consider introducing init params to avoid further cluttering
// constructor params.
WebUIContentsWrapperT(const GURL& webui_url,
content::BrowserContext* browser_context,
int task_manager_string_id,
bool webui_resizes_host = true,
bool esc_closes_ui = true,
bool supports_draggable_regions = false)
: WebUIContentsWrapper(webui_url,
browser_context,
task_manager_string_id,
webui_resizes_host,
esc_closes_ui,
supports_draggable_regions,
T::GetWebUIName()),
webui_url_(webui_url) {
static_assert(
views_metrics::IsValidWebUINameVariant("." + T::GetWebUIName()));
if (is_ready_to_show()) {
CHECK(GetWebUIController());
GetWebUIController()->set_embedder(weak_ptr_factory_.GetWeakPtr());
} else {
ReloadWebContents();
}
}
void ReloadWebContents() override {
web_contents()->GetController().LoadURL(webui_url_, content::Referrer(),
ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
std::string());
// Depends on the WebUIController object being constructed synchronously
// when the navigation is started in LoadInitialURL(). The WebUIController
// may not be defined at this point if the content code encounteres an
// error during navigation so check here to ensure the pointer is valid.
if (T* webui_controller = GetWebUIController())
webui_controller->set_embedder(weak_ptr_factory_.GetWeakPtr());
}
// May return null.
T* GetWebUIController() {
content::WebUI* const webui = web_contents()->GetWebUI();
return webui && webui->GetController()
? webui->GetController()->template GetAs<T>()
: nullptr;
}
base::WeakPtr<WebUIContentsWrapper> GetWeakPtr() override {
return weak_ptr_factory_.GetWeakPtr();
}
private:
const GURL webui_url_;
base::WeakPtrFactory<WebUIContentsWrapper> weak_ptr_factory_{this};
};
#endif // CHROME_BROWSER_UI_WEBUI_TOP_CHROME_WEBUI_CONTENTS_WRAPPER_H_