// This file is generated by TypeBuilder_cpp.template.

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/ui_devtools/dom.h"

#include "components/ui_devtools/protocol.h"

#include "third_party/inspector_protocol/crdtp/cbor.h"
#include "third_party/inspector_protocol/crdtp/find_by_first.h"
#include "third_party/inspector_protocol/crdtp/span.h"

namespace ui_devtools {
namespace protocol {
namespace DOM {

using crdtp::DeserializerState;
using crdtp::FallthroughCallback;
using crdtp::ProtocolTypeTraits;

// ------------- Enum values from types.

const char Metainfo::domainName[] = "DOM";
const char Metainfo::commandPrefix[] = "DOM.";
const char Metainfo::version[] = "1.3";



CRDTP_BEGIN_DESERIALIZER(Node)
    CRDTP_DESERIALIZE_FIELD_OPT("attributes", m_attributes),
    CRDTP_DESERIALIZE_FIELD("backendNodeId", m_backendNodeId),
    CRDTP_DESERIALIZE_FIELD_OPT("childNodeCount", m_childNodeCount),
    CRDTP_DESERIALIZE_FIELD_OPT("children", m_children),
    CRDTP_DESERIALIZE_FIELD_OPT("name", m_name),
    CRDTP_DESERIALIZE_FIELD("nodeId", m_nodeId),
    CRDTP_DESERIALIZE_FIELD("nodeName", m_nodeName),
    CRDTP_DESERIALIZE_FIELD("nodeType", m_nodeType),
    CRDTP_DESERIALIZE_FIELD_OPT("value", m_value),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(Node)
    CRDTP_SERIALIZE_FIELD("nodeId", m_nodeId);
    CRDTP_SERIALIZE_FIELD("backendNodeId", m_backendNodeId);
    CRDTP_SERIALIZE_FIELD("nodeType", m_nodeType);
    CRDTP_SERIALIZE_FIELD("nodeName", m_nodeName);
    CRDTP_SERIALIZE_FIELD("childNodeCount", m_childNodeCount);
    CRDTP_SERIALIZE_FIELD("children", m_children);
    CRDTP_SERIALIZE_FIELD("attributes", m_attributes);
    CRDTP_SERIALIZE_FIELD("name", m_name);
    CRDTP_SERIALIZE_FIELD("value", m_value);
CRDTP_END_SERIALIZER();


CRDTP_BEGIN_DESERIALIZER(RGBA)
    CRDTP_DESERIALIZE_FIELD_OPT("a", m_a),
    CRDTP_DESERIALIZE_FIELD("b", m_b),
    CRDTP_DESERIALIZE_FIELD("g", m_g),
    CRDTP_DESERIALIZE_FIELD("r", m_r),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(RGBA)
    CRDTP_SERIALIZE_FIELD("r", m_r);
    CRDTP_SERIALIZE_FIELD("g", m_g);
    CRDTP_SERIALIZE_FIELD("b", m_b);
    CRDTP_SERIALIZE_FIELD("a", m_a);
CRDTP_END_SERIALIZER();



const char* MouseEvent::TypeEnum::MousePressed = "mousePressed";
const char* MouseEvent::TypeEnum::MouseDragged = "mouseDragged";
const char* MouseEvent::TypeEnum::MouseReleased = "mouseReleased";
const char* MouseEvent::TypeEnum::MouseMoved = "mouseMoved";
const char* MouseEvent::TypeEnum::MouseEntered = "mouseEntered";
const char* MouseEvent::TypeEnum::MouseExited = "mouseExited";
const char* MouseEvent::TypeEnum::MouseWheel = "mouseWheel";

const char* MouseEvent::ButtonEnum::None = "none";
const char* MouseEvent::ButtonEnum::Left = "left";
const char* MouseEvent::ButtonEnum::Right = "right";
const char* MouseEvent::ButtonEnum::Middle = "middle";
const char* MouseEvent::ButtonEnum::Back = "back";
const char* MouseEvent::ButtonEnum::Forward = "forward";

const char* MouseEvent::WheelDirectionEnum::None = "none";
const char* MouseEvent::WheelDirectionEnum::Up = "up";
const char* MouseEvent::WheelDirectionEnum::Down = "down";
const char* MouseEvent::WheelDirectionEnum::Left = "left";
const char* MouseEvent::WheelDirectionEnum::Right = "right";
CRDTP_BEGIN_DESERIALIZER(MouseEvent)
    CRDTP_DESERIALIZE_FIELD("button", m_button),
    CRDTP_DESERIALIZE_FIELD("type", m_type),
    CRDTP_DESERIALIZE_FIELD("wheelDirection", m_wheelDirection),
    CRDTP_DESERIALIZE_FIELD("x", m_x),
    CRDTP_DESERIALIZE_FIELD("y", m_y),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(MouseEvent)
    CRDTP_SERIALIZE_FIELD("type", m_type);
    CRDTP_SERIALIZE_FIELD("x", m_x);
    CRDTP_SERIALIZE_FIELD("y", m_y);
    CRDTP_SERIALIZE_FIELD("button", m_button);
    CRDTP_SERIALIZE_FIELD("wheelDirection", m_wheelDirection);
CRDTP_END_SERIALIZER();



const char* KeyEvent::TypeEnum::KeyPressed = "keyPressed";
const char* KeyEvent::TypeEnum::KeyReleased = "keyReleased";
CRDTP_BEGIN_DESERIALIZER(KeyEvent)
    CRDTP_DESERIALIZE_FIELD("code", m_code),
    CRDTP_DESERIALIZE_FIELD("flags", m_flags),
    CRDTP_DESERIALIZE_FIELD("isChar", m_isChar),
    CRDTP_DESERIALIZE_FIELD("key", m_key),
    CRDTP_DESERIALIZE_FIELD("keyCode", m_keyCode),
    CRDTP_DESERIALIZE_FIELD("type", m_type),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(KeyEvent)
    CRDTP_SERIALIZE_FIELD("type", m_type);
    CRDTP_SERIALIZE_FIELD("keyCode", m_keyCode);
    CRDTP_SERIALIZE_FIELD("code", m_code);
    CRDTP_SERIALIZE_FIELD("flags", m_flags);
    CRDTP_SERIALIZE_FIELD("key", m_key);
    CRDTP_SERIALIZE_FIELD("isChar", m_isChar);
CRDTP_END_SERIALIZER();


CRDTP_BEGIN_DESERIALIZER(Rect)
    CRDTP_DESERIALIZE_FIELD("height", m_height),
    CRDTP_DESERIALIZE_FIELD("width", m_width),
    CRDTP_DESERIALIZE_FIELD("x", m_x),
    CRDTP_DESERIALIZE_FIELD("y", m_y),
CRDTP_END_DESERIALIZER()

CRDTP_BEGIN_SERIALIZER(Rect)
    CRDTP_SERIALIZE_FIELD("x", m_x);
    CRDTP_SERIALIZE_FIELD("y", m_y);
    CRDTP_SERIALIZE_FIELD("width", m_width);
    CRDTP_SERIALIZE_FIELD("height", m_height);
CRDTP_END_SERIALIZER();


// ------------- Enum values from params.


// ------------- Frontend notifications.

void Frontend::childNodeInserted(int parentNodeId, int previousNodeId, std::unique_ptr<protocol::DOM::Node> node)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("parentNodeId"), parentNodeId);
    serializer.AddField(crdtp::MakeSpan("previousNodeId"), previousNodeId);
    serializer.AddField(crdtp::MakeSpan("node"), node);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("DOM.childNodeInserted", serializer.Finish()));
}

