2010-07-12 Ilya Tikhonovsky <loislo@chromium.org>
[WebKit-https.git] / WebCore / inspector / InspectorController.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2009, 2010 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 "CachedResource.h"
36 #include "Chrome.h"
37 #include "Console.h"
38 #include "ConsoleMessage.h"
39 #include "Cookie.h"
40 #include "CookieJar.h"
41 #include "DOMWindow.h"
42 #include "Document.h"
43 #include "DocumentLoader.h"
44 #include "Element.h"
45 #include "FloatConversion.h"
46 #include "FloatQuad.h"
47 #include "FloatRect.h"
48 #include "Frame.h"
49 #include "FrameLoader.h"
50 #include "FrameTree.h"
51 #include "FrameView.h"
52 #include "GraphicsContext.h"
53 #include "HTMLFrameOwnerElement.h"
54 #include "HitTestResult.h"
55 #include "InjectedScript.h"
56 #include "InjectedScriptHost.h"
57 #include "InspectorBackend.h"
58 #include "InspectorCSSStore.h"
59 #include "InspectorClient.h"
60 #include "InspectorFrontendClient.h"
61 #include "InspectorDOMStorageResource.h"
62 #include "InspectorDatabaseResource.h"
63 #include "InspectorFrontend.h"
64 #include "InspectorResource.h"
65 #include "InspectorValues.h"
66 #include "InspectorWorkerResource.h"
67 #include "InspectorTimelineAgent.h"
68 #include "Page.h"
69 #include "ProgressTracker.h"
70 #include "Range.h"
71 #include "RemoteInspectorFrontend.h"
72 #include "RenderInline.h"
73 #include "ResourceRequest.h"
74 #include "ResourceResponse.h"
75 #include "ScriptBreakpoint.h"
76 #include "ScriptCallStack.h"
77 #include "ScriptFunctionCall.h"
78 #include "ScriptObject.h"
79 #include "ScriptProfile.h"
80 #include "ScriptProfiler.h"
81 #include "ScriptSourceCode.h"
82 #include "ScriptString.h"
83 #include "SecurityOrigin.h"
84 #include "Settings.h"
85 #include "SharedBuffer.h"
86 #include "TextEncoding.h"
87 #include "TextIterator.h"
88 #include <wtf/text/CString.h>
89 #include <wtf/CurrentTime.h>
90 #include <wtf/ListHashSet.h>
91 #include <wtf/MD5.h>
92 #include <wtf/RefCounted.h>
93 #include <wtf/StdLibExtras.h>
94
95 #if ENABLE(DATABASE)
96 #include "Database.h"
97 #endif
98
99 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
100 #include "InspectorApplicationCacheAgent.h"
101 #endif
102
103 #if ENABLE(DOM_STORAGE)
104 #include "Storage.h"
105 #include "StorageArea.h"
106 #endif
107
108 #if ENABLE(JAVASCRIPT_DEBUGGER)
109 #include "ScriptDebugServer.h"
110 #if USE(JSC)
111 #include <runtime/JSLock.h>
112 #include <runtime/UString.h>
113 #include "JSScriptProfile.h"
114 #else
115 #include "V8ScriptProfile.h"
116 #endif
117 #endif
118
119 using namespace std;
120
121 namespace WebCore {
122
123 static const char* const UserInitiatedProfileName = "org.webkit.profiles.user-initiated";
124 static const char* const CPUProfileType = "CPU";
125 static const char* const resourceTrackingEnabledSettingName = "resourceTrackingEnabled";
126 static const char* const debuggerEnabledSettingName = "debuggerEnabled";
127 static const char* const profilerEnabledSettingName = "profilerEnabled";
128 static const char* const inspectorAttachedHeightName = "inspectorAttachedHeight";
129 static const char* const lastActivePanelSettingName = "lastActivePanel";
130 static const char* const monitoringXHRSettingName = "xhrMonitor";
131
132 const String& InspectorController::frontendSettingsSettingName()
133 {
134     DEFINE_STATIC_LOCAL(String, settingName, ("frontendSettings"));
135     return settingName;
136 }
137
138 const String& InspectorController::inspectorStartsAttachedSettingName()
139 {
140     DEFINE_STATIC_LOCAL(String, settingName, ("inspectorStartsAttached"));
141     return settingName;
142 }
143
144 static const unsigned defaultAttachedHeight = 300;
145 static const float minimumAttachedHeight = 250.0f;
146 static const float maximumAttachedHeightRatio = 0.75f;
147 static const unsigned maximumConsoleMessages = 1000;
148 static const unsigned expireConsoleMessagesStep = 100;
149
150 static unsigned s_inspectorControllerCount;
151
152 namespace {
153
154 String md5Base16(const String& string)
155 {
156     static const char digits[] = "0123456789abcdef";
157
158     MD5 md5;
159     md5.addBytes(reinterpret_cast<const uint8_t*>(string.characters()), string.length() * 2);
160     Vector<uint8_t, 16> digest;
161     md5.checksum(digest);
162
163     Vector<char, 32> result;
164     for (int i = 0; i < 16; ++i) {
165         result.append(digits[(digest[i] >> 4) & 0xf]);
166         result.append(digits[digest[i] & 0xf]);
167     }
168     return String(result.data(), result.size());
169 }
170
171 String formatBreakpointId(const String& sourceID, unsigned lineNumber)
172 {
173     return String::format("%s:%d", sourceID.utf8().data(), lineNumber);
174 }
175
176 }
177
178 InspectorController::InspectorController(Page* page, InspectorClient* client)
179     : m_inspectedPage(page)
180     , m_client(client)
181     , m_openingFrontend(false)
182     , m_cssStore(new InspectorCSSStore(this))
183     , m_expiredConsoleMessageCount(0)
184     , m_showAfterVisible(CurrentPanel)
185     , m_sessionSettings(InspectorObject::create())
186     , m_groupLevel(0)
187     , m_searchingForNode(false)
188     , m_monitoringXHR(false)
189     , m_previousMessage(0)
190     , m_resourceTrackingEnabled(false)
191     , m_settingsLoaded(false)
192     , m_inspectorBackend(InspectorBackend::create(this))
193     , m_injectedScriptHost(InjectedScriptHost::create(this))
194 #if ENABLE(JAVASCRIPT_DEBUGGER)
195     , m_debuggerEnabled(false)
196     , m_attachDebuggerWhenShown(false)
197     , m_pausedScriptState(0)
198     , m_breakpointsLoaded(false)
199     , m_profilerEnabled(!WTF_USE_JSC)
200     , m_recordingUserInitiatedProfile(false)
201     , m_currentUserInitiatedProfileNumber(-1)
202     , m_nextUserInitiatedProfileNumber(1)
203     , m_startProfiling(this, &InspectorController::startUserInitiatedProfiling)
204 #endif
205 {
206     ASSERT_ARG(page, page);
207     ASSERT_ARG(client, client);
208     ++s_inspectorControllerCount;
209 }
210
211 InspectorController::~InspectorController()
212 {
213     // These should have been cleared in inspectedPageDestroyed().
214     ASSERT(!m_client);
215     ASSERT(!m_inspectedPage);
216     ASSERT(!m_highlightedNode);
217
218     deleteAllValues(m_frameResources);
219     deleteAllValues(m_consoleMessages);
220
221     ASSERT(s_inspectorControllerCount);
222     --s_inspectorControllerCount;
223
224     releaseFrontendLifetimeAgents();
225
226     m_inspectorBackend->disconnectController();
227     m_injectedScriptHost->disconnectController();
228 }
229
230 void InspectorController::inspectedPageDestroyed()
231 {
232     if (m_frontend)
233         m_frontend->inspectedPageDestroyed();
234
235     hideHighlight();
236
237     ASSERT(m_inspectedPage);
238     m_inspectedPage = 0;
239
240     m_client->inspectorDestroyed();
241     m_client = 0;
242 }
243
244 bool InspectorController::enabled() const
245 {
246     if (!m_inspectedPage)
247         return false;
248     return m_inspectedPage->settings()->developerExtrasEnabled();
249 }
250
251 String InspectorController::setting(const String& key) const
252 {
253     Settings::iterator it = m_settings.find(key);
254     if (it != m_settings.end())
255         return it->second;
256
257     String value;
258     m_client->populateSetting(key, &value);
259     m_settings.set(key, value);
260     return value;
261 }
262
263 void InspectorController::setSetting(const String& key, const String& value)
264 {
265     m_settings.set(key, value);
266     m_client->storeSetting(key, value);
267 }
268
269 void InspectorController::setSessionSettings(const String& settingsJSON)
270 {
271     m_sessionSettings = InspectorValue::parseJSON(settingsJSON);
272 }
273
274 void InspectorController::inspect(Node* node)
275 {
276     if (!enabled())
277         return;
278
279     show();
280
281     if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
282         node = node->parentNode();
283     m_nodeToFocus = node;
284
285     if (!m_frontend) {
286         m_showAfterVisible = ElementsPanel;
287         return;
288     }
289
290     focusNode();
291 }
292
293 void InspectorController::focusNode()
294 {
295     if (!enabled())
296         return;
297
298     ASSERT(m_frontend);
299     ASSERT(m_nodeToFocus);
300
301     long id = m_domAgent->pushNodePathToFrontend(m_nodeToFocus.get());
302     m_frontend->updateFocusedNode(id);
303     m_nodeToFocus = 0;
304 }
305
306 void InspectorController::highlight(Node* node)
307 {
308     if (!enabled())
309         return;
310     ASSERT_ARG(node, node);
311     m_highlightedNode = node;
312     m_client->highlight(node);
313 }
314
315 void InspectorController::hideHighlight()
316 {
317     if (!enabled())
318         return;
319     m_highlightedNode = 0;
320     m_client->hideHighlight();
321 }
322
323 bool InspectorController::windowVisible()
324 {
325     return m_frontend;
326 }
327
328 void InspectorController::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, ScriptCallStack* callStack)
329 {
330     if (!enabled())
331         return;
332
333     addConsoleMessage(callStack->state(), new ConsoleMessage(source, type, level, callStack, m_groupLevel, type == TraceMessageType));
334 }
335
336 void InspectorController::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceID)
337 {
338     if (!enabled())
339         return;
340
341     addConsoleMessage(0, new ConsoleMessage(source, type, level, message, lineNumber, sourceID, m_groupLevel));
342 }
343
344 void InspectorController::addConsoleMessage(ScriptState* scriptState, ConsoleMessage* consoleMessage)
345 {
346     ASSERT(enabled());
347     ASSERT_ARG(consoleMessage, consoleMessage);
348
349     if (m_previousMessage && m_previousMessage->isEqual(scriptState, consoleMessage)) {
350         m_previousMessage->incrementCount();
351         delete consoleMessage;
352         if (m_frontend)
353             m_previousMessage->updateRepeatCountInConsole(m_frontend.get());
354     } else {
355         m_previousMessage = consoleMessage;
356         m_consoleMessages.append(consoleMessage);
357         if (m_frontend)
358             m_previousMessage->addToFrontend(m_frontend.get(), m_injectedScriptHost.get());
359     }
360
361     if (!m_frontend && m_consoleMessages.size() >= maximumConsoleMessages) {
362         m_expiredConsoleMessageCount += expireConsoleMessagesStep;
363         for (size_t i = 0; i < expireConsoleMessagesStep; ++i)
364             delete m_consoleMessages[i];
365         m_consoleMessages.remove(0, expireConsoleMessagesStep);
366     }
367 }
368
369 void InspectorController::clearConsoleMessages()
370 {
371     deleteAllValues(m_consoleMessages);
372     m_consoleMessages.clear();
373     m_expiredConsoleMessageCount = 0;
374     m_previousMessage = 0;
375     m_groupLevel = 0;
376     m_injectedScriptHost->releaseWrapperObjectGroup(0 /* release the group in all scripts */, "console");
377     if (m_domAgent)
378         m_domAgent->releaseDanglingNodes();
379     if (m_frontend)
380         m_frontend->clearConsoleMessages();
381 }
382
383 void InspectorController::startGroup(MessageSource source, ScriptCallStack* callStack, bool collapsed)
384 {
385     ++m_groupLevel;
386
387     addConsoleMessage(callStack->state(), new ConsoleMessage(source, collapsed ? StartGroupCollapsedMessageType : StartGroupMessageType, LogMessageLevel, callStack, m_groupLevel));
388 }
389
390 void InspectorController::endGroup(MessageSource source, unsigned lineNumber, const String& sourceURL)
391 {
392     if (!m_groupLevel)
393         return;
394
395     --m_groupLevel;
396
397     addConsoleMessage(0, new ConsoleMessage(source, EndGroupMessageType, LogMessageLevel, String(), lineNumber, sourceURL, m_groupLevel));
398 }
399
400 void InspectorController::markTimeline(const String& message)
401 {
402     if (timelineAgent())
403         timelineAgent()->didMarkTimeline(message);
404 }
405
406 void InspectorController::storeLastActivePanel(const String& panelName)
407 {
408     setSetting(lastActivePanelSettingName, panelName);
409 }
410
411 void InspectorController::mouseDidMoveOverElement(const HitTestResult& result, unsigned)
412 {
413     if (!enabled() || !m_searchingForNode)
414         return;
415
416     Node* node = result.innerNode();
417     while (node && node->nodeType() == Node::TEXT_NODE)
418         node = node->parentNode();
419     if (node)
420         highlight(node);
421 }
422
423 void InspectorController::handleMousePress()
424 {
425     if (!enabled())
426         return;
427
428     ASSERT(m_searchingForNode);
429     if (!m_highlightedNode)
430         return;
431
432     RefPtr<Node> node = m_highlightedNode;
433     setSearchingForNode(false);
434     inspect(node.get());
435 }
436
437 void InspectorController::setInspectorFrontendClient(PassOwnPtr<InspectorFrontendClient> client)
438 {
439     ASSERT(!m_inspectorFrontendClient);
440     m_inspectorFrontendClient = client;
441 }
442
443 void InspectorController::inspectedWindowScriptObjectCleared(Frame* frame)
444 {
445     // If the page is supposed to serve as InspectorFrontend notify inspetor frontend
446     // client that it's cleared so that the client can expose inspector bindings.
447     if (m_inspectorFrontendClient && frame == m_inspectedPage->mainFrame())
448         m_inspectorFrontendClient->windowObjectCleared();
449
450     if (!enabled() || !m_frontend || frame != m_inspectedPage->mainFrame())
451         return;
452     m_injectedScriptHost->discardInjectedScripts();
453 }
454
455 void InspectorController::setSearchingForNode(bool enabled)
456 {
457     if (m_searchingForNode == enabled)
458         return;
459     m_searchingForNode = enabled;
460     if (!m_searchingForNode)
461         hideHighlight();
462     if (m_frontend) {
463         if (enabled)
464             m_frontend->searchingForNodeWasEnabled();
465         else
466             m_frontend->searchingForNodeWasDisabled();
467     }
468 }
469
470 void InspectorController::setMonitoringXHR(bool enabled)
471 {
472     if (m_monitoringXHR == enabled)
473         return;
474     m_monitoringXHR = enabled;
475     setSetting(monitoringXHRSettingName, enabled ? "true" : "false");
476     if (m_frontend) {
477         if (enabled)
478             m_frontend->monitoringXHRWasEnabled();
479         else
480             m_frontend->monitoringXHRWasDisabled();
481     }
482 }
483
484 void InspectorController::connectFrontend(const ScriptObject& webInspector)
485 {
486     m_openingFrontend = false;
487     releaseFrontendLifetimeAgents();
488     m_frontend = new InspectorFrontend(webInspector, m_client);
489     m_remoteFrontend = new RemoteInspectorFrontend(m_client);
490     m_domAgent = InspectorDOMAgent::create(m_cssStore.get(), m_remoteFrontend.get());
491     if (m_timelineAgent)
492         m_timelineAgent->resetFrontendProxyObject(m_remoteFrontend.get());
493
494     // Initialize Web Inspector title.
495     m_frontend->inspectedURLChanged(m_inspectedPage->mainFrame()->loader()->url().string());
496
497     populateScriptObjects();
498
499 #if ENABLE(JAVASCRIPT_DEBUGGER)
500     if (ScriptDebugServer::shared().isDebuggerAlwaysEnabled()) {
501         // FIXME (40364): This will force pushing script sources to frontend even if script
502         // panel is inactive.
503         enableDebuggerFromFrontend(false);
504     } else {
505         String debuggerEnabled = setting(debuggerEnabledSettingName);
506         if (debuggerEnabled == "true" || m_attachDebuggerWhenShown)
507             enableDebugger();
508         String profilerEnabled = setting(profilerEnabledSettingName);
509         if (profilerEnabled == "true")
510             enableProfiler();
511     }
512 #endif
513
514     if (m_showAfterVisible == CurrentPanel) {
515         String lastActivePanelSetting = setting(lastActivePanelSettingName);
516         m_showAfterVisible = specialPanelForJSName(lastActivePanelSetting);
517     }
518
519     if (m_nodeToFocus)
520         focusNode();
521     showPanel(m_showAfterVisible);
522
523 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
524     m_applicationCacheAgent = new InspectorApplicationCacheAgent(this, m_frontend.get());
525 #endif
526 }
527
528 void InspectorController::show()
529 {
530     if (!enabled())
531         return;
532
533     if (m_openingFrontend)
534         return;
535
536     if (m_frontend)
537         m_frontend->bringToFront();
538     else {
539         m_openingFrontend = true;
540         m_client->openInspectorFrontend(this);
541     }
542 }
543
544 void InspectorController::showPanel(SpecialPanels panel)
545 {
546     if (!enabled())
547         return;
548
549     show();
550
551     if (!m_frontend) {
552         m_showAfterVisible = panel;
553         return;
554     }
555
556     if (panel == CurrentPanel)
557         return;
558
559     m_frontend->showPanel(panel);
560 }
561
562 void InspectorController::close()
563 {
564     if (!m_frontend)
565         return;
566     m_frontend->close();
567 }
568
569 void InspectorController::disconnectFrontend()
570 {
571     if (!m_frontend)
572         return;
573     m_frontend.clear();
574
575 #if ENABLE(JAVASCRIPT_DEBUGGER)
576     // If the window is being closed with the debugger enabled,
577     // remember this state to re-enable debugger on the next window
578     // opening.
579     bool debuggerWasEnabled = m_debuggerEnabled;
580     disableDebugger();
581     m_attachDebuggerWhenShown = debuggerWasEnabled;
582 #endif
583     setSearchingForNode(false);
584     unbindAllResources();
585     stopTimelineProfiler();
586
587     m_showAfterVisible = CurrentPanel;
588
589     hideHighlight();
590
591 #if ENABLE(JAVASCRIPT_DEBUGGER)
592     stopUserInitiatedProfiling();
593 #endif
594
595     releaseFrontendLifetimeAgents();
596     m_timelineAgent.clear();
597 }
598
599 void InspectorController::releaseFrontendLifetimeAgents()
600 {
601     // m_domAgent is RefPtr. Remove DOM listeners first to ensure that there are
602     // no references to the DOM agent from the DOM tree.
603     if (m_domAgent)
604         m_domAgent->reset();
605     m_domAgent.clear();
606
607 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
608     m_applicationCacheAgent.clear();
609 #endif
610 }
611
612 void InspectorController::populateScriptObjects()
613 {
614     ASSERT(m_frontend);
615     if (!m_frontend)
616         return;
617
618     m_frontend->populateApplicationSettings(setting(frontendSettingsSettingName()));
619
620     if (m_resourceTrackingEnabled)
621         m_frontend->resourceTrackingWasEnabled();
622
623     if (m_searchingForNode)
624         m_frontend->searchingForNodeWasEnabled();
625
626     if (m_monitoringXHR)
627         m_frontend->monitoringXHRWasEnabled();
628
629 #if ENABLE(JAVASCRIPT_DEBUGGER)
630     if (m_profilerEnabled)
631         m_frontend->profilerWasEnabled();
632 #endif
633
634     ResourcesMap::iterator resourcesEnd = m_resources.end();
635     for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it)
636         it->second->updateScriptObject(m_frontend.get());
637
638     m_domAgent->setDocument(m_inspectedPage->mainFrame()->document());
639
640     if (m_expiredConsoleMessageCount)
641         m_frontend->updateConsoleMessageExpiredCount(m_expiredConsoleMessageCount);
642     unsigned messageCount = m_consoleMessages.size();
643     for (unsigned i = 0; i < messageCount; ++i)
644         m_consoleMessages[i]->addToFrontend(m_frontend.get(), m_injectedScriptHost.get());
645
646 #if ENABLE(JAVASCRIPT_DEBUGGER)
647     if (m_debuggerEnabled)
648         m_frontend->updatePauseOnExceptionsState(ScriptDebugServer::shared().pauseOnExceptionsState());
649 #endif
650 #if ENABLE(DATABASE)
651     DatabaseResourcesMap::iterator databasesEnd = m_databaseResources.end();
652     for (DatabaseResourcesMap::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it)
653         it->second->bind(m_frontend.get());
654 #endif
655 #if ENABLE(DOM_STORAGE)
656     DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources.end();
657     for (DOMStorageResourcesMap::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it)
658         it->second->bind(m_frontend.get());
659 #endif
660 #if ENABLE(WORKERS)
661     WorkersMap::iterator workersEnd = m_workers.end();
662     for (WorkersMap::iterator it = m_workers.begin(); it != workersEnd; ++it)
663         m_frontend->didCreateWorker(*it->second);
664 #endif
665
666     m_frontend->populateSessionSettings(m_sessionSettings->toJSONString());
667     m_frontend->populateInterface();
668
669     // Dispatch pending frontend commands
670     for (Vector<pair<long, String> >::iterator it = m_pendingEvaluateTestCommands.begin(); it != m_pendingEvaluateTestCommands.end(); ++it)
671         m_frontend->evaluateForTestInFrontend((*it).first, (*it).second);
672     m_pendingEvaluateTestCommands.clear();
673 }
674
675 void InspectorController::unbindAllResources()
676 {
677     ResourcesMap::iterator resourcesEnd = m_resources.end();
678     for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it)
679         it->second->releaseScriptObject(0);
680
681 #if ENABLE(DATABASE)
682     DatabaseResourcesMap::iterator databasesEnd = m_databaseResources.end();
683     for (DatabaseResourcesMap::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it)
684         it->second->unbind();
685 #endif
686 #if ENABLE(DOM_STORAGE)
687     DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources.end();
688     for (DOMStorageResourcesMap::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it)
689         it->second->unbind();
690 #endif
691     if (m_timelineAgent)
692         m_timelineAgent->reset();
693 }
694
695 void InspectorController::pruneResources(ResourcesMap* resourceMap, DocumentLoader* loaderToKeep)
696 {
697     ASSERT_ARG(resourceMap, resourceMap);
698
699     ResourcesMap mapCopy(*resourceMap);
700     ResourcesMap::iterator end = mapCopy.end();
701     for (ResourcesMap::iterator it = mapCopy.begin(); it != end; ++it) {
702         InspectorResource* resource = (*it).second.get();
703         if (resource == m_mainResource)
704             continue;
705
706         if (!loaderToKeep || !resource->isSameLoader(loaderToKeep)) {
707             removeResource(resource);
708             if (m_frontend)
709                 resource->releaseScriptObject(m_frontend.get());
710         }
711     }
712 }
713
714 void InspectorController::didCommitLoad(DocumentLoader* loader)
715 {
716     if (!enabled())
717         return;
718
719     ASSERT(m_inspectedPage);
720
721     if (loader->frame() == m_inspectedPage->mainFrame()) {
722         if (m_frontend)
723             m_frontend->inspectedURLChanged(loader->url().string());
724
725         m_injectedScriptHost->discardInjectedScripts();
726         clearConsoleMessages();
727
728         m_times.clear();
729         m_counts.clear();
730 #if ENABLE(JAVASCRIPT_DEBUGGER)
731         m_sourceIDToURL.clear();
732         m_scriptIDToContent.clear();
733         m_stickyBreakpoints.clear();
734         m_breakpointsMapping.clear();
735         m_breakpointsLoaded = false;
736 #endif
737 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
738         m_profiles.clear();
739         m_currentUserInitiatedProfileNumber = 1;
740         m_nextUserInitiatedProfileNumber = 1;
741         if (m_frontend)
742             m_frontend->resetProfilesPanel();
743 #endif
744         // unbindAllResources should be called before database and DOM storage
745         // resources are cleared so that it has a chance to unbind them.
746         unbindAllResources();
747
748         m_cssStore->reset();
749         m_sessionSettings = InspectorObject::create();
750         if (m_frontend) {
751             m_frontend->reset();
752             m_domAgent->reset();
753         }
754 #if ENABLE(WORKERS)
755         m_workers.clear();
756 #endif
757 #if ENABLE(DATABASE)
758         m_databaseResources.clear();
759 #endif
760 #if ENABLE(DOM_STORAGE)
761         m_domStorageResources.clear();
762 #endif
763
764         if (m_frontend) {
765             if (!loader->frameLoader()->isLoadingFromCachedPage()) {
766                 ASSERT(m_mainResource && m_mainResource->isSameLoader(loader));
767                 // We don't add the main resource until its load is committed. This is
768                 // needed to keep the load for a user-entered URL from showing up in the
769                 // list of resources for the page they are navigating away from.
770                 m_mainResource->updateScriptObject(m_frontend.get());
771             } else {
772                 // Pages loaded from the page cache are committed before
773                 // m_mainResource is the right resource for this load, so we
774                 // clear it here. It will be re-assigned in
775                 // identifierForInitialRequest.
776                 m_mainResource = 0;
777             }
778             m_frontend->didCommitLoad();
779             m_domAgent->setDocument(m_inspectedPage->mainFrame()->document());
780         }
781     }
782
783     for (Frame* frame = loader->frame(); frame; frame = frame->tree()->traverseNext(loader->frame()))
784         if (ResourcesMap* resourceMap = m_frameResources.get(frame))
785             pruneResources(resourceMap, loader);
786
787     if (m_scriptsToEvaluateOnLoad.size()) {
788         ScriptState* scriptState = mainWorldScriptState(loader->frame());
789         for (Vector<String>::iterator it = m_scriptsToEvaluateOnLoad.begin();
790              it != m_scriptsToEvaluateOnLoad.end(); ++it) {
791             m_injectedScriptHost->injectScript(*it, scriptState);
792         }
793     }
794 }
795
796 void InspectorController::frameDetachedFromParent(Frame* frame)
797 {
798     if (!enabled())
799         return;
800     if (ResourcesMap* resourceMap = m_frameResources.get(frame))
801         removeAllResources(resourceMap);
802 }
803
804 void InspectorController::addResource(InspectorResource* resource)
805 {
806     m_resources.set(resource->identifier(), resource);
807     m_knownResources.add(resource->requestURL());
808
809     Frame* frame = resource->frame();
810     ResourcesMap* resourceMap = m_frameResources.get(frame);
811     if (resourceMap)
812         resourceMap->set(resource->identifier(), resource);
813     else {
814         resourceMap = new ResourcesMap;
815         resourceMap->set(resource->identifier(), resource);
816         m_frameResources.set(frame, resourceMap);
817     }
818 }
819
820 void InspectorController::removeResource(InspectorResource* resource)
821 {
822     m_resources.remove(resource->identifier());
823     String requestURL = resource->requestURL();
824     if (!requestURL.isNull())
825         m_knownResources.remove(requestURL);
826
827     Frame* frame = resource->frame();
828     ResourcesMap* resourceMap = m_frameResources.get(frame);
829     if (!resourceMap) {
830         ASSERT_NOT_REACHED();
831         return;
832     }
833
834     resourceMap->remove(resource->identifier());
835     if (resourceMap->isEmpty()) {
836         m_frameResources.remove(frame);
837         delete resourceMap;
838     }
839 }
840
841 InspectorResource* InspectorController::getTrackedResource(unsigned long identifier)
842 {
843     if (!enabled())
844         return 0;
845
846     if (m_resourceTrackingEnabled)
847         return m_resources.get(identifier).get();
848
849     bool isMainResource = m_mainResource && m_mainResource->identifier() == identifier;
850     if (isMainResource)
851         return m_mainResource.get();
852
853     return 0;
854 }
855
856 InspectorResource* InspectorController::resourceForURL(const String& url)
857 {
858     for (InspectorController::ResourcesMap::iterator resIt = m_resources.begin(); resIt != m_resources.end(); ++resIt) {
859         if (resIt->second->requestURL().string() == url)
860             return resIt->second.get();
861     }
862     return 0;
863 }
864
865 void InspectorController::didLoadResourceFromMemoryCache(DocumentLoader* loader, const CachedResource* cachedResource)
866 {
867     if (!enabled())
868         return;
869
870     // If the resource URL is already known, we don't need to add it again since this is just a cached load.
871     if (m_knownResources.contains(cachedResource->url()))
872         return;
873
874     ASSERT(m_inspectedPage);
875     bool isMainResource = isMainResourceLoader(loader, KURL(ParsedURLString, cachedResource->url()));
876     ensureSettingsLoaded();
877     if (!isMainResource && !m_resourceTrackingEnabled)
878         return;
879
880     RefPtr<InspectorResource> resource = InspectorResource::createCached(m_inspectedPage->progress()->createUniqueIdentifier(), loader, cachedResource);
881
882     if (isMainResource) {
883         m_mainResource = resource;
884         resource->markMainResource();
885     }
886
887     addResource(resource.get());
888
889     if (m_frontend)
890         resource->updateScriptObject(m_frontend.get());
891 }
892
893 void InspectorController::identifierForInitialRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request)
894 {
895     if (!enabled())
896         return;
897     ASSERT(m_inspectedPage);
898
899     bool isMainResource = isMainResourceLoader(loader, request.url());
900     ensureSettingsLoaded();
901     if (!isMainResource && !m_resourceTrackingEnabled)
902         return;
903
904     RefPtr<InspectorResource> resource = InspectorResource::create(identifier, loader, request.url());
905
906     if (isMainResource) {
907         m_mainResource = resource;
908         resource->markMainResource();
909     }
910
911     addResource(resource.get());
912
913     if (m_frontend && loader->frameLoader()->isLoadingFromCachedPage() && resource == m_mainResource)
914         resource->updateScriptObject(m_frontend.get());
915 }
916
917 void InspectorController::mainResourceFiredDOMContentEvent(DocumentLoader* loader, const KURL& url)
918 {
919     if (!enabled() || !isMainResourceLoader(loader, url))
920         return;
921
922     if (m_mainResource) {
923         m_mainResource->markDOMContentEventTime();
924         if (m_timelineAgent)
925             m_timelineAgent->didMarkDOMContentEvent();
926         if (m_frontend)
927             m_mainResource->updateScriptObject(m_frontend.get());
928     }
929 }
930
931 void InspectorController::mainResourceFiredLoadEvent(DocumentLoader* loader, const KURL& url)
932 {
933     if (!enabled() || !isMainResourceLoader(loader, url))
934         return;
935
936     if (m_mainResource) {
937         m_mainResource->markLoadEventTime();
938         if (m_timelineAgent)
939             m_timelineAgent->didMarkLoadEvent();
940         if (m_frontend)
941             m_mainResource->updateScriptObject(m_frontend.get());
942     }
943 }
944
945 bool InspectorController::isMainResourceLoader(DocumentLoader* loader, const KURL& requestUrl)
946 {
947     return loader->frame() == m_inspectedPage->mainFrame() && requestUrl == loader->requestURL();
948 }
949
950 void InspectorController::willSendRequest(unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse)
951 {
952     if (!enabled())
953         return;
954
955     bool isMainResource = (m_mainResource && m_mainResource->identifier() == identifier);
956     if (m_timelineAgent)
957         m_timelineAgent->willSendResourceRequest(identifier, isMainResource, request);
958
959     RefPtr<InspectorResource> resource = getTrackedResource(identifier);
960     if (!resource)
961         return;
962
963     request.setReportLoadTiming(true);
964
965     if (!redirectResponse.isNull()) {
966         // Redirect may have empty URL and we'd like to not crash with invalid HashMap entry.
967         // See http/tests/misc/will-send-request-returns-null-on-redirect.html
968         if (!request.url().isEmpty()) {
969             resource->endTiming();
970             resource->updateResponse(redirectResponse);
971
972             // We always store last redirect by the original id key. Rest of the redirects are stored within the last one.
973             unsigned long id = m_inspectedPage->progress()->createUniqueIdentifier();
974             RefPtr<InspectorResource> withRedirect = resource->appendRedirect(id, request.url());
975             removeResource(resource.get());
976             addResource(withRedirect.get());
977             if (isMainResource) {
978                 m_mainResource = withRedirect;
979                 withRedirect->markMainResource();
980             }
981             resource = withRedirect;
982         }
983     }
984
985     resource->startTiming();
986     resource->updateRequest(request);
987
988     if (resource != m_mainResource && m_frontend)
989         resource->updateScriptObject(m_frontend.get());
990 }
991
992 void InspectorController::didReceiveResponse(unsigned long identifier, const ResourceResponse& response)
993 {
994     if (!enabled())
995         return;
996
997     if (RefPtr<InspectorResource> resource = getTrackedResource(identifier)) {
998         resource->updateResponse(response);
999
1000         if (resource != m_mainResource && m_frontend)
1001             resource->updateScriptObject(m_frontend.get());
1002     }
1003     if (response.httpStatusCode() >= 400) {
1004         // The ugly code below is due to that String::format() is not utf8-safe at the moment.
1005         String message = String::format("Failed to load resource: the server responded with a status of %u (", response.httpStatusCode()) + response.httpStatusText() + ")";
1006
1007         addMessageToConsole(OtherMessageSource, LogMessageType, ErrorMessageLevel, message, 0, response.url().string());
1008     }
1009 }
1010
1011 void InspectorController::didReceiveContentLength(unsigned long identifier, int lengthReceived)
1012 {
1013     if (!enabled())
1014         return;
1015
1016     RefPtr<InspectorResource> resource = getTrackedResource(identifier);
1017     if (!resource)
1018         return;
1019
1020     resource->addLength(lengthReceived);
1021
1022     if (resource != m_mainResource && m_frontend)
1023         resource->updateScriptObject(m_frontend.get());
1024 }
1025
1026 void InspectorController::didFinishLoading(unsigned long identifier)
1027 {
1028     if (!enabled())
1029         return;
1030
1031     if (m_timelineAgent)
1032         m_timelineAgent->didFinishLoadingResource(identifier, false);
1033
1034     RefPtr<InspectorResource> resource = getTrackedResource(identifier);
1035     if (!resource)
1036         return;
1037
1038     resource->endTiming();
1039
1040     // No need to mute this event for main resource since it happens after did commit load.
1041     if (m_frontend)
1042         resource->updateScriptObject(m_frontend.get());
1043 }
1044
1045 void InspectorController::didFailLoading(unsigned long identifier, const ResourceError& error)
1046 {
1047     if (!enabled())
1048         return;
1049
1050     if (m_timelineAgent)
1051         m_timelineAgent->didFinishLoadingResource(identifier, true);
1052
1053     String message = "Failed to load resource";
1054     if (!error.localizedDescription().isEmpty())
1055         message += ": " + error.localizedDescription();
1056     addMessageToConsole(OtherMessageSource, LogMessageType, ErrorMessageLevel, message, 0, error.failingURL());
1057
1058     RefPtr<InspectorResource> resource = getTrackedResource(identifier);
1059     if (!resource)
1060         return;
1061
1062     resource->markFailed();
1063     resource->endTiming();
1064
1065     // No need to mute this event for main resource since it happens after did commit load.
1066     if (m_frontend)
1067         resource->updateScriptObject(m_frontend.get());
1068 }
1069
1070 void InspectorController::resourceRetrievedByXMLHttpRequest(unsigned long identifier, const ScriptString& sourceString, const String& url, const String& sendURL, unsigned sendLineNumber)
1071 {
1072     if (!enabled())
1073         return;
1074
1075     if (m_monitoringXHR)
1076         addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, "XHR finished loading: \"" + url + "\".", sendLineNumber, sendURL);
1077
1078     if (!m_resourceTrackingEnabled)
1079         return;
1080
1081     InspectorResource* resource = m_resources.get(identifier).get();
1082     if (!resource)
1083         return;
1084
1085     resource->setOverrideContent(sourceString, InspectorResource::XHR);
1086
1087     if (m_frontend)
1088         resource->updateScriptObject(m_frontend.get());
1089 }
1090
1091 void InspectorController::scriptImported(unsigned long identifier, const String& sourceString)
1092 {
1093     if (!enabled() || !m_resourceTrackingEnabled)
1094         return;
1095
1096     InspectorResource* resource = m_resources.get(identifier).get();
1097     if (!resource)
1098         return;
1099
1100     resource->setOverrideContent(ScriptString(sourceString), InspectorResource::Script);
1101
1102     if (m_frontend)
1103         resource->updateScriptObject(m_frontend.get());
1104 }
1105
1106 void InspectorController::enableResourceTracking(bool always, bool reload)
1107 {
1108     if (!enabled())
1109         return;
1110
1111     if (always)
1112         setSetting(resourceTrackingEnabledSettingName, "true");
1113
1114     if (m_resourceTrackingEnabled)
1115         return;
1116
1117     ASSERT(m_inspectedPage);
1118     m_resourceTrackingEnabled = true;
1119     if (m_frontend)
1120         m_frontend->resourceTrackingWasEnabled();
1121     m_client->resourceTrackingWasEnabled();
1122
1123     if (reload)
1124         m_inspectedPage->mainFrame()->redirectScheduler()->scheduleRefresh(true);
1125 }
1126
1127 void InspectorController::disableResourceTracking(bool always)
1128 {
1129     if (!enabled())
1130         return;
1131
1132     if (always)
1133         setSetting(resourceTrackingEnabledSettingName, "false");
1134
1135     ASSERT(m_inspectedPage);
1136     m_resourceTrackingEnabled = false;
1137     if (m_frontend)
1138         m_frontend->resourceTrackingWasDisabled();
1139     m_client->resourceTrackingWasDisabled();
1140 }
1141
1142 void InspectorController::ensureSettingsLoaded()
1143 {
1144     if (m_settingsLoaded)
1145         return;
1146     m_settingsLoaded = true;
1147
1148     String resourceTracking = setting(resourceTrackingEnabledSettingName);
1149     if (resourceTracking == "true")
1150         m_resourceTrackingEnabled = true;
1151     m_client->resourceTrackingWasEnabled();
1152
1153     String monitoringXHR = setting(monitoringXHRSettingName);
1154     if (monitoringXHR == "true")
1155         m_monitoringXHR = true;
1156 }
1157
1158 void InspectorController::startTimelineProfiler()
1159 {
1160     if (!enabled())
1161         return;
1162
1163     if (m_timelineAgent)
1164         return;
1165
1166     m_timelineAgent = new InspectorTimelineAgent(m_remoteFrontend.get());
1167     if (m_frontend)
1168         m_frontend->timelineProfilerWasStarted();
1169     m_client->timelineProfilerWasStarted();
1170 }
1171
1172 void InspectorController::stopTimelineProfiler()
1173 {
1174     if (!enabled())
1175         return;
1176
1177     if (!m_timelineAgent)
1178         return;
1179
1180     m_timelineAgent = 0;
1181     if (m_frontend)
1182         m_frontend->timelineProfilerWasStopped();
1183     m_client->timelineProfilerWasStopped();
1184 }
1185
1186 #if ENABLE(WORKERS)
1187 class PostWorkerNotificationToFrontendTask : public ScriptExecutionContext::Task {
1188 public:
1189     static PassOwnPtr<PostWorkerNotificationToFrontendTask> create(PassRefPtr<InspectorWorkerResource> worker, InspectorController::WorkerAction action)
1190     {
1191         return new PostWorkerNotificationToFrontendTask(worker, action);
1192     }
1193
1194 private:
1195     PostWorkerNotificationToFrontendTask(PassRefPtr<InspectorWorkerResource> worker, InspectorController::WorkerAction action)
1196         : m_worker(worker)
1197         , m_action(action)
1198     {
1199     }
1200
1201     virtual void performTask(ScriptExecutionContext* scriptContext)
1202     {
1203         if (InspectorController* inspector = scriptContext->inspectorController())
1204             inspector->postWorkerNotificationToFrontend(*m_worker, m_action);
1205     }
1206
1207 private:
1208     RefPtr<InspectorWorkerResource> m_worker;
1209     InspectorController::WorkerAction m_action;
1210 };
1211
1212 void InspectorController::postWorkerNotificationToFrontend(const InspectorWorkerResource& worker, InspectorController::WorkerAction action)
1213 {
1214     if (!m_frontend)
1215         return;
1216     switch (action) {
1217     case InspectorController::WorkerCreated:
1218         m_frontend->didCreateWorker(worker);
1219         break;
1220     case InspectorController::WorkerDestroyed:
1221         m_frontend->didDestroyWorker(worker);
1222         break;
1223     }
1224 }
1225
1226 void InspectorController::didCreateWorker(intptr_t id, const String& url, bool isSharedWorker)
1227 {
1228     if (!enabled())
1229         return;
1230
1231     RefPtr<InspectorWorkerResource> workerResource(InspectorWorkerResource::create(id, url, isSharedWorker));
1232     m_workers.set(id, workerResource);
1233     if (m_inspectedPage && m_frontend)
1234         m_inspectedPage->mainFrame()->document()->postTask(PostWorkerNotificationToFrontendTask::create(workerResource, InspectorController::WorkerCreated));
1235 }
1236
1237 void InspectorController::didDestroyWorker(intptr_t id)
1238 {
1239     if (!enabled())
1240         return;
1241
1242     WorkersMap::iterator workerResource = m_workers.find(id);
1243     if (workerResource == m_workers.end())
1244         return;
1245     if (m_inspectedPage && m_frontend)
1246         m_inspectedPage->mainFrame()->document()->postTask(PostWorkerNotificationToFrontendTask::create(workerResource->second, InspectorController::WorkerDestroyed));
1247     m_workers.remove(workerResource);
1248 }
1249 #endif // ENABLE(WORKERS)
1250
1251 #if ENABLE(DATABASE)
1252 void InspectorController::selectDatabase(Database* database)
1253 {
1254     if (!m_frontend)
1255         return;
1256
1257     for (DatabaseResourcesMap::iterator it = m_databaseResources.begin(); it != m_databaseResources.end(); ++it) {
1258         if (it->second->database() == database) {
1259             m_frontend->selectDatabase(it->first);
1260             break;
1261         }
1262     }
1263 }
1264
1265 Database* InspectorController::databaseForId(long databaseId)
1266 {
1267     DatabaseResourcesMap::iterator it = m_databaseResources.find(databaseId);
1268     if (it == m_databaseResources.end())
1269         return 0;
1270     return it->second->database();
1271 }
1272
1273 void InspectorController::didOpenDatabase(Database* database, const String& domain, const String& name, const String& version)
1274 {
1275     if (!enabled())
1276         return;
1277
1278     RefPtr<InspectorDatabaseResource> resource = InspectorDatabaseResource::create(database, domain, name, version);
1279
1280     m_databaseResources.set(resource->id(), resource);
1281
1282     // Resources are only bound while visible.
1283     if (m_frontend)
1284         resource->bind(m_frontend.get());
1285 }
1286 #endif
1287
1288 void InspectorController::getCookies(long callId)
1289 {
1290     if (!m_frontend)
1291         return;
1292
1293     // If we can get raw cookies.
1294     ListHashSet<Cookie> rawCookiesList;
1295
1296     // If we can't get raw cookies - fall back to String representation
1297     String stringCookiesList;
1298
1299     // Return value to getRawCookies should be the same for every call because
1300     // the return value is platform/network backend specific, and the call will
1301     // always return the same true/false value.
1302     bool rawCookiesImplemented = false;
1303
1304     ResourcesMap::iterator resourcesEnd = m_resources.end();
1305     for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it) {
1306         Document* document = it->second->frame()->document();
1307         Vector<Cookie> docCookiesList;
1308         rawCookiesImplemented = getRawCookies(document, it->second->requestURL(), docCookiesList);
1309
1310         if (!rawCookiesImplemented) {
1311             // FIXME: We need duplication checking for the String representation of cookies.
1312             ExceptionCode ec = 0;
1313             stringCookiesList += document->cookie(ec);
1314             // Exceptions are thrown by cookie() in sandboxed frames. That won't happen here
1315             // because "document" is the document of the main frame of the page.
1316             ASSERT(!ec);
1317         } else {
1318             int cookiesSize = docCookiesList.size();
1319             for (int i = 0; i < cookiesSize; i++) {
1320                 if (!rawCookiesList.contains(docCookiesList[i]))
1321                     rawCookiesList.add(docCookiesList[i]);
1322             }
1323         }
1324     }
1325
1326     if (!rawCookiesImplemented)
1327         m_frontend->didGetCookies(callId, m_frontend->newScriptArray(), stringCookiesList);
1328     else
1329         m_frontend->didGetCookies(callId, buildArrayForCookies(rawCookiesList), String());
1330 }
1331
1332 ScriptArray InspectorController::buildArrayForCookies(ListHashSet<Cookie>& cookiesList)
1333 {
1334     ScriptArray cookies = m_frontend->newScriptArray();
1335
1336     ListHashSet<Cookie>::iterator end = cookiesList.end();
1337     ListHashSet<Cookie>::iterator it = cookiesList.begin();
1338     for (int i = 0; it != end; ++it, i++)
1339         cookies.set(i, buildObjectForCookie(*it));
1340
1341     return cookies;
1342 }
1343
1344 ScriptObject InspectorController::buildObjectForCookie(const Cookie& cookie)
1345 {
1346     ScriptObject value = m_frontend->newScriptObject();
1347     value.set("name", cookie.name);
1348     value.set("value", cookie.value);
1349     value.set("domain", cookie.domain);
1350     value.set("path", cookie.path);
1351     value.set("expires", cookie.expires);
1352     value.set("size", (cookie.name.length() + cookie.value.length()));
1353     value.set("httpOnly", cookie.httpOnly);
1354     value.set("secure", cookie.secure);
1355     value.set("session", cookie.session);
1356     return value;
1357 }
1358
1359 void InspectorController::deleteCookie(const String& cookieName, const String& domain)
1360 {
1361     ResourcesMap::iterator resourcesEnd = m_resources.end();
1362     for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it) {
1363         Document* document = it->second->frame()->document();
1364         if (document->url().host() == domain)
1365             WebCore::deleteCookie(document, it->second->requestURL(), cookieName);
1366     }
1367 }
1368
1369 #if ENABLE(DOM_STORAGE)
1370 void InspectorController::didUseDOMStorage(StorageArea* storageArea, bool isLocalStorage, Frame* frame)
1371 {
1372     if (!enabled())
1373         return;
1374
1375     DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources.end();
1376     for (DOMStorageResourcesMap::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it)
1377         if (it->second->isSameHostAndType(frame, isLocalStorage))
1378             return;
1379
1380     RefPtr<Storage> domStorage = Storage::create(frame, storageArea);
1381     RefPtr<InspectorDOMStorageResource> resource = InspectorDOMStorageResource::create(domStorage.get(), isLocalStorage, frame);
1382
1383     m_domStorageResources.set(resource->id(), resource);
1384
1385     // Resources are only bound while visible.
1386     if (m_frontend)
1387         resource->bind(m_frontend.get());
1388 }
1389
1390 void InspectorController::selectDOMStorage(Storage* storage)
1391 {
1392     ASSERT(storage);
1393     if (!m_frontend)
1394         return;
1395
1396     Frame* frame = storage->frame();
1397     ExceptionCode ec = 0;
1398     bool isLocalStorage = (frame->domWindow()->localStorage(ec) == storage && !ec);
1399     long storageResourceId = 0;
1400     DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources.end();
1401     for (DOMStorageResourcesMap::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it) {
1402         if (it->second->isSameHostAndType(frame, isLocalStorage)) {
1403             storageResourceId = it->first;
1404             break;
1405         }
1406     }
1407     if (storageResourceId)
1408         m_frontend->selectDOMStorage(storageResourceId);
1409 }
1410
1411 void InspectorController::getDOMStorageEntries(long callId, long storageId)
1412 {
1413     if (!m_frontend)
1414         return;
1415
1416     ScriptArray jsonArray = m_frontend->newScriptArray();
1417     InspectorDOMStorageResource* storageResource = getDOMStorageResourceForId(storageId);
1418     if (storageResource) {
1419         storageResource->startReportingChangesToFrontend();
1420         Storage* domStorage = storageResource->domStorage();
1421         for (unsigned i = 0; i < domStorage->length(); ++i) {
1422             String name(domStorage->key(i));
1423             String value(domStorage->getItem(name));
1424             ScriptArray entry = m_frontend->newScriptArray();
1425             entry.set(0, name);
1426             entry.set(1, value);
1427             jsonArray.set(i, entry);
1428         }
1429     }
1430     m_frontend->didGetDOMStorageEntries(callId, jsonArray);
1431 }
1432
1433 void InspectorController::setDOMStorageItem(long callId, long storageId, const String& key, const String& value)
1434 {
1435     if (!m_frontend)
1436         return;
1437
1438     bool success = false;
1439     InspectorDOMStorageResource* storageResource = getDOMStorageResourceForId(storageId);
1440     if (storageResource) {
1441         ExceptionCode exception = 0;
1442         storageResource->domStorage()->setItem(key, value, exception);
1443         success = !exception;
1444     }
1445     m_frontend->didSetDOMStorageItem(callId, success);
1446 }
1447
1448 void InspectorController::removeDOMStorageItem(long callId, long storageId, const String& key)
1449 {
1450     if (!m_frontend)
1451         return;
1452
1453     bool success = false;
1454     InspectorDOMStorageResource* storageResource = getDOMStorageResourceForId(storageId);
1455     if (storageResource) {
1456         storageResource->domStorage()->removeItem(key);
1457         success = true;
1458     }
1459     m_frontend->didRemoveDOMStorageItem(callId, success);
1460 }
1461
1462 InspectorDOMStorageResource* InspectorController::getDOMStorageResourceForId(long storageId)
1463 {
1464     DOMStorageResourcesMap::iterator it = m_domStorageResources.find(storageId);
1465     if (it == m_domStorageResources.end())
1466         return 0;
1467     return it->second.get();
1468 }
1469 #endif
1470
1471 #if ENABLE(JAVASCRIPT_DEBUGGER)
1472 void InspectorController::addProfile(PassRefPtr<ScriptProfile> prpProfile, unsigned lineNumber, const String& sourceURL)
1473 {
1474     if (!enabled())
1475         return;
1476
1477     RefPtr<ScriptProfile> profile = prpProfile;
1478     m_profiles.add(profile->uid(), profile);
1479
1480     if (m_frontend) {
1481 #if USE(JSC)
1482         JSC::JSLock lock(JSC::SilenceAssertionsOnly);
1483 #endif
1484         m_frontend->addProfileHeader(createProfileHeader(*profile));
1485     }
1486
1487     addProfileFinishedMessageToConsole(profile, lineNumber, sourceURL);
1488 }
1489
1490 void InspectorController::addProfileFinishedMessageToConsole(PassRefPtr<ScriptProfile> prpProfile, unsigned lineNumber, const String& sourceURL)
1491 {
1492     RefPtr<ScriptProfile> profile = prpProfile;
1493
1494 #if USE(JSC)
1495     String title = ustringToString(profile->title());
1496 #else
1497     String title = profile->title();
1498 #endif
1499     String message = String::format("Profile \"webkit-profile://%s/%s#%d\" finished.", CPUProfileType, encodeWithURLEscapeSequences(title).utf8().data(), profile->uid());
1500     addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lineNumber, sourceURL);
1501 }
1502
1503 void InspectorController::addStartProfilingMessageToConsole(const String& title, unsigned lineNumber, const String& sourceURL)
1504 {
1505     String message = String::format("Profile \"webkit-profile://%s/%s#0\" started.", CPUProfileType, encodeWithURLEscapeSequences(title).utf8().data());
1506     addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lineNumber, sourceURL);
1507 }
1508
1509 void InspectorController::removeProfile(unsigned uid)
1510 {
1511     if (!enabled())
1512         return;
1513
1514     if (m_profiles.contains(uid))
1515         m_profiles.remove(uid);
1516 }
1517
1518 void InspectorController::clearProfiles()
1519 {
1520     if (!enabled())
1521         return;
1522
1523     m_profiles.clear();
1524     m_currentUserInitiatedProfileNumber = 1;
1525     m_nextUserInitiatedProfileNumber = 1;
1526 }
1527
1528 void InspectorController::getProfileHeaders(long callId)
1529 {
1530     if (!m_frontend)
1531         return;
1532     ScriptArray result = m_frontend->newScriptArray();
1533     ProfilesMap::iterator profilesEnd = m_profiles.end();
1534     int i = 0;
1535     for (ProfilesMap::iterator it = m_profiles.begin(); it != profilesEnd; ++it)
1536         result.set(i++, createProfileHeader(*it->second));
1537     m_frontend->didGetProfileHeaders(callId, result);
1538 }
1539
1540 void InspectorController::getProfile(long callId, unsigned uid)
1541 {
1542     if (!m_frontend)
1543         return;
1544     ProfilesMap::iterator it = m_profiles.find(uid);
1545     if (it != m_profiles.end())
1546 #if USE(JSC)
1547         m_frontend->didGetProfile(callId, toJS(m_frontend->scriptState(), it->second.get()));
1548 #else
1549         m_frontend->didGetProfile(callId, toV8(it->second.get()));
1550 #endif
1551 }
1552
1553 ScriptObject InspectorController::createProfileHeader(const ScriptProfile& profile)
1554 {
1555 #if USE(JSC)
1556     String title = ustringToString(profile.title());
1557 #else
1558     String title = profile.title();
1559 #endif
1560
1561     ScriptObject header = m_frontend->newScriptObject();
1562     header.set("title", title);
1563     header.set("uid", profile.uid());
1564     header.set("typeId", String(CPUProfileType));
1565     return header;
1566 }
1567
1568 String InspectorController::getCurrentUserInitiatedProfileName(bool incrementProfileNumber = false)
1569 {
1570     if (incrementProfileNumber)
1571         m_currentUserInitiatedProfileNumber = m_nextUserInitiatedProfileNumber++;
1572
1573     return String::format("%s.%d", UserInitiatedProfileName, m_currentUserInitiatedProfileNumber);
1574 }
1575
1576 void InspectorController::startUserInitiatedProfilingSoon()
1577 {
1578     m_startProfiling.startOneShot(0);
1579 }
1580
1581 void InspectorController::startUserInitiatedProfiling(Timer<InspectorController>*)
1582 {
1583     if (!enabled())
1584         return;
1585
1586     if (!profilerEnabled()) {
1587         enableProfiler(false, true);
1588         ScriptDebugServer::shared().recompileAllJSFunctions();
1589     }
1590
1591     m_recordingUserInitiatedProfile = true;
1592
1593     String title = getCurrentUserInitiatedProfileName(true);
1594
1595 #if USE(JSC)
1596     JSC::ExecState* scriptState = toJSDOMWindow(m_inspectedPage->mainFrame(), debuggerWorld())->globalExec();
1597 #else
1598     ScriptState* scriptState = 0;
1599 #endif
1600     ScriptProfiler::start(scriptState, title);
1601
1602     addStartProfilingMessageToConsole(title, 0, String());
1603
1604     toggleRecordButton(true);
1605 }
1606
1607 void InspectorController::stopUserInitiatedProfiling()
1608 {
1609     if (!enabled())
1610         return;
1611
1612     m_recordingUserInitiatedProfile = false;
1613
1614     String title = getCurrentUserInitiatedProfileName();
1615
1616 #if USE(JSC)
1617     JSC::ExecState* scriptState = toJSDOMWindow(m_inspectedPage->mainFrame(), debuggerWorld())->globalExec();
1618 #else
1619     // Use null script state to avoid filtering by context security token.
1620     // All functions from all iframes should be visible from Inspector UI.
1621     ScriptState* scriptState = 0;
1622 #endif
1623     RefPtr<ScriptProfile> profile = ScriptProfiler::stop(scriptState, title);
1624     if (profile)
1625         addProfile(profile, 0, String());
1626
1627     toggleRecordButton(false);
1628 }
1629
1630 void InspectorController::toggleRecordButton(bool isProfiling)
1631 {
1632     if (!m_frontend)
1633         return;
1634     m_frontend->setRecordingProfile(isProfiling);
1635 }
1636
1637 void InspectorController::enableProfiler(bool always, bool skipRecompile)
1638 {
1639     if (always)
1640         setSetting(profilerEnabledSettingName, "true");
1641
1642     if (m_profilerEnabled)
1643         return;
1644
1645     m_profilerEnabled = true;
1646
1647     if (!skipRecompile)
1648         ScriptDebugServer::shared().recompileAllJSFunctionsSoon();
1649
1650     if (m_frontend)
1651         m_frontend->profilerWasEnabled();
1652 }
1653
1654 void InspectorController::disableProfiler(bool always)
1655 {
1656     if (always)
1657         setSetting(profilerEnabledSettingName, "false");
1658
1659     if (!m_profilerEnabled)
1660         return;
1661
1662     m_profilerEnabled = false;
1663
1664     ScriptDebugServer::shared().recompileAllJSFunctionsSoon();
1665
1666     if (m_frontend)
1667         m_frontend->profilerWasDisabled();
1668 }
1669
1670 void InspectorController::takeHeapSnapshot()
1671 {
1672     if (!enabled())
1673         return;
1674
1675     ScriptProfiler::takeHeapSnapshot();
1676 }
1677 #endif
1678
1679 #if ENABLE(JAVASCRIPT_DEBUGGER)
1680 void InspectorController::enableDebuggerFromFrontend(bool always)
1681 {
1682     ASSERT(!m_debuggerEnabled);
1683     if (always)
1684         setSetting(debuggerEnabledSettingName, "true");
1685
1686     ASSERT(m_inspectedPage);
1687
1688     ScriptDebugServer::shared().clearBreakpoints();
1689     ScriptDebugServer::shared().addListener(this, m_inspectedPage);
1690
1691     m_debuggerEnabled = true;
1692     m_frontend->debuggerWasEnabled();
1693 }
1694
1695 void InspectorController::enableDebugger()
1696 {
1697     if (!enabled())
1698         return;
1699
1700     if (m_debuggerEnabled)
1701         return;
1702
1703     if (!m_frontend)
1704         m_attachDebuggerWhenShown = true;
1705     else {
1706         m_frontend->attachDebuggerWhenShown();
1707         m_attachDebuggerWhenShown = false;
1708     }
1709 }
1710
1711 void InspectorController::disableDebugger(bool always)
1712 {
1713     if (!enabled())
1714         return;
1715
1716     if (always)
1717         setSetting(debuggerEnabledSettingName, "false");
1718
1719     ASSERT(m_inspectedPage);
1720
1721     ScriptDebugServer::shared().removeListener(this, m_inspectedPage);
1722
1723     m_debuggerEnabled = false;
1724     m_attachDebuggerWhenShown = false;
1725     m_pausedScriptState = 0;
1726
1727     if (m_frontend)
1728         m_frontend->debuggerWasDisabled();
1729 }
1730
1731 void InspectorController::editScriptSource(long callId, const String& sourceID, const String& newContent)
1732 {
1733     String result;
1734     bool success = ScriptDebugServer::shared().editScriptSource(sourceID, newContent, result);
1735     RefPtr<SerializedScriptValue> callFrames;
1736     if (success)
1737         callFrames = currentCallFrames();
1738     m_frontend->didEditScriptSource(callId, success, result, callFrames.get());
1739 }
1740
1741 void InspectorController::getScriptSource(long callId, const String& sourceID)
1742 {
1743     if (!m_frontend)
1744         return;
1745     String scriptSource = m_scriptIDToContent.get(sourceID);
1746     m_frontend->didGetScriptSource(callId, scriptSource);
1747 }
1748
1749 void InspectorController::resumeDebugger()
1750 {
1751     if (!m_debuggerEnabled)
1752         return;
1753     ScriptDebugServer::shared().continueProgram();
1754 }
1755
1756 PassRefPtr<SerializedScriptValue> InspectorController::currentCallFrames()
1757 {
1758     if (!m_pausedScriptState)
1759         return 0;
1760     InjectedScript injectedScript = m_injectedScriptHost->injectedScriptFor(m_pausedScriptState);
1761     if (injectedScript.hasNoValue()) {
1762         ASSERT_NOT_REACHED();
1763         return 0;
1764     }
1765     return injectedScript.callFrames();
1766 }
1767
1768 void InspectorController::setBreakpoint(long callId, const String& sourceID, unsigned lineNumber, bool enabled, const String& condition)
1769 {
1770     ScriptBreakpoint breakpoint(enabled, condition);
1771     unsigned actualLineNumber = 0;
1772     bool success = ScriptDebugServer::shared().setBreakpoint(sourceID, breakpoint, lineNumber, &actualLineNumber);
1773     m_frontend->didSetBreakpoint(callId, success, actualLineNumber);
1774     if (!success)
1775         return;
1776
1777     String url = m_sourceIDToURL.get(sourceID);
1778     if (url.isEmpty())
1779         return;
1780
1781     String breakpointId = formatBreakpointId(sourceID, actualLineNumber);
1782     m_breakpointsMapping.set(breakpointId, actualLineNumber);
1783
1784     String key = md5Base16(url);
1785     HashMap<String, SourceBreakpoints>::iterator it = m_stickyBreakpoints.find(key);
1786     if (it == m_stickyBreakpoints.end())
1787         it = m_stickyBreakpoints.set(key, SourceBreakpoints()).first;
1788     it->second.set(actualLineNumber, breakpoint);
1789     saveBreakpoints();
1790 }
1791
1792 void InspectorController::removeBreakpoint(const String& sourceID, unsigned lineNumber)
1793 {
1794     ScriptDebugServer::shared().removeBreakpoint(sourceID, lineNumber);
1795
1796     String url = m_sourceIDToURL.get(sourceID);
1797     if (url.isEmpty())
1798         return;
1799
1800     String breakpointId = formatBreakpointId(sourceID, lineNumber);
1801     HashMap<String, unsigned>::iterator mappingIt = m_breakpointsMapping.find(breakpointId);
1802     if (mappingIt == m_breakpointsMapping.end())
1803         return;
1804     unsigned stickyLine = mappingIt->second;
1805     m_breakpointsMapping.remove(mappingIt);
1806
1807     HashMap<String, SourceBreakpoints>::iterator it = m_stickyBreakpoints.find(md5Base16(url));
1808     if (it == m_stickyBreakpoints.end())
1809         return;
1810
1811     it->second.remove(stickyLine);
1812     saveBreakpoints();
1813 }
1814
1815 // JavaScriptDebugListener functions
1816
1817 void InspectorController::didParseSource(const String& sourceID, const String& url, const String& data, int firstLine, ScriptWorldType worldType)
1818 {
1819     // Don't send script content to the front end until it's really needed.
1820     m_frontend->parsedScriptSource(sourceID, url, "", firstLine, worldType);
1821
1822     m_scriptIDToContent.set(sourceID, data);
1823
1824     if (url.isEmpty())
1825         return;
1826
1827     loadBreakpoints();
1828     HashMap<String, SourceBreakpoints>::iterator it = m_stickyBreakpoints.find(md5Base16(url));
1829     if (it != m_stickyBreakpoints.end()) {
1830         for (SourceBreakpoints::iterator breakpointIt = it->second.begin(); breakpointIt != it->second.end(); ++breakpointIt) {
1831             int lineNumber = breakpointIt->first;
1832             if (firstLine > lineNumber)
1833                 continue;
1834             unsigned actualLineNumber = 0;
1835             bool success = ScriptDebugServer::shared().setBreakpoint(sourceID, breakpointIt->second, lineNumber, &actualLineNumber);
1836             if (!success)
1837                 continue;
1838             m_frontend->restoredBreakpoint(sourceID, url, actualLineNumber, breakpointIt->second.enabled, breakpointIt->second.condition);
1839             String breakpointId = formatBreakpointId(sourceID, actualLineNumber);
1840             m_breakpointsMapping.set(breakpointId, lineNumber);
1841         }
1842     }
1843     m_sourceIDToURL.set(sourceID, url);
1844 }
1845
1846 void InspectorController::failedToParseSource(const String& url, const String& data, int firstLine, int errorLine, const String& errorMessage)
1847 {
1848     m_frontend->failedToParseScriptSource(url, data, firstLine, errorLine, errorMessage);
1849 }
1850
1851 void InspectorController::didPause(ScriptState* scriptState)
1852 {
1853     ASSERT(scriptState && !m_pausedScriptState);
1854     m_pausedScriptState = scriptState;
1855     RefPtr<SerializedScriptValue> callFrames = currentCallFrames();
1856     m_frontend->pausedScript(callFrames.get());
1857 }
1858
1859 void InspectorController::didContinue()
1860 {
1861     m_pausedScriptState = 0;
1862     m_frontend->resumedScript();
1863 }
1864
1865 #endif
1866
1867 void InspectorController::evaluateForTestInFrontend(long callId, const String& script)
1868 {
1869     if (m_frontend)
1870         m_frontend->evaluateForTestInFrontend(callId, script);
1871     else
1872         m_pendingEvaluateTestCommands.append(pair<long, String>(callId, script));
1873 }
1874
1875 void InspectorController::didEvaluateForTestInFrontend(long callId, const String& jsonResult)
1876 {
1877     ScriptState* scriptState = scriptStateFromPage(debuggerWorld(), m_inspectedPage);
1878     ScriptObject window;
1879     ScriptGlobalObject::get(scriptState, "window", window);
1880     ScriptFunctionCall function(window, "didEvaluateForTestInFrontend");
1881     function.appendArgument(callId);
1882     function.appendArgument(jsonResult);
1883     function.call();
1884 }
1885
1886 #if ENABLE(JAVASCRIPT_DEBUGGER)
1887 String InspectorController::breakpointsSettingKey()
1888 {
1889     DEFINE_STATIC_LOCAL(String, keyPrefix, ("breakpoints:"));
1890     return keyPrefix + md5Base16(m_mainResource->requestURL());
1891 }
1892
1893 void InspectorController::loadBreakpoints()
1894 {
1895     if (m_breakpointsLoaded)
1896         return;
1897     m_breakpointsLoaded = true;
1898
1899     RefPtr<InspectorValue> parsedSetting = InspectorValue::parseJSON(setting(breakpointsSettingKey()));
1900     if (!parsedSetting)
1901         return;
1902     RefPtr<InspectorObject> breakpoints = parsedSetting->asObject();
1903     if (!breakpoints)
1904         return;
1905     for (InspectorObject::iterator it = breakpoints->begin(); it != breakpoints->end(); ++it) {
1906         RefPtr<InspectorObject> breakpointsForURL = it->second->asObject();
1907         if (!breakpointsForURL)
1908             continue;
1909         HashMap<String, SourceBreakpoints>::iterator sourceBreakpointsIt = m_stickyBreakpoints.set(it->first, SourceBreakpoints()).first;
1910         ScriptBreakpoint::sourceBreakpointsFromInspectorObject(breakpointsForURL, &sourceBreakpointsIt->second);
1911     }
1912 }
1913
1914 void InspectorController::saveBreakpoints()
1915 {
1916     RefPtr<InspectorObject> breakpoints = InspectorObject::create();
1917     for (HashMap<String, SourceBreakpoints>::iterator it(m_stickyBreakpoints.begin()); it != m_stickyBreakpoints.end(); ++it) {
1918         if (it->second.isEmpty())
1919             continue;
1920         RefPtr<InspectorObject> breakpointsForURL = ScriptBreakpoint::inspectorObjectFromSourceBreakpoints(it->second);
1921         breakpoints->set(it->first, breakpointsForURL);
1922     }
1923     setSetting(breakpointsSettingKey(), breakpoints->toJSONString());
1924 }
1925 #endif
1926
1927 static Path quadToPath(const FloatQuad& quad)
1928 {
1929     Path quadPath;
1930     quadPath.moveTo(quad.p1());
1931     quadPath.addLineTo(quad.p2());
1932     quadPath.addLineTo(quad.p3());
1933     quadPath.addLineTo(quad.p4());
1934     quadPath.closeSubpath();
1935     return quadPath;
1936 }
1937
1938 static void drawOutlinedQuad(GraphicsContext& context, const FloatQuad& quad, const Color& fillColor)
1939 {
1940     static const int outlineThickness = 2;
1941     static const Color outlineColor(62, 86, 180, 228);
1942
1943     Path quadPath = quadToPath(quad);
1944
1945     // Clip out the quad, then draw with a 2px stroke to get a pixel
1946     // of outline (because inflating a quad is hard)
1947     {
1948         context.save();
1949         context.addPath(quadPath);
1950         context.clipOut(quadPath);
1951
1952         context.addPath(quadPath);
1953         context.setStrokeThickness(outlineThickness);
1954         context.setStrokeColor(outlineColor, DeviceColorSpace);
1955         context.strokePath();
1956
1957         context.restore();
1958     }
1959
1960     // Now do the fill
1961     context.addPath(quadPath);
1962     context.setFillColor(fillColor, DeviceColorSpace);
1963     context.fillPath();
1964 }
1965
1966 static void drawOutlinedQuadWithClip(GraphicsContext& context, const FloatQuad& quad, const FloatQuad& clipQuad, const Color& fillColor)
1967 {
1968     context.save();
1969     Path clipQuadPath = quadToPath(clipQuad);
1970     context.clipOut(clipQuadPath);
1971     drawOutlinedQuad(context, quad, fillColor);
1972     context.restore();
1973 }
1974
1975 static void drawHighlightForBox(GraphicsContext& context, const FloatQuad& contentQuad, const FloatQuad& paddingQuad, const FloatQuad& borderQuad, const FloatQuad& marginQuad)
1976 {
1977     static const Color contentBoxColor(125, 173, 217, 128);
1978     static const Color paddingBoxColor(125, 173, 217, 160);
1979     static const Color borderBoxColor(125, 173, 217, 192);
1980     static const Color marginBoxColor(125, 173, 217, 228);
1981
1982     if (marginQuad != borderQuad)
1983         drawOutlinedQuadWithClip(context, marginQuad, borderQuad, marginBoxColor);
1984     if (borderQuad != paddingQuad)
1985         drawOutlinedQuadWithClip(context, borderQuad, paddingQuad, borderBoxColor);
1986     if (paddingQuad != contentQuad)
1987         drawOutlinedQuadWithClip(context, paddingQuad, contentQuad, paddingBoxColor);
1988
1989     drawOutlinedQuad(context, contentQuad, contentBoxColor);
1990 }
1991
1992 static void drawHighlightForLineBoxesOrSVGRenderer(GraphicsContext& context, const Vector<FloatQuad>& lineBoxQuads)
1993 {
1994     static const Color lineBoxColor(125, 173, 217, 128);
1995
1996     for (size_t i = 0; i < lineBoxQuads.size(); ++i)
1997         drawOutlinedQuad(context, lineBoxQuads[i], lineBoxColor);
1998 }
1999
2000 static inline void convertFromFrameToMainFrame(Frame* frame, IntRect& rect)
2001 {
2002     rect = frame->page()->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(rect));
2003 }
2004
2005 static inline IntSize frameToMainFrameOffset(Frame* frame)
2006 {
2007     IntPoint mainFramePoint = frame->page()->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(IntPoint()));
2008     return mainFramePoint - IntPoint();
2009 }
2010
2011 void InspectorController::drawNodeHighlight(GraphicsContext& context) const
2012 {
2013     if (!m_highlightedNode)
2014         return;
2015
2016     RenderObject* renderer = m_highlightedNode->renderer();
2017     Frame* containingFrame = m_highlightedNode->document()->frame();
2018     if (!renderer || !containingFrame)
2019         return;
2020
2021     IntSize mainFrameOffset = frameToMainFrameOffset(containingFrame);
2022     IntRect boundingBox = renderer->absoluteBoundingBoxRect(true);
2023     boundingBox.move(mainFrameOffset);
2024
2025     ASSERT(m_inspectedPage);
2026
2027     FrameView* view = m_inspectedPage->mainFrame()->view();
2028     FloatRect overlayRect = view->visibleContentRect();
2029     if (!overlayRect.contains(boundingBox) && !boundingBox.contains(enclosingIntRect(overlayRect)))
2030         overlayRect = view->visibleContentRect();
2031     context.translate(-overlayRect.x(), -overlayRect.y());
2032
2033     // RenderSVGRoot should be highlighted through the isBox() code path, all other SVG elements should just dump their absoluteQuads().
2034 #if ENABLE(SVG)
2035     bool isSVGRenderer = renderer->node() && renderer->node()->isSVGElement() && !renderer->isSVGRoot();
2036 #else
2037     bool isSVGRenderer = false;
2038 #endif
2039
2040     if (renderer->isBox() && !isSVGRenderer) {
2041         RenderBox* renderBox = toRenderBox(renderer);
2042
2043         IntRect contentBox = renderBox->contentBoxRect();
2044
2045         IntRect paddingBox(contentBox.x() - renderBox->paddingLeft(), contentBox.y() - renderBox->paddingTop(),
2046                            contentBox.width() + renderBox->paddingLeft() + renderBox->paddingRight(), contentBox.height() + renderBox->paddingTop() + renderBox->paddingBottom());
2047         IntRect borderBox(paddingBox.x() - renderBox->borderLeft(), paddingBox.y() - renderBox->borderTop(),
2048                           paddingBox.width() + renderBox->borderLeft() + renderBox->borderRight(), paddingBox.height() + renderBox->borderTop() + renderBox->borderBottom());
2049         IntRect marginBox(borderBox.x() - renderBox->marginLeft(), borderBox.y() - renderBox->marginTop(),
2050                           borderBox.width() + renderBox->marginLeft() + renderBox->marginRight(), borderBox.height() + renderBox->marginTop() + renderBox->marginBottom());
2051
2052         FloatQuad absContentQuad = renderBox->localToAbsoluteQuad(FloatRect(contentBox));
2053         FloatQuad absPaddingQuad = renderBox->localToAbsoluteQuad(FloatRect(paddingBox));
2054         FloatQuad absBorderQuad = renderBox->localToAbsoluteQuad(FloatRect(borderBox));
2055         FloatQuad absMarginQuad = renderBox->localToAbsoluteQuad(FloatRect(marginBox));
2056
2057         absContentQuad.move(mainFrameOffset);
2058         absPaddingQuad.move(mainFrameOffset);
2059         absBorderQuad.move(mainFrameOffset);
2060         absMarginQuad.move(mainFrameOffset);
2061
2062         drawHighlightForBox(context, absContentQuad, absPaddingQuad, absBorderQuad, absMarginQuad);
2063     } else if (renderer->isRenderInline() || isSVGRenderer) {
2064         // FIXME: We should show margins/padding/border for inlines.
2065         Vector<FloatQuad> lineBoxQuads;
2066         renderer->absoluteQuads(lineBoxQuads);
2067         for (unsigned i = 0; i < lineBoxQuads.size(); ++i)
2068             lineBoxQuads[i] += mainFrameOffset;
2069
2070         drawHighlightForLineBoxesOrSVGRenderer(context, lineBoxQuads);
2071     }
2072 }
2073
2074 void InspectorController::count(const String& title, unsigned lineNumber, const String& sourceID)
2075 {
2076     String identifier = title + String::format("@%s:%d", sourceID.utf8().data(), lineNumber);
2077     HashMap<String, unsigned>::iterator it = m_counts.find(identifier);
2078     int count;
2079     if (it == m_counts.end())
2080         count = 1;
2081     else {
2082         count = it->second + 1;
2083         m_counts.remove(it);
2084     }
2085
2086     m_counts.add(identifier, count);
2087
2088     String message = String::format("%s: %d", title.utf8().data(), count);
2089     addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lineNumber, sourceID);
2090 }
2091
2092 void InspectorController::startTiming(const String& title)
2093 {
2094     m_times.add(title, currentTime() * 1000);
2095 }
2096
2097 bool InspectorController::stopTiming(const String& title, double& elapsed)
2098 {
2099     HashMap<String, double>::iterator it = m_times.find(title);
2100     if (it == m_times.end())
2101         return false;
2102
2103     double startTime = it->second;
2104     m_times.remove(it);
2105
2106     elapsed = currentTime() * 1000 - startTime;
2107     return true;
2108 }
2109
2110 InspectorController::SpecialPanels InspectorController::specialPanelForJSName(const String& panelName)
2111 {
2112     if (panelName == "elements")
2113         return ElementsPanel;
2114     if (panelName == "resources")
2115         return ResourcesPanel;
2116     if (panelName == "scripts")
2117         return ScriptsPanel;
2118     if (panelName == "timeline")
2119         return TimelinePanel;
2120     if (panelName == "profiles")
2121         return ProfilesPanel;
2122     if (panelName == "storage" || panelName == "databases")
2123         return StoragePanel;
2124     if (panelName == "audits")
2125         return AuditsPanel;
2126     if (panelName == "console")
2127         return ConsolePanel;
2128     return ElementsPanel;
2129 }
2130
2131 InjectedScript InspectorController::injectedScriptForNodeId(long id)
2132 {
2133
2134     Frame* frame = 0;
2135     if (id) {
2136         ASSERT(m_domAgent);
2137         Node* node = m_domAgent->nodeForId(id);
2138         if (node) {
2139             Document* document = node->ownerDocument();
2140             if (document)
2141                 frame = document->frame();
2142         }
2143     } else
2144         frame = m_inspectedPage->mainFrame();
2145
2146     if (frame)
2147         return m_injectedScriptHost->injectedScriptFor(mainWorldScriptState(frame));
2148
2149     return InjectedScript();
2150 }
2151
2152 void InspectorController::addScriptToEvaluateOnLoad(const String& source)
2153 {
2154     m_scriptsToEvaluateOnLoad.append(source);
2155 }
2156
2157 void InspectorController::removeAllScriptsToEvaluateOnLoad()
2158 {
2159     m_scriptsToEvaluateOnLoad.clear();
2160 }
2161
2162 } // namespace WebCore
2163
2164 #endif // ENABLE(INSPECTOR)