• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
4  * Copyright (C) 2011 Google Inc. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1.  Redistributions of source code must retain the above copyright
11  *     notice, this list of conditions and the following disclaimer.
12  * 2.  Redistributions in binary form must reproduce the above copyright
13  *     notice, this list of conditions and the following disclaimer in the
14  *     documentation and/or other materials provided with the distribution.
15  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
16  *     its contributors may be used to endorse or promote products derived
17  *     from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "config.h"
32 #include "InspectorAgent.h"
33 
34 #if ENABLE(INSPECTOR)
35 
36 #include "Document.h"
37 #include "DocumentLoader.h"
38 #include "Frame.h"
39 #include "GraphicsContext.h"
40 #include "InjectedScriptHost.h"
41 #include "InjectedScriptManager.h"
42 #include "InspectorBrowserDebuggerAgent.h"
43 #include "InspectorCSSAgent.h"
44 #include "InspectorClient.h"
45 #include "InspectorConsoleAgent.h"
46 #include "InspectorController.h"
47 #include "InspectorDOMAgent.h"
48 #include "InspectorFrontend.h"
49 #include "InspectorInstrumentation.h"
50 #include "InspectorPageAgent.h"
51 #include "InspectorProfilerAgent.h"
52 #include "InspectorResourceAgent.h"
53 #include "InspectorRuntimeAgent.h"
54 #include "InspectorState.h"
55 #include "InspectorTimelineAgent.h"
56 #include "InspectorValues.h"
57 #include "InspectorWorkerResource.h"
58 #include "InstrumentingAgents.h"
59 #include "Page.h"
60 #include "PageDebuggerAgent.h"
61 #include "ResourceRequest.h"
62 #include "ScriptFunctionCall.h"
63 #include "ScriptObject.h"
64 #include "ScriptState.h"
65 #include "Settings.h"
66 
67 #if ENABLE(DATABASE)
68 #include "InspectorDatabaseAgent.h"
69 #endif
70 
71 #if ENABLE(DOM_STORAGE)
72 #include "InspectorDOMStorageAgent.h"
73 #endif
74 
75 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
76 #include "InspectorApplicationCacheAgent.h"
77 #endif
78 
79 using namespace std;
80 
81 namespace WebCore {
82 
83 namespace InspectorAgentState {
84 static const char timelineProfilerEnabled[] = "timelineProfilerEnabled";
85 static const char debuggerEnabled[] = "debuggerEnabled";
86 }
87 
88 static const char scriptsPanelName[] = "scripts";
89 static const char consolePanelName[] = "console";
90 static const char profilesPanelName[] = "profiles";
91 
92 namespace {
93 
94 class PageRuntimeAgent : public InspectorRuntimeAgent {
95 public:
PageRuntimeAgent(InjectedScriptManager * injectedScriptManager,Page * page)96     PageRuntimeAgent(InjectedScriptManager* injectedScriptManager, Page* page)
97         : InspectorRuntimeAgent(injectedScriptManager)
98         , m_inspectedPage(page) { }
~PageRuntimeAgent()99     virtual ~PageRuntimeAgent() { }
100 
101 private:
getDefaultInspectedState()102     virtual ScriptState* getDefaultInspectedState() { return mainWorldScriptState(m_inspectedPage->mainFrame()); }
103     Page* m_inspectedPage;
104 };
105 
106 }
107 
InspectorAgent(Page * page,InspectorClient * client,InjectedScriptManager * injectedScriptManager)108 InspectorAgent::InspectorAgent(Page* page, InspectorClient* client, InjectedScriptManager* injectedScriptManager)
109     : m_inspectedPage(page)
110     , m_client(client)
111     , m_frontend(0)
112     , m_instrumentingAgents(new InstrumentingAgents())
113     , m_injectedScriptManager(injectedScriptManager)
114     , m_state(new InspectorState(client))
115     , m_pageAgent(InspectorPageAgent::create(m_instrumentingAgents.get(), page, injectedScriptManager))
116     , m_domAgent(InspectorDOMAgent::create(m_instrumentingAgents.get(), page, m_client, m_state.get(), injectedScriptManager))
117     , m_cssAgent(new InspectorCSSAgent(m_instrumentingAgents.get(), m_domAgent.get()))
118 #if ENABLE(DATABASE)
119     , m_databaseAgent(InspectorDatabaseAgent::create(m_instrumentingAgents.get(), m_state.get()))
120 #endif
121 #if ENABLE(DOM_STORAGE)
122     , m_domStorageAgent(InspectorDOMStorageAgent::create(m_instrumentingAgents.get()))
123 #endif
124     , m_timelineAgent(InspectorTimelineAgent::create(m_instrumentingAgents.get(), m_state.get()))
125 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
126     , m_applicationCacheAgent(new InspectorApplicationCacheAgent(m_instrumentingAgents.get(), page))
127 #endif
128     , m_resourceAgent(InspectorResourceAgent::create(m_instrumentingAgents.get(), page, m_state.get()))
129     , m_runtimeAgent(adoptPtr(new PageRuntimeAgent(m_injectedScriptManager, page)))
130     , m_consoleAgent(new InspectorConsoleAgent(m_instrumentingAgents.get(), this, m_state.get(), injectedScriptManager, m_domAgent.get()))
131 #if ENABLE(JAVASCRIPT_DEBUGGER)
132     , m_debuggerAgent(PageDebuggerAgent::create(m_instrumentingAgents.get(), m_state.get(), page, injectedScriptManager))
133     , m_browserDebuggerAgent(InspectorBrowserDebuggerAgent::create(m_instrumentingAgents.get(), m_state.get(), m_domAgent.get(), m_debuggerAgent.get(), this))
134     , m_profilerAgent(InspectorProfilerAgent::create(m_instrumentingAgents.get(), m_consoleAgent.get(), page, m_state.get()))
135 #endif
136     , m_canIssueEvaluateForTestInFrontend(false)
137 {
138     ASSERT_ARG(page, page);
139     ASSERT_ARG(client, client);
140     InspectorInstrumentation::bindInspectorAgent(m_inspectedPage, this);
141     m_instrumentingAgents->setInspectorAgent(this);
142 
143     m_injectedScriptManager->injectedScriptHost()->init(this
144         , m_consoleAgent.get()
145 #if ENABLE(DATABASE)
146         , m_databaseAgent.get()
147 #endif
148 #if ENABLE(DOM_STORAGE)
149         , m_domStorageAgent.get()
150 #endif
151 #if ENABLE(JAVASCRIPT_DEBUGGER)
152         , m_debuggerAgent.get()
153 #endif
154     );
155 }
156 
~InspectorAgent()157 InspectorAgent::~InspectorAgent()
158 {
159     m_instrumentingAgents->setInspectorAgent(0);
160 
161     // These should have been cleared in inspectedPageDestroyed().
162     ASSERT(!m_client);
163     ASSERT(!m_inspectedPage);
164 }
165 
inspectedPageDestroyed()166 void InspectorAgent::inspectedPageDestroyed()
167 {
168     if (m_frontend) {
169         m_frontend->inspector()->disconnectFromBackend();
170         disconnectFrontend();
171     }
172 
173 #if ENABLE(JAVASCRIPT_DEBUGGER)
174     m_browserDebuggerAgent.clear();
175     m_debuggerAgent.clear();
176 #endif
177 
178     ASSERT(m_inspectedPage);
179     InspectorInstrumentation::unbindInspectorAgent(m_inspectedPage);
180     m_inspectedPage = 0;
181 
182     m_injectedScriptManager->disconnect();
183 
184     m_client->inspectorDestroyed();
185     m_client = 0;
186 }
187 
restoreInspectorStateFromCookie(const String & inspectorStateCookie)188 void InspectorAgent::restoreInspectorStateFromCookie(const String& inspectorStateCookie)
189 {
190     m_state->loadFromCookie(inspectorStateCookie);
191 
192     m_frontend->inspector()->frontendReused();
193     m_pageAgent->restore();
194 
195     m_domAgent->restore();
196     m_resourceAgent->restore();
197     m_timelineAgent->restore();
198 
199 #if ENABLE(DATABASE)
200     m_databaseAgent->restore();
201 #endif
202 
203 #if ENABLE(JAVASCRIPT_DEBUGGER)
204     m_debuggerAgent->restore();
205     m_profilerAgent->restore();
206 #endif
207 }
208 
didClearWindowObjectInWorld(Frame * frame,DOMWrapperWorld * world)209 void InspectorAgent::didClearWindowObjectInWorld(Frame* frame, DOMWrapperWorld* world)
210 {
211     if (world != mainThreadNormalWorld())
212         return;
213 
214     if (!m_inspectorExtensionAPI.isEmpty())
215         m_injectedScriptManager->injectScript(m_inspectorExtensionAPI, mainWorldScriptState(frame));
216 }
217 
setFrontend(InspectorFrontend * inspectorFrontend)218 void InspectorAgent::setFrontend(InspectorFrontend* inspectorFrontend)
219 {
220     // We can reconnect to existing front-end -> unmute state.
221     m_state->unmute();
222 
223     m_frontend = inspectorFrontend;
224 
225 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
226     m_applicationCacheAgent->setFrontend(m_frontend);
227 #endif
228     m_pageAgent->setFrontend(m_frontend);
229     m_domAgent->setFrontend(m_frontend);
230     m_consoleAgent->setFrontend(m_frontend);
231     m_timelineAgent->setFrontend(m_frontend);
232     m_resourceAgent->setFrontend(m_frontend);
233 #if ENABLE(JAVASCRIPT_DEBUGGER)
234     m_debuggerAgent->setFrontend(m_frontend);
235     m_profilerAgent->setFrontend(m_frontend);
236 #endif
237 #if ENABLE(DATABASE)
238     m_databaseAgent->setFrontend(m_frontend);
239 #endif
240 #if ENABLE(DOM_STORAGE)
241     m_domStorageAgent->setFrontend(m_frontend);
242 #endif
243 
244     if (!m_showPanelAfterVisible.isEmpty()) {
245         m_frontend->inspector()->showPanel(m_showPanelAfterVisible);
246         m_showPanelAfterVisible = String();
247     }
248 #if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(WORKERS)
249     WorkersMap::iterator workersEnd = m_workers.end();
250     for (WorkersMap::iterator it = m_workers.begin(); it != workersEnd; ++it) {
251         InspectorWorkerResource* worker = it->second.get();
252         m_frontend->inspector()->didCreateWorker(worker->id(), worker->url(), worker->isSharedWorker());
253     }
254 #endif
255     // Dispatch pending frontend commands
256     issueEvaluateForTestCommands();
257 }
258 
disconnectFrontend()259 void InspectorAgent::disconnectFrontend()
260 {
261     if (!m_frontend)
262         return;
263 
264     m_canIssueEvaluateForTestInFrontend = false;
265     m_pendingEvaluateTestCommands.clear();
266 
267     // Destroying agents would change the state, but we don't want that.
268     // Pre-disconnect state will be used to restore inspector agents.
269     m_state->mute();
270 
271     m_frontend = 0;
272 
273 #if ENABLE(JAVASCRIPT_DEBUGGER)
274     m_debuggerAgent->clearFrontend();
275     m_browserDebuggerAgent->clearFrontend();
276     m_profilerAgent->clearFrontend();
277 #endif
278 
279 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
280     m_applicationCacheAgent->clearFrontend();
281 #endif
282 
283     m_consoleAgent->clearFrontend();
284     m_domAgent->clearFrontend();
285     m_timelineAgent->clearFrontend();
286     m_resourceAgent->clearFrontend();
287 #if ENABLE(DATABASE)
288     m_databaseAgent->clearFrontend();
289 #endif
290 #if ENABLE(DOM_STORAGE)
291     m_domStorageAgent->clearFrontend();
292 #endif
293     m_pageAgent->clearFrontend();
294 }
295 
didCommitLoad()296 void InspectorAgent::didCommitLoad()
297 {
298     if (m_frontend)
299         m_frontend->inspector()->reset();
300 
301     m_injectedScriptManager->discardInjectedScripts();
302 #if ENABLE(WORKERS)
303     m_workers.clear();
304 #endif
305 }
306 
domContentLoadedEventFired()307 void InspectorAgent::domContentLoadedEventFired()
308 {
309     m_injectedScriptManager->injectedScriptHost()->clearInspectedNodes();
310 }
311 
isMainResourceLoader(DocumentLoader * loader,const KURL & requestUrl)312 bool InspectorAgent::isMainResourceLoader(DocumentLoader* loader, const KURL& requestUrl)
313 {
314     return loader->frame() == m_inspectedPage->mainFrame() && requestUrl == loader->requestURL();
315 }
316 
317 #if ENABLE(WORKERS)
318 class PostWorkerNotificationToFrontendTask : public ScriptExecutionContext::Task {
319 public:
create(PassRefPtr<InspectorWorkerResource> worker,InspectorAgent::WorkerAction action)320     static PassOwnPtr<PostWorkerNotificationToFrontendTask> create(PassRefPtr<InspectorWorkerResource> worker, InspectorAgent::WorkerAction action)
321     {
322         return new PostWorkerNotificationToFrontendTask(worker, action);
323     }
324 
325 private:
PostWorkerNotificationToFrontendTask(PassRefPtr<InspectorWorkerResource> worker,InspectorAgent::WorkerAction action)326     PostWorkerNotificationToFrontendTask(PassRefPtr<InspectorWorkerResource> worker, InspectorAgent::WorkerAction action)
327         : m_worker(worker)
328         , m_action(action)
329     {
330     }
331 
performTask(ScriptExecutionContext * scriptContext)332     virtual void performTask(ScriptExecutionContext* scriptContext)
333     {
334         if (scriptContext->isDocument()) {
335             if (InspectorAgent* inspectorAgent = static_cast<Document*>(scriptContext)->page()->inspectorController()->m_inspectorAgent.get())
336                 inspectorAgent->postWorkerNotificationToFrontend(*m_worker, m_action);
337         }
338     }
339 
340 private:
341     RefPtr<InspectorWorkerResource> m_worker;
342     InspectorAgent::WorkerAction m_action;
343 };
344 
postWorkerNotificationToFrontend(const InspectorWorkerResource & worker,InspectorAgent::WorkerAction action)345 void InspectorAgent::postWorkerNotificationToFrontend(const InspectorWorkerResource& worker, InspectorAgent::WorkerAction action)
346 {
347     if (!m_frontend)
348         return;
349 #if ENABLE(JAVASCRIPT_DEBUGGER)
350     switch (action) {
351     case InspectorAgent::WorkerCreated:
352         m_frontend->inspector()->didCreateWorker(worker.id(), worker.url(), worker.isSharedWorker());
353         break;
354     case InspectorAgent::WorkerDestroyed:
355         m_frontend->inspector()->didDestroyWorker(worker.id());
356         break;
357     }
358 #endif
359 }
360 
didCreateWorker(intptr_t id,const String & url,bool isSharedWorker)361 void InspectorAgent::didCreateWorker(intptr_t id, const String& url, bool isSharedWorker)
362 {
363     if (!enabled())
364         return;
365 
366     RefPtr<InspectorWorkerResource> workerResource(InspectorWorkerResource::create(id, url, isSharedWorker));
367     m_workers.set(id, workerResource);
368     if (m_inspectedPage && m_frontend)
369         m_inspectedPage->mainFrame()->document()->postTask(PostWorkerNotificationToFrontendTask::create(workerResource, InspectorAgent::WorkerCreated));
370 }
371 
didDestroyWorker(intptr_t id)372 void InspectorAgent::didDestroyWorker(intptr_t id)
373 {
374     if (!enabled())
375         return;
376 
377     WorkersMap::iterator workerResource = m_workers.find(id);
378     if (workerResource == m_workers.end())
379         return;
380     if (m_inspectedPage && m_frontend)
381         m_inspectedPage->mainFrame()->document()->postTask(PostWorkerNotificationToFrontendTask::create(workerResource->second, InspectorAgent::WorkerDestroyed));
382     m_workers.remove(workerResource);
383 }
384 #endif // ENABLE(WORKERS)
385 
386 #if ENABLE(JAVASCRIPT_DEBUGGER)
showProfilesPanel()387 void InspectorAgent::showProfilesPanel()
388 {
389     showPanel(profilesPanelName);
390 }
391 #endif
392 
evaluateForTestInFrontend(long callId,const String & script)393 void InspectorAgent::evaluateForTestInFrontend(long callId, const String& script)
394 {
395     m_pendingEvaluateTestCommands.append(pair<long, String>(callId, script));
396     if (m_canIssueEvaluateForTestInFrontend)
397         issueEvaluateForTestCommands();
398 }
399 
setInspectorExtensionAPI(const String & source)400 void InspectorAgent::setInspectorExtensionAPI(const String& source)
401 {
402     m_inspectorExtensionAPI = source;
403 }
404 
inspectedURL() const405 KURL InspectorAgent::inspectedURL() const
406 {
407     return m_inspectedPage->mainFrame()->document()->url();
408 }
409 
inspectedURLWithoutFragment() const410 KURL InspectorAgent::inspectedURLWithoutFragment() const
411 {
412     KURL url = inspectedURL();
413     url.removeFragmentIdentifier();
414     return url;
415 }
416 
enabled() const417 bool InspectorAgent::enabled() const
418 {
419     if (!m_inspectedPage)
420         return false;
421     return m_inspectedPage->settings()->developerExtrasEnabled();
422 }
423 
showConsole()424 void InspectorAgent::showConsole()
425 {
426     showPanel(consolePanelName);
427 }
428 
showPanel(const String & panel)429 void InspectorAgent::showPanel(const String& panel)
430 {
431     if (!m_frontend) {
432         m_showPanelAfterVisible = panel;
433         return;
434     }
435     m_frontend->inspector()->showPanel(panel);
436 }
437 
issueEvaluateForTestCommands()438 void InspectorAgent::issueEvaluateForTestCommands()
439 {
440     if (m_frontend) {
441         Vector<pair<long, String> > copy = m_pendingEvaluateTestCommands;
442         m_pendingEvaluateTestCommands.clear();
443         for (Vector<pair<long, String> >::iterator it = copy.begin(); m_frontend && it != copy.end(); ++it)
444             m_frontend->inspector()->evaluateForTestInFrontend((*it).first, (*it).second);
445         m_canIssueEvaluateForTestInFrontend = true;
446     }
447 }
448 
449 } // namespace WebCore
450 
451 #endif // ENABLE(INSPECTOR)
452