#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();
if (!web_ui) {
return false;
}
auto* concrete_controller =
web_ui->GetController()->GetAs<WebUIControllerSubclass>();
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 true;
}
return BinderHelper<Interface, N - 1, std::tuple<Subclasses...>>::
BindInterface(host, std::move(receiver));
}
};
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>(
[](RenderFrameHost* host, mojo::PendingReceiver<Interface> receiver) {
if (host->GetParentOrOuterDocument()) {
internal::ReceivedInvalidWebUIControllerMessage(host);
return;
}
constexpr int size = sizeof...(WebUIControllerSubclasses);
const bool is_bound =
internal::BinderHelper<Interface, size - 1,
std::tuple<WebUIControllerSubclasses...>>::
BindInterface(host, std::move(receiver));
if (is_bound) {
return;
}
LOG(ERROR) << "WebUIController binder missing for: "
<< Interface::Name_;
internal::ReceivedInvalidWebUIControllerMessage(host);
});
}
}
#endif