2010-11-02 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 "CachedResourceLoader.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 "FrameLoadRequest.h"
51 #include "FrameLoader.h"
52 #include "FrameTree.h"
53 #include "FrameView.h"
54 #include "GraphicsContext.h"
55 #include "HTMLFrameOwnerElement.h"
56 #include "HitTestResult.h"
57 #include "InjectedScript.h"
58 #include "InjectedScriptHost.h"
59 #include "InspectorBackend.h"
60 #include "InspectorBackendDispatcher.h"
61 #include "InspectorCSSStore.h"
62 #include "InspectorClient.h"
63 #include "InspectorDOMAgent.h"
64 #include "InspectorDOMStorageResource.h"
65 #include "InspectorDatabaseResource.h"
66 #include "InspectorDebuggerAgent.h"
67 #include "InspectorFrontend.h"
68 #include "InspectorFrontendClient.h"
69 #include "InspectorInstrumentation.h"
70 #include "InspectorProfilerAgent.h"
71 #include "InspectorResourceAgent.h"
72 #include "InspectorState.h"
73 #include "InspectorStorageAgent.h"
74 #include "InspectorTimelineAgent.h"
75 #include "InspectorValues.h"
76 #include "InspectorWorkerResource.h"
77 #include "IntRect.h"
78 #include "Page.h"
79 #include "ProgressTracker.h"
80 #include "Range.h"
81 #include "RenderInline.h"
82 #include "ResourceRequest.h"
83 #include "ResourceResponse.h"
84 #include "ScriptCallStack.h"
85 #include "ScriptFunctionCall.h"
86 #include "ScriptObject.h"
87 #include "ScriptProfile.h"
88 #include "ScriptProfiler.h"
89 #include "ScriptSourceCode.h"
90 #include "ScriptState.h"
91 #include "SecurityOrigin.h"
92 #include "Settings.h"
93 #include "SharedBuffer.h"
94 #include "TextEncoding.h"
95 #include "TextIterator.h"
96 #include "UserGestureIndicator.h"
97 #include "WindowFeatures.h"
98 #include <wtf/text/StringConcatenate.h>
99 #include <wtf/CurrentTime.h>
100 #include <wtf/ListHashSet.h>
101 #include <wtf/RefCounted.h>
102 #include <wtf/StdLibExtras.h>
103 #include <wtf/UnusedParam.h>
104
105 #if ENABLE(DATABASE)
106 #include "Database.h"
107 #endif
108
109 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
110 #include "InspectorApplicationCacheAgent.h"
111 #endif
112
113 #if ENABLE(FILE_SYSTEM)
114 #include "InspectorFileSystemAgent.h"
115 #endif
116
117 #if ENABLE(DOM_STORAGE)
118 #include "Storage.h"
119 #include "StorageArea.h"
120 #endif
121
122 using namespace std;
123
124 namespace WebCore {
125
126 static const char* const domNativeBreakpointType = "DOM";
127 static const char* const eventListenerNativeBreakpointType = "EventListener";
128 static const char* const xhrNativeBreakpointType = "XHR";
129
130 const char* const InspectorController::ElementsPanel = "elements";
131 const char* const InspectorController::ConsolePanel = "console";
132 const char* const InspectorController::ScriptsPanel = "scripts";
133 const char* const InspectorController::ProfilesPanel = "profiles";
134
135 const unsigned InspectorController::defaultAttachedHeight = 300;
136
137 static const unsigned maximumConsoleMessages = 1000;
138 static const unsigned expireConsoleMessagesStep = 100;
139
140 InspectorController::InspectorController(Page* page, InspectorClient* client)
141     : m_inspectedPage(page)
142     , m_client(client)
143     , m_openingFrontend(false)
144     , m_cssStore(new InspectorCSSStore(this))
145     , m_mainResourceIdentifier(0)
146     , m_expiredConsoleMessageCount(0)
147     , m_groupLevel(0)
148     , m_previousMessage(0)
149     , m_settingsLoaded(false)
150     , m_inspectorBackend(InspectorBackend::create(this))
151     , m_inspectorBackendDispatcher(new InspectorBackendDispatcher(this))
152     , m_injectedScriptHost(InjectedScriptHost::create(this))
153 #if ENABLE(JAVASCRIPT_DEBUGGER)
154     , m_attachDebuggerWhenShown(false)
155     , m_lastBreakpointId(0)
156     , m_profilerAgent(InspectorProfilerAgent::create(this))
157 #endif
158 {
159     m_state = new InspectorState(client);
160     ASSERT_ARG(page, page);
161     ASSERT_ARG(client, client);
162 }
163
164 InspectorController::~InspectorController()
165 {
166     // These should have been cleared in inspectedPageDestroyed().
167     ASSERT(!m_client);
168     ASSERT(!m_inspectedPage);
169     ASSERT(!m_highlightedNode);
170
171     releaseFrontendLifetimeAgents();
172
173     m_inspectorBackend->disconnectController();
174     m_injectedScriptHost->disconnectController();
175 }
176
177 void InspectorController::inspectedPageDestroyed()
178 {
179     if (m_frontend)
180         m_frontend->disconnectFromBackend();
181
182     hideHighlight();
183
184 #if ENABLE(JAVASCRIPT_DEBUGGER)
185     m_debuggerAgent.clear();
186 #endif
187     ASSERT(m_inspectedPage);
188     m_inspectedPage = 0;
189
190     m_client->inspectorDestroyed();
191     m_client = 0;
192 }
193
194 bool InspectorController::enabled() const
195 {
196     if (!m_inspectedPage)
197         return false;
198     return m_inspectedPage->settings()->developerExtrasEnabled();
199 }
200
201 bool InspectorController::inspectorStartsAttached()
202 {
203     return m_state->getBoolean(InspectorState::inspectorStartsAttached);
204 }
205
206 void InspectorController::setInspectorStartsAttached(bool attached)
207 {
208     m_state->setBoolean(InspectorState::inspectorStartsAttached, attached);
209 }
210
211 void InspectorController::setInspectorAttachedHeight(long height)
212 {
213     m_state->setLong(InspectorState::inspectorAttachedHeight, height);
214 }
215
216 int InspectorController::inspectorAttachedHeight() const
217 {
218     return m_state->getBoolean(InspectorState::inspectorAttachedHeight);
219 }
220
221 bool InspectorController::searchingForNodeInPage() const
222 {
223     return m_state->getBoolean(InspectorState::searchingForNode);
224 }
225
226 void InspectorController::getInspectorState(RefPtr<InspectorObject>* state)
227 {
228 #if ENABLE(JAVASCRIPT_DEBUGGER)
229     if (m_debuggerAgent)
230         m_state->setLong(InspectorState::pauseOnExceptionsState, m_debuggerAgent->pauseOnExceptionsState());
231 #endif
232     *state = m_state->generateStateObjectForFrontend();
233 }
234
235 void InspectorController::restoreInspectorStateFromCookie(const String& inspectorStateCookie)
236 {
237     m_state->restoreFromInspectorCookie(inspectorStateCookie);
238     if (m_state->getBoolean(InspectorState::timelineProfilerEnabled))
239         startTimelineProfiler();
240 }
241
242 void InspectorController::inspect(Node* node)
243 {
244     if (!enabled())
245         return;
246
247     show();
248
249     if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE)
250         node = node->parentNode();
251     m_nodeToFocus = node;
252
253     if (!m_frontend)
254         return;
255
256     focusNode();
257 }
258
259 void InspectorController::focusNode()
260 {
261     if (!enabled())
262         return;
263
264     ASSERT(m_frontend);
265     ASSERT(m_nodeToFocus);
266
267     long id = m_domAgent->pushNodePathToFrontend(m_nodeToFocus.get());
268     m_frontend->updateFocusedNode(id);
269     m_nodeToFocus = 0;
270 }
271
272 void InspectorController::highlight(Node* node)
273 {
274     if (!enabled())
275         return;
276     ASSERT_ARG(node, node);
277     m_highlightedNode = node;
278     m_client->highlight(node);
279 }
280
281 void InspectorController::highlightDOMNode(long nodeId)
282 {
283     Node* node = 0;
284     if (m_domAgent && (node = m_domAgent->nodeForId(nodeId)))
285         highlight(node);
286 }
287
288 void InspectorController::highlightFrame(unsigned long frameId)
289 {
290     Frame* mainFrame = m_inspectedPage->mainFrame();
291     for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext(mainFrame)) {
292         if (reinterpret_cast<uintptr_t>(frame) == frameId && frame->ownerElement()) {
293             highlight(frame->ownerElement());
294             return;
295         }
296     }
297 }
298
299 void InspectorController::hideHighlight()
300 {
301     if (!enabled())
302         return;
303     m_highlightedNode = 0;
304     m_client->hideHighlight();
305 }
306
307 void InspectorController::setConsoleMessagesEnabled(bool enabled, bool* newState)
308 {
309     *newState = enabled;
310     setConsoleMessagesEnabled(enabled);
311 }
312
313 void InspectorController::setConsoleMessagesEnabled(bool enabled)
314 {
315     m_state->setBoolean(InspectorState::consoleMessagesEnabled, enabled);
316     if (!enabled)
317         return;
318
319     if (m_expiredConsoleMessageCount)
320         m_frontend->updateConsoleMessageExpiredCount(m_expiredConsoleMessageCount);
321     unsigned messageCount = m_consoleMessages.size();
322     for (unsigned i = 0; i < messageCount; ++i)
323         m_consoleMessages[i]->addToFrontend(m_frontend.get(), m_injectedScriptHost.get());
324 }
325
326 void InspectorController::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, ScriptCallStack* callStack, const String& message)
327 {
328     if (!enabled())
329         return;
330
331     bool storeStackTrace = type == TraceMessageType || type == UncaughtExceptionMessageType || type == AssertMessageType;
332     addConsoleMessage(new ConsoleMessage(source, type, level, message, callStack, m_groupLevel, storeStackTrace));
333 }
334
335 void InspectorController::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceID)
336 {
337     if (!enabled())
338         return;
339
340     addConsoleMessage(new ConsoleMessage(source, type, level, message, lineNumber, sourceID, m_groupLevel));
341 }
342
343 void InspectorController::addConsoleMessage(PassOwnPtr<ConsoleMessage> consoleMessage)
344 {
345     ASSERT(enabled());
346     ASSERT_ARG(consoleMessage, consoleMessage);
347
348     if (m_previousMessage && m_previousMessage->isEqual(consoleMessage.get())) {
349         m_previousMessage->incrementCount();
350         if (m_state->getBoolean(InspectorState::consoleMessagesEnabled) && m_frontend)
351             m_previousMessage->updateRepeatCountInConsole(m_frontend.get());
352     } else {
353         m_previousMessage = consoleMessage.get();
354         m_consoleMessages.append(consoleMessage);
355         if (m_state->getBoolean(InspectorState::consoleMessagesEnabled) && m_frontend)
356             m_previousMessage->addToFrontend(m_frontend.get(), m_injectedScriptHost.get());
357     }
358
359     if (!m_frontend && m_consoleMessages.size() >= maximumConsoleMessages) {
360         m_expiredConsoleMessageCount += expireConsoleMessagesStep;
361         m_consoleMessages.remove(0, expireConsoleMessagesStep);
362     }
363 }
364
365 void InspectorController::clearConsoleMessages()
366 {
367     m_consoleMessages.clear();
368     m_expiredConsoleMessageCount = 0;
369     m_previousMessage = 0;
370     m_groupLevel = 0;
371     m_injectedScriptHost->releaseWrapperObjectGroup(0 /* release the group in all scripts */, "console");
372     if (m_domAgent)
373         m_domAgent->releaseDanglingNodes();
374     if (m_frontend)
375         m_frontend->consoleMessagesCleared();
376 }
377
378 void InspectorController::startGroup(MessageSource source, ScriptCallStack* callStack, bool collapsed)
379 {
380     ++m_groupLevel;
381
382     addConsoleMessage(new ConsoleMessage(source, collapsed ? StartGroupCollapsedMessageType : StartGroupMessageType, LogMessageLevel, String(), callStack, m_groupLevel));
383 }
384
385 void InspectorController::endGroup(MessageSource source, unsigned lineNumber, const String& sourceURL)
386 {
387     if (!m_groupLevel)
388         return;
389
390     --m_groupLevel;
391
392     addConsoleMessage(new ConsoleMessage(source, EndGroupMessageType, LogMessageLevel, String(), lineNumber, sourceURL, m_groupLevel));
393 }
394
395 void InspectorController::markTimeline(const String& message)
396 {
397     if (timelineAgent())
398         timelineAgent()->didMarkTimeline(message);
399 }
400
401 void InspectorController::mouseDidMoveOverElement(const HitTestResult& result, unsigned)
402 {
403     if (!enabled() || !searchingForNodeInPage())
404         return;
405
406     Node* node = result.innerNode();
407     while (node && node->nodeType() == Node::TEXT_NODE)
408         node = node->parentNode();
409     if (node)
410         highlight(node);
411 }
412
413 void InspectorController::handleMousePress()
414 {
415     if (!enabled())
416         return;
417
418     ASSERT(searchingForNodeInPage());
419     if (!m_highlightedNode)
420         return;
421
422     RefPtr<Node> node = m_highlightedNode;
423     setSearchingForNode(false);
424     inspect(node.get());
425 }
426
427 void InspectorController::setInspectorFrontendClient(PassOwnPtr<InspectorFrontendClient> client)
428 {
429     ASSERT(!m_inspectorFrontendClient);
430     m_inspectorFrontendClient = client;
431 }
432
433 void InspectorController::inspectedWindowScriptObjectCleared(Frame* frame)
434 {
435     // If the page is supposed to serve as InspectorFrontend notify inspetor frontend
436     // client that it's cleared so that the client can expose inspector bindings.
437     if (m_inspectorFrontendClient && frame == m_inspectedPage->mainFrame())
438         m_inspectorFrontendClient->windowObjectCleared();
439
440     if (enabled()) {
441         if (m_frontend && frame == m_inspectedPage->mainFrame())
442             m_injectedScriptHost->discardInjectedScripts();
443         if (m_scriptsToEvaluateOnLoad.size()) {
444             ScriptState* scriptState = mainWorldScriptState(frame);
445             for (Vector<String>::iterator it = m_scriptsToEvaluateOnLoad.begin();
446                  it != m_scriptsToEvaluateOnLoad.end(); ++it) {
447                 m_injectedScriptHost->injectScript(*it, scriptState);
448             }
449         }
450     }
451     if (!m_inspectorExtensionAPI.isEmpty())
452         m_injectedScriptHost->injectScript(m_inspectorExtensionAPI, mainWorldScriptState(frame));
453 }
454
455 void InspectorController::setSearchingForNode(bool enabled)
456 {
457     if (searchingForNodeInPage() == enabled)
458         return;
459     m_state->setBoolean(InspectorState::searchingForNode, enabled);
460     if (!enabled)
461         hideHighlight();
462 }
463
464 void InspectorController::setSearchingForNode(bool enabled, bool* newState)
465 {
466     *newState = enabled;
467     setSearchingForNode(enabled);
468 }
469
470 void InspectorController::setMonitoringXHREnabled(bool enabled, bool* newState)
471 {
472     *newState = enabled;
473     m_state->setBoolean(InspectorState::monitoringXHR, enabled);
474 }
475
476 void InspectorController::connectFrontend()
477 {
478     m_openingFrontend = false;
479     releaseFrontendLifetimeAgents();
480     m_frontend = new InspectorFrontend(m_client);
481     m_domAgent = InspectorDOMAgent::create(m_cssStore.get(), m_frontend.get());
482     m_resourceAgent = InspectorResourceAgent::create(m_inspectedPage, m_frontend.get());
483
484 #if ENABLE(DATABASE)
485     m_storageAgent = InspectorStorageAgent::create(m_frontend.get());
486 #endif
487
488     if (m_timelineAgent)
489         m_timelineAgent->resetFrontendProxyObject(m_frontend.get());
490
491     // Initialize Web Inspector title.
492     m_frontend->inspectedURLChanged(m_inspectedPage->mainFrame()->loader()->url().string());
493
494 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
495     m_applicationCacheAgent = new InspectorApplicationCacheAgent(this, m_frontend.get());
496 #endif
497
498 #if ENABLE(FILE_SYSTEM)
499     m_fileSystemAgent = InspectorFileSystemAgent::create(this, m_frontend.get());
500 #endif
501     
502     if (!InspectorInstrumentation::hasFrontends())
503         ScriptController::setCaptureCallStackForUncaughtExceptions(true);
504     InspectorInstrumentation::frontendCreated();
505 }
506
507 void InspectorController::reuseFrontend()
508 {
509     connectFrontend();
510     restoreDebugger();
511     restoreProfiler();
512 }
513
514 void InspectorController::show()
515 {
516     if (!enabled())
517         return;
518
519     if (m_openingFrontend)
520         return;
521
522     if (m_frontend)
523         m_frontend->bringToFront();
524     else {
525         m_openingFrontend = true;
526         m_client->openInspectorFrontend(this);
527     }
528 }
529
530 void InspectorController::showPanel(const String& panel)
531 {
532     if (!enabled())
533         return;
534
535     show();
536
537     if (!m_frontend) {
538         m_showAfterVisible = panel;
539         return;
540     }
541     m_frontend->showPanel(panel);
542 }
543
544 void InspectorController::close()
545 {
546     if (!m_frontend)
547         return;
548     m_frontend->disconnectFromBackend();
549     disconnectFrontend();
550 }
551
552 void InspectorController::disconnectFrontend()
553 {
554     if (!m_frontend)
555         return;
556
557     m_frontend.clear();
558
559     InspectorInstrumentation::frontendDeleted();
560     if (!InspectorInstrumentation::hasFrontends())
561         ScriptController::setCaptureCallStackForUncaughtExceptions(false);
562
563 #if ENABLE(JAVASCRIPT_DEBUGGER)
564     // If the window is being closed with the debugger enabled,
565     // remember this state to re-enable debugger on the next window
566     // opening.
567     bool debuggerWasEnabled = debuggerEnabled();
568     disableDebugger();
569     m_attachDebuggerWhenShown = debuggerWasEnabled;
570     clearNativeBreakpoints();
571 #endif
572     setSearchingForNode(false);
573     unbindAllResources();
574     stopTimelineProfiler();
575
576     hideHighlight();
577
578 #if ENABLE(JAVASCRIPT_DEBUGGER)
579     m_profilerAgent->setFrontend(0);
580     m_profilerAgent->stopUserInitiatedProfiling();
581 #endif
582
583     releaseFrontendLifetimeAgents();
584     m_timelineAgent.clear();
585 }
586
587 void InspectorController::releaseFrontendLifetimeAgents()
588 {
589     m_resourceAgent.clear();
590
591     // m_domAgent is RefPtr. Remove DOM listeners first to ensure that there are
592     // no references to the DOM agent from the DOM tree.
593     if (m_domAgent)
594         m_domAgent->reset();
595     m_domAgent.clear();
596
597 #if ENABLE(DATABASE)
598     if (m_storageAgent)
599         m_storageAgent->clearFrontend();
600     m_storageAgent.clear();
601 #endif
602
603 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
604     m_applicationCacheAgent.clear();
605 #endif
606
607 #if ENABLE(FILE_SYSTEM)
608     if (m_fileSystemAgent)
609         m_fileSystemAgent->stop(); 
610         m_fileSystemAgent.clear();
611 #endif
612 }
613
614 void InspectorController::populateScriptObjects()
615 {
616     ASSERT(m_frontend);
617     if (!m_frontend)
618         return;
619
620     if (!m_showAfterVisible.isEmpty()) {
621         showPanel(m_showAfterVisible);
622         m_showAfterVisible = "";
623     }
624
625 #if ENABLE(JAVASCRIPT_DEBUGGER)
626     if (m_profilerAgent->enabled())
627         m_frontend->profilerWasEnabled();
628 #endif
629
630     m_domAgent->setDocument(m_inspectedPage->mainFrame()->document());
631
632     if (m_nodeToFocus)
633         focusNode();
634
635 #if ENABLE(DATABASE)
636     DatabaseResourcesMap::iterator databasesEnd = m_databaseResources.end();
637     for (DatabaseResourcesMap::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it)
638         it->second->bind(m_frontend.get());
639 #endif
640 #if ENABLE(DOM_STORAGE)
641     DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources.end();
642     for (DOMStorageResourcesMap::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it)
643         it->second->bind(m_frontend.get());
644 #endif
645 #if ENABLE(WORKERS)
646     WorkersMap::iterator workersEnd = m_workers.end();
647     for (WorkersMap::iterator it = m_workers.begin(); it != workersEnd; ++it) {
648         InspectorWorkerResource* worker = it->second.get();
649         m_frontend->didCreateWorker(worker->id(), worker->url(), worker->isSharedWorker());
650     }
651 #endif
652
653     // Dispatch pending frontend commands
654     for (Vector<pair<long, String> >::iterator it = m_pendingEvaluateTestCommands.begin(); it != m_pendingEvaluateTestCommands.end(); ++it)
655         m_frontend->evaluateForTestInFrontend((*it).first, (*it).second);
656     m_pendingEvaluateTestCommands.clear();
657
658     restoreDebugger();
659     restoreProfiler();
660 }
661
662 void InspectorController::restoreDebugger()
663 {
664     ASSERT(m_frontend);
665 #if ENABLE(JAVASCRIPT_DEBUGGER)
666     if (InspectorDebuggerAgent::isDebuggerAlwaysEnabled())
667         enableDebuggerFromFrontend(false);
668     else {
669         if (m_state->getBoolean(InspectorState::debuggerAlwaysEnabled) || m_attachDebuggerWhenShown)
670             enableDebugger();
671     }
672 #endif
673 }
674
675 void InspectorController::restoreProfiler()
676 {
677     ASSERT(m_frontend);
678 #if ENABLE(JAVASCRIPT_DEBUGGER)
679     m_profilerAgent->setFrontend(m_frontend.get());
680     if (!ScriptProfiler::isProfilerAlwaysEnabled() && m_state->getBoolean(InspectorState::profilerAlwaysEnabled))
681         enableProfiler();
682 #endif
683 }
684
685 void InspectorController::unbindAllResources()
686 {
687 #if ENABLE(DATABASE)
688     DatabaseResourcesMap::iterator databasesEnd = m_databaseResources.end();
689     for (DatabaseResourcesMap::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it)
690         it->second->unbind();
691 #endif
692 #if ENABLE(DOM_STORAGE)
693     DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources.end();
694     for (DOMStorageResourcesMap::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it)
695         it->second->unbind();
696 #endif
697     if (m_timelineAgent)
698         m_timelineAgent->reset();
699 }
700
701 void InspectorController::didCommitLoad(DocumentLoader* loader)
702 {
703     if (!enabled())
704         return;
705
706     if (m_resourceAgent)
707         m_resourceAgent->didCommitLoad(loader);
708     
709     ASSERT(m_inspectedPage);
710
711     if (loader->frame() == m_inspectedPage->mainFrame()) {
712         if (m_frontend)
713             m_frontend->inspectedURLChanged(loader->url().string());
714
715         m_injectedScriptHost->discardInjectedScripts();
716         clearConsoleMessages();
717
718         m_times.clear();
719         m_counts.clear();
720
721 #if ENABLE(JAVASCRIPT_DEBUGGER)
722         if (m_debuggerAgent)
723             m_debuggerAgent->clearForPageNavigation();
724
725         clearNativeBreakpoints();
726 #endif
727
728 #if ENABLE(JAVASCRIPT_DEBUGGER) && USE(JSC)
729         m_profilerAgent->resetState();
730 #endif
731
732         // unbindAllResources should be called before database and DOM storage
733         // resources are cleared so that it has a chance to unbind them.
734         unbindAllResources();
735
736         m_cssStore->reset();
737         if (m_frontend) {
738             m_frontend->reset();
739             m_domAgent->reset();
740         }
741 #if ENABLE(WORKERS)
742         m_workers.clear();
743 #endif
744 #if ENABLE(DATABASE)
745         m_databaseResources.clear();
746 #endif
747 #if ENABLE(DOM_STORAGE)
748         m_domStorageResources.clear();
749 #endif
750
751         if (m_frontend) {
752             m_mainResourceIdentifier = 0;
753             m_frontend->didCommitLoad();
754             m_domAgent->setDocument(m_inspectedPage->mainFrame()->document());
755         }
756     }
757 }
758
759 void InspectorController::frameDetachedFromParent(Frame* rootFrame)
760 {
761     if (!enabled())
762         return;
763
764     if (m_resourceAgent)
765         m_resourceAgent->frameDetachedFromParent(rootFrame);
766 }
767
768 void InspectorController::didLoadResourceFromMemoryCache(DocumentLoader* loader, const CachedResource* cachedResource)
769 {
770     if (!enabled())
771         return;
772
773     ensureSettingsLoaded();
774
775     if (m_resourceAgent)
776         m_resourceAgent->didLoadResourceFromMemoryCache(loader, cachedResource);
777 }
778
779 void InspectorController::identifierForInitialRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request)
780 {
781     if (!enabled())
782         return;
783     ASSERT(m_inspectedPage);
784
785     bool isMainResource = isMainResourceLoader(loader, request.url());
786     if (isMainResource)
787         m_mainResourceIdentifier = identifier;
788
789     ensureSettingsLoaded();
790
791     if (m_resourceAgent)
792         m_resourceAgent->identifierForInitialRequest(identifier, request.url(), loader);
793 }
794
795 void InspectorController::mainResourceFiredDOMContentEvent(DocumentLoader* loader, const KURL& url)
796 {
797     if (!enabled() || !isMainResourceLoader(loader, url))
798         return;
799
800     if (m_timelineAgent)
801         m_timelineAgent->didMarkDOMContentEvent();
802     if (m_frontend)
803         m_frontend->domContentEventFired(currentTime());
804 }
805
806 void InspectorController::mainResourceFiredLoadEvent(DocumentLoader* loader, const KURL& url)
807 {
808     if (!enabled() || !isMainResourceLoader(loader, url))
809         return;
810
811     if (m_timelineAgent)
812         m_timelineAgent->didMarkLoadEvent();
813     if (m_frontend)
814         m_frontend->loadEventFired(currentTime());
815 }
816
817 bool InspectorController::isMainResourceLoader(DocumentLoader* loader, const KURL& requestUrl)
818 {
819     return loader->frame() == m_inspectedPage->mainFrame() && requestUrl == loader->requestURL();
820 }
821
822 void InspectorController::willSendRequest(unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse)
823 {
824     if (!enabled())
825         return;
826
827     request.setReportLoadTiming(true);
828     // Only enable raw headers if front-end is attached, as otherwise we may lack
829     // permissions to fetch the headers.
830     if (m_frontend)
831         request.setReportRawHeaders(true);
832
833     bool isMainResource = m_mainResourceIdentifier == identifier;
834
835     if (m_timelineAgent)
836         m_timelineAgent->willSendResourceRequest(identifier, isMainResource, request);
837
838     if (m_resourceAgent)
839         m_resourceAgent->willSendRequest(identifier, request, redirectResponse);
840 }
841
842 void InspectorController::markResourceAsCached(unsigned long identifier)
843 {
844     if (!enabled())
845         return;
846
847     if (m_resourceAgent)
848         m_resourceAgent->markResourceAsCached(identifier);
849 }
850
851 void InspectorController::didReceiveResponse(unsigned long identifier, DocumentLoader* loader, const ResourceResponse& response)
852 {
853     if (!enabled())
854         return;
855
856     if (m_resourceAgent)
857         m_resourceAgent->didReceiveResponse(identifier, loader, response);
858
859     if (response.httpStatusCode() >= 400) {
860         String message = makeString("Failed to load resource: the server responded with a status of ", String::number(response.httpStatusCode()), " (", response.httpStatusText(), ')');
861         addMessageToConsole(OtherMessageSource, LogMessageType, ErrorMessageLevel, message, 0, response.url().string());
862     }
863 }
864
865 void InspectorController::didReceiveContentLength(unsigned long identifier, int lengthReceived)
866 {
867     if (!enabled())
868         return;
869
870     if (m_resourceAgent)
871         m_resourceAgent->didReceiveContentLength(identifier, lengthReceived);
872 }
873
874 void InspectorController::didFinishLoading(unsigned long identifier, double finishTime)
875 {
876     if (!enabled())
877         return;
878
879     if (m_timelineAgent)
880         m_timelineAgent->didFinishLoadingResource(identifier, false, finishTime);
881
882     if (m_resourceAgent)
883         m_resourceAgent->didFinishLoading(identifier, finishTime);
884 }
885
886 void InspectorController::didFailLoading(unsigned long identifier, const ResourceError& error)
887 {
888     if (!enabled())
889         return;
890
891     if (m_timelineAgent)
892         m_timelineAgent->didFinishLoadingResource(identifier, true, 0);
893
894     String message = "Failed to load resource";
895         if (!error.localizedDescription().isEmpty())
896             message += ": " + error.localizedDescription();
897         addMessageToConsole(OtherMessageSource, LogMessageType, ErrorMessageLevel, message, 0, error.failingURL());
898
899     if (m_resourceAgent)
900         m_resourceAgent->didFailLoading(identifier, error);
901 }
902
903 void InspectorController::resourceRetrievedByXMLHttpRequest(unsigned long identifier, const String& sourceString, const String& url, const String& sendURL, unsigned sendLineNumber)
904 {
905     if (!enabled())
906         return;
907
908     if (m_state->getBoolean(InspectorState::monitoringXHR))
909         addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, "XHR finished loading: \"" + url + "\".", sendLineNumber, sendURL);
910
911     if (m_resourceAgent)
912         m_resourceAgent->setOverrideContent(identifier, sourceString, "XHR");
913 }
914
915 void InspectorController::scriptImported(unsigned long identifier, const String& sourceString)
916 {
917     if (!enabled())
918         return;
919
920     if (m_resourceAgent)
921         m_resourceAgent->setOverrideContent(identifier, sourceString, "Script");
922 }
923
924 void InspectorController::ensureSettingsLoaded()
925 {
926     if (m_settingsLoaded)
927         return;
928     m_settingsLoaded = true;
929
930     m_state->loadFromSettings();
931
932     if (m_state->getBoolean(InspectorState::resourceTrackingAlwaysEnabled))
933         m_state->setBoolean(InspectorState::resourceTrackingEnabled, true);
934 }
935
936 void InspectorController::startTimelineProfiler()
937 {
938     if (!enabled())
939         return;
940
941     if (m_timelineAgent)
942         return;
943
944     m_timelineAgent = new InspectorTimelineAgent(m_frontend.get());
945     if (m_frontend)
946         m_frontend->timelineProfilerWasStarted();
947
948     m_state->setBoolean(InspectorState::timelineProfilerEnabled, true);
949 }
950
951 void InspectorController::stopTimelineProfiler()
952 {
953     if (!enabled())
954         return;
955
956     if (!m_timelineAgent)
957         return;
958
959     m_timelineAgent = 0;
960     if (m_frontend)
961         m_frontend->timelineProfilerWasStopped();
962
963     m_state->setBoolean(InspectorState::timelineProfilerEnabled, false);
964 }
965
966 #if ENABLE(WORKERS)
967 class PostWorkerNotificationToFrontendTask : public ScriptExecutionContext::Task {
968 public:
969     static PassOwnPtr<PostWorkerNotificationToFrontendTask> create(PassRefPtr<InspectorWorkerResource> worker, InspectorController::WorkerAction action)
970     {
971         return new PostWorkerNotificationToFrontendTask(worker, action);
972     }
973
974 private:
975     PostWorkerNotificationToFrontendTask(PassRefPtr<InspectorWorkerResource> worker, InspectorController::WorkerAction action)
976         : m_worker(worker)
977         , m_action(action)
978     {
979     }
980
981     virtual void performTask(ScriptExecutionContext* scriptContext)
982     {
983         if (InspectorController* inspector = scriptContext->inspectorController())
984             inspector->postWorkerNotificationToFrontend(*m_worker, m_action);
985     }
986
987 private:
988     RefPtr<InspectorWorkerResource> m_worker;
989     InspectorController::WorkerAction m_action;
990 };
991
992 void InspectorController::postWorkerNotificationToFrontend(const InspectorWorkerResource& worker, InspectorController::WorkerAction action)
993 {
994     if (!m_frontend)
995         return;
996     switch (action) {
997     case InspectorController::WorkerCreated:
998         m_frontend->didCreateWorker(worker.id(), worker.url(), worker.isSharedWorker());
999         break;
1000     case InspectorController::WorkerDestroyed:
1001         m_frontend->didDestroyWorker(worker.id());
1002         break;
1003     }
1004 }
1005
1006 void InspectorController::didCreateWorker(intptr_t id, const String& url, bool isSharedWorker)
1007 {
1008     if (!enabled())
1009         return;
1010
1011     RefPtr<InspectorWorkerResource> workerResource(InspectorWorkerResource::create(id, url, isSharedWorker));
1012     m_workers.set(id, workerResource);
1013     if (m_inspectedPage && m_frontend)
1014         m_inspectedPage->mainFrame()->document()->postTask(PostWorkerNotificationToFrontendTask::create(workerResource, InspectorController::WorkerCreated));
1015 }
1016
1017 void InspectorController::didDestroyWorker(intptr_t id)
1018 {
1019     if (!enabled())
1020         return;
1021
1022     WorkersMap::iterator workerResource = m_workers.find(id);
1023     if (workerResource == m_workers.end())
1024         return;
1025     if (m_inspectedPage && m_frontend)
1026         m_inspectedPage->mainFrame()->document()->postTask(PostWorkerNotificationToFrontendTask::create(workerResource->second, InspectorController::WorkerDestroyed));
1027     m_workers.remove(workerResource);
1028 }
1029 #endif // ENABLE(WORKERS)
1030
1031 #if ENABLE(DATABASE)
1032 void InspectorController::selectDatabase(Database* database)
1033 {
1034     if (!m_frontend)
1035         return;
1036
1037     for (DatabaseResourcesMap::iterator it = m_databaseResources.begin(); it != m_databaseResources.end(); ++it) {
1038         if (it->second->database() == database) {
1039             m_frontend->selectDatabase(it->first);
1040             break;
1041         }
1042     }
1043 }
1044
1045 Database* InspectorController::databaseForId(long databaseId)
1046 {
1047     DatabaseResourcesMap::iterator it = m_databaseResources.find(databaseId);
1048     if (it == m_databaseResources.end())
1049         return 0;
1050     return it->second->database();
1051 }
1052
1053 void InspectorController::didOpenDatabase(PassRefPtr<Database> database, const String& domain, const String& name, const String& version)
1054 {
1055     if (!enabled())
1056         return;
1057
1058     RefPtr<InspectorDatabaseResource> resource = InspectorDatabaseResource::create(database, domain, name, version);
1059
1060     m_databaseResources.set(resource->id(), resource);
1061
1062     // Resources are only bound while visible.
1063     if (m_frontend)
1064         resource->bind(m_frontend.get());
1065 }
1066 #endif
1067
1068 void InspectorController::getCookies(RefPtr<InspectorArray>* cookies, WTF::String* cookiesString)
1069 {
1070     // If we can get raw cookies.
1071     ListHashSet<Cookie> rawCookiesList;
1072
1073     // If we can't get raw cookies - fall back to String representation
1074     String stringCookiesList;
1075
1076     // Return value to getRawCookies should be the same for every call because
1077     // the return value is platform/network backend specific, and the call will
1078     // always return the same true/false value.
1079     bool rawCookiesImplemented = false;
1080
1081     for (Frame* frame = m_inspectedPage->mainFrame(); frame; frame = frame->tree()->traverseNext(m_inspectedPage->mainFrame())) {
1082         Document* document = frame->document();
1083         const CachedResourceLoader::DocumentResourceMap& allResources = document->cachedResourceLoader()->allCachedResources();
1084         CachedResourceLoader::DocumentResourceMap::const_iterator end = allResources.end();
1085         for (CachedResourceLoader::DocumentResourceMap::const_iterator it = allResources.begin(); it != end; ++it) {
1086             Vector<Cookie> docCookiesList;
1087             rawCookiesImplemented = getRawCookies(document, KURL(ParsedURLString, it->second->url()), docCookiesList);
1088
1089             if (!rawCookiesImplemented) {
1090                 // FIXME: We need duplication checking for the String representation of cookies.
1091                 ExceptionCode ec = 0;
1092                 stringCookiesList += document->cookie(ec);
1093                 // Exceptions are thrown by cookie() in sandboxed frames. That won't happen here
1094                 // because "document" is the document of the main frame of the page.
1095                 ASSERT(!ec);
1096             } else {
1097                 int cookiesSize = docCookiesList.size();
1098                 for (int i = 0; i < cookiesSize; i++) {
1099                     if (!rawCookiesList.contains(docCookiesList[i]))
1100                         rawCookiesList.add(docCookiesList[i]);
1101                 }
1102             }
1103         }
1104     }
1105
1106     if (rawCookiesImplemented)
1107         *cookies = buildArrayForCookies(rawCookiesList);
1108     else
1109         *cookiesString = stringCookiesList;
1110 }
1111
1112 PassRefPtr<InspectorArray> InspectorController::buildArrayForCookies(ListHashSet<Cookie>& cookiesList)
1113 {
1114     RefPtr<InspectorArray> cookies = InspectorArray::create();
1115
1116     ListHashSet<Cookie>::iterator end = cookiesList.end();
1117     ListHashSet<Cookie>::iterator it = cookiesList.begin();
1118     for (int i = 0; it != end; ++it, i++)
1119         cookies->pushObject(buildObjectForCookie(*it));
1120
1121     return cookies;
1122 }
1123
1124 PassRefPtr<InspectorObject> InspectorController::buildObjectForCookie(const Cookie& cookie)
1125 {
1126     RefPtr<InspectorObject> value = InspectorObject::create();
1127     value->setString("name", cookie.name);
1128     value->setString("value", cookie.value);
1129     value->setString("domain", cookie.domain);
1130     value->setString("path", cookie.path);
1131     value->setNumber("expires", cookie.expires);
1132     value->setNumber("size", (cookie.name.length() + cookie.value.length()));
1133     value->setBoolean("httpOnly", cookie.httpOnly);
1134     value->setBoolean("secure", cookie.secure);
1135     value->setBoolean("session", cookie.session);
1136     return value;
1137 }
1138
1139 void InspectorController::deleteCookie(const String& cookieName, const String& domain)
1140 {
1141     for (Frame* frame = m_inspectedPage->mainFrame(); frame; frame = frame->tree()->traverseNext(m_inspectedPage->mainFrame())) {
1142         Document* document = frame->document();
1143         if (document->url().host() != domain)
1144             continue;
1145         const CachedResourceLoader::DocumentResourceMap& allResources = document->cachedResourceLoader()->allCachedResources();
1146         CachedResourceLoader::DocumentResourceMap::const_iterator end = allResources.end();
1147         for (CachedResourceLoader::DocumentResourceMap::const_iterator it = allResources.begin(); it != end; ++it)
1148             WebCore::deleteCookie(document, KURL(ParsedURLString, it->second->url()), cookieName);
1149     }
1150 }
1151
1152 #if ENABLE(DOM_STORAGE)
1153 void InspectorController::didUseDOMStorage(StorageArea* storageArea, bool isLocalStorage, Frame* frame)
1154 {
1155     if (!enabled())
1156         return;
1157
1158     DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources.end();
1159     for (DOMStorageResourcesMap::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it)
1160         if (it->second->isSameHostAndType(frame, isLocalStorage))
1161             return;
1162
1163     RefPtr<Storage> domStorage = Storage::create(frame, storageArea);
1164     RefPtr<InspectorDOMStorageResource> resource = InspectorDOMStorageResource::create(domStorage.get(), isLocalStorage, frame);
1165
1166     m_domStorageResources.set(resource->id(), resource);
1167
1168     // Resources are only bound while visible.
1169     if (m_frontend)
1170         resource->bind(m_frontend.get());
1171 }
1172
1173 void InspectorController::selectDOMStorage(Storage* storage)
1174 {
1175     ASSERT(storage);
1176     if (!m_frontend)
1177         return;
1178
1179     Frame* frame = storage->frame();
1180     ExceptionCode ec = 0;
1181     bool isLocalStorage = (frame->domWindow()->localStorage(ec) == storage && !ec);
1182     long storageResourceId = 0;
1183     DOMStorageResourcesMap::iterator domStorageEnd = m_domStorageResources.end();
1184     for (DOMStorageResourcesMap::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it) {
1185         if (it->second->isSameHostAndType(frame, isLocalStorage)) {
1186             storageResourceId = it->first;
1187             break;
1188         }
1189     }
1190     if (storageResourceId)
1191         m_frontend->selectDOMStorage(storageResourceId);
1192 }
1193
1194 void InspectorController::getDOMStorageEntries(long storageId, RefPtr<InspectorArray>* entries)
1195 {
1196     InspectorDOMStorageResource* storageResource = getDOMStorageResourceForId(storageId);
1197     if (storageResource) {
1198         storageResource->startReportingChangesToFrontend();
1199         Storage* domStorage = storageResource->domStorage();
1200         for (unsigned i = 0; i < domStorage->length(); ++i) {
1201             String name(domStorage->key(i));
1202             String value(domStorage->getItem(name));
1203             RefPtr<InspectorArray> entry = InspectorArray::create();
1204             entry->pushString(name);
1205             entry->pushString(value);
1206             (*entries)->pushArray(entry);
1207         }
1208     }
1209 }
1210
1211 void InspectorController::setDOMStorageItem(long storageId, const String& key, const String& value, bool* success)
1212 {
1213     InspectorDOMStorageResource* storageResource = getDOMStorageResourceForId(storageId);
1214     if (storageResource) {
1215         ExceptionCode exception = 0;
1216         storageResource->domStorage()->setItem(key, value, exception);
1217         *success = !exception;
1218     }
1219 }
1220
1221 void InspectorController::removeDOMStorageItem(long storageId, const String& key, bool* success)
1222 {
1223     InspectorDOMStorageResource* storageResource = getDOMStorageResourceForId(storageId);
1224     if (storageResource) {
1225         storageResource->domStorage()->removeItem(key);
1226         *success = true;
1227     }
1228 }
1229
1230 InspectorDOMStorageResource* InspectorController::getDOMStorageResourceForId(long storageId)
1231 {
1232     DOMStorageResourcesMap::iterator it = m_domStorageResources.find(storageId);
1233     if (it == m_domStorageResources.end())
1234         return 0;
1235     return it->second.get();
1236 }
1237 #endif
1238
1239 #if ENABLE(WEB_SOCKETS)
1240 void InspectorController::didCreateWebSocket(unsigned long identifier, const KURL& requestURL, const KURL& documentURL)
1241 {
1242     if (!enabled())
1243         return;
1244     ASSERT(m_inspectedPage);
1245
1246     if (m_resourceAgent)
1247         m_resourceAgent->didCreateWebSocket(identifier, requestURL);
1248     UNUSED_PARAM(documentURL);
1249 }
1250
1251 void InspectorController::willSendWebSocketHandshakeRequest(unsigned long identifier, const WebSocketHandshakeRequest& request)
1252 {
1253     if (m_resourceAgent)
1254         m_resourceAgent->willSendWebSocketHandshakeRequest(identifier, request);
1255 }
1256
1257 void InspectorController::didReceiveWebSocketHandshakeResponse(unsigned long identifier, const WebSocketHandshakeResponse& response)
1258 {
1259     if (m_resourceAgent)
1260         m_resourceAgent->didReceiveWebSocketHandshakeResponse(identifier, response);
1261 }
1262
1263 void InspectorController::didCloseWebSocket(unsigned long identifier)
1264 {
1265     if (m_resourceAgent)
1266         m_resourceAgent->didCloseWebSocket(identifier);
1267 }
1268 #endif // ENABLE(WEB_SOCKETS)
1269
1270 #if ENABLE(JAVASCRIPT_DEBUGGER)
1271 void InspectorController::addProfile(PassRefPtr<ScriptProfile> prpProfile, unsigned lineNumber, const String& sourceURL)
1272 {
1273     if (!enabled())
1274         return;
1275     m_profilerAgent->addProfile(prpProfile, lineNumber, sourceURL);
1276 }
1277
1278 void InspectorController::addProfileFinishedMessageToConsole(PassRefPtr<ScriptProfile> prpProfile, unsigned lineNumber, const String& sourceURL)
1279 {
1280     m_profilerAgent->addProfileFinishedMessageToConsole(prpProfile, lineNumber, sourceURL);
1281 }
1282
1283 void InspectorController::addStartProfilingMessageToConsole(const String& title, unsigned lineNumber, const String& sourceURL)
1284 {
1285     m_profilerAgent->addStartProfilingMessageToConsole(title, lineNumber, sourceURL);
1286 }
1287
1288
1289 bool InspectorController::isRecordingUserInitiatedProfile() const
1290 {
1291     return m_profilerAgent->isRecordingUserInitiatedProfile();
1292 }
1293
1294 String InspectorController::getCurrentUserInitiatedProfileName(bool incrementProfileNumber)
1295 {
1296     return m_profilerAgent->getCurrentUserInitiatedProfileName(incrementProfileNumber);
1297 }
1298
1299 void InspectorController::startUserInitiatedProfiling()
1300 {
1301     if (!enabled())
1302         return;
1303     m_profilerAgent->startUserInitiatedProfiling();
1304 }
1305
1306 void InspectorController::stopUserInitiatedProfiling()
1307 {
1308     if (!enabled())
1309         return;
1310     m_profilerAgent->stopUserInitiatedProfiling();
1311 }
1312
1313 bool InspectorController::profilerEnabled() const
1314 {
1315     return enabled() && m_profilerAgent->enabled();
1316 }
1317
1318 void InspectorController::enableProfiler(bool always, bool skipRecompile)
1319 {
1320     if (always)
1321         m_state->setBoolean(InspectorState::profilerAlwaysEnabled, true);
1322     m_profilerAgent->enable(skipRecompile);
1323 }
1324
1325 void InspectorController::disableProfiler(bool always)
1326 {
1327     if (always)
1328         m_state->setBoolean(InspectorState::profilerAlwaysEnabled, false);
1329     m_profilerAgent->disable();
1330 }
1331 #endif
1332
1333 #if ENABLE(JAVASCRIPT_DEBUGGER)
1334 void InspectorController::enableDebuggerFromFrontend(bool always)
1335 {
1336     ASSERT(!debuggerEnabled());
1337     if (always)
1338         m_state->setBoolean(InspectorState::debuggerAlwaysEnabled, true);
1339
1340     ASSERT(m_inspectedPage);
1341
1342     m_debuggerAgent = InspectorDebuggerAgent::create(this, m_frontend.get());
1343
1344     m_frontend->debuggerWasEnabled();
1345 }
1346
1347 void InspectorController::enableDebugger()
1348 {
1349     if (!enabled())
1350         return;
1351
1352     if (debuggerEnabled())
1353         return;
1354
1355     if (!m_frontend)
1356         m_attachDebuggerWhenShown = true;
1357     else {
1358         m_frontend->attachDebuggerWhenShown();
1359         m_attachDebuggerWhenShown = false;
1360     }
1361 }
1362
1363 void InspectorController::disableDebugger(bool always)
1364 {
1365     if (!enabled())
1366         return;
1367
1368     if (always)
1369         m_state->setBoolean(InspectorState::debuggerAlwaysEnabled, false);
1370
1371     ASSERT(m_inspectedPage);
1372
1373     m_debuggerAgent.clear();
1374
1375     m_attachDebuggerWhenShown = false;
1376
1377     if (m_frontend)
1378         m_frontend->debuggerWasDisabled();
1379 }
1380
1381 void InspectorController::resume()
1382 {
1383     if (m_debuggerAgent)
1384         m_debuggerAgent->resume();
1385 }
1386
1387 void InspectorController::setNativeBreakpoint(PassRefPtr<InspectorObject> breakpoint, String* breakpointId)
1388 {
1389     *breakpointId = "";
1390     String type;
1391     if (!breakpoint->getString("type", &type))
1392         return;
1393     RefPtr<InspectorObject> condition = breakpoint->getObject("condition");
1394     if (!condition)
1395         return;
1396     if (type == xhrNativeBreakpointType) {
1397         String url;
1398         if (!condition->getString("url", &url))
1399             return;
1400         *breakpointId = String::number(++m_lastBreakpointId);
1401         m_XHRBreakpoints.set(*breakpointId, url);
1402         m_nativeBreakpoints.set(*breakpointId, type);
1403     } else if (type == eventListenerNativeBreakpointType) {
1404         String eventName;
1405         if (!condition->getString("eventName", &eventName))
1406             return;
1407         if (m_eventListenerBreakpoints.contains(eventName))
1408             return;
1409         *breakpointId = eventName;
1410         m_eventListenerBreakpoints.add(eventName);
1411         m_nativeBreakpoints.set(*breakpointId, type);
1412     } else if (type == domNativeBreakpointType) {
1413         if (!m_domAgent)
1414             return;
1415         double nodeIdNumber;
1416         if (!condition->getNumber("nodeId", &nodeIdNumber))
1417             return;
1418         double domBreakpointTypeNumber;
1419         if (!condition->getNumber("type", &domBreakpointTypeNumber))
1420             return;
1421         long nodeId = (long) nodeIdNumber;
1422         long domBreakpointType = (long) domBreakpointTypeNumber;
1423         *breakpointId = m_domAgent->setDOMBreakpoint(nodeId, domBreakpointType);
1424         if (!breakpointId->isEmpty())
1425             m_nativeBreakpoints.set(*breakpointId, type);
1426     }
1427 }
1428
1429 void InspectorController::removeNativeBreakpoint(const String& breakpointId)
1430 {
1431     String type = m_nativeBreakpoints.take(breakpointId);
1432     if (type == xhrNativeBreakpointType)
1433         m_XHRBreakpoints.remove(breakpointId);
1434     else if (type == eventListenerNativeBreakpointType)
1435         m_eventListenerBreakpoints.remove(breakpointId);
1436     else if (type == domNativeBreakpointType) {
1437         if (m_domAgent)
1438             m_domAgent->removeDOMBreakpoint(breakpointId);
1439     }
1440 }
1441
1442 String InspectorController::findEventListenerBreakpoint(const String& eventName)
1443 {
1444     return m_eventListenerBreakpoints.contains(eventName) ? eventName : "";
1445 }
1446
1447 String InspectorController::findXHRBreakpoint(const String& url)
1448 {
1449     for (HashMap<String, String>::iterator it = m_XHRBreakpoints.begin(); it != m_XHRBreakpoints.end(); ++it) {
1450         if (url.contains(it->second))
1451             return it->first;
1452     }
1453     return "";
1454 }
1455
1456 void InspectorController::clearNativeBreakpoints()
1457 {
1458     m_nativeBreakpoints.clear();
1459     m_eventListenerBreakpoints.clear();
1460     m_XHRBreakpoints.clear();
1461     m_lastBreakpointId = 0;
1462 }
1463 #endif
1464
1465 void InspectorController::evaluateForTestInFrontend(long callId, const String& script)
1466 {
1467     if (m_frontend)
1468         m_frontend->evaluateForTestInFrontend(callId, script);
1469     else
1470         m_pendingEvaluateTestCommands.append(pair<long, String>(callId, script));
1471 }
1472
1473 void InspectorController::didEvaluateForTestInFrontend(long callId, const String& jsonResult)
1474 {
1475     ScriptState* scriptState = scriptStateFromPage(debuggerWorld(), m_inspectedPage);
1476     ScriptObject window;
1477     ScriptGlobalObject::get(scriptState, "window", window);
1478     ScriptFunctionCall function(window, "didEvaluateForTestInFrontend");
1479     function.appendArgument(callId);
1480     function.appendArgument(jsonResult);
1481     function.call();
1482 }
1483
1484 #if ENABLE(JAVASCRIPT_DEBUGGER)
1485 String InspectorController::breakpointsSettingKey()
1486 {
1487     DEFINE_STATIC_LOCAL(String, keyPrefix, ("breakpoints:"));
1488     return keyPrefix + InspectorDebuggerAgent::md5Base16(m_inspectedPage->mainFrame()->loader()->url().string());
1489 }
1490
1491 PassRefPtr<InspectorValue> InspectorController::loadBreakpoints()
1492 {
1493     String jsonString;
1494     m_client->populateSetting(breakpointsSettingKey(), &jsonString);
1495     return InspectorValue::parseJSON(jsonString);
1496 }
1497
1498 void InspectorController::saveBreakpoints(PassRefPtr<InspectorObject> breakpoints)
1499 {
1500     m_client->storeSetting(breakpointsSettingKey(), breakpoints->toJSONString());
1501 }
1502 #endif
1503
1504 static Path quadToPath(const FloatQuad& quad)
1505 {
1506     Path quadPath;
1507     quadPath.moveTo(quad.p1());
1508     quadPath.addLineTo(quad.p2());
1509     quadPath.addLineTo(quad.p3());
1510     quadPath.addLineTo(quad.p4());
1511     quadPath.closeSubpath();
1512     return quadPath;
1513 }
1514
1515 static void drawOutlinedQuad(GraphicsContext& context, const FloatQuad& quad, const Color& fillColor)
1516 {
1517     static const int outlineThickness = 2;
1518     static const Color outlineColor(62, 86, 180, 228);
1519
1520     Path quadPath = quadToPath(quad);
1521
1522     // Clip out the quad, then draw with a 2px stroke to get a pixel
1523     // of outline (because inflating a quad is hard)
1524     {
1525         context.save();
1526         context.addPath(quadPath);
1527         context.clipOut(quadPath);
1528
1529         context.addPath(quadPath);
1530         context.setStrokeThickness(outlineThickness);
1531         context.setStrokeColor(outlineColor, ColorSpaceDeviceRGB);
1532         context.strokePath();
1533
1534         context.restore();
1535     }
1536
1537     // Now do the fill
1538     context.addPath(quadPath);
1539     context.setFillColor(fillColor, ColorSpaceDeviceRGB);
1540     context.fillPath();
1541 }
1542
1543 static void drawOutlinedQuadWithClip(GraphicsContext& context, const FloatQuad& quad, const FloatQuad& clipQuad, const Color& fillColor)
1544 {
1545     context.save();
1546     Path clipQuadPath = quadToPath(clipQuad);
1547     context.clipOut(clipQuadPath);
1548     drawOutlinedQuad(context, quad, fillColor);
1549     context.restore();
1550 }
1551
1552 static void drawHighlightForBox(GraphicsContext& context, const FloatQuad& contentQuad, const FloatQuad& paddingQuad, const FloatQuad& borderQuad, const FloatQuad& marginQuad)
1553 {
1554     static const Color contentBoxColor(125, 173, 217, 128);
1555     static const Color paddingBoxColor(125, 173, 217, 160);
1556     static const Color borderBoxColor(125, 173, 217, 192);
1557     static const Color marginBoxColor(125, 173, 217, 228);
1558
1559     if (marginQuad != borderQuad)
1560         drawOutlinedQuadWithClip(context, marginQuad, borderQuad, marginBoxColor);
1561     if (borderQuad != paddingQuad)
1562         drawOutlinedQuadWithClip(context, borderQuad, paddingQuad, borderBoxColor);
1563     if (paddingQuad != contentQuad)
1564         drawOutlinedQuadWithClip(context, paddingQuad, contentQuad, paddingBoxColor);
1565
1566     drawOutlinedQuad(context, contentQuad, contentBoxColor);
1567 }
1568
1569 static void drawHighlightForLineBoxesOrSVGRenderer(GraphicsContext& context, const Vector<FloatQuad>& lineBoxQuads)
1570 {
1571     static const Color lineBoxColor(125, 173, 217, 128);
1572
1573     for (size_t i = 0; i < lineBoxQuads.size(); ++i)
1574         drawOutlinedQuad(context, lineBoxQuads[i], lineBoxColor);
1575 }
1576
1577 static inline void convertFromFrameToMainFrame(Frame* frame, IntRect& rect)
1578 {
1579     rect = frame->page()->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(rect));
1580 }
1581
1582 static inline IntSize frameToMainFrameOffset(Frame* frame)
1583 {
1584     IntPoint mainFramePoint = frame->page()->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(IntPoint()));
1585     return mainFramePoint - IntPoint();
1586 }
1587
1588 void InspectorController::drawNodeHighlight(GraphicsContext& context) const
1589 {
1590     if (!m_highlightedNode)
1591         return;
1592
1593     RenderObject* renderer = m_highlightedNode->renderer();
1594     Frame* containingFrame = m_highlightedNode->document()->frame();
1595     if (!renderer || !containingFrame)
1596         return;
1597
1598     IntSize mainFrameOffset = frameToMainFrameOffset(containingFrame);
1599     IntRect boundingBox = renderer->absoluteBoundingBoxRect(true);
1600     boundingBox.move(mainFrameOffset);
1601
1602     ASSERT(m_inspectedPage);
1603
1604     FrameView* view = m_inspectedPage->mainFrame()->view();
1605     FloatRect overlayRect = view->visibleContentRect();
1606     if (!overlayRect.contains(boundingBox) && !boundingBox.contains(enclosingIntRect(overlayRect)))
1607         overlayRect = view->visibleContentRect();
1608     context.translate(-overlayRect.x(), -overlayRect.y());
1609
1610     // RenderSVGRoot should be highlighted through the isBox() code path, all other SVG elements should just dump their absoluteQuads().
1611 #if ENABLE(SVG)
1612     bool isSVGRenderer = renderer->node() && renderer->node()->isSVGElement() && !renderer->isSVGRoot();
1613 #else
1614     bool isSVGRenderer = false;
1615 #endif
1616
1617     if (renderer->isBox() && !isSVGRenderer) {
1618         RenderBox* renderBox = toRenderBox(renderer);
1619
1620         IntRect contentBox = renderBox->contentBoxRect();
1621
1622         IntRect paddingBox(contentBox.x() - renderBox->paddingLeft(), contentBox.y() - renderBox->paddingTop(),
1623                            contentBox.width() + renderBox->paddingLeft() + renderBox->paddingRight(), contentBox.height() + renderBox->paddingTop() + renderBox->paddingBottom());
1624         IntRect borderBox(paddingBox.x() - renderBox->borderLeft(), paddingBox.y() - renderBox->borderTop(),
1625                           paddingBox.width() + renderBox->borderLeft() + renderBox->borderRight(), paddingBox.height() + renderBox->borderTop() + renderBox->borderBottom());
1626         IntRect marginBox(borderBox.x() - renderBox->marginLeft(), borderBox.y() - renderBox->marginTop(),
1627                           borderBox.width() + renderBox->marginLeft() + renderBox->marginRight(), borderBox.height() + renderBox->marginTop() + renderBox->marginBottom());
1628
1629         FloatQuad absContentQuad = renderBox->localToAbsoluteQuad(FloatRect(contentBox));
1630         FloatQuad absPaddingQuad = renderBox->localToAbsoluteQuad(FloatRect(paddingBox));
1631         FloatQuad absBorderQuad = renderBox->localToAbsoluteQuad(FloatRect(borderBox));
1632         FloatQuad absMarginQuad = renderBox->localToAbsoluteQuad(FloatRect(marginBox));
1633
1634         absContentQuad.move(mainFrameOffset);
1635         absPaddingQuad.move(mainFrameOffset);
1636         absBorderQuad.move(mainFrameOffset);
1637         absMarginQuad.move(mainFrameOffset);
1638
1639         drawHighlightForBox(context, absContentQuad, absPaddingQuad, absBorderQuad, absMarginQuad);
1640     } else if (renderer->isRenderInline() || isSVGRenderer) {
1641         // FIXME: We should show margins/padding/border for inlines.
1642         Vector<FloatQuad> lineBoxQuads;
1643         renderer->absoluteQuads(lineBoxQuads);
1644         for (unsigned i = 0; i < lineBoxQuads.size(); ++i)
1645             lineBoxQuads[i] += mainFrameOffset;
1646
1647         drawHighlightForLineBoxesOrSVGRenderer(context, lineBoxQuads);
1648     }
1649
1650     // Draw node title if necessary.
1651
1652     if (!m_highlightedNode->isElementNode())
1653         return;
1654
1655     WebCore::Settings* settings = containingFrame->settings();
1656     drawElementTitle(context, boundingBox, overlayRect, settings);
1657 }
1658
1659 void InspectorController::drawElementTitle(GraphicsContext& context, const IntRect& boundingBox, const FloatRect& overlayRect, WebCore::Settings* settings) const
1660 {
1661     static const int rectInflatePx = 4;
1662     static const int fontHeightPx = 12;
1663     static const int borderWidthPx = 1;
1664     static const Color tooltipBackgroundColor(255, 255, 194, 255);
1665     static const Color tooltipBorderColor(Color::black);
1666     static const Color tooltipFontColor(Color::black);
1667
1668     Element* element = static_cast<Element*>(m_highlightedNode.get());
1669     bool isXHTML = element->document()->isXHTMLDocument();
1670     String nodeTitle = isXHTML ? element->nodeName() : element->nodeName().lower();
1671     const AtomicString& idValue = element->getIdAttribute();
1672     if (!idValue.isNull() && !idValue.isEmpty()) {
1673         nodeTitle += "#";
1674         nodeTitle += idValue;
1675     }
1676     if (element->hasClass() && element->isStyledElement()) {
1677         const SpaceSplitString& classNamesString = static_cast<StyledElement*>(element)->classNames();
1678         size_t classNameCount = classNamesString.size();
1679         if (classNameCount) {
1680             HashSet<AtomicString> usedClassNames;
1681             for (size_t i = 0; i < classNameCount; ++i) {
1682                 const AtomicString& className = classNamesString[i];
1683                 if (usedClassNames.contains(className))
1684                     continue;
1685                 usedClassNames.add(className);
1686                 nodeTitle += ".";
1687                 nodeTitle += className;
1688             }
1689         }
1690     }
1691     nodeTitle += " [";
1692     nodeTitle += String::number(boundingBox.width());
1693     nodeTitle.append(static_cast<UChar>(0x00D7)); // &times;
1694     nodeTitle += String::number(boundingBox.height());
1695     nodeTitle += "]";
1696
1697     FontDescription desc;
1698     FontFamily family;
1699     family.setFamily(settings->fixedFontFamily());
1700     desc.setFamily(family);
1701     desc.setComputedSize(fontHeightPx);
1702     Font font = Font(desc, 0, 0);
1703     font.update(0);
1704
1705     TextRun nodeTitleRun(nodeTitle);
1706     IntPoint titleBasePoint = boundingBox.bottomLeft();
1707     titleBasePoint.move(rectInflatePx, rectInflatePx);
1708     IntRect titleRect = enclosingIntRect(font.selectionRectForText(nodeTitleRun, titleBasePoint, fontHeightPx));
1709     titleRect.inflate(rectInflatePx);
1710
1711     // The initial offsets needed to compensate for a 1px-thick border stroke (which is not a part of the rectangle).
1712     int dx = -borderWidthPx;
1713     int dy = borderWidthPx;
1714     if (titleRect.right() > overlayRect.right())
1715         dx += overlayRect.right() - titleRect.right();
1716     if (titleRect.x() + dx < overlayRect.x())
1717         dx = overlayRect.x() - titleRect.x();
1718     if (titleRect.bottom() > overlayRect.bottom())
1719         dy += overlayRect.bottom() - titleRect.bottom() - borderWidthPx;
1720     titleRect.move(dx, dy);
1721     context.setStrokeColor(tooltipBorderColor, ColorSpaceDeviceRGB);
1722     context.setStrokeThickness(borderWidthPx);
1723     context.setFillColor(tooltipBackgroundColor, ColorSpaceDeviceRGB);
1724     context.drawRect(titleRect);
1725     context.setFillColor(tooltipFontColor, ColorSpaceDeviceRGB);
1726     context.drawText(font, nodeTitleRun, IntPoint(titleRect.x() + rectInflatePx, titleRect.y() + font.height()));
1727 }
1728
1729 void InspectorController::openInInspectedWindow(const String& url)
1730 {
1731     ResourceRequest request;
1732     FrameLoadRequest frameRequest(request, "_blank");
1733     bool created;
1734     Frame* mainFrame = m_inspectedPage->mainFrame();
1735     WindowFeatures windowFeatures;
1736     Frame* newFrame = WebCore::createWindow(mainFrame, mainFrame, frameRequest, windowFeatures, created);
1737     if (!newFrame)
1738         return;
1739
1740     UserGestureIndicator indicator(DefinitelyProcessingUserGesture);
1741     newFrame->loader()->setOpener(mainFrame);
1742     newFrame->page()->setOpenedByDOM();
1743     newFrame->loader()->changeLocation(newFrame->loader()->completeURL(url), "", false, false);
1744 }
1745
1746 void InspectorController::count(const String& title, unsigned lineNumber, const String& sourceID)
1747 {
1748     String identifier = makeString(title, '@', sourceID, ':', String::number(lineNumber));
1749     HashMap<String, unsigned>::iterator it = m_counts.find(identifier);
1750     int count;
1751     if (it == m_counts.end())
1752         count = 1;
1753     else {
1754         count = it->second + 1;
1755         m_counts.remove(it);
1756     }
1757
1758     m_counts.add(identifier, count);
1759
1760     String message = makeString(title, ": ", String::number(count));
1761     addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lineNumber, sourceID);
1762 }
1763
1764 void InspectorController::startTiming(const String& title)
1765 {
1766     m_times.add(title, currentTime() * 1000);
1767 }
1768
1769 bool InspectorController::stopTiming(const String& title, double& elapsed)
1770 {
1771     HashMap<String, double>::iterator it = m_times.find(title);
1772     if (it == m_times.end())
1773         return false;
1774
1775     double startTime = it->second;
1776     m_times.remove(it);
1777
1778     elapsed = currentTime() * 1000 - startTime;
1779     return true;
1780 }
1781
1782 InjectedScript InspectorController::injectedScriptForNodeId(long id)
1783 {
1784
1785     Frame* frame = 0;
1786     if (id) {
1787         ASSERT(m_domAgent);
1788         Node* node = m_domAgent->nodeForId(id);
1789         if (node) {
1790             Document* document = node->ownerDocument();
1791             if (document)
1792                 frame = document->frame();
1793         }
1794     } else
1795         frame = m_inspectedPage->mainFrame();
1796
1797     if (frame)
1798         return m_injectedScriptHost->injectedScriptFor(mainWorldScriptState(frame));
1799
1800     return InjectedScript();
1801 }
1802
1803 void InspectorController::addScriptToEvaluateOnLoad(const String& source)
1804 {
1805     m_scriptsToEvaluateOnLoad.append(source);
1806 }
1807
1808 void InspectorController::removeAllScriptsToEvaluateOnLoad()
1809 {
1810     m_scriptsToEvaluateOnLoad.clear();
1811 }
1812
1813 void InspectorController::setInspectorExtensionAPI(const String& source)
1814 {
1815     m_inspectorExtensionAPI = source;
1816 }
1817
1818 void InspectorController::reloadPage()
1819 {
1820     // FIXME: Why do we set the user gesture indicator here?
1821     UserGestureIndicator indicator(DefinitelyProcessingUserGesture);
1822     m_inspectedPage->mainFrame()->navigationScheduler()->scheduleRefresh();
1823 }
1824
1825 } // namespace WebCore
1826
1827 #endif // ENABLE(INSPECTOR)