InspectorController.cpp [plain text]
#include "config.h"
#include "InspectorController.h"
#include "CommandLineAPIHost.h"
#include "CommonVM.h"
#include "DOMWindow.h"
#include "DOMWrapperWorld.h"
#include "Frame.h"
#include "GraphicsContext.h"
#include "InspectorApplicationCacheAgent.h"
#include "InspectorCPUProfilerAgent.h"
#include "InspectorCSSAgent.h"
#include "InspectorCanvasAgent.h"
#include "InspectorClient.h"
#include "InspectorDOMAgent.h"
#include "InspectorDOMDebuggerAgent.h"
#include "InspectorDOMStorageAgent.h"
#include "InspectorDatabaseAgent.h"
#include "InspectorDatabaseResource.h"
#include "InspectorFrontendClient.h"
#include "InspectorIndexedDBAgent.h"
#include "InspectorInstrumentation.h"
#include "InspectorLayerTreeAgent.h"
#include "InspectorMemoryAgent.h"
#include "InspectorPageAgent.h"
#include "InspectorTimelineAgent.h"
#include "InspectorWorkerAgent.h"
#include "InstrumentingAgents.h"
#include "JSDOMBindingSecurity.h"
#include "JSDOMWindow.h"
#include "JSDOMWindowCustom.h"
#include "JSExecState.h"
#include "Page.h"
#include "PageAuditAgent.h"
#include "PageConsoleAgent.h"
#include "PageDebuggerAgent.h"
#include "PageHeapAgent.h"
#include "PageNetworkAgent.h"
#include "PageRuntimeAgent.h"
#include "PageScriptDebugServer.h"
#include "Settings.h"
#include "WebInjectedScriptHost.h"
#include "WebInjectedScriptManager.h"
#include <JavaScriptCore/IdentifiersFactory.h>
#include <JavaScriptCore/InspectorAgent.h>
#include <JavaScriptCore/InspectorBackendDispatcher.h>
#include <JavaScriptCore/InspectorBackendDispatchers.h>
#include <JavaScriptCore/InspectorFrontendDispatchers.h>
#include <JavaScriptCore/InspectorFrontendRouter.h>
#include <JavaScriptCore/InspectorScriptProfilerAgent.h>
#include <JavaScriptCore/JSLock.h>
#include <wtf/Stopwatch.h>
#if ENABLE(REMOTE_INSPECTOR)
#include "PageDebuggable.h"
#endif
namespace WebCore {
using namespace JSC;
using namespace Inspector;
InspectorController::InspectorController(Page& page, InspectorClient* inspectorClient)
: m_instrumentingAgents(InstrumentingAgents::create(*this))
, m_injectedScriptManager(std::make_unique<WebInjectedScriptManager>(*this, WebInjectedScriptHost::create()))
, m_frontendRouter(FrontendRouter::create())
, m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef()))
, m_overlay(std::make_unique<InspectorOverlay>(page, inspectorClient))
, m_executionStopwatch(Stopwatch::create())
, m_scriptDebugServer(page)
, m_page(page)
, m_inspectorClient(inspectorClient)
{
ASSERT_ARG(inspectorClient, inspectorClient);
auto pageContext = pageAgentContext();
auto consoleAgent = std::make_unique<PageConsoleAgent>(pageContext);
m_instrumentingAgents->setWebConsoleAgent(consoleAgent.get());
m_agents.append(WTFMove(consoleAgent));
}
InspectorController::~InspectorController()
{
m_instrumentingAgents->reset();
ASSERT(!m_inspectorClient);
}
PageAgentContext InspectorController::pageAgentContext()
{
AgentContext baseContext = {
*this,
*m_injectedScriptManager,
m_frontendRouter.get(),
m_backendDispatcher.get()
};
WebAgentContext webContext = {
baseContext,
m_instrumentingAgents.get()
};
PageAgentContext pageContext = {
webContext,
m_page
};
return pageContext;
}
void InspectorController::createLazyAgents()
{
if (m_didCreateLazyAgents)
return;
m_didCreateLazyAgents = true;
m_injectedScriptManager->connect();
auto pageContext = pageAgentContext();
ensureInspectorAgent();
ensurePageAgent();
m_agents.append(std::make_unique<PageRuntimeAgent>(pageContext));
auto debuggerAgent = std::make_unique<PageDebuggerAgent>(pageContext);
auto debuggerAgentPtr = debuggerAgent.get();
m_agents.append(WTFMove(debuggerAgent));
m_agents.append(std::make_unique<PageNetworkAgent>(pageContext));
m_agents.append(std::make_unique<InspectorCSSAgent>(pageContext));
ensureDOMAgent();
m_agents.append(std::make_unique<InspectorDOMDebuggerAgent>(pageContext, debuggerAgentPtr));
m_agents.append(std::make_unique<InspectorApplicationCacheAgent>(pageContext));
m_agents.append(std::make_unique<InspectorLayerTreeAgent>(pageContext));
m_agents.append(std::make_unique<InspectorWorkerAgent>(pageContext));
m_agents.append(std::make_unique<InspectorDOMStorageAgent>(pageContext));
m_agents.append(std::make_unique<InspectorDatabaseAgent>(pageContext));
#if ENABLE(INDEXED_DATABASE)
m_agents.append(std::make_unique<InspectorIndexedDBAgent>(pageContext));
#endif
auto scriptProfilerAgentPtr = std::make_unique<InspectorScriptProfilerAgent>(pageContext);
m_instrumentingAgents->setInspectorScriptProfilerAgent(scriptProfilerAgentPtr.get());
m_agents.append(WTFMove(scriptProfilerAgentPtr));
#if ENABLE(RESOURCE_USAGE)
m_agents.append(std::make_unique<InspectorCPUProfilerAgent>(pageContext));
m_agents.append(std::make_unique<InspectorMemoryAgent>(pageContext));
#endif
m_agents.append(std::make_unique<PageHeapAgent>(pageContext));
m_agents.append(std::make_unique<PageAuditAgent>(pageContext));
m_agents.append(std::make_unique<InspectorCanvasAgent>(pageContext));
m_agents.append(std::make_unique<InspectorTimelineAgent>(pageContext));
if (auto& commandLineAPIHost = m_injectedScriptManager->commandLineAPIHost())
commandLineAPIHost->init(m_instrumentingAgents.copyRef());
}
void InspectorController::inspectedPageDestroyed()
{
disconnectAllFrontends();
m_inspectorClient->inspectedPageDestroyed();
m_inspectorClient = nullptr;
m_agents.discardValues();
}
void InspectorController::setInspectorFrontendClient(InspectorFrontendClient* inspectorFrontendClient)
{
m_inspectorFrontendClient = inspectorFrontendClient;
}
bool InspectorController::hasLocalFrontend() const
{
return m_frontendRouter->hasLocalFrontend();
}
bool InspectorController::hasRemoteFrontend() const
{
return m_frontendRouter->hasRemoteFrontend();
}
unsigned InspectorController::inspectionLevel() const
{
return m_inspectorFrontendClient ? m_inspectorFrontendClient->inspectionLevel() : 0;
}
void InspectorController::didClearWindowObjectInWorld(Frame& frame, DOMWrapperWorld& world)
{
if (&world != &mainThreadNormalWorld())
return;
if (frame.isMainFrame())
m_injectedScriptManager->discardInjectedScripts();
if (m_inspectorFrontendClient && frame.isMainFrame())
m_inspectorFrontendClient->windowObjectCleared();
}
void InspectorController::connectFrontend(Inspector::FrontendChannel& frontendChannel, bool isAutomaticInspection, bool immediatelyPause)
{
ASSERT(m_inspectorClient);
m_page.settings().setDeveloperExtrasEnabled(true);
createLazyAgents();
bool connectedFirstFrontend = !m_frontendRouter->hasFrontends();
m_isAutomaticInspection = isAutomaticInspection;
m_pauseAfterInitialization = immediatelyPause;
m_frontendRouter->connectFrontend(frontendChannel);
InspectorInstrumentation::frontendCreated();
if (connectedFirstFrontend) {
InspectorInstrumentation::registerInstrumentingAgents(m_instrumentingAgents.get());
m_agents.didCreateFrontendAndBackend(&m_frontendRouter.get(), &m_backendDispatcher.get());
}
m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount());
#if ENABLE(REMOTE_INSPECTOR)
if (hasLocalFrontend())
m_page.remoteInspectorInformationDidChange();
#endif
}
void InspectorController::disconnectFrontend(FrontendChannel& frontendChannel)
{
m_frontendRouter->disconnectFrontend(frontendChannel);
m_isAutomaticInspection = false;
m_pauseAfterInitialization = false;
InspectorInstrumentation::frontendDeleted();
bool disconnectedLastFrontend = !m_frontendRouter->hasFrontends();
if (disconnectedLastFrontend) {
m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectorDestroyed);
m_injectedScriptManager->discardInjectedScripts();
InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get());
}
m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount());
#if ENABLE(REMOTE_INSPECTOR)
if (disconnectedLastFrontend)
m_page.remoteInspectorInformationDidChange();
#endif
}
void InspectorController::disconnectAllFrontends()
{
if (m_inspectorFrontendClient)
m_inspectorFrontendClient->closeWindow();
ASSERT(!m_inspectorFrontendClient);
if (!m_frontendRouter->hasFrontends())
return;
for (unsigned i = 0; i < m_frontendRouter->frontendCount(); ++i)
InspectorInstrumentation::frontendDeleted();
InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get());
m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectedTargetDestroyed);
m_injectedScriptManager->disconnect();
m_frontendRouter->disconnectAllFrontends();
m_isAutomaticInspection = false;
m_pauseAfterInitialization = false;
m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount());
#if ENABLE(REMOTE_INSPECTOR)
m_page.remoteInspectorInformationDidChange();
#endif
}
void InspectorController::show()
{
ASSERT(!hasRemoteFrontend());
if (!enabled())
return;
if (m_frontendRouter->hasLocalFrontend())
m_inspectorClient->bringFrontendToFront();
else if (Inspector::FrontendChannel* frontendChannel = m_inspectorClient->openLocalFrontend(this))
connectFrontend(*frontendChannel);
}
void InspectorController::setIsUnderTest(bool value)
{
if (value == m_isUnderTest)
return;
m_isUnderTest = value;
RELEASE_ASSERT(!m_isUnderTest || !m_frontendRouter->hasFrontends());
}
void InspectorController::evaluateForTestInFrontend(const String& script)
{
ensureInspectorAgent().evaluateForTestInFrontend(script);
}
void InspectorController::drawHighlight(GraphicsContext& context) const
{
m_overlay->paint(context);
}
void InspectorController::getHighlight(Highlight& highlight, InspectorOverlay::CoordinateSystem coordinateSystem) const
{
m_overlay->getHighlight(highlight, coordinateSystem);
}
void InspectorController::inspect(Node* node)
{
if (!enabled())
return;
if (!hasRemoteFrontend())
show();
ensureDOMAgent().inspect(node);
}
bool InspectorController::enabled() const
{
return developerExtrasEnabled();
}
Page& InspectorController::inspectedPage() const
{
return m_page;
}
void InspectorController::dispatchMessageFromFrontend(const String& message)
{
m_backendDispatcher->dispatch(message);
}
void InspectorController::hideHighlight()
{
m_overlay->hideHighlight();
}
Node* InspectorController::highlightedNode() const
{
return m_overlay->highlightedNode();
}
void InspectorController::setIndicating(bool indicating)
{
#if !PLATFORM(IOS_FAMILY)
m_overlay->setIndicating(indicating);
#else
if (indicating)
m_inspectorClient->showInspectorIndication();
else
m_inspectorClient->hideInspectorIndication();
#endif
}
InspectorAgent& InspectorController::ensureInspectorAgent()
{
if (!m_inspectorAgent) {
auto pageContext = pageAgentContext();
auto inspectorAgent = std::make_unique<InspectorAgent>(pageContext);
m_inspectorAgent = inspectorAgent.get();
m_instrumentingAgents->setInspectorAgent(m_inspectorAgent);
m_agents.append(WTFMove(inspectorAgent));
}
return *m_inspectorAgent;
}
InspectorDOMAgent& InspectorController::ensureDOMAgent()
{
if (!m_inspectorDOMAgent) {
auto pageContext = pageAgentContext();
auto domAgent = std::make_unique<InspectorDOMAgent>(pageContext, m_overlay.get());
m_inspectorDOMAgent = domAgent.get();
m_agents.append(WTFMove(domAgent));
}
return *m_inspectorDOMAgent;
}
InspectorPageAgent& InspectorController::ensurePageAgent()
{
if (!m_inspectorPageAgent) {
auto pageContext = pageAgentContext();
auto pageAgent = std::make_unique<InspectorPageAgent>(pageContext, m_inspectorClient, m_overlay.get());
m_inspectorPageAgent = pageAgent.get();
m_agents.append(WTFMove(pageAgent));
}
return *m_inspectorPageAgent;
}
bool InspectorController::developerExtrasEnabled() const
{
return m_page.settings().developerExtrasEnabled();
}
bool InspectorController::canAccessInspectedScriptState(JSC::ExecState* scriptState) const
{
JSLockHolder lock(scriptState);
JSDOMWindow* inspectedWindow = toJSDOMWindow(scriptState->vm(), scriptState->lexicalGlobalObject());
if (!inspectedWindow)
return false;
return BindingSecurity::shouldAllowAccessToDOMWindow(scriptState, inspectedWindow->wrapped(), DoNotReportSecurityError);
}
InspectorFunctionCallHandler InspectorController::functionCallHandler() const
{
return WebCore::functionCallHandlerFromAnyThread;
}
InspectorEvaluateHandler InspectorController::evaluateHandler() const
{
return WebCore::evaluateHandlerFromAnyThread;
}
void InspectorController::frontendInitialized()
{
if (m_pauseAfterInitialization) {
m_pauseAfterInitialization = false;
if (PageDebuggerAgent* debuggerAgent = m_instrumentingAgents->pageDebuggerAgent()) {
ErrorString ignored;
debuggerAgent->pause(ignored);
}
}
#if ENABLE(REMOTE_INSPECTOR)
if (m_isAutomaticInspection)
m_page.inspectorDebuggable().unpauseForInitializedInspector();
#endif
}
Ref<Stopwatch> InspectorController::executionStopwatch()
{
return m_executionStopwatch.copyRef();
}
PageScriptDebugServer& InspectorController::scriptDebugServer()
{
return m_scriptDebugServer;
}
JSC::VM& InspectorController::vm()
{
return commonVM();
}
void InspectorController::willComposite(Frame& frame)
{
InspectorInstrumentation::willComposite(frame);
}
void InspectorController::didComposite(Frame& frame)
{
InspectorInstrumentation::didComposite(frame);
}
}