• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "config.h"
31 #include "InspectorController.h"
32 
33 #if ENABLE(INSPECTOR)
34 
35 #include "CString.h"
36 #include "CachedResource.h"
37 #include "Chrome.h"
38 #include "Console.h"
39 #include "ConsoleMessage.h"
40 #include "Cookie.h"
41 #include "CookieJar.h"
42 #include "DOMWindow.h"
43 #include "Document.h"
44 #include "DocumentLoader.h"
45 #include "Element.h"
46 #include "FloatConversion.h"
47 #include "FloatQuad.h"
48 #include "FloatRect.h"
49 #include "Frame.h"
50 #include "FrameLoader.h"
51 #include "FrameTree.h"
52 #include "FrameView.h"
53 #include "GraphicsContext.h"
54 #include "HTMLFrameOwnerElement.h"
55 #include "HitTestResult.h"
56 #include "InjectedScript.h"
57 #include "InjectedScriptHost.h"
58 #include "InspectorBackend.h"
59 #include "InspectorClient.h"
60 #include "InspectorDOMAgent.h"
61 #include "InspectorDOMStorageResource.h"
62 #include "InspectorDatabaseResource.h"
63 #include "InspectorFrontend.h"
64 #include "InspectorFrontendHost.h"
65 #include "InspectorResource.h"
66 #include "InspectorTimelineAgent.h"
67 #include "JavaScriptProfile.h"
68 #include "Page.h"
69 #include "ProgressTracker.h"
70 #include "Range.h"
71 #include "RenderInline.h"
72 #include "ResourceRequest.h"
73 #include "ResourceResponse.h"
74 #include "ScriptCallStack.h"
75 #include "ScriptDebugServer.h"
76 #include "ScriptFunctionCall.h"
77 #include "ScriptObject.h"
78 #include "ScriptProfile.h"
79 #include "ScriptProfiler.h"
80 #include "ScriptString.h"
81 #include "SecurityOrigin.h"
82 #include "Settings.h"
83 #include "SharedBuffer.h"
84 #include "TextEncoding.h"
85 #include "TextIterator.h"
86 #include <wtf/CurrentTime.h>
87 #include <wtf/ListHashSet.h>
88 #include <wtf/RefCounted.h>
89 #include <wtf/StdLibExtras.h>
90 
91 #if ENABLE(DATABASE)
92 #include "Database.h"
93 #endif
94 
95 #if ENABLE(DOM_STORAGE)
96 #include "Storage.h"
97 #include "StorageArea.h"
98 #endif
99 
100 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
101 #include "JSJavaScriptCallFrame.h"
102 #include "JavaScriptCallFrame.h"
103 #include "JavaScriptDebugServer.h"
104 
105 #include <runtime/JSLock.h>
106 #include <runtime/UString.h>
107 
108 using namespace JSC;
109 #endif
110 using namespace std;
111 
112 namespace WebCore {
113 
114 static const char* const UserInitiatedProfileName = "org.webkit.profiles.user-initiated";
115 static const char* const CPUProfileType = "CPU";
116 static const char* const resourceTrackingEnabledSettingName = "resourceTrackingEnabled";
117 static const char* const debuggerEnabledSettingName = "debuggerEnabled";
118 static const char* const profilerEnabledSettingName = "profilerEnabled";
119 static const char* const inspectorAttachedHeightName = "inspectorAttachedHeight";
120 static const char* const lastActivePanelSettingName = "lastActivePanel";
121 const char* const InspectorController::FrontendSettingsSettingName = "frontendSettings";
122 
123 static const unsigned defaultAttachedHeight = 300;
124 static const float minimumAttachedHeight = 250.0f;
125 static const float maximumAttachedHeightRatio = 0.75f;
126 static const unsigned maximumConsoleMessages = 1000;
127 static const unsigned expireConsoleMessagesStep = 100;
128 
129 static unsigned s_inspectorControllerCount;
130 
InspectorController(Page * page,InspectorClient * client)131 InspectorController::InspectorController(Page* page, InspectorClient* client)
132     : m_inspectedPage(page)
133     , m_client(client)
134     , m_page(0)
135     , m_expiredConsoleMessageCount(0)
136     , m_frontendScriptState(0)
137     , m_windowVisible(false)
138     , m_showAfterVisible(CurrentPanel)
139     , m_groupLevel(0)
140     , m_searchingForNode(false)
141     , m_previousMessage(0)
142     , m_resourceTrackingEnabled(false)
143     , m_resourceTrackingSettingsLoaded(false)
144     , m_inspectorBackend(InspectorBackend::create(this))
145     , m_inspectorFrontendHost(InspectorFrontendHost::create(this, client))
146     , m_injectedScriptHost(InjectedScriptHost::create(this))
147 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
148     , m_debuggerEnabled(false)
149     , m_attachDebuggerWhenShown(false)
150 #endif
151 #if ENABLE(JAVASCRIPT_DEBUGGER)
152     , m_profilerEnabled(!WTF_USE_JSC)
153     , m_recordingUserInitiatedProfile(false)
154     , m_currentUserInitiatedProfileNumber(-1)
155     , m_nextUserInitiatedProfileNumber(1)
156     , m_startProfiling(this, &InspectorController::startUserInitiatedProfiling)
157 #endif
158 {
159     ASSERT_ARG(page, page);
160     ASSERT_ARG(client, client);
161     ++s_inspectorControllerCount;
162 }
163 
~InspectorController()164 InspectorController::~InspectorController()
165 {
166     // These should have been cleared in inspectedPageDestroyed().
167     ASSERT(!m_client);
168     ASSERT(!m_frontendScriptState);
169     ASSERT(!m_inspectedPage);
170     ASSERT(!m_page || (m_page && !m_page->parentInspectorController()));
171 
172     deleteAllValues(m_frameResources);
173     deleteAllValues(m_consoleMessages);
174 
175     ASSERT(s_inspectorControllerCount);
176     --s_inspectorControllerCount;
177 
178     releaseDOMAgent();
179 
180     m_inspectorBackend->disconnectController();
181     m_inspectorFrontendHost->disconnectController();
182     m_injectedScriptHost->disconnectController();
183 }
184 
inspectedPageDestroyed()185 void InspectorController::inspectedPageDestroyed()
186 {
187     close();
188 
189     if (m_frontendScriptState) {
190         ScriptGlobalObject::remove(m_frontendScriptState, "InspectorBackend");
191         ScriptGlobalObject::remove(m_frontendScriptState, "InspectorFrontendHost");
192     }
193     ASSERT(m_inspectedPage);
194     m_inspectedPage = 0;
195 
196     m_client->inspectorDestroyed();
197     m_client = 0;
198 }
199 
enabled() const200 bool InspectorController::enabled() const
201 {
202     if (!m_inspectedPage)
203         return false;
204     return m_inspectedPage->settings()->developerExtrasEnabled();
205 }
206 
setting(const String & key) const207 String InspectorController::setting(const String& key) const
208 {
209     Settings::iterator it = m_settings.find(key);
210     if (it != m_settings.end())
211         return it->second;
212 
213     String value;
214     m_client->populateSetting(key, &value);
215     m_settings.set(key, value);
216     return value;
217 }
218 
setSetting(const String & key,const String & value)219 void InspectorController::setSetting(const String& key, const String& value)
220 {
221     m_settings.set(key, value);
222     m_client->storeSetting(key, value);
223 }
224 
225 // Trying to inspect something in a frame with JavaScript disabled would later lead to
226 // crashes trying to create JavaScript wrappers. Some day we could fix this issue, but
227 // for now prevent crashes here by never targeting a node in such a frame.
canPassNodeToJavaScript(Node * node)228 static bool canPassNodeToJavaScript(Node* node)
229 {
230     if (!node)
231         return false;
232     Frame* frame = node->document()->frame();
233     return frame && frame->script()->canExecuteScripts();
234 }
235 
inspect(Node * node)236 void InspectorController::inspect(Node* node)
237 {
238     if (!canPassNodeToJavaScript(node) || !enabled())
239         return;
240 
241     show();
242 
243     if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
244         node = node->parentNode();
245     m_nodeToFocus = node;
246 
247     if (!m_frontend) {
248         m_showAfterVisible = ElementsPanel;
249         return;
250     }
251 
252     focusNode();
253 }
254 
focusNode()255 void InspectorController::focusNode()
256 {
257     if (!enabled())
258         return;
259 
260     ASSERT(m_frontend);
261     ASSERT(m_nodeToFocus);
262 
263     long id = m_domAgent->pushNodePathToFrontend(m_nodeToFocus.get());
264     m_frontend->updateFocusedNode(id);
265     m_nodeToFocus = 0;
266 }
267 
highlight(Node * node)268 void InspectorController::highlight(Node* node)
269 {
270     if (!enabled())
271         return;
272     ASSERT_ARG(node, node);
273     m_highlightedNode = node;
274     m_client->highlight(node);
275 }
276 
hideHighlight()277 void InspectorController::hideHighlight()
278 {
279     if (!enabled())
280         return;
281     m_highlightedNode = 0;
282     m_client->hideHighlight();
283 }
284 
windowVisible()285 bool InspectorController::windowVisible()
286 {
287     return m_windowVisible;
288 }
289 
setWindowVisible(bool visible,bool attached)290 void InspectorController::setWindowVisible(bool visible, bool attached)
291 {
292     if (visible == m_windowVisible || !m_frontend)
293         return;
294 
295     m_windowVisible = visible;
296 
297     if (m_windowVisible) {
298         setAttachedWindow(attached);
299         populateScriptObjects();
300 
301         if (m_showAfterVisible == CurrentPanel) {
302           String lastActivePanelSetting = setting(lastActivePanelSettingName);
303           m_showAfterVisible = specialPanelForJSName(lastActivePanelSetting);
304         }
305 
306         if (m_nodeToFocus)
307             focusNode();
308 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
309         if (m_attachDebuggerWhenShown)
310             enableDebugger();
311 #endif
312         showPanel(m_showAfterVisible);
313     } else {
314 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
315         // If the window is being closed with the debugger enabled,
316         // remember this state to re-enable debugger on the next window
317         // opening.
318         bool debuggerWasEnabled = m_debuggerEnabled;
319         disableDebugger();
320         if (debuggerWasEnabled)
321             m_attachDebuggerWhenShown = true;
322 #endif
323         if (m_searchingForNode)
324             toggleSearchForNodeInPage();
325         resetScriptObjects();
326         stopTimelineProfiler();
327     }
328     m_showAfterVisible = CurrentPanel;
329 }
330 
addMessageToConsole(MessageSource source,MessageType type,MessageLevel level,ScriptCallStack * callStack)331 void InspectorController::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, ScriptCallStack* callStack)
332 {
333     if (!enabled())
334         return;
335 
336     addConsoleMessage(callStack->state(), new ConsoleMessage(source, type, level, callStack, m_groupLevel, type == TraceMessageType));
337 }
338 
addMessageToConsole(MessageSource source,MessageType type,MessageLevel level,const String & message,unsigned lineNumber,const String & sourceID)339 void InspectorController::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceID)
340 {
341     if (!enabled())
342         return;
343 
344     addConsoleMessage(0, new ConsoleMessage(source, type, level, message, lineNumber, sourceID, m_groupLevel));
345 }
346 
addConsoleMessage(ScriptState * scriptState,ConsoleMessage * consoleMessage)347 void InspectorController::addConsoleMessage(ScriptState* scriptState, ConsoleMessage* consoleMessage)
348 {
349     ASSERT(enabled());
350     ASSERT_ARG(consoleMessage, consoleMessage);
351 
352     if (m_previousMessage && m_previousMessage->isEqual(scriptState, consoleMessage)) {
353         m_previousMessage->incrementCount();
354         delete consoleMessage;
355         if (windowVisible())
356             m_previousMessage->updateRepeatCountInConsole(m_frontend.get());
357     } else {
358         m_previousMessage = consoleMessage;
359         m_consoleMessages.append(consoleMessage);
360         if (windowVisible())
361             m_previousMessage->addToConsole(m_frontend.get());
362     }
363 
364     if (!windowVisible() && m_consoleMessages.size() >= maximumConsoleMessages) {
365         m_expiredConsoleMessageCount += expireConsoleMessagesStep;
366         for (size_t i = 0; i < expireConsoleMessagesStep; ++i)
367             delete m_consoleMessages[i];
368         m_consoleMessages.remove(0, expireConsoleMessagesStep);
369     }
370 }
371 
clearConsoleMessages()372 void InspectorController::clearConsoleMessages()
373 {
374     deleteAllValues(m_consoleMessages);
375     m_consoleMessages.clear();
376     m_expiredConsoleMessageCount = 0;
377     m_previousMessage = 0;
378     m_groupLevel = 0;
379     m_injectedScriptHost->releaseWrapperObjectGroup(0 /* release the group in all scripts */, "console");
380     if (m_domAgent)
381         m_domAgent->releaseDanglingNodes();
382     if (m_frontend)
383         m_frontend->clearConsoleMessages();
384 }
385 
startGroup(MessageSource source,ScriptCallStack * callStack)386 void InspectorController::startGroup(MessageSource source, ScriptCallStack* callStack)
387 {
388     ++m_groupLevel;
389 
390     addConsoleMessage(callStack->state(), new ConsoleMessage(source, StartGroupMessageType, LogMessageLevel, callStack, m_groupLevel));
391 }
392 
endGroup(MessageSource source,unsigned lineNumber,const String & sourceURL)393 void InspectorController::endGroup(MessageSource source, unsigned lineNumber, const String& sourceURL)
394 {
395     if (!m_groupLevel)
396         return;
397 
398     --m_groupLevel;
399 
400     addConsoleMessage(0, new ConsoleMessage(source, EndGroupMessageType, LogMessageLevel, String(), lineNumber, sourceURL, m_groupLevel));
401 }
402 
markTimeline(const String & message)403 void InspectorController::markTimeline(const String& message)
404 {
405     if (timelineAgent())
406         timelineAgent()->didMarkTimeline(message);
407 }
408 
constrainedAttachedWindowHeight(unsigned preferredHeight,unsigned totalWindowHeight)409 static unsigned constrainedAttachedWindowHeight(unsigned preferredHeight, unsigned totalWindowHeight)
410 {
411     return roundf(max(minimumAttachedHeight, min<float>(preferredHeight, totalWindowHeight * maximumAttachedHeightRatio)));
412 }
413 
attachWindow()414 void InspectorController::attachWindow()
415 {
416     if (!enabled())
417         return;
418 
419     unsigned inspectedPageHeight = m_inspectedPage->mainFrame()->view()->visibleHeight();
420 
421     m_client->attachWindow();
422 
423     String attachedHeight = setting(inspectorAttachedHeightName);
424     bool success = true;
425     int height = attachedHeight.toInt(&success);
426     unsigned preferredHeight = success ? height : defaultAttachedHeight;
427 
428     // We need to constrain the window height here in case the user has resized the inspected page's window so that
429     // the user's preferred height would be too big to display.
430     m_client->setAttachedWindowHeight(constrainedAttachedWindowHeight(preferredHeight, inspectedPageHeight));
431 }
432 
detachWindow()433 void InspectorController::detachWindow()
434 {
435     if (!enabled())
436         return;
437     m_client->detachWindow();
438 }
439 
setAttachedWindow(bool attached)440 void InspectorController::setAttachedWindow(bool attached)
441 {
442     if (!enabled() || !m_frontend)
443         return;
444 
445     m_frontend->setAttachedWindow(attached);
446 }
447 
setAttachedWindowHeight(unsigned height)448 void InspectorController::setAttachedWindowHeight(unsigned height)
449 {
450     if (!enabled())
451         return;
452 
453     unsigned totalHeight = m_page->mainFrame()->view()->visibleHeight() + m_inspectedPage->mainFrame()->view()->visibleHeight();
454     unsigned attachedHeight = constrainedAttachedWindowHeight(height, totalHeight);
455 
456     setSetting(inspectorAttachedHeightName, String::number(attachedHeight));
457 
458     m_client->setAttachedWindowHeight(attachedHeight);
459 }
460 
storeLastActivePanel(const String & panelName)461 void InspectorController::storeLastActivePanel(const String& panelName)
462 {
463     setSetting(lastActivePanelSettingName, panelName);
464 }
465 
toggleSearchForNodeInPage()466 void InspectorController::toggleSearchForNodeInPage()
467 {
468     if (!enabled())
469         return;
470 
471     m_searchingForNode = !m_searchingForNode;
472     if (!m_searchingForNode)
473         hideHighlight();
474 }
475 
mouseDidMoveOverElement(const HitTestResult & result,unsigned)476 void InspectorController::mouseDidMoveOverElement(const HitTestResult& result, unsigned)
477 {
478     if (!enabled() || !m_searchingForNode)
479         return;
480 
481     Node* node = result.innerNode();
482     if (node)
483         highlight(node);
484 }
485 
handleMousePressOnNode(Node * node)486 void InspectorController::handleMousePressOnNode(Node* node)
487 {
488     if (!enabled())
489         return;
490 
491     ASSERT(m_searchingForNode);
492     ASSERT(node);
493     if (!node)
494         return;
495 
496     // inspect() will implicitly call ElementsPanel's focusedNodeChanged() and the hover feedback will be stopped there.
497     inspect(node);
498 }
499 
inspectedWindowScriptObjectCleared(Frame * frame)500 void InspectorController::inspectedWindowScriptObjectCleared(Frame* frame)
501 {
502     if (!enabled() || !m_frontend || frame != m_inspectedPage->mainFrame())
503         return;
504     m_injectedScriptHost->discardInjectedScripts();
505 }
506 
windowScriptObjectAvailable()507 void InspectorController::windowScriptObjectAvailable()
508 {
509     if (!m_page || !enabled())
510         return;
511 
512     // Grant the inspector the ability to script the inspected page.
513     m_page->mainFrame()->document()->securityOrigin()->grantUniversalAccess();
514     m_frontendScriptState = scriptStateFromPage(debuggerWorld(), m_page);
515     ScriptGlobalObject::set(m_frontendScriptState, "InspectorBackend", m_inspectorBackend.get());
516     ScriptGlobalObject::set(m_frontendScriptState, "InspectorFrontendHost", m_inspectorFrontendHost.get());
517 }
518 
scriptObjectReady()519 void InspectorController::scriptObjectReady()
520 {
521     ASSERT(m_frontendScriptState);
522     if (!m_frontendScriptState)
523         return;
524 
525     ScriptObject webInspectorObj;
526     if (!ScriptGlobalObject::get(m_frontendScriptState, "WebInspector", webInspectorObj))
527         return;
528     setFrontendProxyObject(m_frontendScriptState, webInspectorObj);
529 
530 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
531     String debuggerEnabled = setting(debuggerEnabledSettingName);
532     if (debuggerEnabled == "true")
533         enableDebugger();
534     String profilerEnabled = setting(profilerEnabledSettingName);
535     if (profilerEnabled == "true")
536         enableProfiler();
537 #endif
538 
539     // Make sure our window is visible now that the page loaded
540     showWindow();
541 
542     m_client->inspectorWindowObjectCleared();
543 }
544 
setFrontendProxyObject(ScriptState * scriptState,ScriptObject webInspectorObj,ScriptObject)545 void InspectorController::setFrontendProxyObject(ScriptState* scriptState, ScriptObject webInspectorObj, ScriptObject)
546 {
547     m_frontendScriptState = scriptState;
548     m_frontend.set(new InspectorFrontend(this, webInspectorObj));
549     releaseDOMAgent();
550     m_domAgent = InspectorDOMAgent::create(m_frontend.get());
551     if (m_timelineAgent)
552         m_timelineAgent->resetFrontendProxyObject(m_frontend.get());
553 }
554 
show()555 void InspectorController::show()
556 {
557     if (!enabled())
558         return;
559 
560     if (!m_page) {
561         if (m_frontend)
562             return; // We are using custom frontend - no need to create page.
563 
564         m_page = m_client->createPage();
565         if (!m_page)
566             return;
567         m_page->setParentInspectorController(this);
568 
569         // showWindow() will be called after the page loads in scriptObjectReady()
570         return;
571     }
572 
573     showWindow();
574 }
575 
showPanel(SpecialPanels panel)576 void InspectorController::showPanel(SpecialPanels panel)
577 {
578     if (!enabled())
579         return;
580 
581     show();
582 
583     if (!m_frontend) {
584         m_showAfterVisible = panel;
585         return;
586     }
587 
588     if (panel == CurrentPanel)
589         return;
590 
591     m_frontend->showPanel(panel);
592 }
593 
close()594 void InspectorController::close()
595 {
596     if (!enabled())
597         return;
598 
599 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
600     stopUserInitiatedProfiling();
601     disableDebugger();
602 #endif
603     closeWindow();
604 
605     releaseDOMAgent();
606     m_frontend.set(0);
607     m_timelineAgent = 0;
608     m_frontendScriptState = 0;
609     if (m_page) {
610         if (!m_page->mainFrame() || !m_page->mainFrame()->loader() || !m_page->mainFrame()->loader()->isLoading()) {
611             m_page->setParentInspectorController(0);
612             m_page = 0;
613         }
614     }
615 }
616 
showWindow()617 void InspectorController::showWindow()
618 {
619     ASSERT(enabled());
620 
621     unsigned inspectedPageHeight = m_inspectedPage->mainFrame()->view()->visibleHeight();
622 
623     m_client->showWindow();
624 
625     String attachedHeight = setting(inspectorAttachedHeightName);
626     bool success = true;
627     int height = attachedHeight.toInt(&success);
628     unsigned preferredHeight = success ? height : defaultAttachedHeight;
629 
630     // This call might not go through (if the window starts out detached), but if the window is initially created attached,
631     // InspectorController::attachWindow is never called, so we need to make sure to set the attachedWindowHeight.
632     // FIXME: Clean up code so we only have to call setAttachedWindowHeight in InspectorController::attachWindow
633     m_client->setAttachedWindowHeight(constrainedAttachedWindowHeight(preferredHeight, inspectedPageHeight));
634 }
635 
closeWindow()636 void InspectorController::closeWindow()
637 {
638     m_client->closeWindow();
639 }
640 
releaseDOMAgent()641 void InspectorController::releaseDOMAgent()
642 {
643     // m_domAgent is RefPtr. Remove DOM listeners first to ensure that there are
644     // no references to the DOM agent from the DOM tree.
645     if (m_domAgent)
646         m_domAgent->reset();
647     m_domAgent = 0;
648 }
649 
populateScriptObjects()650 void InspectorController::populateScriptObjects()
651 {
652     ASSERT(m_frontend);
653     if (!m_frontend)
654         return;
655 
656     m_frontend->populateFrontendSettings(setting(FrontendSettingsSettingName));
657     m_domAgent->setDocument(m_inspectedPage->mainFrame()->document());
658 
659     ResourcesMap::iterator resourcesEnd = m_resources.end();
660     for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it)
661         it->second->updateScriptObject(m_frontend.get());
662 
663     if (m_expiredConsoleMessageCount)
664         m_frontend->updateConsoleMessageExpiredCount(m_expiredConsoleMessageCount);
665     unsigned messageCount = m_consoleMessages.size();
666     for (unsigned i = 0; i < messageCount; ++i)
667         m_consoleMessages[i]->addToConsole(m_frontend.get());
668 
669 #if ENABLE(DATABASE)
670     DatabaseResourcesMap::iterator databasesEnd = m_databaseResources.end();
671     for (DatabaseResourcesMap::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it)
672         it->second->bind(m_frontend.get());
673 #endif
674 #if ENABLE(DOM_STORAGE)
675     DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources.end();
676     for (DOMStorageResourcesMap::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it)
677         it->second->bind(m_frontend.get());
678 #endif
679 
680     m_frontend->populateInterface();
681 
682     // Dispatch pending frontend commands
683     for (Vector<pair<long, String> >::iterator it = m_pendingEvaluateTestCommands.begin(); it != m_pendingEvaluateTestCommands.end(); ++it)
684         m_frontend->evaluateForTestInFrontend((*it).first, (*it).second);
685     m_pendingEvaluateTestCommands.clear();
686 }
687 
resetScriptObjects()688 void InspectorController::resetScriptObjects()
689 {
690     if (!m_frontend)
691         return;
692 
693     ResourcesMap::iterator resourcesEnd = m_resources.end();
694     for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it)
695         it->second->releaseScriptObject(m_frontend.get(), false);
696 
697 #if ENABLE(DATABASE)
698     DatabaseResourcesMap::iterator databasesEnd = m_databaseResources.end();
699     for (DatabaseResourcesMap::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it)
700         it->second->unbind();
701 #endif
702 #if ENABLE(DOM_STORAGE)
703     DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources.end();
704     for (DOMStorageResourcesMap::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it)
705         it->second->unbind();
706 #endif
707 
708     if (m_timelineAgent)
709         m_timelineAgent->reset();
710 
711     m_frontend->reset();
712     m_domAgent->reset();
713 }
714 
pruneResources(ResourcesMap * resourceMap,DocumentLoader * loaderToKeep)715 void InspectorController::pruneResources(ResourcesMap* resourceMap, DocumentLoader* loaderToKeep)
716 {
717     ASSERT_ARG(resourceMap, resourceMap);
718 
719     ResourcesMap mapCopy(*resourceMap);
720     ResourcesMap::iterator end = mapCopy.end();
721     for (ResourcesMap::iterator it = mapCopy.begin(); it != end; ++it) {
722         InspectorResource* resource = (*it).second.get();
723         if (resource == m_mainResource)
724             continue;
725 
726         if (!loaderToKeep || !resource->isSameLoader(loaderToKeep)) {
727             removeResource(resource);
728             if (windowVisible())
729                 resource->releaseScriptObject(m_frontend.get(), true);
730         }
731     }
732 }
733 
didCommitLoad(DocumentLoader * loader)734 void InspectorController::didCommitLoad(DocumentLoader* loader)
735 {
736     if (!enabled())
737         return;
738 
739     ASSERT(m_inspectedPage);
740 
741     if (loader->frame() == m_inspectedPage->mainFrame()) {
742         m_client->inspectedURLChanged(loader->url().string());
743 
744         m_injectedScriptHost->discardInjectedScripts();
745         clearConsoleMessages();
746 
747         m_times.clear();
748         m_counts.clear();
749 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
750         m_profiles.clear();
751         m_currentUserInitiatedProfileNumber = 1;
752         m_nextUserInitiatedProfileNumber = 1;
753 #endif
754         // resetScriptObjects should be called before database and DOM storage
755         // resources are cleared so that it has a chance to unbind them.
756         resetScriptObjects();
757 
758 #if ENABLE(DATABASE)
759         m_databaseResources.clear();
760 #endif
761 #if ENABLE(DOM_STORAGE)
762         m_domStorageResources.clear();
763 #endif
764 
765         if (m_frontend) {
766             if (!loader->frameLoader()->isLoadingFromCachedPage()) {
767                 ASSERT(m_mainResource && m_mainResource->isSameLoader(loader));
768                 // We don't add the main resource until its load is committed. This is
769                 // needed to keep the load for a user-entered URL from showing up in the
770                 // list of resources for the page they are navigating away from.
771                 if (windowVisible())
772                     m_mainResource->updateScriptObject(m_frontend.get());
773             } else {
774                 // Pages loaded from the page cache are committed before
775                 // m_mainResource is the right resource for this load, so we
776                 // clear it here. It will be re-assigned in
777                 // identifierForInitialRequest.
778                 m_mainResource = 0;
779             }
780             if (windowVisible()) {
781                 m_frontend->didCommitLoad();
782                 m_domAgent->setDocument(m_inspectedPage->mainFrame()->document());
783             }
784         }
785     }
786 
787     for (Frame* frame = loader->frame(); frame; frame = frame->tree()->traverseNext(loader->frame()))
788         if (ResourcesMap* resourceMap = m_frameResources.get(frame))
789             pruneResources(resourceMap, loader);
790 }
791 
frameDetachedFromParent(Frame * frame)792 void InspectorController::frameDetachedFromParent(Frame* frame)
793 {
794     if (!enabled())
795         return;
796     if (ResourcesMap* resourceMap = m_frameResources.get(frame))
797         removeAllResources(resourceMap);
798 }
799 
addResource(InspectorResource * resource)800 void InspectorController::addResource(InspectorResource* resource)
801 {
802     m_resources.set(resource->identifier(), resource);
803     m_knownResources.add(resource->requestURL());
804 
805     Frame* frame = resource->frame();
806     ResourcesMap* resourceMap = m_frameResources.get(frame);
807     if (resourceMap)
808         resourceMap->set(resource->identifier(), resource);
809     else {
810         resourceMap = new ResourcesMap;
811         resourceMap->set(resource->identifier(), resource);
812         m_frameResources.set(frame, resourceMap);
813     }
814 }
815 
removeResource(InspectorResource * resource)816 void InspectorController::removeResource(InspectorResource* resource)
817 {
818     m_resources.remove(resource->identifier());
819     String requestURL = resource->requestURL();
820     if (!requestURL.isNull())
821         m_knownResources.remove(requestURL);
822 
823     Frame* frame = resource->frame();
824     ResourcesMap* resourceMap = m_frameResources.get(frame);
825     if (!resourceMap) {
826         ASSERT_NOT_REACHED();
827         return;
828     }
829 
830     resourceMap->remove(resource->identifier());
831     if (resourceMap->isEmpty()) {
832         m_frameResources.remove(frame);
833         delete resourceMap;
834     }
835 }
836 
getTrackedResource(unsigned long identifier)837 InspectorResource* InspectorController::getTrackedResource(unsigned long identifier)
838 {
839     if (!enabled())
840         return 0;
841 
842     if (m_resourceTrackingEnabled)
843         return m_resources.get(identifier).get();
844 
845     bool isMainResource = m_mainResource && m_mainResource->identifier() == identifier;
846     if (isMainResource)
847         return m_mainResource.get();
848 
849     return 0;
850 }
851 
didLoadResourceFromMemoryCache(DocumentLoader * loader,const CachedResource * cachedResource)852 void InspectorController::didLoadResourceFromMemoryCache(DocumentLoader* loader, const CachedResource* cachedResource)
853 {
854     if (!enabled())
855         return;
856 
857     // If the resource URL is already known, we don't need to add it again since this is just a cached load.
858     if (m_knownResources.contains(cachedResource->url()))
859         return;
860 
861     ASSERT(m_inspectedPage);
862     bool isMainResource = isMainResourceLoader(loader, KURL(ParsedURLString, cachedResource->url()));
863     ensureResourceTrackingSettingsLoaded();
864     if (!isMainResource && !m_resourceTrackingEnabled)
865         return;
866 
867     RefPtr<InspectorResource> resource = InspectorResource::createCached(m_inspectedPage->progress()->createUniqueIdentifier(), loader, cachedResource);
868 
869     if (isMainResource) {
870         m_mainResource = resource;
871         resource->markMainResource();
872     }
873 
874     addResource(resource.get());
875 
876     if (windowVisible())
877         resource->updateScriptObject(m_frontend.get());
878 }
879 
identifierForInitialRequest(unsigned long identifier,DocumentLoader * loader,const ResourceRequest & request)880 void InspectorController::identifierForInitialRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request)
881 {
882     if (!enabled())
883         return;
884     ASSERT(m_inspectedPage);
885 
886     bool isMainResource = isMainResourceLoader(loader, request.url());
887     ensureResourceTrackingSettingsLoaded();
888     if (!isMainResource && !m_resourceTrackingEnabled)
889         return;
890 
891     RefPtr<InspectorResource> resource = InspectorResource::create(identifier, loader, request.url());
892 
893     if (isMainResource) {
894         m_mainResource = resource;
895         resource->markMainResource();
896     }
897 
898     addResource(resource.get());
899 
900     if (windowVisible() && loader->frameLoader()->isLoadingFromCachedPage() && resource == m_mainResource)
901         resource->updateScriptObject(m_frontend.get());
902 }
903 
mainResourceFiredDOMContentEvent(DocumentLoader * loader,const KURL & url)904 void InspectorController::mainResourceFiredDOMContentEvent(DocumentLoader* loader, const KURL& url)
905 {
906     if (!enabled() || !isMainResourceLoader(loader, url))
907         return;
908 
909     if (m_mainResource) {
910         m_mainResource->markDOMContentEventTime();
911         if (windowVisible())
912             m_mainResource->updateScriptObject(m_frontend.get());
913     }
914 }
915 
mainResourceFiredLoadEvent(DocumentLoader * loader,const KURL & url)916 void InspectorController::mainResourceFiredLoadEvent(DocumentLoader* loader, const KURL& url)
917 {
918     if (!enabled() || !isMainResourceLoader(loader, url))
919         return;
920 
921     if (m_mainResource) {
922         m_mainResource->markLoadEventTime();
923         if (windowVisible())
924             m_mainResource->updateScriptObject(m_frontend.get());
925     }
926 }
927 
isMainResourceLoader(DocumentLoader * loader,const KURL & requestUrl)928 bool InspectorController::isMainResourceLoader(DocumentLoader* loader, const KURL& requestUrl)
929 {
930     return loader->frame() == m_inspectedPage->mainFrame() && requestUrl == loader->requestURL();
931 }
932 
willSendRequest(unsigned long identifier,const ResourceRequest & request,const ResourceResponse & redirectResponse)933 void InspectorController::willSendRequest(unsigned long identifier, const ResourceRequest& request, const ResourceResponse& redirectResponse)
934 {
935     bool isMainResource = (m_mainResource && m_mainResource->identifier() == identifier);
936     if (m_timelineAgent)
937         m_timelineAgent->willSendResourceRequest(identifier, isMainResource, request);
938 
939     RefPtr<InspectorResource> resource = getTrackedResource(identifier);
940     if (!resource)
941         return;
942 
943     if (!redirectResponse.isNull()) {
944         resource->markResponseReceivedTime();
945         resource->endTiming();
946         resource->updateResponse(redirectResponse);
947 
948         // We always store last redirect by the original id key. Rest of the redirects are stored within the last one.
949         unsigned long id = m_inspectedPage->progress()->createUniqueIdentifier();
950         RefPtr<InspectorResource> withRedirect = resource->appendRedirect(id, request.url());
951         removeResource(resource.get());
952         addResource(withRedirect.get());
953         if (isMainResource) {
954             m_mainResource = withRedirect;
955             withRedirect->markMainResource();
956         }
957         resource = withRedirect;
958     }
959 
960     resource->startTiming();
961     resource->updateRequest(request);
962 
963     if (resource != m_mainResource && windowVisible())
964         resource->updateScriptObject(m_frontend.get());
965 }
966 
didReceiveResponse(unsigned long identifier,const ResourceResponse & response)967 void InspectorController::didReceiveResponse(unsigned long identifier, const ResourceResponse& response)
968 {
969     if (m_timelineAgent)
970         m_timelineAgent->didReceiveResourceResponse(identifier, response);
971 
972     RefPtr<InspectorResource> resource = getTrackedResource(identifier);
973     if (!resource)
974         return;
975 
976     resource->updateResponse(response);
977     resource->markResponseReceivedTime();
978 
979     if (resource != m_mainResource && windowVisible())
980         resource->updateScriptObject(m_frontend.get());
981 }
982 
didReceiveContentLength(unsigned long identifier,int lengthReceived)983 void InspectorController::didReceiveContentLength(unsigned long identifier, int lengthReceived)
984 {
985     RefPtr<InspectorResource> resource = getTrackedResource(identifier);
986     if (!resource)
987         return;
988 
989     resource->addLength(lengthReceived);
990 
991     if (resource != m_mainResource && windowVisible())
992         resource->updateScriptObject(m_frontend.get());
993 }
994 
didFinishLoading(unsigned long identifier)995 void InspectorController::didFinishLoading(unsigned long identifier)
996 {
997     if (m_timelineAgent)
998         m_timelineAgent->didFinishLoadingResource(identifier, false);
999 
1000     RefPtr<InspectorResource> resource = getTrackedResource(identifier);
1001     if (!resource)
1002         return;
1003 
1004     resource->endTiming();
1005 
1006     if (resource != m_mainResource && windowVisible())
1007         resource->updateScriptObject(m_frontend.get());
1008 }
1009 
didFailLoading(unsigned long identifier,const ResourceError &)1010 void InspectorController::didFailLoading(unsigned long identifier, const ResourceError& /*error*/)
1011 {
1012     if (m_timelineAgent)
1013         m_timelineAgent->didFinishLoadingResource(identifier, true);
1014 
1015     RefPtr<InspectorResource> resource = getTrackedResource(identifier);
1016     if (!resource)
1017         return;
1018 
1019     resource->markFailed();
1020     resource->endTiming();
1021 
1022     if (resource != m_mainResource && windowVisible())
1023         resource->updateScriptObject(m_frontend.get());
1024 }
1025 
resourceRetrievedByXMLHttpRequest(unsigned long identifier,const ScriptString & sourceString)1026 void InspectorController::resourceRetrievedByXMLHttpRequest(unsigned long identifier, const ScriptString& sourceString)
1027 {
1028     if (!enabled() || !m_resourceTrackingEnabled)
1029         return;
1030 
1031     InspectorResource* resource = m_resources.get(identifier).get();
1032     if (!resource)
1033         return;
1034 
1035     resource->setXMLHttpResponseText(sourceString);
1036 
1037     if (windowVisible())
1038         resource->updateScriptObject(m_frontend.get());
1039 }
1040 
scriptImported(unsigned long identifier,const String & sourceString)1041 void InspectorController::scriptImported(unsigned long identifier, const String& sourceString)
1042 {
1043     if (!enabled() || !m_resourceTrackingEnabled)
1044         return;
1045 
1046     InspectorResource* resource = m_resources.get(identifier).get();
1047     if (!resource)
1048         return;
1049 
1050     // FIXME: imported script and XHR response are currently viewed as the same
1051     // thing by the Inspector. They should be made into distinct types.
1052     resource->setXMLHttpResponseText(ScriptString(sourceString));
1053 
1054     if (windowVisible())
1055         resource->updateScriptObject(m_frontend.get());
1056 }
1057 
enableResourceTracking(bool always,bool reload)1058 void InspectorController::enableResourceTracking(bool always, bool reload)
1059 {
1060     if (!enabled())
1061         return;
1062 
1063     if (always)
1064         setSetting(resourceTrackingEnabledSettingName, "true");
1065 
1066     if (m_resourceTrackingEnabled)
1067         return;
1068 
1069     ASSERT(m_inspectedPage);
1070     m_resourceTrackingEnabled = true;
1071     if (m_frontend)
1072         m_frontend->resourceTrackingWasEnabled();
1073 
1074     if (reload)
1075         m_inspectedPage->mainFrame()->loader()->reload();
1076 }
1077 
disableResourceTracking(bool always)1078 void InspectorController::disableResourceTracking(bool always)
1079 {
1080     if (!enabled())
1081         return;
1082 
1083     if (always)
1084         setSetting(resourceTrackingEnabledSettingName, "false");
1085 
1086     ASSERT(m_inspectedPage);
1087     m_resourceTrackingEnabled = false;
1088     if (m_frontend)
1089         m_frontend->resourceTrackingWasDisabled();
1090 }
1091 
ensureResourceTrackingSettingsLoaded()1092 void InspectorController::ensureResourceTrackingSettingsLoaded()
1093 {
1094     if (m_resourceTrackingSettingsLoaded)
1095         return;
1096     m_resourceTrackingSettingsLoaded = true;
1097 
1098     String resourceTracking = setting(resourceTrackingEnabledSettingName);
1099     if (resourceTracking == "true")
1100         m_resourceTrackingEnabled = true;
1101 }
1102 
startTimelineProfiler()1103 void InspectorController::startTimelineProfiler()
1104 {
1105     if (!enabled())
1106         return;
1107 
1108     if (m_timelineAgent)
1109         return;
1110 
1111     m_timelineAgent = new InspectorTimelineAgent(m_frontend.get());
1112     if (m_frontend)
1113         m_frontend->timelineProfilerWasStarted();
1114 }
1115 
stopTimelineProfiler()1116 void InspectorController::stopTimelineProfiler()
1117 {
1118     if (!enabled())
1119         return;
1120 
1121     if (!m_timelineAgent)
1122         return;
1123 
1124     m_timelineAgent = 0;
1125     if (m_frontend)
1126         m_frontend->timelineProfilerWasStopped();
1127 }
1128 
1129 #if ENABLE(DATABASE)
selectDatabase(Database * database)1130 void InspectorController::selectDatabase(Database* database)
1131 {
1132     if (!m_frontend)
1133         return;
1134 
1135     for (DatabaseResourcesMap::iterator it = m_databaseResources.begin(); it != m_databaseResources.end(); ++it) {
1136         if (it->second->database() == database) {
1137             m_frontend->selectDatabase(it->first);
1138             break;
1139         }
1140     }
1141 }
1142 
databaseForId(int databaseId)1143 Database* InspectorController::databaseForId(int databaseId)
1144 {
1145     DatabaseResourcesMap::iterator it = m_databaseResources.find(databaseId);
1146     if (it == m_databaseResources.end())
1147         return 0;
1148     return it->second->database();
1149 }
1150 
didOpenDatabase(Database * database,const String & domain,const String & name,const String & version)1151 void InspectorController::didOpenDatabase(Database* database, const String& domain, const String& name, const String& version)
1152 {
1153     if (!enabled())
1154         return;
1155 
1156     RefPtr<InspectorDatabaseResource> resource = InspectorDatabaseResource::create(database, domain, name, version);
1157 
1158     m_databaseResources.set(resource->id(), resource);
1159 
1160     // Resources are only bound while visible.
1161     if (windowVisible())
1162         resource->bind(m_frontend.get());
1163 }
1164 #endif
1165 
getCookies(long callId)1166 void InspectorController::getCookies(long callId)
1167 {
1168     if (!m_frontend)
1169         return;
1170 
1171     // If we can get raw cookies.
1172     ListHashSet<Cookie> rawCookiesList;
1173 
1174     // If we can't get raw cookies - fall back to String representation
1175     String stringCookiesList;
1176 
1177     // Return value to getRawCookies should be the same for every call because
1178     // the return value is platform/network backend specific, and the call will
1179     // always return the same true/false value.
1180     bool rawCookiesImplemented = false;
1181 
1182     ResourcesMap::iterator resourcesEnd = m_resources.end();
1183     for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it) {
1184         Document* document = it->second->frame()->document();
1185         Vector<Cookie> docCookiesList;
1186         rawCookiesImplemented = getRawCookies(document, it->second->requestURL(), docCookiesList);
1187 
1188         if (!rawCookiesImplemented) {
1189             // FIXME: We need duplication checking for the String representation of cookies.
1190             ExceptionCode ec = 0;
1191             stringCookiesList += document->cookie(ec);
1192             // Exceptions are thrown by cookie() in sandboxed frames. That won't happen here
1193             // because "document" is the document of the main frame of the page.
1194             ASSERT(!ec);
1195         } else {
1196             int cookiesSize = docCookiesList.size();
1197             for (int i = 0; i < cookiesSize; i++) {
1198                 if (!rawCookiesList.contains(docCookiesList[i]))
1199                     rawCookiesList.add(docCookiesList[i]);
1200             }
1201         }
1202     }
1203 
1204     if (!rawCookiesImplemented)
1205         m_frontend->didGetCookies(callId, m_frontend->newScriptArray(), stringCookiesList);
1206     else
1207         m_frontend->didGetCookies(callId, buildArrayForCookies(rawCookiesList), String());
1208 }
1209 
buildArrayForCookies(ListHashSet<Cookie> & cookiesList)1210 ScriptArray InspectorController::buildArrayForCookies(ListHashSet<Cookie>& cookiesList)
1211 {
1212     ScriptArray cookies = m_frontend->newScriptArray();
1213 
1214     ListHashSet<Cookie>::iterator end = cookiesList.end();
1215     ListHashSet<Cookie>::iterator it = cookiesList.begin();
1216     for (int i = 0; it != end; ++it, i++)
1217         cookies.set(i, buildObjectForCookie(*it));
1218 
1219     return cookies;
1220 }
1221 
buildObjectForCookie(const Cookie & cookie)1222 ScriptObject InspectorController::buildObjectForCookie(const Cookie& cookie)
1223 {
1224     ScriptObject value = m_frontend->newScriptObject();
1225     value.set("name", cookie.name);
1226     value.set("value", cookie.value);
1227     value.set("domain", cookie.domain);
1228     value.set("path", cookie.path);
1229     value.set("expires", cookie.expires);
1230     value.set("size", (cookie.name.length() + cookie.value.length()));
1231     value.set("httpOnly", cookie.httpOnly);
1232     value.set("secure", cookie.secure);
1233     value.set("session", cookie.session);
1234     return value;
1235 }
1236 
1237 #if ENABLE(DOM_STORAGE)
didUseDOMStorage(StorageArea * storageArea,bool isLocalStorage,Frame * frame)1238 void InspectorController::didUseDOMStorage(StorageArea* storageArea, bool isLocalStorage, Frame* frame)
1239 {
1240     if (!enabled())
1241         return;
1242 
1243     DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources.end();
1244     for (DOMStorageResourcesMap::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it)
1245         if (it->second->isSameHostAndType(frame, isLocalStorage))
1246             return;
1247 
1248     RefPtr<Storage> domStorage = Storage::create(frame, storageArea);
1249     RefPtr<InspectorDOMStorageResource> resource = InspectorDOMStorageResource::create(domStorage.get(), isLocalStorage, frame);
1250 
1251     m_domStorageResources.set(resource->id(), resource);
1252 
1253     // Resources are only bound while visible.
1254     if (windowVisible())
1255         resource->bind(m_frontend.get());
1256 }
1257 
selectDOMStorage(Storage * storage)1258 void InspectorController::selectDOMStorage(Storage* storage)
1259 {
1260     ASSERT(storage);
1261     if (!m_frontend)
1262         return;
1263 
1264     Frame* frame = storage->frame();
1265     bool isLocalStorage = (frame->domWindow()->localStorage() == storage);
1266     int storageResourceId = 0;
1267     DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources.end();
1268     for (DOMStorageResourcesMap::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it) {
1269         if (it->second->isSameHostAndType(frame, isLocalStorage)) {
1270             storageResourceId = it->first;
1271             break;
1272         }
1273     }
1274     if (storageResourceId)
1275         m_frontend->selectDOMStorage(storageResourceId);
1276 }
1277 
getDOMStorageEntries(int callId,int storageId)1278 void InspectorController::getDOMStorageEntries(int callId, int storageId)
1279 {
1280     if (!m_frontend)
1281         return;
1282 
1283     ScriptArray jsonArray = m_frontend->newScriptArray();
1284     InspectorDOMStorageResource* storageResource = getDOMStorageResourceForId(storageId);
1285     if (storageResource) {
1286         storageResource->startReportingChangesToFrontend();
1287         Storage* domStorage = storageResource->domStorage();
1288         for (unsigned i = 0; i < domStorage->length(); ++i) {
1289             String name(domStorage->key(i));
1290             String value(domStorage->getItem(name));
1291             ScriptArray entry = m_frontend->newScriptArray();
1292             entry.set(0, name);
1293             entry.set(1, value);
1294             jsonArray.set(i, entry);
1295         }
1296     }
1297     m_frontend->didGetDOMStorageEntries(callId, jsonArray);
1298 }
1299 
setDOMStorageItem(long callId,long storageId,const String & key,const String & value)1300 void InspectorController::setDOMStorageItem(long callId, long storageId, const String& key, const String& value)
1301 {
1302     if (!m_frontend)
1303         return;
1304 
1305     bool success = false;
1306     InspectorDOMStorageResource* storageResource = getDOMStorageResourceForId(storageId);
1307     if (storageResource) {
1308         ExceptionCode exception = 0;
1309         storageResource->domStorage()->setItem(key, value, exception);
1310         success = !exception;
1311     }
1312     m_frontend->didSetDOMStorageItem(callId, success);
1313 }
1314 
removeDOMStorageItem(long callId,long storageId,const String & key)1315 void InspectorController::removeDOMStorageItem(long callId, long storageId, const String& key)
1316 {
1317     if (!m_frontend)
1318         return;
1319 
1320     bool success = false;
1321     InspectorDOMStorageResource* storageResource = getDOMStorageResourceForId(storageId);
1322     if (storageResource) {
1323         storageResource->domStorage()->removeItem(key);
1324         success = true;
1325     }
1326     m_frontend->didRemoveDOMStorageItem(callId, success);
1327 }
1328 
getDOMStorageResourceForId(int storageId)1329 InspectorDOMStorageResource* InspectorController::getDOMStorageResourceForId(int storageId)
1330 {
1331     DOMStorageResourcesMap::iterator it = m_domStorageResources.find(storageId);
1332     if (it == m_domStorageResources.end())
1333         return 0;
1334     return it->second.get();
1335 }
1336 #endif
1337 
moveWindowBy(float x,float y) const1338 void InspectorController::moveWindowBy(float x, float y) const
1339 {
1340     if (!m_page || !enabled())
1341         return;
1342 
1343     FloatRect frameRect = m_page->chrome()->windowRect();
1344     frameRect.move(x, y);
1345     m_page->chrome()->setWindowRect(frameRect);
1346 }
1347 
1348 #if ENABLE(JAVASCRIPT_DEBUGGER)
addProfile(PassRefPtr<ScriptProfile> prpProfile,unsigned lineNumber,const String & sourceURL)1349 void InspectorController::addProfile(PassRefPtr<ScriptProfile> prpProfile, unsigned lineNumber, const String& sourceURL)
1350 {
1351     if (!enabled())
1352         return;
1353 
1354     RefPtr<ScriptProfile> profile = prpProfile;
1355     m_profiles.add(profile->uid(), profile);
1356 
1357     if (m_frontend) {
1358 #if USE(JSC)
1359         JSLock lock(SilenceAssertionsOnly);
1360 #endif
1361         m_frontend->addProfileHeader(createProfileHeader(*profile));
1362     }
1363 
1364     addProfileFinishedMessageToConsole(profile, lineNumber, sourceURL);
1365 }
1366 
addProfileFinishedMessageToConsole(PassRefPtr<ScriptProfile> prpProfile,unsigned lineNumber,const String & sourceURL)1367 void InspectorController::addProfileFinishedMessageToConsole(PassRefPtr<ScriptProfile> prpProfile, unsigned lineNumber, const String& sourceURL)
1368 {
1369     RefPtr<ScriptProfile> profile = prpProfile;
1370 
1371     String message = String::format("Profile \"webkit-profile://%s/%s#%d\" finished.", CPUProfileType, encodeWithURLEscapeSequences(profile->title()).utf8().data(), profile->uid());
1372     addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lineNumber, sourceURL);
1373 }
1374 
addStartProfilingMessageToConsole(const String & title,unsigned lineNumber,const String & sourceURL)1375 void InspectorController::addStartProfilingMessageToConsole(const String& title, unsigned lineNumber, const String& sourceURL)
1376 {
1377     String message = String::format("Profile \"webkit-profile://%s/%s#0\" started.", CPUProfileType, encodeWithURLEscapeSequences(title).utf8().data());
1378     addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lineNumber, sourceURL);
1379 }
1380 
getProfileHeaders(long callId)1381 void InspectorController::getProfileHeaders(long callId)
1382 {
1383     if (!m_frontend)
1384         return;
1385     ScriptArray result = m_frontend->newScriptArray();
1386     ProfilesMap::iterator profilesEnd = m_profiles.end();
1387     int i = 0;
1388     for (ProfilesMap::iterator it = m_profiles.begin(); it != profilesEnd; ++it)
1389         result.set(i++, createProfileHeader(*it->second));
1390     m_frontend->didGetProfileHeaders(callId, result);
1391 }
1392 
getProfile(long callId,unsigned uid)1393 void InspectorController::getProfile(long callId, unsigned uid)
1394 {
1395     if (!m_frontend)
1396         return;
1397     ProfilesMap::iterator it = m_profiles.find(uid);
1398 #if USE(JSC)
1399     if (it != m_profiles.end())
1400         m_frontend->didGetProfile(callId, toJS(m_frontendScriptState, it->second.get()));
1401 #endif
1402 }
1403 
createProfileHeader(const ScriptProfile & profile)1404 ScriptObject InspectorController::createProfileHeader(const ScriptProfile& profile)
1405 {
1406     ScriptObject header = m_frontend->newScriptObject();
1407     header.set("title", profile.title());
1408     header.set("uid", profile.uid());
1409     header.set("typeId", String(CPUProfileType));
1410     return header;
1411 }
1412 
getCurrentUserInitiatedProfileName(bool incrementProfileNumber=false)1413 String InspectorController::getCurrentUserInitiatedProfileName(bool incrementProfileNumber = false)
1414 {
1415     if (incrementProfileNumber)
1416         m_currentUserInitiatedProfileNumber = m_nextUserInitiatedProfileNumber++;
1417 
1418     return String::format("%s.%d", UserInitiatedProfileName, m_currentUserInitiatedProfileNumber);
1419 }
1420 
startUserInitiatedProfilingSoon()1421 void InspectorController::startUserInitiatedProfilingSoon()
1422 {
1423     m_startProfiling.startOneShot(0);
1424 }
1425 
startUserInitiatedProfiling(Timer<InspectorController> *)1426 void InspectorController::startUserInitiatedProfiling(Timer<InspectorController>*)
1427 {
1428     if (!enabled())
1429         return;
1430 
1431     if (!profilerEnabled()) {
1432         enableProfiler(false, true);
1433         ScriptDebugServer::recompileAllJSFunctions();
1434     }
1435 
1436     m_recordingUserInitiatedProfile = true;
1437 
1438     String title = getCurrentUserInitiatedProfileName(true);
1439 
1440 #if USE(JSC)
1441     ExecState* scriptState = toJSDOMWindow(m_inspectedPage->mainFrame(), debuggerWorld())->globalExec();
1442 #else
1443     ScriptState* scriptState = 0;
1444 #endif
1445     ScriptProfiler::start(scriptState, title);
1446 
1447     addStartProfilingMessageToConsole(title, 0, String());
1448 
1449     toggleRecordButton(true);
1450 }
1451 
stopUserInitiatedProfiling()1452 void InspectorController::stopUserInitiatedProfiling()
1453 {
1454     if (!enabled())
1455         return;
1456 
1457     m_recordingUserInitiatedProfile = false;
1458 
1459     String title = getCurrentUserInitiatedProfileName();
1460 
1461 #if USE(JSC)
1462     ExecState* scriptState = toJSDOMWindow(m_inspectedPage->mainFrame(), debuggerWorld())->globalExec();
1463 #else
1464     ScriptState* scriptState = 0;
1465 #endif
1466     RefPtr<ScriptProfile> profile = ScriptProfiler::stop(scriptState, title);
1467     if (profile)
1468         addProfile(profile, 0, String());
1469 
1470     toggleRecordButton(false);
1471 }
1472 
toggleRecordButton(bool isProfiling)1473 void InspectorController::toggleRecordButton(bool isProfiling)
1474 {
1475     if (!m_frontend)
1476         return;
1477     m_frontend->setRecordingProfile(isProfiling);
1478 }
1479 
enableProfiler(bool always,bool skipRecompile)1480 void InspectorController::enableProfiler(bool always, bool skipRecompile)
1481 {
1482     if (always)
1483         setSetting(profilerEnabledSettingName, "true");
1484 
1485     if (m_profilerEnabled)
1486         return;
1487 
1488     m_profilerEnabled = true;
1489 
1490     if (!skipRecompile)
1491         ScriptDebugServer::recompileAllJSFunctionsSoon();
1492 
1493     if (m_frontend)
1494         m_frontend->profilerWasEnabled();
1495 }
1496 
disableProfiler(bool always)1497 void InspectorController::disableProfiler(bool always)
1498 {
1499     if (always)
1500         setSetting(profilerEnabledSettingName, "false");
1501 
1502     if (!m_profilerEnabled)
1503         return;
1504 
1505     m_profilerEnabled = false;
1506 
1507     ScriptDebugServer::recompileAllJSFunctionsSoon();
1508 
1509     if (m_frontend)
1510         m_frontend->profilerWasDisabled();
1511 }
1512 #endif
1513 
1514 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
enableDebuggerFromFrontend(bool always)1515 void InspectorController::enableDebuggerFromFrontend(bool always)
1516 {
1517     if (always)
1518         setSetting(debuggerEnabledSettingName, "true");
1519 
1520     ASSERT(m_inspectedPage);
1521 
1522     JavaScriptDebugServer::shared().addListener(this, m_inspectedPage);
1523     JavaScriptDebugServer::shared().clearBreakpoints();
1524 
1525     m_debuggerEnabled = true;
1526     m_frontend->debuggerWasEnabled();
1527 }
1528 
enableDebugger()1529 void InspectorController::enableDebugger()
1530 {
1531     if (!enabled())
1532         return;
1533 
1534     if (m_debuggerEnabled)
1535         return;
1536 
1537     if (!m_frontendScriptState || !m_frontend)
1538         m_attachDebuggerWhenShown = true;
1539     else {
1540         m_frontend->attachDebuggerWhenShown();
1541         m_attachDebuggerWhenShown = false;
1542     }
1543 }
1544 
disableDebugger(bool always)1545 void InspectorController::disableDebugger(bool always)
1546 {
1547     if (!enabled())
1548         return;
1549 
1550     if (always)
1551         setSetting(debuggerEnabledSettingName, "false");
1552 
1553     ASSERT(m_inspectedPage);
1554 
1555     JavaScriptDebugServer::shared().removeListener(this, m_inspectedPage);
1556 
1557     m_debuggerEnabled = false;
1558     m_attachDebuggerWhenShown = false;
1559 
1560     if (m_frontend)
1561         m_frontend->debuggerWasDisabled();
1562 }
1563 
resumeDebugger()1564 void InspectorController::resumeDebugger()
1565 {
1566     if (!m_debuggerEnabled)
1567         return;
1568     JavaScriptDebugServer::shared().continueProgram();
1569 }
1570 
1571 // JavaScriptDebugListener functions
1572 
didParseSource(ExecState *,const SourceCode & source)1573 void InspectorController::didParseSource(ExecState*, const SourceCode& source)
1574 {
1575     m_frontend->parsedScriptSource(source);
1576 }
1577 
failedToParseSource(ExecState *,const SourceCode & source,int errorLine,const UString & errorMessage)1578 void InspectorController::failedToParseSource(ExecState*, const SourceCode& source, int errorLine, const UString& errorMessage)
1579 {
1580     m_frontend->failedToParseScriptSource(source, errorLine, errorMessage);
1581 }
1582 
didPause()1583 void InspectorController::didPause()
1584 {
1585     JavaScriptCallFrame* callFrame = m_injectedScriptHost->currentCallFrame();
1586     ScriptState* scriptState = callFrame->scopeChain()->globalObject->globalExec();
1587     ASSERT(scriptState);
1588     InjectedScript injectedScript = m_injectedScriptHost->injectedScriptFor(scriptState);
1589     RefPtr<SerializedScriptValue> callFrames = injectedScript.callFrames();
1590     m_frontend->pausedScript(callFrames.get());
1591 }
1592 
didContinue()1593 void InspectorController::didContinue()
1594 {
1595     m_frontend->resumedScript();
1596 }
1597 
1598 #endif
1599 
evaluateForTestInFrontend(long callId,const String & script)1600 void InspectorController::evaluateForTestInFrontend(long callId, const String& script)
1601 {
1602     if (m_frontend)
1603         m_frontend->evaluateForTestInFrontend(callId, script);
1604     else
1605         m_pendingEvaluateTestCommands.append(pair<long, String>(callId, script));
1606 }
1607 
didEvaluateForTestInFrontend(long callId,const String & jsonResult)1608 void InspectorController::didEvaluateForTestInFrontend(long callId, const String& jsonResult)
1609 {
1610     ScriptState* scriptState = scriptStateFromPage(debuggerWorld(), m_inspectedPage);
1611     ScriptObject window;
1612     ScriptGlobalObject::get(scriptState, "window", window);
1613     ScriptFunctionCall function(window, "didEvaluateForTestInFrontend");
1614     function.appendArgument(callId);
1615     function.appendArgument(jsonResult);
1616     function.call();
1617 }
1618 
quadToPath(const FloatQuad & quad)1619 static Path quadToPath(const FloatQuad& quad)
1620 {
1621     Path quadPath;
1622     quadPath.moveTo(quad.p1());
1623     quadPath.addLineTo(quad.p2());
1624     quadPath.addLineTo(quad.p3());
1625     quadPath.addLineTo(quad.p4());
1626     quadPath.closeSubpath();
1627     return quadPath;
1628 }
1629 
drawOutlinedQuad(GraphicsContext & context,const FloatQuad & quad,const Color & fillColor)1630 static void drawOutlinedQuad(GraphicsContext& context, const FloatQuad& quad, const Color& fillColor)
1631 {
1632     static const int outlineThickness = 2;
1633     static const Color outlineColor(62, 86, 180, 228);
1634 
1635     Path quadPath = quadToPath(quad);
1636 
1637     // Clip out the quad, then draw with a 2px stroke to get a pixel
1638     // of outline (because inflating a quad is hard)
1639     {
1640         context.save();
1641         context.addPath(quadPath);
1642         context.clipOut(quadPath);
1643 
1644         context.addPath(quadPath);
1645         context.setStrokeThickness(outlineThickness);
1646         context.setStrokeColor(outlineColor, DeviceColorSpace);
1647         context.strokePath();
1648 
1649         context.restore();
1650     }
1651 
1652     // Now do the fill
1653     context.addPath(quadPath);
1654     context.setFillColor(fillColor, DeviceColorSpace);
1655     context.fillPath();
1656 }
1657 
drawOutlinedQuadWithClip(GraphicsContext & context,const FloatQuad & quad,const FloatQuad & clipQuad,const Color & fillColor)1658 static void drawOutlinedQuadWithClip(GraphicsContext& context, const FloatQuad& quad, const FloatQuad& clipQuad, const Color& fillColor)
1659 {
1660     context.save();
1661     Path clipQuadPath = quadToPath(clipQuad);
1662     context.clipOut(clipQuadPath);
1663     drawOutlinedQuad(context, quad, fillColor);
1664     context.restore();
1665 }
1666 
drawHighlightForBox(GraphicsContext & context,const FloatQuad & contentQuad,const FloatQuad & paddingQuad,const FloatQuad & borderQuad,const FloatQuad & marginQuad)1667 static void drawHighlightForBox(GraphicsContext& context, const FloatQuad& contentQuad, const FloatQuad& paddingQuad, const FloatQuad& borderQuad, const FloatQuad& marginQuad)
1668 {
1669     static const Color contentBoxColor(125, 173, 217, 128);
1670     static const Color paddingBoxColor(125, 173, 217, 160);
1671     static const Color borderBoxColor(125, 173, 217, 192);
1672     static const Color marginBoxColor(125, 173, 217, 228);
1673 
1674     if (marginQuad != borderQuad)
1675         drawOutlinedQuadWithClip(context, marginQuad, borderQuad, marginBoxColor);
1676     if (borderQuad != paddingQuad)
1677         drawOutlinedQuadWithClip(context, borderQuad, paddingQuad, borderBoxColor);
1678     if (paddingQuad != contentQuad)
1679         drawOutlinedQuadWithClip(context, paddingQuad, contentQuad, paddingBoxColor);
1680 
1681     drawOutlinedQuad(context, contentQuad, contentBoxColor);
1682 }
1683 
drawHighlightForLineBoxes(GraphicsContext & context,const Vector<FloatQuad> & lineBoxQuads)1684 static void drawHighlightForLineBoxes(GraphicsContext& context, const Vector<FloatQuad>& lineBoxQuads)
1685 {
1686     static const Color lineBoxColor(125, 173, 217, 128);
1687 
1688     for (size_t i = 0; i < lineBoxQuads.size(); ++i)
1689         drawOutlinedQuad(context, lineBoxQuads[i], lineBoxColor);
1690 }
1691 
convertFromFrameToMainFrame(Frame * frame,IntRect & rect)1692 static inline void convertFromFrameToMainFrame(Frame* frame, IntRect& rect)
1693 {
1694     rect = frame->page()->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(rect));
1695 }
1696 
frameToMainFrameOffset(Frame * frame)1697 static inline IntSize frameToMainFrameOffset(Frame* frame)
1698 {
1699     IntPoint mainFramePoint = frame->page()->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(IntPoint()));
1700     return mainFramePoint - IntPoint();
1701 }
1702 
drawNodeHighlight(GraphicsContext & context) const1703 void InspectorController::drawNodeHighlight(GraphicsContext& context) const
1704 {
1705     if (!m_highlightedNode)
1706         return;
1707 
1708     RenderObject* renderer = m_highlightedNode->renderer();
1709     Frame* containingFrame = m_highlightedNode->document()->frame();
1710     if (!renderer || !containingFrame)
1711         return;
1712 
1713     IntSize mainFrameOffset = frameToMainFrameOffset(containingFrame);
1714     IntRect boundingBox = renderer->absoluteBoundingBoxRect(true);
1715     boundingBox.move(mainFrameOffset);
1716 
1717     ASSERT(m_inspectedPage);
1718 
1719     FrameView* view = m_inspectedPage->mainFrame()->view();
1720     FloatRect overlayRect = view->visibleContentRect();
1721     if (!overlayRect.contains(boundingBox) && !boundingBox.contains(enclosingIntRect(overlayRect)))
1722         overlayRect = view->visibleContentRect();
1723     context.translate(-overlayRect.x(), -overlayRect.y());
1724 
1725     if (renderer->isBox()) {
1726         RenderBox* renderBox = toRenderBox(renderer);
1727 
1728         IntRect contentBox = renderBox->contentBoxRect();
1729 
1730         IntRect paddingBox(contentBox.x() - renderBox->paddingLeft(), contentBox.y() - renderBox->paddingTop(),
1731                            contentBox.width() + renderBox->paddingLeft() + renderBox->paddingRight(), contentBox.height() + renderBox->paddingTop() + renderBox->paddingBottom());
1732         IntRect borderBox(paddingBox.x() - renderBox->borderLeft(), paddingBox.y() - renderBox->borderTop(),
1733                           paddingBox.width() + renderBox->borderLeft() + renderBox->borderRight(), paddingBox.height() + renderBox->borderTop() + renderBox->borderBottom());
1734         IntRect marginBox(borderBox.x() - renderBox->marginLeft(), borderBox.y() - renderBox->marginTop(),
1735                           borderBox.width() + renderBox->marginLeft() + renderBox->marginRight(), borderBox.height() + renderBox->marginTop() + renderBox->marginBottom());
1736 
1737         FloatQuad absContentQuad = renderBox->localToAbsoluteQuad(FloatRect(contentBox));
1738         FloatQuad absPaddingQuad = renderBox->localToAbsoluteQuad(FloatRect(paddingBox));
1739         FloatQuad absBorderQuad = renderBox->localToAbsoluteQuad(FloatRect(borderBox));
1740         FloatQuad absMarginQuad = renderBox->localToAbsoluteQuad(FloatRect(marginBox));
1741 
1742         absContentQuad.move(mainFrameOffset);
1743         absPaddingQuad.move(mainFrameOffset);
1744         absBorderQuad.move(mainFrameOffset);
1745         absMarginQuad.move(mainFrameOffset);
1746 
1747         drawHighlightForBox(context, absContentQuad, absPaddingQuad, absBorderQuad, absMarginQuad);
1748     } else if (renderer->isRenderInline()) {
1749         RenderInline* renderInline = toRenderInline(renderer);
1750 
1751         // FIXME: We should show margins/padding/border for inlines.
1752         Vector<FloatQuad> lineBoxQuads;
1753         renderInline->absoluteQuads(lineBoxQuads);
1754         for (unsigned i = 0; i < lineBoxQuads.size(); ++i)
1755             lineBoxQuads[i] += mainFrameOffset;
1756 
1757         drawHighlightForLineBoxes(context, lineBoxQuads);
1758     }
1759 }
1760 
count(const String & title,unsigned lineNumber,const String & sourceID)1761 void InspectorController::count(const String& title, unsigned lineNumber, const String& sourceID)
1762 {
1763     String identifier = title + String::format("@%s:%d", sourceID.utf8().data(), lineNumber);
1764     HashMap<String, unsigned>::iterator it = m_counts.find(identifier);
1765     int count;
1766     if (it == m_counts.end())
1767         count = 1;
1768     else {
1769         count = it->second + 1;
1770         m_counts.remove(it);
1771     }
1772 
1773     m_counts.add(identifier, count);
1774 
1775     String message = String::format("%s: %d", title.utf8().data(), count);
1776     addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lineNumber, sourceID);
1777 }
1778 
startTiming(const String & title)1779 void InspectorController::startTiming(const String& title)
1780 {
1781     m_times.add(title, currentTime() * 1000);
1782 }
1783 
stopTiming(const String & title,double & elapsed)1784 bool InspectorController::stopTiming(const String& title, double& elapsed)
1785 {
1786     HashMap<String, double>::iterator it = m_times.find(title);
1787     if (it == m_times.end())
1788         return false;
1789 
1790     double startTime = it->second;
1791     m_times.remove(it);
1792 
1793     elapsed = currentTime() * 1000 - startTime;
1794     return true;
1795 }
1796 
specialPanelForJSName(const String & panelName)1797 InspectorController::SpecialPanels InspectorController::specialPanelForJSName(const String& panelName)
1798 {
1799     if (panelName == "elements")
1800         return ElementsPanel;
1801     if (panelName == "resources")
1802         return ResourcesPanel;
1803     if (panelName == "scripts")
1804         return ScriptsPanel;
1805     if (panelName == "timeline")
1806         return TimelinePanel;
1807     if (panelName == "profiles")
1808         return ProfilesPanel;
1809     if (panelName == "storage" || panelName == "databases")
1810         return StoragePanel;
1811     if (panelName == "console")
1812         return ConsolePanel;
1813     return ElementsPanel;
1814 }
1815 
deleteCookie(const String & cookieName,const String & domain)1816 void InspectorController::deleteCookie(const String& cookieName, const String& domain)
1817 {
1818     ResourcesMap::iterator resourcesEnd = m_resources.end();
1819     for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it) {
1820         Document* document = it->second->frame()->document();
1821         if (document->url().host() == domain)
1822             WebCore::deleteCookie(document, it->second->requestURL(), cookieName);
1823     }
1824 }
1825 
injectedScriptForNodeId(long id)1826 InjectedScript InspectorController::injectedScriptForNodeId(long id)
1827 {
1828 
1829     Frame* frame = 0;
1830     if (id) {
1831         ASSERT(m_domAgent);
1832         Node* node = m_domAgent->nodeForId(id);
1833         if (node) {
1834             Document* document = node->ownerDocument();
1835             if (document)
1836                 frame = document->frame();
1837         }
1838     } else
1839         frame = m_inspectedPage->mainFrame();
1840 
1841     if (frame)
1842         return m_injectedScriptHost->injectedScriptFor(mainWorldScriptState(frame));
1843 
1844     return InjectedScript();
1845 }
1846 
1847 } // namespace WebCore
1848 
1849 #endif // ENABLE(INSPECTOR)
1850