#ifndef CONTENT_PUBLIC_BROWSER_WEB_UI_CONTROLLER_INTERFACE_BINDER_H_
#define CONTENT_PUBLIC_BROWSER_WEB_UI_CONTROLLER_INTERFACE_BINDER_H_
#include <type_traits>
#include "content/common/content_export.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_controller.h"
#include "mojo/public/cpp/bindings/binder_map.h"
namespace content {
namespace internal {
template <typename Interface, int N, typename... Subclasses>
struct BinderHelper;
template <typename Interface, typename WebUIControllerSubclass, typename = void>
struct BinderTakesRenderFrameHost : std::false_type {};
template <typename Interface, typename WebUIControllerSubclass>
struct BinderTakesRenderFrameHost<
Interface,
WebUIControllerSubclass,
decltype(std::declval<WebUIControllerSubclass>().BindInterface(
std::declval<RenderFrameHost*>(),
std::declval<mojo::PendingReceiver<Interface>>()))> : std::true_type {};
template <typename Interface, typename WebUIControllerSubclass>
bool SafeDownCastAndBindInterface(RenderFrameHost* host,
mojo::PendingReceiver<Interface>& receiver) {
WebUI* web_ui = host->GetWebUI();
WebUIControllerSubclass* concrete_controller =
web_ui ? web_ui->GetController()->GetAs<WebUIControllerSubclass>()
: nullptr;
if (!concrete_controller)
return false;
if constexpr (BinderTakesRenderFrameHost<Interface,
WebUIControllerSubclass>::value) {
concrete_controller->BindInterface(host, std::move(receiver));
} else {
concrete_controller->BindInterface(std::move(receiver));
}
return true;
}
template <typename Interface, int N, typename Subclass, typename... Subclasses>
struct BinderHelper<Interface, N, std::tuple<Subclass, Subclasses...>> {
static bool BindInterface(RenderFrameHost* host,
mojo::PendingReceiver<Interface> receiver) {
if (!SafeDownCastAndBindInterface<Interface, Subclass>(host, receiver)) {
return BinderHelper<Interface, N - 1, std::tuple<Subclasses...>>::
BindInterface(host, std::move(receiver));
}
return true;
}
};
template <typename Interface, typename Subclass, typename... Subclasses>
struct BinderHelper<Interface, 0, std::tuple<Subclass, Subclasses...>> {
static bool BindInterface(RenderFrameHost* host,
mojo::PendingReceiver<Interface> receiver) {
return SafeDownCastAndBindInterface<Interface, Subclass>(host, receiver);
}
};
void CONTENT_EXPORT ReceivedInvalidWebUIControllerMessage(RenderFrameHost* rfh);
}
template <typename Interface, typename... WebUIControllerSubclasses>
void RegisterWebUIControllerInterfaceBinder(
mojo::BinderMapWithContext<RenderFrameHost*>* map) {
DCHECK(!map->Contains<Interface>())
<< "A binder for " << Interface::Name_ << " has already been registered.";
map->Add<Interface>(base::BindRepeating(
[](RenderFrameHost* host, mojo::PendingReceiver<Interface> receiver) {
if (host->GetParentOrOuterDocument()) {
internal::ReceivedInvalidWebUIControllerMessage(host);
return;
}
const int size = sizeof...(WebUIControllerSubclasses);
bool is_bound =
internal::BinderHelper<Interface, size - 1,
std::tuple<WebUIControllerSubclasses...>>::
BindInterface(host, std::move(receiver));
if (!is_bound) {
internal::ReceivedInvalidWebUIControllerMessage(host);
return;
}
}));
}
}
#endif