void Frontend::childNodeRemoved(int parentNodeId, int nodeId)
{
    if (!frontend_channel_)
        return;
    crdtp::ObjectSerializer serializer;
    serializer.AddField(crdtp::MakeSpan("parentNodeId"), parentNodeId);
    serializer.AddField(crdtp::MakeSpan("nodeId"), nodeId);
    frontend_channel_->SendProtocolNotification(crdtp::CreateNotification("DOM.childNodeRemoved", serializer.Finish()));
}

void Frontend::flush()
{
    frontend_channel_->FlushProtocolNotifications();
}

void Frontend::sendRawNotification(std::unique_ptr<Serializable> notification)
{
    frontend_channel_->SendProtocolNotification(std::move(notification));
}

// --------------------- Dispatcher.

class DomainDispatcherImpl : public protocol::DomainDispatcher {
public:
    DomainDispatcherImpl(FrontendChannel* frontendChannel, Backend* backend)
        : DomainDispatcher(frontendChannel)
        , m_backend(backend) {}
    ~DomainDispatcherImpl() override { }

    using CallHandler = void (DomainDispatcherImpl::*)(crdtp::Dispatchable& dispatchable);

    bool Dispatch(crdtp::span<uint8_t> command_name, crdtp::Dispatchable& dispatchable) override;

