blob: 6d2eea53791c63398cbfb48836eff3b40fb85c4d [file] [log] [blame]
// Copyright 2012 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_PUBLIC_BROWSER_WEB_UI_H_
#define CONTENT_PUBLIC_BROWSER_WEB_UI_H_
#include <memory>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/values.h"
#include "content/common/content_export.h"
#include "ui/base/page_transition_types.h"
class GURL;
namespace content {
class RenderFrameHost;
class WebContents;
class WebUIController;
class WebUIMessageHandler;
// A WebUI sets up the datasources and message handlers for a given HTML-based
// UI.
class CONTENT_EXPORT WebUI {
public:
// An opaque identifier used to identify a WebUI. This can only be compared to
// kNoWebUI or other WebUI types. See GetWebUIType.
typedef const void* TypeID;
// A special WebUI type that signifies that a given page would not use the
// Web UI system.
static const TypeID kNoWebUI;
// Returns JavaScript code that, when executed, calls the function specified
// by |function_name| with the arguments specified in |arg_list|.
static std::u16string GetJavascriptCall(
std::string_view function_name,
base::span<const base::ValueView> arg_list);
static std::u16string GetJavascriptCall(std::string_view function_name,
const base::Value::List& arg_list);
virtual ~WebUI() {}
virtual WebContents* GetWebContents() = 0;
virtual WebUIController* GetController() = 0;
virtual void SetController(std::unique_ptr<WebUIController> controller) = 0;
// This might return nullptr
// 1. During construction, until the WebUI is associated with
// a RenderFrameHost.
// 2. During destruction, if the WebUI's destruction causes the
// RenderFrameHost to be destroyed (crbug.com/1308391).
// 3. In unittests where the WebUI is mocked, notably by TestWebUI.
virtual RenderFrameHost* GetRenderFrameHost() = 0;
// Returns the device scale factor of the monitor that the renderer is on.
// Whenever possible, WebUI should push resources with this scale factor to
// Javascript.
virtual float GetDeviceScaleFactor() = 0;
// Gets a custom tab title provided by the Web UI. If there is no title
// override, the string will be empty which should trigger the default title
// behavior for the tab.
virtual const std::u16string& GetOverriddenTitle() = 0;
virtual void OverrideTitle(const std::u16string& title) = 0;
// Allows a controller to override the BindingsPolicy that should be enabled
// for this page.
virtual int GetBindings() = 0;
virtual void SetBindings(int bindings) = 0;
// Allows a scheme to be requested which is provided by the WebUIController.
virtual const std::vector<std::string>& GetRequestableSchemes() = 0;
virtual void AddRequestableScheme(const char* scheme) = 0;
virtual void AddMessageHandler(
std::unique_ptr<WebUIMessageHandler> handler) = 0;
// Used by WebUIMessageHandlers. If the given message is already registered,
// the call has no effect.
using MessageCallback =
base::RepeatingCallback<void(const base::Value::List&)>;
virtual void RegisterMessageCallback(std::string_view message,
MessageCallback callback) = 0;
template <typename... Args>
void RegisterHandlerCallback(
std::string_view message,
base::RepeatingCallback<void(Args...)> callback) {
RegisterMessageCallback(
message, base::BindRepeating(
&Call<std::index_sequence_for<Args...>, Args...>::Impl,
callback, message));
}
// This is only needed if an embedder overrides handling of a WebUIMessage and
// then later wants to undo that, or to route it to a different WebUI object.
virtual void ProcessWebUIMessage(const GURL& source_url,
const std::string& message,
base::Value::List args) = 0;
// Returns true if this WebUI can currently call JavaScript.
virtual bool CanCallJavascript() = 0;
// Calling these functions directly is discouraged. It's generally preferred
// to call WebUIMessageHandler::CallJavascriptFunction, as that has
// lifecycle controls to prevent calling JavaScript before the page is ready.
//
// Call a Javascript function by sending its name and arguments down to
// the renderer. This is asynchronous; there's no way to get the result
// of the call, and should be thought of more like sending a message to
// the page.
//
// All function names in WebUI must consist of only ASCII characters.
// There are variants for calls with more arguments.
virtual void CallJavascriptFunctionUnsafe(std::string_view function_name) = 0;
virtual void CallJavascriptFunctionUnsafe(
std::string_view function_name,
base::span<const base::ValueView> args) = 0;
template <typename... Args>
void CallJavascriptFunctionUnsafe(std::string_view function_name,
const base::ValueView arg1,
const Args&... arg) {
base::ValueView args[] = {arg1, arg...};
CallJavascriptFunctionUnsafe(function_name, args);
}
// Allows mutable access to this WebUI's message handlers for testing.
virtual std::vector<std::unique_ptr<WebUIMessageHandler>>*
GetHandlersForTesting() = 0;
private:
template <typename T>
static T GetValue(const base::Value& value);
template <typename Is, typename... Args>
struct Call;
// Helper to unpack a base::Value::List and invoke a callback, passing
// list[0] as the first argument, list[1] as the second argument, et cetera.
// Each value in the list will be coerced to the type of the corresponding
// function parameter, CHECK()ing if the conversion is not possible or if the
// number of arguments is wrong.
template <size_t... Is, typename... Args>
struct Call<std::index_sequence<Is...>, Args...> {
static void Impl(base::RepeatingCallback<void(Args...)> callback,
std::string_view message,
const base::Value::List& list) {
CHECK_EQ(list.size(), sizeof...(Args)) << message;
callback.Run(GetValue<Args>(list[Is])...);
}
};
};
template <>
inline bool WebUI::GetValue<bool>(const base::Value& value) {
return value.GetBool();
}
template <>
inline int WebUI::GetValue<int>(const base::Value& value) {
return value.GetInt();
}
template <>
inline const std::string& WebUI::GetValue<const std::string&>(
const base::Value& value) {
return value.GetString();
}
template <>
inline const base::Value::Dict& WebUI::GetValue<const base::Value::Dict&>(
const base::Value& value) {
return value.GetDict();
}
template <>
inline const base::Value::List& WebUI::GetValue<const base::Value::List&>(
const base::Value& value) {
return value.GetList();
}
} // namespace content
#endif // CONTENT_PUBLIC_BROWSER_WEB_UI_H_