Web Inspector: replace HTMLCanvasElement with CanvasRenderingContext for instrumentat...
[WebKit-https.git] / Source / WebCore / inspector / InspectorController.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "InspectorController.h"
34
35 #include "CommandLineAPIHost.h"
36 #include "CommonVM.h"
37 #include "DOMWindow.h"
38 #include "DOMWrapperWorld.h"
39 #include "GraphicsContext.h"
40 #include "InspectorApplicationCacheAgent.h"
41 #include "InspectorCSSAgent.h"
42 #include "InspectorCanvasAgent.h"
43 #include "InspectorClient.h"
44 #include "InspectorDOMAgent.h"
45 #include "InspectorDOMDebuggerAgent.h"
46 #include "InspectorDOMStorageAgent.h"
47 #include "InspectorDatabaseAgent.h"
48 #include "InspectorFrontendClient.h"
49 #include "InspectorIndexedDBAgent.h"
50 #include "InspectorInstrumentation.h"
51 #include "InspectorLayerTreeAgent.h"
52 #include "InspectorMemoryAgent.h"
53 #include "InspectorPageAgent.h"
54 #include "InspectorTimelineAgent.h"
55 #include "InspectorWorkerAgent.h"
56 #include "InstrumentingAgents.h"
57 #include "JSDOMBindingSecurity.h"
58 #include "JSDOMWindow.h"
59 #include "JSDOMWindowCustom.h"
60 #include "JSMainThreadExecState.h"
61 #include "MainFrame.h"
62 #include "Page.h"
63 #include "PageConsoleAgent.h"
64 #include "PageDebuggerAgent.h"
65 #include "PageHeapAgent.h"
66 #include "PageNetworkAgent.h"
67 #include "PageRuntimeAgent.h"
68 #include "PageScriptDebugServer.h"
69 #include "Settings.h"
70 #include "WebInjectedScriptHost.h"
71 #include "WebInjectedScriptManager.h"
72 #include <inspector/IdentifiersFactory.h>
73 #include <inspector/InspectorBackendDispatcher.h>
74 #include <inspector/InspectorBackendDispatchers.h>
75 #include <inspector/InspectorFrontendDispatchers.h>
76 #include <inspector/InspectorFrontendRouter.h>
77 #include <inspector/agents/InspectorAgent.h>
78 #include <inspector/agents/InspectorScriptProfilerAgent.h>
79 #include <runtime/JSLock.h>
80 #include <wtf/Stopwatch.h>
81
82 #if ENABLE(REMOTE_INSPECTOR)
83 #include "PageDebuggable.h"
84 #endif
85
86 namespace WebCore {
87
88 using namespace JSC;
89 using namespace Inspector;
90
91 InspectorController::InspectorController(Page& page, InspectorClient* inspectorClient)
92     : m_instrumentingAgents(InstrumentingAgents::create(*this))
93     , m_injectedScriptManager(std::make_unique<WebInjectedScriptManager>(*this, WebInjectedScriptHost::create()))
94     , m_frontendRouter(FrontendRouter::create())
95     , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef()))
96     , m_overlay(std::make_unique<InspectorOverlay>(page, inspectorClient))
97     , m_executionStopwatch(Stopwatch::create())
98     , m_scriptDebugServer(page)
99     , m_page(page)
100     , m_inspectorClient(inspectorClient)
101 {
102     ASSERT_ARG(inspectorClient, inspectorClient);
103
104     auto pageContext = pageAgentContext();
105
106     auto inspectorAgentPtr = std::make_unique<InspectorAgent>(pageContext);
107     m_inspectorAgent = inspectorAgentPtr.get();
108     m_instrumentingAgents->setInspectorAgent(m_inspectorAgent);
109     m_agents.append(WTFMove(inspectorAgentPtr));
110
111     auto pageAgentPtr = std::make_unique<InspectorPageAgent>(pageContext, inspectorClient, m_overlay.get());
112     InspectorPageAgent* pageAgent = pageAgentPtr.get();
113     m_pageAgent = pageAgentPtr.get();
114     m_agents.append(WTFMove(pageAgentPtr));
115
116     auto runtimeAgent = std::make_unique<PageRuntimeAgent>(pageContext, pageAgent);
117     m_instrumentingAgents->setPageRuntimeAgent(runtimeAgent.get());
118     m_agents.append(WTFMove(runtimeAgent));
119
120     auto domAgentPtr = std::make_unique<InspectorDOMAgent>(pageContext, pageAgent, m_overlay.get());
121     m_domAgent = domAgentPtr.get();
122     m_agents.append(WTFMove(domAgentPtr));
123
124     auto databaseAgentPtr = std::make_unique<InspectorDatabaseAgent>(pageContext);
125     InspectorDatabaseAgent* databaseAgent = databaseAgentPtr.get();
126     m_agents.append(WTFMove(databaseAgentPtr));
127
128     auto domStorageAgentPtr = std::make_unique<InspectorDOMStorageAgent>(pageContext, m_pageAgent);
129     InspectorDOMStorageAgent* domStorageAgent = domStorageAgentPtr.get();
130     m_agents.append(WTFMove(domStorageAgentPtr));
131
132     auto heapAgentPtr = std::make_unique<PageHeapAgent>(pageContext);
133     InspectorHeapAgent* heapAgent = heapAgentPtr.get();
134     m_agents.append(WTFMove(heapAgentPtr));
135
136     auto scriptProfilerAgentPtr = std::make_unique<InspectorScriptProfilerAgent>(pageContext);
137     InspectorScriptProfilerAgent* scriptProfilerAgent = scriptProfilerAgentPtr.get();
138     m_agents.append(WTFMove(scriptProfilerAgentPtr));
139
140     auto consoleAgentPtr = std::make_unique<PageConsoleAgent>(pageContext, heapAgent, m_domAgent);
141     WebConsoleAgent* consoleAgent = consoleAgentPtr.get();
142     m_instrumentingAgents->setWebConsoleAgent(consoleAgentPtr.get());
143     m_agents.append(WTFMove(consoleAgentPtr));
144
145     m_agents.append(std::make_unique<InspectorTimelineAgent>(pageContext, scriptProfilerAgent, heapAgent, pageAgent));
146
147     auto canvasAgentPtr = std::make_unique<InspectorCanvasAgent>(pageContext);
148     m_instrumentingAgents->setInspectorCanvasAgent(canvasAgentPtr.get());
149     m_agents.append(WTFMove(canvasAgentPtr));
150
151     ASSERT(m_injectedScriptManager->commandLineAPIHost());
152     if (CommandLineAPIHost* commandLineAPIHost = m_injectedScriptManager->commandLineAPIHost())
153         commandLineAPIHost->init(m_inspectorAgent, consoleAgent, m_domAgent, domStorageAgent, databaseAgent);
154 }
155
156 InspectorController::~InspectorController()
157 {
158     m_instrumentingAgents->reset();
159     ASSERT(!m_inspectorClient);
160 }
161
162 PageAgentContext InspectorController::pageAgentContext()
163 {
164     AgentContext baseContext = {
165         *this,
166         *m_injectedScriptManager,
167         m_frontendRouter.get(),
168         m_backendDispatcher.get()
169     };
170
171     WebAgentContext webContext = {
172         baseContext,
173         m_instrumentingAgents.get()
174     };
175
176     PageAgentContext pageContext = {
177         webContext,
178         m_page
179     };
180
181     return pageContext;
182 }
183
184 void InspectorController::createLazyAgents()
185 {
186     if (m_didCreateLazyAgents)
187         return;
188
189     m_didCreateLazyAgents = true;
190
191     auto pageContext = pageAgentContext();
192
193     auto debuggerAgent = std::make_unique<PageDebuggerAgent>(pageContext, m_pageAgent, m_overlay.get());
194     auto debuggerAgentPtr = debuggerAgent.get();
195
196     m_agents.append(WTFMove(debuggerAgent));
197     m_agents.append(std::make_unique<PageNetworkAgent>(pageContext, m_pageAgent));
198     m_agents.append(std::make_unique<InspectorCSSAgent>(pageContext, m_domAgent));
199     m_agents.append(std::make_unique<InspectorDOMDebuggerAgent>(pageContext, m_domAgent, debuggerAgentPtr));
200     m_agents.append(std::make_unique<InspectorApplicationCacheAgent>(pageContext, m_pageAgent));
201     m_agents.append(std::make_unique<InspectorLayerTreeAgent>(pageContext));
202     m_agents.append(std::make_unique<InspectorWorkerAgent>(pageContext));
203 #if ENABLE(INDEXED_DATABASE)
204     m_agents.append(std::make_unique<InspectorIndexedDBAgent>(pageContext, m_pageAgent));
205 #endif
206 #if ENABLE(RESOURCE_USAGE)
207     m_agents.append(std::make_unique<InspectorMemoryAgent>(pageContext));
208 #endif
209 }
210
211 void InspectorController::inspectedPageDestroyed()
212 {
213     // Clean up resources and disconnect local and remote frontends.
214     disconnectAllFrontends();
215
216     // Disconnect the client.
217     m_inspectorClient->inspectedPageDestroyed();
218     m_inspectorClient = nullptr;
219
220     m_agents.discardValues();
221 }
222
223 void InspectorController::setInspectorFrontendClient(InspectorFrontendClient* inspectorFrontendClient)
224 {
225     m_inspectorFrontendClient = inspectorFrontendClient;
226 }
227
228 bool InspectorController::hasLocalFrontend() const
229 {
230     return m_frontendRouter->hasLocalFrontend();
231 }
232
233 bool InspectorController::hasRemoteFrontend() const
234 {
235     return m_frontendRouter->hasRemoteFrontend();
236 }
237
238 unsigned InspectorController::inspectionLevel() const
239 {
240     return m_inspectorFrontendClient ? m_inspectorFrontendClient->inspectionLevel() : 0;
241 }
242
243 void InspectorController::didClearWindowObjectInWorld(Frame& frame, DOMWrapperWorld& world)
244 {
245     if (&world != &mainThreadNormalWorld())
246         return;
247
248     if (frame.isMainFrame())
249         m_injectedScriptManager->discardInjectedScripts();
250
251     // If the page is supposed to serve as InspectorFrontend notify inspector frontend
252     // client that it's cleared so that the client can expose inspector bindings.
253     if (m_inspectorFrontendClient && frame.isMainFrame())
254         m_inspectorFrontendClient->windowObjectCleared();
255 }
256
257 void InspectorController::connectFrontend(Inspector::FrontendChannel* frontendChannel, bool isAutomaticInspection, bool immediatelyPause)
258 {
259     ASSERT_ARG(frontendChannel, frontendChannel);
260     ASSERT(m_inspectorClient);
261
262     createLazyAgents();
263
264     bool connectedFirstFrontend = !m_frontendRouter->hasFrontends();
265     m_isAutomaticInspection = isAutomaticInspection;
266     m_pauseAfterInitialization = immediatelyPause;
267
268     m_frontendRouter->connectFrontend(frontendChannel);
269
270     InspectorInstrumentation::frontendCreated();
271
272     if (connectedFirstFrontend) {
273         InspectorInstrumentation::registerInstrumentingAgents(m_instrumentingAgents.get());
274         m_agents.didCreateFrontendAndBackend(&m_frontendRouter.get(), &m_backendDispatcher.get());
275     }
276
277 #if ENABLE(REMOTE_INSPECTOR)
278     if (!m_frontendRouter->hasRemoteFrontend())
279         m_page.remoteInspectorInformationDidChange();
280 #endif
281 }
282
283 void InspectorController::disconnectFrontend(FrontendChannel* frontendChannel)
284 {
285     m_frontendRouter->disconnectFrontend(frontendChannel);
286
287     m_isAutomaticInspection = false;
288     m_pauseAfterInitialization = false;
289
290     InspectorInstrumentation::frontendDeleted();
291
292     bool disconnectedLastFrontend = !m_frontendRouter->hasFrontends();
293     if (disconnectedLastFrontend) {
294         // Notify agents first.
295         m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectorDestroyed);
296
297         // Clean up inspector resources.
298         m_overlay->freePage();
299         m_injectedScriptManager->discardInjectedScripts();
300
301         // Unplug all instrumentations since they aren't needed now.
302         InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get());
303     }
304
305 #if ENABLE(REMOTE_INSPECTOR)
306     if (!m_frontendRouter->hasFrontends())
307         m_page.remoteInspectorInformationDidChange();
308 #endif
309 }
310
311 void InspectorController::disconnectAllFrontends()
312 {
313     // If the local frontend page was destroyed, close the window.
314     if (m_inspectorFrontendClient)
315         m_inspectorFrontendClient->closeWindow();
316
317     // The frontend should call setInspectorFrontendClient(nullptr) under closeWindow().
318     ASSERT(!m_inspectorFrontendClient);
319
320     if (!m_frontendRouter->hasFrontends())
321         return;
322
323     for (unsigned i = 0; i < m_frontendRouter->frontendCount(); ++i)
324         InspectorInstrumentation::frontendDeleted();
325
326     // Unplug all instrumentations to prevent further agent callbacks.
327     InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get());
328
329     // Notify agents first, since they may need to use InspectorClient.
330     m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectedTargetDestroyed);
331
332     // Clean up inspector resources.
333     m_overlay->freePage();
334     m_injectedScriptManager->disconnect();
335
336     // Disconnect any remaining remote frontends.
337     m_frontendRouter->disconnectAllFrontends();
338     m_isAutomaticInspection = false;
339     m_pauseAfterInitialization = false;
340
341 #if ENABLE(REMOTE_INSPECTOR)
342     m_page.remoteInspectorInformationDidChange();
343 #endif
344 }
345
346 void InspectorController::show()
347 {
348     ASSERT(!m_frontendRouter->hasRemoteFrontend());
349
350     if (!enabled())
351         return;
352
353     if (m_frontendRouter->hasLocalFrontend())
354         m_inspectorClient->bringFrontendToFront();
355     else if (Inspector::FrontendChannel* frontendChannel = m_inspectorClient->openLocalFrontend(this))
356         connectFrontend(frontendChannel);
357 }
358
359 void InspectorController::setProcessId(long processId)
360 {
361     IdentifiersFactory::setProcessId(processId);
362 }
363
364 void InspectorController::setIsUnderTest(bool value)
365 {
366     if (value == m_isUnderTest)
367         return;
368
369     m_isUnderTest = value;
370
371     // <rdar://problem/26768628> Try to catch suspicious scenarios where we may have a dangling frontend while running tests.
372     RELEASE_ASSERT(!m_isUnderTest || !m_frontendRouter->hasFrontends());
373 }
374
375 void InspectorController::evaluateForTestInFrontend(const String& script)
376 {
377     m_inspectorAgent->evaluateForTestInFrontend(script);
378 }
379
380 void InspectorController::drawHighlight(GraphicsContext& context) const
381 {
382     m_overlay->paint(context);
383 }
384
385 void InspectorController::getHighlight(Highlight& highlight, InspectorOverlay::CoordinateSystem coordinateSystem) const
386 {
387     m_overlay->getHighlight(highlight, coordinateSystem);
388 }
389
390 Ref<JSON::ArrayOf<Inspector::Protocol::OverlayTypes::NodeHighlightData>> InspectorController::buildObjectForHighlightedNodes() const
391 {
392     return m_overlay->buildObjectForHighlightedNodes();
393 }
394
395 void InspectorController::inspect(Node* node)
396 {
397     if (!enabled())
398         return;
399
400     if (!hasRemoteFrontend())
401         show();
402
403     m_domAgent->inspect(node);
404 }
405
406 bool InspectorController::enabled() const
407 {
408     return developerExtrasEnabled();
409 }
410
411 Page& InspectorController::inspectedPage() const
412 {
413     return m_page;
414 }
415
416 void InspectorController::dispatchMessageFromFrontend(const String& message)
417 {
418     m_backendDispatcher->dispatch(message);
419 }
420
421 void InspectorController::hideHighlight()
422 {
423     ErrorString unused;
424     m_domAgent->hideHighlight(unused);
425 }
426
427 Node* InspectorController::highlightedNode() const
428 {
429     return m_overlay->highlightedNode();
430 }
431
432 void InspectorController::setIndicating(bool indicating)
433 {
434 #if !PLATFORM(IOS)
435     m_overlay->setIndicating(indicating);
436 #else
437     if (indicating)
438         m_inspectorClient->showInspectorIndication();
439     else
440         m_inspectorClient->hideInspectorIndication();
441 #endif
442 }
443
444 bool InspectorController::developerExtrasEnabled() const
445 {
446     return m_page.settings().developerExtrasEnabled();
447 }
448
449 bool InspectorController::canAccessInspectedScriptState(JSC::ExecState* scriptState) const
450 {
451     JSLockHolder lock(scriptState);
452
453     JSDOMWindow* inspectedWindow = toJSDOMWindow(scriptState->vm(), scriptState->lexicalGlobalObject());
454     if (!inspectedWindow)
455         return false;
456
457     return BindingSecurity::shouldAllowAccessToDOMWindow(scriptState, inspectedWindow->wrapped(), DoNotReportSecurityError);
458 }
459
460 InspectorFunctionCallHandler InspectorController::functionCallHandler() const
461 {
462     return WebCore::functionCallHandlerFromAnyThread;
463 }
464
465 InspectorEvaluateHandler InspectorController::evaluateHandler() const
466 {
467     return WebCore::evaluateHandlerFromAnyThread;
468 }
469
470 void InspectorController::frontendInitialized()
471 {
472     if (m_pauseAfterInitialization) {
473         m_pauseAfterInitialization = false;
474         if (PageDebuggerAgent* debuggerAgent = m_instrumentingAgents->pageDebuggerAgent()) {
475             ErrorString ignored;
476             debuggerAgent->pause(ignored);
477         }
478     }
479
480 #if ENABLE(REMOTE_INSPECTOR)
481     if (m_isAutomaticInspection)
482         m_page.inspectorDebuggable().unpauseForInitializedInspector();
483 #endif
484 }
485
486 Ref<Stopwatch> InspectorController::executionStopwatch()
487 {
488     return m_executionStopwatch.copyRef();
489 }
490
491 PageScriptDebugServer& InspectorController::scriptDebugServer()
492 {
493     return m_scriptDebugServer;
494 }
495
496 JSC::VM& InspectorController::vm()
497 {
498     return commonVM();
499 }
500
501 void InspectorController::didComposite(Frame& frame)
502 {
503     InspectorInstrumentation::didComposite(frame);
504 }
505
506 } // namespace WebCore