    void disable(crdtp::Dispatchable& dispatchable);
    void enable(crdtp::Dispatchable& dispatchable);
    void getDocument(crdtp::Dispatchable& dispatchable);
    void pushNodesByBackendIdsToFrontend(crdtp::Dispatchable& dispatchable);
    void performSearch(crdtp::Dispatchable& dispatchable);
    void getSearchResults(crdtp::Dispatchable& dispatchable);
    void discardSearchResults(crdtp::Dispatchable& dispatchable);
    void dispatchMouseEvent(crdtp::Dispatchable& dispatchable);
    void dispatchKeyEvent(crdtp::Dispatchable& dispatchable);
    void getNodeBoundsInScreen(crdtp::Dispatchable& dispatchable);
    void getDeviceScaleFactor(crdtp::Dispatchable& dispatchable);
    void getOuterHTML(crdtp::Dispatchable& dispatchable);
 protected:
    Backend* m_backend;
};

namespace {
// This helper method with a static map of command methods (instance methods
// of DomainDispatcherImpl declared just above) by their name is used immediately below,
// in the DomainDispatcherImpl::Dispatch method.
DomainDispatcherImpl::CallHandler CommandByName(crdtp::span<uint8_t> command_name) {
  static auto* commands = [](){
    auto* commands = new std::vector<std::pair<crdtp::span<uint8_t>,
                              DomainDispatcherImpl::CallHandler>>{
    {
          crdtp::SpanFrom("disable"),
          &DomainDispatcherImpl::disable
    },
    {
          crdtp::SpanFrom("discardSearchResults"),
          &DomainDispatcherImpl::discardSearchResults
    },
    {
          crdtp::SpanFrom("dispatchKeyEvent"),
          &DomainDispatcherImpl::dispatchKeyEvent
    },
    {
          crdtp::SpanFrom("dispatchMouseEvent"),
          &DomainDispatcherImpl::dispatchMouseEvent
    },
    {
          crdtp::SpanFrom("enable"),
          &DomainDispatcherImpl::enable
    },
    {
          crdtp::SpanFrom("getDeviceScaleFactor"),
          &DomainDispatcherImpl::getDeviceScaleFactor
    },
    {
          crdtp::SpanFrom("getDocument"),
          &DomainDispatcherImpl::getDocument
    },
    {
          crdtp::SpanFrom("getNodeBoundsInScreen"),
          &DomainDispatcherImpl::getNodeBoundsInScreen
    },
    {
          crdtp::SpanFrom("getOuterHTML"),
          &DomainDispatcherImpl::getOuterHTML
    },
    {
          crdtp::SpanFrom("getSearchResults"),
          &DomainDispatcherImpl::getSearchResults
    },
    {
          crdtp::SpanFrom("performSearch"),
          &DomainDispatcherImpl::performSearch
    },
    {
          crdtp::SpanFrom("pushNodesByBackendIdsToFrontend"),
          &DomainDispatcherImpl::pushNodesByBackendIdsToFrontend
    },
    };
    return commands;
  }();
  return crdtp::FindByFirst<DomainDispatcherImpl::CallHandler>(*commands, command_name, nullptr);
}
}  // namespace

