1 /*
2 * Copyright (C) 2007 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #ifndef InspectorController_h
30 #define InspectorController_h
31
32 #include "Console.h"
33 #include "Cookie.h"
34 #include "InspectorDOMAgent.h"
35 #include "PlatformString.h"
36 #include "ScriptArray.h"
37 #include "ScriptObject.h"
38 #include "ScriptProfile.h"
39 #include "ScriptState.h"
40 #include "ScriptValue.h"
41 #include "StringHash.h"
42 #include "Timer.h"
43
44 #include <wtf/HashMap.h>
45 #include <wtf/HashSet.h>
46 #include <wtf/ListHashSet.h>
47 #include <wtf/RefCounted.h>
48 #include <wtf/Vector.h>
49
50 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
51 #include "JavaScriptDebugListener.h"
52
53 namespace JSC {
54 class UString;
55 }
56 #endif
57
58 namespace WebCore {
59
60 class CachedResource;
61 class Database;
62 class Document;
63 class DocumentLoader;
64 class Element;
65 class GraphicsContext;
66 class HitTestResult;
67 class InjectedScript;
68 class InjectedScriptHost;
69 class InspectorBackend;
70 class InspectorClient;
71 class InspectorFrontend;
72 class InspectorFrontendHost;
73 class InspectorTimelineAgent;
74 class JavaScriptCallFrame;
75 class KURL;
76 class Node;
77 class Page;
78 class ResourceRequest;
79 class ResourceResponse;
80 class ResourceError;
81 class ScriptCallStack;
82 class ScriptString;
83 class SharedBuffer;
84 class Storage;
85 class StorageArea;
86
87 class ConsoleMessage;
88 class InspectorDatabaseResource;
89 class InspectorDOMStorageResource;
90 class InspectorResource;
91
92 class InspectorController
93 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
94 : JavaScriptDebugListener, public Noncopyable
95 #else
96 : public Noncopyable
97 #endif
98 {
99 public:
100 typedef HashMap<unsigned long, RefPtr<InspectorResource> > ResourcesMap;
101 typedef HashMap<RefPtr<Frame>, ResourcesMap*> FrameResourcesMap;
102 typedef HashMap<int, RefPtr<InspectorDatabaseResource> > DatabaseResourcesMap;
103 typedef HashMap<int, RefPtr<InspectorDOMStorageResource> > DOMStorageResourcesMap;
104
105 typedef enum {
106 CurrentPanel,
107 ConsolePanel,
108 ElementsPanel,
109 ResourcesPanel,
110 ScriptsPanel,
111 TimelinePanel,
112 ProfilesPanel,
113 StoragePanel
114 } SpecialPanels;
115
116 InspectorController(Page*, InspectorClient*);
117 ~InspectorController();
118
inspectorBackend()119 InspectorBackend* inspectorBackend() { return m_inspectorBackend.get(); }
inspectorFrontendHost()120 InspectorFrontendHost* inspectorFrontendHost() { return m_inspectorFrontendHost.get(); }
injectedScriptHost()121 InjectedScriptHost* injectedScriptHost() { return m_injectedScriptHost.get(); }
122
123 void inspectedPageDestroyed();
pageDestroyed()124 void pageDestroyed() { m_page = 0; }
125
126 bool enabled() const;
127
inspectedPage()128 Page* inspectedPage() const { return m_inspectedPage; }
129
130 String setting(const String& key) const;
131 void setSetting(const String& key, const String& value);
132
133 void inspect(Node*);
134 void highlight(Node*);
135 void hideHighlight();
136
137 void show();
138 void showPanel(SpecialPanels);
139 void close();
140
141 bool windowVisible();
142 void setWindowVisible(bool visible = true, bool attached = false);
143
144 void addMessageToConsole(MessageSource, MessageType, MessageLevel, ScriptCallStack*);
145 void addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message, unsigned lineNumber, const String& sourceID);
146 void clearConsoleMessages();
consoleMessages()147 const Vector<ConsoleMessage*>& consoleMessages() const { return m_consoleMessages; }
148
149 void attachWindow();
150 void detachWindow();
151
152 void toggleSearchForNodeInPage();
searchingForNodeInPage()153 bool searchingForNodeInPage() const { return m_searchingForNode; }
154 void mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags);
155 void handleMousePressOnNode(Node*);
156
157 void inspectedWindowScriptObjectCleared(Frame*);
158 void windowScriptObjectAvailable();
159
160 void setFrontendProxyObject(ScriptState* state, ScriptObject webInspectorObj, ScriptObject injectedScriptObj = ScriptObject());
frontendScriptState()161 ScriptState* frontendScriptState() const { return m_frontendScriptState; }
162
163 void populateScriptObjects();
164 void resetScriptObjects();
165
166 void didCommitLoad(DocumentLoader*);
167 void frameDetachedFromParent(Frame*);
168
169 void didLoadResourceFromMemoryCache(DocumentLoader*, const CachedResource*);
170
171 void identifierForInitialRequest(unsigned long identifier, DocumentLoader*, const ResourceRequest&);
172 void willSendRequest(unsigned long identifier, const ResourceRequest&, const ResourceResponse& redirectResponse);
173 void didReceiveResponse(unsigned long identifier, const ResourceResponse&);
174 void didReceiveContentLength(unsigned long identifier, int lengthReceived);
175 void didFinishLoading(unsigned long identifier);
176 void didFailLoading(unsigned long identifier, const ResourceError&);
177 void resourceRetrievedByXMLHttpRequest(unsigned long identifier, const ScriptString& sourceString);
178 void scriptImported(unsigned long identifier, const String& sourceString);
179
180 void enableResourceTracking(bool always = false, bool reload = true);
181 void disableResourceTracking(bool always = false);
resourceTrackingEnabled()182 bool resourceTrackingEnabled() const { return m_resourceTrackingEnabled; }
183 void ensureResourceTrackingSettingsLoaded();
184
185 void startTimelineProfiler();
186 void stopTimelineProfiler();
timelineAgent()187 InspectorTimelineAgent* timelineAgent() { return m_timelineAgent.get(); }
188
189 void mainResourceFiredLoadEvent(DocumentLoader*, const KURL&);
190 void mainResourceFiredDOMContentEvent(DocumentLoader*, const KURL&);
191
192 void didInsertDOMNode(Node*);
193 void didRemoveDOMNode(Node*);
194 void didModifyDOMAttr(Element*);
195
196 void getCookies(long callId);
197
198 #if ENABLE(DATABASE)
199 void didOpenDatabase(Database*, const String& domain, const String& name, const String& version);
200 #endif
201 #if ENABLE(DOM_STORAGE)
202 void didUseDOMStorage(StorageArea* storageArea, bool isLocalStorage, Frame* frame);
203 void selectDOMStorage(Storage* storage);
204 void getDOMStorageEntries(int callId, int storageId);
205 void setDOMStorageItem(long callId, long storageId, const String& key, const String& value);
206 void removeDOMStorageItem(long callId, long storageId, const String& key);
207 #endif
208
resources()209 const ResourcesMap& resources() const { return m_resources; }
210
211 void drawNodeHighlight(GraphicsContext&) const;
212
213 void count(const String& title, unsigned lineNumber, const String& sourceID);
214
215 void startTiming(const String& title);
216 bool stopTiming(const String& title, double& elapsed);
217
218 void startGroup(MessageSource source, ScriptCallStack* callFrame);
219 void endGroup(MessageSource source, unsigned lineNumber, const String& sourceURL);
220
221 void markTimeline(const String& message);
222
223 #if ENABLE(JAVASCRIPT_DEBUGGER)
224 void addProfile(PassRefPtr<ScriptProfile>, unsigned lineNumber, const String& sourceURL);
225 void addProfileFinishedMessageToConsole(PassRefPtr<ScriptProfile>, unsigned lineNumber, const String& sourceURL);
226 void addStartProfilingMessageToConsole(const String& title, unsigned lineNumber, const String& sourceURL);
227
isRecordingUserInitiatedProfile()228 bool isRecordingUserInitiatedProfile() const { return m_recordingUserInitiatedProfile; }
229
230 String getCurrentUserInitiatedProfileName(bool incrementProfileNumber);
231 void startUserInitiatedProfiling(Timer<InspectorController>* = 0);
232 void stopUserInitiatedProfiling();
233
234 void enableProfiler(bool always = false, bool skipRecompile = false);
235 void disableProfiler(bool always = false);
profilerEnabled()236 bool profilerEnabled() const { return enabled() && m_profilerEnabled; }
237 #endif
238
239 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
240 void enableDebugger();
241 void disableDebugger(bool always = false);
debuggerEnabled()242 bool debuggerEnabled() const { return m_debuggerEnabled; }
243
244 void resumeDebugger();
245
246 virtual void didParseSource(JSC::ExecState*, const JSC::SourceCode&);
247 virtual void failedToParseSource(JSC::ExecState*, const JSC::SourceCode&, int errorLine, const JSC::UString& errorMessage);
248 virtual void didPause();
249 virtual void didContinue();
250 #endif
251
252 void evaluateForTestInFrontend(long callId, const String& script);
253
254 InjectedScript injectedScriptForNodeId(long id);
255
256 private:
257 static const char* const FrontendSettingsSettingName;
258 friend class InspectorBackend;
259 friend class InspectorFrontendHost;
260 friend class InjectedScriptHost;
261 // Following are used from InspectorBackend and internally.
262 void scriptObjectReady();
263 void moveWindowBy(float x, float y) const;
264 void setAttachedWindow(bool);
265 void setAttachedWindowHeight(unsigned height);
266 void storeLastActivePanel(const String& panelName);
267 void closeWindow();
domAgent()268 InspectorDOMAgent* domAgent() { return m_domAgent.get(); }
269 void releaseDOMAgent();
270
271 void deleteCookie(const String& cookieName, const String& domain);
272
273 #if ENABLE(JAVASCRIPT_DEBUGGER)
274 typedef HashMap<unsigned int, RefPtr<ScriptProfile> > ProfilesMap;
275
276 void startUserInitiatedProfilingSoon();
277 void toggleRecordButton(bool);
278 void enableDebuggerFromFrontend(bool always);
279 void getProfileHeaders(long callId);
280 void getProfile(long callId, unsigned uid);
281 ScriptObject createProfileHeader(const ScriptProfile& profile);
282 #endif
283 #if ENABLE(DATABASE)
284 void selectDatabase(Database* database);
285 Database* databaseForId(int databaseId);
286 #endif
287 #if ENABLE(DOM_STORAGE)
288 InspectorDOMStorageResource* getDOMStorageResourceForId(int storageId);
289 #endif
290
291 ScriptObject buildObjectForCookie(const Cookie&);
292 ScriptArray buildArrayForCookies(ListHashSet<Cookie>&);
293
294 void focusNode();
295
296 void addConsoleMessage(ScriptState*, ConsoleMessage*);
297
298 void addResource(InspectorResource*);
299 void removeResource(InspectorResource*);
300 InspectorResource* getTrackedResource(unsigned long identifier);
301
302 void pruneResources(ResourcesMap*, DocumentLoader* loaderToKeep = 0);
removeAllResources(ResourcesMap * map)303 void removeAllResources(ResourcesMap* map) { pruneResources(map); }
304
305 void showWindow();
306
307 bool isMainResourceLoader(DocumentLoader* loader, const KURL& requestUrl);
308
309 SpecialPanels specialPanelForJSName(const String& panelName);
310
311 void didEvaluateForTestInFrontend(long callId, const String& jsonResult);
312
313 Page* m_inspectedPage;
314 InspectorClient* m_client;
315 OwnPtr<InspectorFrontend> m_frontend;
316 RefPtr<InspectorDOMAgent> m_domAgent;
317 OwnPtr<InspectorTimelineAgent> m_timelineAgent;
318 Page* m_page;
319 RefPtr<Node> m_nodeToFocus;
320 RefPtr<InspectorResource> m_mainResource;
321 ResourcesMap m_resources;
322 HashSet<String> m_knownResources;
323 FrameResourcesMap m_frameResources;
324 Vector<ConsoleMessage*> m_consoleMessages;
325 unsigned m_expiredConsoleMessageCount;
326 HashMap<String, double> m_times;
327 HashMap<String, unsigned> m_counts;
328 #if ENABLE(DATABASE)
329 DatabaseResourcesMap m_databaseResources;
330 #endif
331 #if ENABLE(DOM_STORAGE)
332 DOMStorageResourcesMap m_domStorageResources;
333 #endif
334 ScriptState* m_frontendScriptState;
335 bool m_windowVisible;
336 SpecialPanels m_showAfterVisible;
337 RefPtr<Node> m_highlightedNode;
338 unsigned m_groupLevel;
339 bool m_searchingForNode;
340 ConsoleMessage* m_previousMessage;
341 bool m_resourceTrackingEnabled;
342 bool m_resourceTrackingSettingsLoaded;
343 RefPtr<InspectorBackend> m_inspectorBackend;
344 RefPtr<InspectorFrontendHost> m_inspectorFrontendHost;
345 RefPtr<InjectedScriptHost> m_injectedScriptHost;
346
347 typedef HashMap<String, String> Settings;
348 mutable Settings m_settings;
349
350 Vector<pair<long, String> > m_pendingEvaluateTestCommands;
351 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
352 bool m_debuggerEnabled;
353 bool m_attachDebuggerWhenShown;
354 #endif
355 #if ENABLE(JAVASCRIPT_DEBUGGER)
356 bool m_profilerEnabled;
357 bool m_recordingUserInitiatedProfile;
358 int m_currentUserInitiatedProfileNumber;
359 unsigned m_nextUserInitiatedProfileNumber;
360 Timer<InspectorController> m_startProfiling;
361 ProfilesMap m_profiles;
362 #endif
363 };
364
didInsertDOMNode(Node * node)365 inline void InspectorController::didInsertDOMNode(Node* node)
366 {
367 if (m_domAgent)
368 m_domAgent->didInsertDOMNode(node);
369 }
370
didRemoveDOMNode(Node * node)371 inline void InspectorController::didRemoveDOMNode(Node* node)
372 {
373 if (m_domAgent)
374 m_domAgent->didRemoveDOMNode(node);
375 }
376
didModifyDOMAttr(Element * element)377 inline void InspectorController::didModifyDOMAttr(Element* element)
378 {
379 if (m_domAgent)
380 m_domAgent->didModifyDOMAttr(element);
381 }
382
383 } // namespace WebCore
384
385 #endif // !defined(InspectorController_h)
386