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
53namespace JSC {
54class UString;
55}
56#endif
57
58namespace WebCore {
59
60class CachedResource;
61class Database;
62class Document;
63class DocumentLoader;
64class Element;
65class GraphicsContext;
66class HitTestResult;
67class InjectedScript;
68class InjectedScriptHost;
69class InspectorBackend;
70class InspectorClient;
71class InspectorFrontend;
72class InspectorFrontendHost;
73class InspectorTimelineAgent;
74class JavaScriptCallFrame;
75class KURL;
76class Node;
77class Page;
78class ResourceRequest;
79class ResourceResponse;
80class ResourceError;
81class ScriptCallStack;
82class ScriptString;
83class SharedBuffer;
84class Storage;
85class StorageArea;
86
87class ConsoleMessage;
88class InspectorDatabaseResource;
89class InspectorDOMStorageResource;
90class InspectorResource;
91
92class InspectorController
93#if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
94                          : JavaScriptDebugListener, public Noncopyable
95#else
96                          : public Noncopyable
97#endif
98                                                    {
99public:
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
119    InspectorBackend* inspectorBackend() { return m_inspectorBackend.get(); }
120    InspectorFrontendHost* inspectorFrontendHost() { return m_inspectorFrontendHost.get(); }
121    InjectedScriptHost* injectedScriptHost() { return m_injectedScriptHost.get(); }
122
123    void inspectedPageDestroyed();
124    void pageDestroyed() { m_page = 0; }
125
126    bool enabled() const;
127
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();
147    const Vector<ConsoleMessage*>& consoleMessages() const { return m_consoleMessages; }
148
149    void attachWindow();
150    void detachWindow();
151
152    void toggleSearchForNodeInPage();
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());
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);
182    bool resourceTrackingEnabled() const { return m_resourceTrackingEnabled; }
183    void ensureResourceTrackingSettingsLoaded();
184
185    void startTimelineProfiler();
186    void stopTimelineProfiler();
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
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
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);
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);
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
256private:
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();
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);
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
365inline void InspectorController::didInsertDOMNode(Node* node)
366{
367    if (m_domAgent)
368        m_domAgent->didInsertDOMNode(node);
369}
370
371inline void InspectorController::didRemoveDOMNode(Node* node)
372{
373    if (m_domAgent)
374        m_domAgent->didRemoveDOMNode(node);
375}
376
377inline 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