bool DomainDispatcherImpl::Dispatch(crdtp::span<uint8_t> command_name, crdtp::Dispatchable& dispatchable) {
  CallHandler handler = CommandByName(command_name);
  if (!handler) return false;

  (this->*handler)(dispatchable);
  return true;
}


namespace {


}  // namespace

void DomainDispatcherImpl::disable(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->disable();
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {


}  // namespace

void DomainDispatcherImpl::enable(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->enable();
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {


}  // namespace

void DomainDispatcherImpl::getDocument(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    // Declare output parameters.
    std::unique_ptr<protocol::DOM::Node> out_root;

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->getDocument(&out_root);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
      if (weak->get()) {
        std::unique_ptr<crdtp::Serializable> result;
        if (response.IsSuccess()) {
          crdtp::ObjectSerializer serializer;
          serializer.AddField(crdtp::MakeSpan("root"), out_root);
          result = serializer.Finish();
        } else {
          result = Serializable::From({});
        }
        weak->get()->sendResponse(dispatchable.CallId(), response, std::move(result));
      }
    return;
}

namespace {

struct pushNodesByBackendIdsToFrontendParams : public crdtp::DeserializableProtocolObject<pushNodesByBackendIdsToFrontendParams> {
    std::unique_ptr<protocol::Array<int>> backendNodeIds;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(pushNodesByBackendIdsToFrontendParams)
    CRDTP_DESERIALIZE_FIELD("backendNodeIds", backendNodeIds),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::pushNodesByBackendIdsToFrontend(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    pushNodesByBackendIdsToFrontendParams params;
    if (!pushNodesByBackendIdsToFrontendParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }
    // Declare output parameters.
    std::unique_ptr<protocol::Array<int>> out_nodeIds;

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->pushNodesByBackendIdsToFrontend(std::move(params.backendNodeIds), &out_nodeIds);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
      if (weak->get()) {
        std::unique_ptr<crdtp::Serializable> result;
        if (response.IsSuccess()) {
          crdtp::ObjectSerializer serializer;
          serializer.AddField(crdtp::MakeSpan("nodeIds"), out_nodeIds);
          result = serializer.Finish();
        } else {
          result = Serializable::From({});
        }
        weak->get()->sendResponse(dispatchable.CallId(), response, std::move(result));
      }
    return;
}

namespace {

struct performSearchParams : public crdtp::DeserializableProtocolObject<performSearchParams> {
    String query;
    std::optional<bool> includeUserAgentShadowDOM;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(performSearchParams)
    CRDTP_DESERIALIZE_FIELD_OPT("includeUserAgentShadowDOM", includeUserAgentShadowDOM),
    CRDTP_DESERIALIZE_FIELD("query", query),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::performSearch(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    performSearchParams params;
    if (!performSearchParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }
    // Declare output parameters.
    String out_searchId;
    int out_resultCount;

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->performSearch(params.query, std::move(params.includeUserAgentShadowDOM), &out_searchId, &out_resultCount);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
      if (weak->get()) {
        std::unique_ptr<crdtp::Serializable> result;
        if (response.IsSuccess()) {
          crdtp::ObjectSerializer serializer;
          serializer.AddField(crdtp::MakeSpan("searchId"), out_searchId);
          serializer.AddField(crdtp::MakeSpan("resultCount"), out_resultCount);
          result = serializer.Finish();
        } else {
          result = Serializable::From({});
        }
        weak->get()->sendResponse(dispatchable.CallId(), response, std::move(result));
      }
    return;
}

namespace {

struct getSearchResultsParams : public crdtp::DeserializableProtocolObject<getSearchResultsParams> {
    String searchId;
    int fromIndex;
    int toIndex;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(getSearchResultsParams)
    CRDTP_DESERIALIZE_FIELD("fromIndex", fromIndex),
    CRDTP_DESERIALIZE_FIELD("searchId", searchId),
    CRDTP_DESERIALIZE_FIELD("toIndex", toIndex),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::getSearchResults(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    getSearchResultsParams params;
    if (!getSearchResultsParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }
    // Declare output parameters.
    std::unique_ptr<protocol::Array<int>> out_nodeIds;

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->getSearchResults(params.searchId, params.fromIndex, params.toIndex, &out_nodeIds);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
      if (weak->get()) {
        std::unique_ptr<crdtp::Serializable> result;
        if (response.IsSuccess()) {
          crdtp::ObjectSerializer serializer;
          serializer.AddField(crdtp::MakeSpan("nodeIds"), out_nodeIds);
          result = serializer.Finish();
        } else {
          result = Serializable::From({});
        }
        weak->get()->sendResponse(dispatchable.CallId(), response, std::move(result));
      }
    return;
}

namespace {

struct discardSearchResultsParams : public crdtp::DeserializableProtocolObject<discardSearchResultsParams> {
    String searchId;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(discardSearchResultsParams)
    CRDTP_DESERIALIZE_FIELD("searchId", searchId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::discardSearchResults(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    discardSearchResultsParams params;
    if (!discardSearchResultsParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->discardSearchResults(params.searchId);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct dispatchMouseEventParams : public crdtp::DeserializableProtocolObject<dispatchMouseEventParams> {
    int nodeId;
    std::unique_ptr<protocol::DOM::MouseEvent> event;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(dispatchMouseEventParams)
    CRDTP_DESERIALIZE_FIELD("event", event),
    CRDTP_DESERIALIZE_FIELD("nodeId", nodeId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::dispatchMouseEvent(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    dispatchMouseEventParams params;
    if (!dispatchMouseEventParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->dispatchMouseEvent(params.nodeId, std::move(params.event));
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct dispatchKeyEventParams : public crdtp::DeserializableProtocolObject<dispatchKeyEventParams> {
    int nodeId;
    std::unique_ptr<protocol::DOM::KeyEvent> event;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(dispatchKeyEventParams)
    CRDTP_DESERIALIZE_FIELD("event", event),
    CRDTP_DESERIALIZE_FIELD("nodeId", nodeId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::dispatchKeyEvent(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    dispatchKeyEventParams params;
    if (!dispatchKeyEventParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->dispatchKeyEvent(params.nodeId, std::move(params.event));
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
    if (weak->get())
        weak->get()->sendResponse(dispatchable.CallId(), response);
    return;
}

namespace {

struct getNodeBoundsInScreenParams : public crdtp::DeserializableProtocolObject<getNodeBoundsInScreenParams> {
    int nodeId;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(getNodeBoundsInScreenParams)
    CRDTP_DESERIALIZE_FIELD("nodeId", nodeId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::getNodeBoundsInScreen(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    getNodeBoundsInScreenParams params;
    if (!getNodeBoundsInScreenParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }
    // Declare output parameters.
    std::unique_ptr<protocol::DOM::Rect> out_boundsInScreen;

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->getNodeBoundsInScreen(params.nodeId, &out_boundsInScreen);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
      if (weak->get()) {
        std::unique_ptr<crdtp::Serializable> result;
        if (response.IsSuccess()) {
          crdtp::ObjectSerializer serializer;
          serializer.AddField(crdtp::MakeSpan("boundsInScreen"), out_boundsInScreen);
          result = serializer.Finish();
        } else {
          result = Serializable::From({});
        }
        weak->get()->sendResponse(dispatchable.CallId(), response, std::move(result));
      }
    return;
}

namespace {

struct getDeviceScaleFactorParams : public crdtp::DeserializableProtocolObject<getDeviceScaleFactorParams> {
    int nodeId;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(getDeviceScaleFactorParams)
    CRDTP_DESERIALIZE_FIELD("nodeId", nodeId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::getDeviceScaleFactor(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    getDeviceScaleFactorParams params;
    if (!getDeviceScaleFactorParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }
    // Declare output parameters.
    double out_deviceScaleFactor;

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->getDeviceScaleFactor(params.nodeId, &out_deviceScaleFactor);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
      if (weak->get()) {
        std::unique_ptr<crdtp::Serializable> result;
        if (response.IsSuccess()) {
          crdtp::ObjectSerializer serializer;
          serializer.AddField(crdtp::MakeSpan("deviceScaleFactor"), out_deviceScaleFactor);
          result = serializer.Finish();
        } else {
          result = Serializable::From({});
        }
        weak->get()->sendResponse(dispatchable.CallId(), response, std::move(result));
      }
    return;
}

namespace {

struct getOuterHTMLParams : public crdtp::DeserializableProtocolObject<getOuterHTMLParams> {
    int nodeId;
    DECLARE_DESERIALIZATION_SUPPORT();
};

CRDTP_BEGIN_DESERIALIZER(getOuterHTMLParams)
    CRDTP_DESERIALIZE_FIELD("nodeId", nodeId),
CRDTP_END_DESERIALIZER()

}  // namespace

void DomainDispatcherImpl::getOuterHTML(crdtp::Dispatchable& dispatchable)
{
    // Prepare input parameters.
    auto deserializer = crdtp::DeferredMessage::FromSpan(dispatchable.Params())->MakeDeserializer();
    getOuterHTMLParams params;
    if (!getOuterHTMLParams::Deserialize(&deserializer, &params)) {
      ReportInvalidParams(dispatchable, deserializer);
      return;
    }
    // Declare output parameters.
    String out_outerHTML;

    std::unique_ptr<DomainDispatcher::WeakPtr> weak = weakPtr();
    DispatchResponse response = m_backend->getOuterHTML(params.nodeId, &out_outerHTML);
    if (response.IsFallThrough()) {
        dispatchable.DispatchFallThrough(response.Message());
        return;
    }
      if (weak->get()) {
        std::unique_ptr<crdtp::Serializable> result;
        if (response.IsSuccess()) {
          crdtp::ObjectSerializer serializer;
          serializer.AddField(crdtp::MakeSpan("outerHTML"), out_outerHTML);
          result = serializer.Finish();
        } else {
          result = Serializable::From({});
        }
        weak->get()->sendResponse(dispatchable.CallId(), response, std::move(result));
      }
    return;
}

namespace {
// This helper method (with a static map of redirects) is used from Dispatcher::wire
// immediately below.
const std::vector<std::pair<crdtp::span<uint8_t>, crdtp::span<uint8_t>>>& SortedRedirects() {
  static auto* redirects = [](){
    auto* redirects = new std::vector<std::pair<crdtp::span<uint8_t>, crdtp::span<uint8_t>>>{
          { crdtp::SpanFrom("DOM.hideHighlight"), crdtp::SpanFrom("Overlay.hideHighlight") },
          { crdtp::SpanFrom("DOM.highlightNode"), crdtp::SpanFrom("Overlay.highlightNode") },
    };
    return redirects;
  }();
  return *redirects;
}
}  // namespace

// static
void Dispatcher::wire(UberDispatcher* uber, Backend* backend)
{
    auto dispatcher = std::make_unique<DomainDispatcherImpl>(uber->channel(), backend);
    uber->WireBackend(crdtp::SpanFrom("DOM"), SortedRedirects(), std::move(dispatcher));
}

} // DOM
} // namespace ui_devtools
} // namespace protocol
