Web Inspector: Change the InspectorOverlay to use native rather than canvas
[WebKit.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 "Frame.h"
40 #include "GraphicsContext.h"
41 #include "InspectorApplicationCacheAgent.h"
42 #include "InspectorCPUProfilerAgent.h"
43 #include "InspectorCSSAgent.h"
44 #include "InspectorCanvasAgent.h"
45 #include "InspectorClient.h"
46 #include "InspectorDOMAgent.h"
47 #include "InspectorDOMDebuggerAgent.h"
48 #include "InspectorDOMStorageAgent.h"
49 #include "InspectorDatabaseAgent.h"
50 #include "InspectorFrontendClient.h"
51 #include "InspectorIndexedDBAgent.h"
52 #include "InspectorInstrumentation.h"
53 #include "InspectorLayerTreeAgent.h"
54 #include "InspectorMemoryAgent.h"
55 #include "InspectorPageAgent.h"
56 #include "InspectorTimelineAgent.h"
57 #include "InspectorWorkerAgent.h"
58 #include "InstrumentingAgents.h"
59 #include "JSDOMBindingSecurity.h"
60 #include "JSDOMWindow.h"
61 #include "JSDOMWindowCustom.h"
62 #include "JSExecState.h"
63 #include "Page.h"
64 #include "PageAuditAgent.h"
65 #include "PageConsoleAgent.h"
66 #include "PageDebuggerAgent.h"
67 #include "PageHeapAgent.h"
68 #include "PageNetworkAgent.h"
69 #include "PageRuntimeAgent.h"
70 #include "PageScriptDebugServer.h"
71 #include "Settings.h"
72 #include "WebInjectedScriptHost.h"
73 #include "WebInjectedScriptManager.h"
74 #include <JavaScriptCore/IdentifiersFactory.h>
75 #include <JavaScriptCore/InspectorAgent.h>
76 #include <JavaScriptCore/InspectorBackendDispatcher.h>
77 #include <JavaScriptCore/InspectorBackendDispatchers.h>
78 #include <JavaScriptCore/InspectorFrontendDispatchers.h>
79 #include <JavaScriptCore/InspectorFrontendRouter.h>
80 #include <JavaScriptCore/InspectorScriptProfilerAgent.h>
81 #include <JavaScriptCore/JSLock.h>
82 #include <wtf/Stopwatch.h>
83
84 #if ENABLE(REMOTE_INSPECTOR)
85 #include "PageDebuggable.h"
86 #endif
87
88 namespace WebCore {
89
90 using namespace JSC;
91 using namespace Inspector;
92
93 InspectorController::InspectorController(Page& page, InspectorClient* inspectorClient)
94     : m_instrumentingAgents(InstrumentingAgents::create(*this))
95     , m_injectedScriptManager(std::make_unique<WebInjectedScriptManager>(*this, WebInjectedScriptHost::create()))
96     , m_frontendRouter(FrontendRouter::create())
97     , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef()))
98     , m_overlay(std::make_unique<InspectorOverlay>(page, inspectorClient))
99     , m_executionStopwatch(Stopwatch::create())
100     , m_scriptDebugServer(page)
101     , m_page(page)
102     , m_inspectorClient(inspectorClient)
103 {
104     ASSERT_ARG(inspectorClient, inspectorClient);
105
106     auto pageContext = pageAgentContext();
107
108     auto inspectorAgentPtr = std::make_unique<InspectorAgent>(pageContext);
109     m_inspectorAgent = inspectorAgentPtr.get();
110     m_instrumentingAgents->setInspectorAgent(m_inspectorAgent);
111     m_agents.append(WTFMove(inspectorAgentPtr));
112
113     auto pageAgentPtr = std::make_unique<InspectorPageAgent>(pageContext, inspectorClient, m_overlay.get());
114     InspectorPageAgent* pageAgent = pageAgentPtr.get();
115     m_pageAgent = pageAgentPtr.get();
116     m_agents.append(WTFMove(pageAgentPtr));
117
118     auto runtimeAgent = std::make_unique<PageRuntimeAgent>(pageContext, pageAgent);
119     m_instrumentingAgents->setPageRuntimeAgent(runtimeAgent.get());
120     m_agents.append(WTFMove(runtimeAgent));
121
122     auto domAgentPtr = std::make_unique<InspectorDOMAgent>(pageContext, pageAgent, m_overlay.get());
123     m_domAgent = domAgentPtr.get();
124     m_agents.append(WTFMove(domAgentPtr));
125
126     auto databaseAgentPtr = std::make_unique<InspectorDatabaseAgent>(pageContext);
127     InspectorDatabaseAgent* databaseAgent = databaseAgentPtr.get();
128     m_agents.append(WTFMove(databaseAgentPtr));
129
130     auto domStorageAgentPtr = std::make_unique<InspectorDOMStorageAgent>(pageContext, m_pageAgent);
131     InspectorDOMStorageAgent* domStorageAgent = domStorageAgentPtr.get();
132     m_agents.append(WTFMove(domStorageAgentPtr));
133
134     auto heapAgentPtr = std::make_unique<PageHeapAgent>(pageContext);
135     InspectorHeapAgent* heapAgent = heapAgentPtr.get();
136     m_agents.append(WTFMove(heapAgentPtr));
137
138     auto scriptProfilerAgentPtr = std::make_unique<InspectorScriptProfilerAgent>(pageContext);
139     InspectorScriptProfilerAgent* scriptProfilerAgent = scriptProfilerAgentPtr.get();
140     m_agents.append(WTFMove(scriptProfilerAgentPtr));
141
142     auto consoleAgentPtr = std::make_unique<PageConsoleAgent>(pageContext, heapAgent, m_domAgent);
143     WebConsoleAgent* consoleAgent = consoleAgentPtr.get();
144     m_instrumentingAgents->setWebConsoleAgent(consoleAgentPtr.get());
145     m_agents.append(WTFMove(consoleAgentPtr));
146
147     m_agents.append(std::make_unique<InspectorTimelineAgent>(pageContext, scriptProfilerAgent, heapAgent, pageAgent));
148
149     auto canvasAgentPtr = std::make_unique<InspectorCanvasAgent>(pageContext);
150     m_instrumentingAgents->setInspectorCanvasAgent(canvasAgentPtr.get());
151     m_agents.append(WTFMove(canvasAgentPtr));
152
153     ASSERT(m_injectedScriptManager->commandLineAPIHost());
154     if (CommandLineAPIHost* commandLineAPIHost = m_injectedScriptManager->commandLineAPIHost())
155         commandLineAPIHost->init(m_inspectorAgent, consoleAgent, m_domAgent, domStorageAgent, databaseAgent);
156 }
157
158 InspectorController::~InspectorController()
159 {
160     m_instrumentingAgents->reset();
161     ASSERT(!m_inspectorClient);
162 }
163
164 PageAgentContext InspectorController::pageAgentContext()
165 {
166     AgentContext baseContext = {
167         *this,
168         *m_injectedScriptManager,
169         m_frontendRouter.get(),
170         m_backendDispatcher.get()
171     };
172
173     WebAgentContext webContext = {
174         baseContext,
175         m_instrumentingAgents.get()
176     };
177
178     PageAgentContext pageContext = {
179         webContext,
180         m_page
181     };
182
183     return pageContext;
184 }
185
186 void InspectorController::createLazyAgents()
187 {
188     if (m_didCreateLazyAgents)
189         return;
190
191     m_didCreateLazyAgents = true;
192
193     auto pageContext = pageAgentContext();
194
195     auto debuggerAgent = std::make_unique<PageDebuggerAgent>(pageContext, m_pageAgent);
196     auto debuggerAgentPtr = debuggerAgent.get();
197
198     m_agents.append(WTFMove(debuggerAgent));
199     m_agents.append(std::make_unique<PageNetworkAgent>(pageContext, m_pageAgent));
200     m_agents.append(std::make_unique<InspectorCSSAgent>(pageContext, m_domAgent));
201     m_agents.append(std::make_unique<InspectorDOMDebuggerAgent>(pageContext, m_domAgent, debuggerAgentPtr));
202     m_agents.append(std::make_unique<InspectorApplicationCacheAgent>(pageContext, m_pageAgent));
203     m_agents.append(std::make_unique<InspectorLayerTreeAgent>(pageContext));
204     m_agents.append(std::make_unique<InspectorWorkerAgent>(pageContext));
205 #if ENABLE(INDEXED_DATABASE)
206     m_agents.append(std::make_unique<InspectorIndexedDBAgent>(pageContext, m_pageAgent));
207 #endif
208 #if ENABLE(RESOURCE_USAGE)
209     m_agents.append(std::make_unique<InspectorCPUProfilerAgent>(pageContext));
210     m_agents.append(std::make_unique<InspectorMemoryAgent>(pageContext));
211 #endif
212     m_agents.append(std::make_unique<PageAuditAgent>(pageContext));
213 }
214
215 void InspectorController::inspectedPageDestroyed()
216 {
217     // Clean up resources and disconnect local and remote frontends.
218     disconnectAllFrontends();
219
220     // Disconnect the client.
221     m_inspectorClient->inspectedPageDestroyed();
222     m_inspectorClient = nullptr;
223
224     m_agents.discardValues();
225 }
226
227 void InspectorController::setInspectorFrontendClient(InspectorFrontendClient* inspectorFrontendClient)
228 {
229     m_inspectorFrontendClient = inspectorFrontendClient;
230 }
231
232 bool InspectorController::hasLocalFrontend() const
233 {
234     return m_frontendRouter->hasLocalFrontend();
235 }
236
237 bool InspectorController::hasRemoteFrontend() const
238 {
239     return m_frontendRouter->hasRemoteFrontend();
240 }
241
242 unsigned InspectorController::inspectionLevel() const
243 {
244     return m_inspectorFrontendClient ? m_inspectorFrontendClient->inspectionLevel() : 0;
245 }
246
247 void InspectorController::didClearWindowObjectInWorld(Frame& frame, DOMWrapperWorld& world)
248 {
249     if (&world != &mainThreadNormalWorld())
250         return;
251
252     if (frame.isMainFrame())
253         m_injectedScriptManager->discardInjectedScripts();
254
255     // If the page is supposed to serve as InspectorFrontend notify inspector frontend
256     // client that it's cleared so that the client can expose inspector bindings.
257     if (m_inspectorFrontendClient && frame.isMainFrame())
258         m_inspectorFrontendClient->windowObjectCleared();
259 }
260
261 void InspectorController::connectFrontend(Inspector::FrontendChannel& frontendChannel, bool isAutomaticInspection, bool immediatelyPause)
262 {
263     ASSERT(m_inspectorClient);
264
265     // If a frontend has connected enable the developer extras and keep them enabled.
266     m_page.settings().setDeveloperExtrasEnabled(true);
267
268     createLazyAgents();
269
270     bool connectedFirstFrontend = !m_frontendRouter->hasFrontends();
271     m_isAutomaticInspection = isAutomaticInspection;
272     m_pauseAfterInitialization = immediatelyPause;
273
274     m_frontendRouter->connectFrontend(frontendChannel);
275
276     InspectorInstrumentation::frontendCreated();
277
278     if (connectedFirstFrontend) {
279         InspectorInstrumentation::registerInstrumentingAgents(m_instrumentingAgents.get());
280         m_agents.didCreateFrontendAndBackend(&m_frontendRouter.get(), &m_backendDispatcher.get());
281     }
282
283     m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount());
284
285 #if ENABLE(REMOTE_INSPECTOR)
286     if (hasLocalFrontend())
287         m_page.remoteInspectorInformationDidChange();
288 #endif
289 }
290
291 void InspectorController::disconnectFrontend(FrontendChannel& frontendChannel)
292 {
293     m_frontendRouter->disconnectFrontend(frontendChannel);
294
295     m_isAutomaticInspection = false;
296     m_pauseAfterInitialization = false;
297
298     InspectorInstrumentation::frontendDeleted();
299
300     bool disconnectedLastFrontend = !m_frontendRouter->hasFrontends();
301     if (disconnectedLastFrontend) {
302         // Notify agents first.
303         m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectorDestroyed);
304
305         // Clean up inspector resources.
306         m_injectedScriptManager->discardInjectedScripts();
307
308         // Unplug all instrumentations since they aren't needed now.
309         InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get());
310     }
311
312     m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount());
313
314 #if ENABLE(REMOTE_INSPECTOR)
315     if (disconnectedLastFrontend)
316         m_page.remoteInspectorInformationDidChange();
317 #endif
318 }
319
320 void InspectorController::disconnectAllFrontends()
321 {
322     // If the local frontend page was destroyed, close the window.
323     if (m_inspectorFrontendClient)
324         m_inspectorFrontendClient->closeWindow();
325
326     // The frontend should call setInspectorFrontendClient(nullptr) under closeWindow().
327     ASSERT(!m_inspectorFrontendClient);
328
329     if (!m_frontendRouter->hasFrontends())
330         return;
331
332     for (unsigned i = 0; i < m_frontendRouter->frontendCount(); ++i)
333         InspectorInstrumentation::frontendDeleted();
334
335     // Unplug all instrumentations to prevent further agent callbacks.
336     InspectorInstrumentation::unregisterInstrumentingAgents(m_instrumentingAgents.get());
337
338     // Notify agents first, since they may need to use InspectorClient.
339     m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectedTargetDestroyed);
340
341     // Clean up inspector resources.
342     m_injectedScriptManager->disconnect();
343
344     // Disconnect any remaining remote frontends.
345     m_frontendRouter->disconnectAllFrontends();
346     m_isAutomaticInspection = false;
347     m_pauseAfterInitialization = false;
348
349     m_inspectorClient->frontendCountChanged(m_frontendRouter->frontendCount());
350
351 #if ENABLE(REMOTE_INSPECTOR)
352     m_page.remoteInspectorInformationDidChange();
353 #endif
354 }
355
356 void InspectorController::show()
357 {
358     ASSERT(!hasRemoteFrontend());
359
360     if (!enabled())
361         return;
362
363     if (m_frontendRouter->hasLocalFrontend())
364         m_inspectorClient->bringFrontendToFront();
365     else if (Inspector::FrontendChannel* frontendChannel = m_inspectorClient->openLocalFrontend(this))
366         connectFrontend(*frontendChannel);
367 }
368
369 void InspectorController::setIsUnderTest(bool value)
370 {
371     if (value == m_isUnderTest)
372         return;
373
374     m_isUnderTest = value;
375
376     // <rdar://problem/26768628> Try to catch suspicious scenarios where we may have a dangling frontend while running tests.
377     RELEASE_ASSERT(!m_isUnderTest || !m_frontendRouter->hasFrontends());
378 }
379
380 void InspectorController::evaluateForTestInFrontend(const String& script)
381 {
382     m_inspectorAgent->evaluateForTestInFrontend(script);
383 }
384
385 void InspectorController::drawHighlight(GraphicsContext& context) const
386 {
387     m_overlay->paint(context);
388 }
389
390 void InspectorController::getHighlight(Highlight& highlight, InspectorOverlay::CoordinateSystem coordinateSystem) const
391 {
392     m_overlay->getHighlight(highlight, coordinateSystem);
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_FAMILY)
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