1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198

content / public / browser / web_ui.h [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 "content/public/common/bindings_policy.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 BindingsPolicySet GetBindings() = 0;
  virtual void SetBindings(BindingsPolicySet 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.
  void CallJavascriptFunctionUnsafe(std::string_view function_name) {
    CallJavascriptFunctionUnsafe(function_name, {});
  }

  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_