initial import
[vuplus_webkit] / Source / WebCore / inspector / InspectorAgent.cpp
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 "InspectorController.h"
43 #include "InspectorFrontend.h"
44 #include "InspectorInstrumentation.h"
45 #include "InspectorValues.h"
46 #include "InspectorWorkerResource.h"
47 #include "InstrumentingAgents.h"
48 #include "Page.h"
49 #include "ResourceRequest.h"
50 #include "ScriptFunctionCall.h"
51 #include "ScriptObject.h"
52 #include "Settings.h"
53 #include <wtf/PassRefPtr.h>
54 #include <wtf/RefPtr.h>
55
56 using namespace std;
57
58 namespace WebCore {
59
60 static const char scriptsPanelName[] = "scripts";
61 static const char consolePanelName[] = "console";
62 static const char profilesPanelName[] = "profiles";
63
64 InspectorAgent::InspectorAgent(Page* page, InjectedScriptManager* injectedScriptManager, InstrumentingAgents* instrumentingAgents)
65     : m_inspectedPage(page)
66     , m_frontend(0)
67     , m_instrumentingAgents(instrumentingAgents)
68     , m_injectedScriptManager(injectedScriptManager)
69     , m_canIssueEvaluateForTestInFrontend(false)
70     , m_didCommitLoadFired(false)
71 {
72     ASSERT_ARG(page, page);
73     m_instrumentingAgents->setInspectorAgent(this);
74 }
75
76 InspectorAgent::~InspectorAgent()
77 {
78     m_instrumentingAgents->setInspectorAgent(0);
79
80     // These should have been cleared in inspectedPageDestroyed().
81     ASSERT(!m_inspectedPage);
82 }
83
84 void InspectorAgent::inspectedPageDestroyed()
85 {
86     if (m_frontend)
87         m_frontend->inspector()->disconnectFromBackend();
88     ASSERT(m_inspectedPage);
89     m_inspectedPage = 0;
90 }
91
92 void InspectorAgent::restore()
93 {
94     if (m_didCommitLoadFired)
95         m_frontend->inspector()->frontendReused();
96 }
97
98 void InspectorAgent::didClearWindowObjectInWorld(Frame* frame, DOMWrapperWorld* world)
99 {
100     if (world != mainThreadNormalWorld())
101         return;
102
103     if (!m_inspectorExtensionAPI.isEmpty())
104         m_injectedScriptManager->injectScript(m_inspectorExtensionAPI, mainWorldScriptState(frame));
105 }
106
107 void InspectorAgent::setFrontend(InspectorFrontend* inspectorFrontend)
108 {
109     m_frontend = inspectorFrontend;
110
111     if (!m_showPanelAfterVisible.isEmpty()) {
112         m_frontend->inspector()->showPanel(m_showPanelAfterVisible);
113         m_showPanelAfterVisible = String();
114     }
115 #if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(WORKERS)
116     WorkersMap::iterator workersEnd = m_workers.end();
117     for (WorkersMap::iterator it = m_workers.begin(); it != workersEnd; ++it) {
118         InspectorWorkerResource* worker = it->second.get();
119         m_frontend->inspector()->didCreateWorker(worker->id(), worker->url(), worker->isSharedWorker());
120     }
121 #endif
122
123     // Dispatch pending frontend commands
124     issueEvaluateForTestCommands();
125 }
126
127 void InspectorAgent::clearFrontend()
128 {
129     m_canIssueEvaluateForTestInFrontend = false;
130     m_pendingEvaluateTestCommands.clear();
131     m_frontend = 0;
132     m_didCommitLoadFired = false;
133 }
134
135 void InspectorAgent::didCommitLoad()
136 {
137     m_didCommitLoadFired = true;
138     if (m_frontend)
139         m_frontend->inspector()->reset();
140
141     m_injectedScriptManager->discardInjectedScripts();
142 #if ENABLE(WORKERS)
143     m_workers.clear();
144 #endif
145 }
146
147 void InspectorAgent::domContentLoadedEventFired()
148 {
149     m_injectedScriptManager->injectedScriptHost()->clearInspectedNodes();
150 }
151
152 bool InspectorAgent::isMainResourceLoader(DocumentLoader* loader, const KURL& requestUrl)
153 {
154     return loader->frame() == m_inspectedPage->mainFrame() && requestUrl == loader->requestURL();
155 }
156
157 #if ENABLE(WORKERS)
158 class PostWorkerNotificationToFrontendTask : public ScriptExecutionContext::Task {
159 public:
160     static PassOwnPtr<PostWorkerNotificationToFrontendTask> create(PassRefPtr<InspectorWorkerResource> worker, InspectorAgent::WorkerAction action)
161     {
162         return adoptPtr(new PostWorkerNotificationToFrontendTask(worker, action));
163     }
164
165 private:
166     PostWorkerNotificationToFrontendTask(PassRefPtr<InspectorWorkerResource> worker, InspectorAgent::WorkerAction action)
167         : m_worker(worker)
168         , m_action(action)
169     {
170     }
171
172     virtual void performTask(ScriptExecutionContext* scriptContext)
173     {
174         if (scriptContext->isDocument()) {
175             if (InspectorAgent* inspectorAgent = static_cast<Document*>(scriptContext)->page()->inspectorController()->m_inspectorAgent.get())
176                 inspectorAgent->postWorkerNotificationToFrontend(*m_worker, m_action);
177         }
178     }
179
180 private:
181     RefPtr<InspectorWorkerResource> m_worker;
182     InspectorAgent::WorkerAction m_action;
183 };
184
185 void InspectorAgent::postWorkerNotificationToFrontend(const InspectorWorkerResource& worker, InspectorAgent::WorkerAction action)
186 {
187     if (!m_frontend)
188         return;
189 #if ENABLE(JAVASCRIPT_DEBUGGER)
190     switch (action) {
191     case InspectorAgent::WorkerCreated:
192         m_frontend->inspector()->didCreateWorker(worker.id(), worker.url(), worker.isSharedWorker());
193         break;
194     case InspectorAgent::WorkerDestroyed:
195         m_frontend->inspector()->didDestroyWorker(worker.id());
196         break;
197     }
198 #endif
199 }
200
201 void InspectorAgent::didCreateWorker(intptr_t id, const String& url, bool isSharedWorker)
202 {
203     if (!enabled())
204         return;
205
206     RefPtr<InspectorWorkerResource> workerResource(InspectorWorkerResource::create(id, url, isSharedWorker));
207     m_workers.set(id, workerResource);
208     if (m_inspectedPage && m_frontend)
209         m_inspectedPage->mainFrame()->document()->postTask(PostWorkerNotificationToFrontendTask::create(workerResource, InspectorAgent::WorkerCreated));
210 }
211
212 void InspectorAgent::didDestroyWorker(intptr_t id)
213 {
214     if (!enabled())
215         return;
216
217     WorkersMap::iterator workerResource = m_workers.find(id);
218     if (workerResource == m_workers.end())
219         return;
220     if (m_inspectedPage && m_frontend)
221         m_inspectedPage->mainFrame()->document()->postTask(PostWorkerNotificationToFrontendTask::create(workerResource->second, InspectorAgent::WorkerDestroyed));
222     m_workers.remove(workerResource);
223 }
224 #endif // ENABLE(WORKERS)
225
226 #if ENABLE(JAVASCRIPT_DEBUGGER)
227 void InspectorAgent::showProfilesPanel()
228 {
229     showPanel(profilesPanelName);
230 }
231 #endif
232
233 void InspectorAgent::evaluateForTestInFrontend(long callId, const String& script)
234 {
235     m_pendingEvaluateTestCommands.append(pair<long, String>(callId, script));
236     if (m_canIssueEvaluateForTestInFrontend)
237         issueEvaluateForTestCommands();
238 }
239
240 void InspectorAgent::setInspectorExtensionAPI(const String& source)
241 {
242     m_inspectorExtensionAPI = source;
243 }
244
245 KURL InspectorAgent::inspectedURL() const
246 {
247     return m_inspectedPage->mainFrame()->document()->url();
248 }
249
250 KURL InspectorAgent::inspectedURLWithoutFragment() const
251 {
252     KURL url = inspectedURL();
253     url.removeFragmentIdentifier();
254     return url;
255 }
256
257 bool InspectorAgent::enabled() const
258 {
259     if (!m_inspectedPage)
260         return false;
261     return m_inspectedPage->settings()->developerExtrasEnabled();
262 }
263
264 void InspectorAgent::showConsole()
265 {
266     showPanel(consolePanelName);
267 }
268
269 void InspectorAgent::showPanel(const String& panel)
270 {
271     if (!m_frontend) {
272         m_showPanelAfterVisible = panel;
273         return;
274     }
275     m_frontend->inspector()->showPanel(panel);
276 }
277
278 void InspectorAgent::issueEvaluateForTestCommands()
279 {
280     if (m_frontend) {
281         Vector<pair<long, String> > copy = m_pendingEvaluateTestCommands;
282         m_pendingEvaluateTestCommands.clear();
283         for (Vector<pair<long, String> >::iterator it = copy.begin(); m_frontend && it != copy.end(); ++it)
284             m_frontend->inspector()->evaluateForTestInFrontend((*it).first, (*it).second);
285         m_canIssueEvaluateForTestInFrontend = true;
286     }
287 }
288
289 } // namespace WebCore
290
291 #endif // ENABLE(INSPECTOR)